单链表的简介与实现(Java)

news2024/9/20 18:38:06

一、前言

线性结构的链式存储是用若干地址分散的存储单元存储数据元素,逻辑上相邻的两个数据元素在物理位置上并不一定相邻,必须采用附加信息来表示数据元素之间的顺序关系。因此存储一个数据元素的数据单元至少包含两部分------数据域和地址域

 

上述的结构通常称为结点

一个节点表示一个数据元素,通常节点当中的地址会把数据结点连接起来,节点当中的连接关系体现了线性表当中数据元素间的顺序关系,采用这种关系的称为线性链表

从上图当中,head是线性链表当中的第一个节点,但是这个节点在数据域当中并没有存储数据,这里之所以写这个的目的是我们能够通过头指针去遍历我们整个链表。

最后一个节点的地址域为空,表示其后不再有节点。每个结点只有一个地址域的链表称为单链表

单链表:该地址域通常指向候机节点; 每个节点有两个地址域的线性表称为双链表

双链表:两个地址域分别指向前驱节点和后继节点。

二、单链表的实现

 定义单链表的节点

value表示当前节点的值,next表示指向下个节点的地址

public class ListNode {

    int value;
    ListNode next;

    public ListNode(int value){
        this.value = value;
    }
}

 头插法和尾插法

创建一个链表类,定义头节点

public class LinkList {

    ListNode head = null;
}

头插法

public  void HeadInsert(int val) {
		//每次执行这个方法的时候,都要新建路一个节点用来存储数据、
		ListNode listNode = new ListNode(val);
		//判断头特点是否为空,如果是那么将头结点指向新的节点,然后结束
		if (head == null) {
			head = listNode;
			return;
		}
		
		listNode.next = head;
		head= listNode;
	}

尾插法

public  void EndInsert(int val) {
		//每次执行这个方法的时候,都要新建路一个节点用来存储数据、
		ListNode listNode = new ListNode(val);
		//判断头特点是否为空,如果是那么将头结点指向新的节点,然后结束
		if (head == null) {
			head = listNode;
			return;
		}
		
		//定义一个临时结点由他的充当指针,指针最开始指向头节点
		ListNode indexNode = listNode;
		//从头结点可是遍历,到最尾部插入
		while (indexNode.next != null) {
			indexNode = indexNode.next;
			
		}
		indexNode.next = listNode;
	}

遍历链表

输出链表每个节点的值

public void printLink() {
		//定义一个临时结点充当指针,从头结点喀什不断想向后移动
		ListNode tempListNode = head;
		
		//将临时结点不断的往后边移动,直到临时结点指向了 null;
		while (tempListNode  !=null) {
			System.out.print(tempListNode.val);
			tempListNode = tempListNode.next;
		}
		System.out.println();
	}

输出链表长度

public int getLenght() {
		//定义一个节点指向该链表
		ListNode tempListNode = head;
		int length = 0;
		while (tempListNode != null) {
			length ++;
			tempListNode = tempListNode.next;
		}
		
		return length;
	}	

链表反转

假设我们准备1-》2-》3-》4

准备两个空结点 pre用来保存先前结点、next用来做临时变量

在头结点node遍历的时候此时为1结点

next = 1结点.next(2结点)

1结点.next=pre(null)

pre = 1结点

node = 2结点

进行下一次循环node=2结点

next = 2结点.next(3结点)

2结点.next=pre(1结点)=>即完成2->1

pre = 2结点

node = 3结点

进行循环…

public void reverseList(LinkList list){
        ListNode pre = null;
        ListNode next = null;
        while (list.head != null){
            next = head.next;
            head.next = pre;
            pre = head;
            head = next;
        }
        head = pre;
    }

判断链表是否成环

如果一个链表中有环,也就是说用一个指针去遍历,是永远走不到头的。因此,我们可以用两个指针去遍历,一个指针一次走两步, 一个指针一次走一步,如果有环,两个指针肯定会在环中相遇。时间复杂度为O(n)。

public boolean ring(LinkList list){
        ListNode fastNode = list.head;
        ListNode slowNode = list.head;
        while (fastNode != null && fastNode.next != null){
            fastNode = fastNode.next.next;
            slowNode = slowNode.next;
            if (fastNode == slowNode){
                return true;
            }
        }
        return false;
    }

获取链表的后K个节点

使用两个指针,先让前面的指针走到正向第k个结点,这样前后两个指针的距离差是k-1,  之后前后两个指针一起向前走,前面的指针走到最后一个结点时,后面指针所指就是后K个结点

public void kList(LinkList list,int k){
        if (k > list.getLength(list)) throw new RuntimeException("k值超出链表长度");
        ListNode aHead = list.head;
        ListNode bHead = list.head;
        while (aHead != null && k >= 1){
            aHead = aHead.next;
            k--;
        }
        while (aHead != null){
            aHead = aHead.next;
            bHead = bHead.next;
        }
        list.head = bHead;
    }

三、测试

写一个测试类

public class LinkTest {
    public static void main(String[] args) {
        LinkList list1 = new LinkList();
        list1.endInsert(1);
        list1.endInsert(2);
        list1.headInsert(0);
        System.out.println(list1.getLength(list1));
        list1.printLink(list1);
        System.out.println("reverseList");
        list1.reverseList(list1);
        list1.printLink(list1);
        list1.kList(list1,2);
        System.out.println(list1.ring(list1));
    }
}

运行测试

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/698246.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

java简易计算器的设计

简易计算器的设计 1.1实训内容 模仿Windows自带的标准版计算器,设计并用Java语言实现简易的计算器(根据自己的能力,可以适当地增加或删除部分功能)。 最低要求: 计算器运行界面如下图所示,包含二个文本框…

Android Binder通信原理(七):java 下的C-S

源码基于:Android R 0. 前言 在之前的几篇博文中,对Android binder 的通信原理进行的深入的剖析,这些博文包括:binder 简介、servicemanager启动、service注册、service获取、Java 端的service 注册和获取。 在前一文中&#xf…

PostgreSQL处理JSON数据

源:https://blog.csdn.net/c_zyer/article/details/130968257?ops_request_misc&request_id&biz_id102&utm_termPostgreSQL%20%E7%9A%84JSON%20%E5%A4%84%E7%90%86&utm_mediumdistribute.pc_search_result.none-task-blog-2allsobaiduweb~default-…

pgsql:纵列字段转为横列字段

问题: 想要将查询出来的数据纵列字段转为横列字段。如以下是24小时内每个小时的数据表: SELECT deviceid,press_avg, hh FROM site_data 想要转换后的效果如下,将24小时内所有数据横向展示: 解决方案: 实现的sql查询…

Spring事务的介绍和使用

目录 一、Spring事务作用 二、代码实现 三、Spring事务相关配置 1、事务配置 2、事务传播行为 一、Spring事务作用 事务作用:在数据层保障一系列的数据库操作同成功同失败 Spring事务作用:在数据层或业务层保障一系列的数据库操作同成功同失败 二、…

分散输入和集中输出(Scatter-Gather I/O):readv()和writev()

readv()和writev()系统调用分别实现了分散输入和集中输出的功能。 NAMEreadv, writev, preadv, pwritev - read or write data into multiple buffersSYNOPSIS#include <sys/uio.h>ssize_t readv(int fd, const struct iovec *iov, int iovcnt);ssize_t writev(int fd, c…

蓝桥杯专题-试题版-【数字游戏】【城市建设】【最大子阵】【蚂蚁感冒】

点击跳转专栏>Unity3D特效百例点击跳转专栏>案例项目实战源码点击跳转专栏>游戏脚本-辅助自动化点击跳转专栏>Android控件全解手册点击跳转专栏>Scratch编程案例点击跳转>软考全系列点击跳转>蓝桥系列 &#x1f449;关于作者 专注于Android/Unity和各种游…

数字人解决方案——基于真人视频的三维重建数字人源码与训练方法

前言 1.真人视频三维重建数字人源码是基于NeRF改进的RAD-NeRF&#xff0c;NeRF&#xff08;Neural Radiance Fields&#xff09;是最早在2020年ECCV会议上的Best Paper&#xff0c;其将隐式表达推上了一个新的高度&#xff0c;仅用 2D 的 posed images 作为监督&#xff0c;即…

MongoDB存储引擎

1、前言 存储引擎是数据库的组成部分&#xff0c;负责管理数据存储。 MongoDB支持的以下存储引擎&#xff1a; 存储引擎 描述 WiredTiger存储引擎 从MongoDB 3.2开始默认的存储引擎&#xff0c;新的版本MongoDB推荐使用WiredTiger存储引擎。 MMAPv1存储引擎 MMAPv1是Mon…

微信小程序使用vant组件样式未生效解决办法

1.删除小程序自带的样式 首先在app.json里面删除这一行 2.清除缓存 重新编译 3.重新构建npm 重新编译 在工具里面

nginx之rewrite

一、Rewrite跳转的场景二、Rewrite跳转实现三、Rewrite实际场景四、常用的 Nginx 正则表达式五、Rewrite命令、语法格式六、location的分类七、location的优先级八、rewrite与location的区别九、rewrite示例9.1 基于域名的跳转9.2 基于客户端 IP 访问跳转9.3 基于旧域名跳转到新…

chatgpt赋能python:Python迭代运算:概述、应用及效果分析

Python迭代运算&#xff1a;概述、应用及效果分析 在Python编程领域中&#xff0c;迭代运算是一项基础性操作。它不仅适用于循环遍历数据&#xff0c;还支持函数式编程中的高阶函数应用&#xff08;例如map、filter等&#xff09;。本文将从多个方面探讨Python迭代运算的应用和…

高性能计算开发软件培训班-选猿代码科技IT培训机构!

学习CPU并行程序性能优化的意义&#xff1a; 学习CPU计算是现代计算机科学中不可或缺的一部分。掌握CPU计算原理和应用&#xff0c;能够提高我们的编程技能和解决问题的能力&#xff0c;帮助我们更好地应对计算机科学领域中的挑战和机遇。此外&#xff0c;CPU计算在计算机体系结…

python写路径时候的问题————转载ningqingzy的文章

作为笔记总结学习&#xff0c;如有侵权&#xff0c;立马删除。 总结有三种方法&#xff1a; 更换为绝对路径的写法&#xff1a;func1(“C:\Users\renyc”)显式声明字符串不用转义&#xff08;加r&#xff09;&#xff1a;func1(r"C:\Users\renyc")使用Linux的路径&a…

workbench 链接mysql 报错 authentication plugin caching_sha2_password

用workbench连接MySQL出现Authentication plugin ‘caching_sha2_password’ cannot be loaded的问题&#xff0c;如下图 原因 出现这个问题的原因是由于Navicat和MySQL的版本问题&#xff0c; mysql8 之前&#xff0c;加密规则是mysql_native_password&#xff1b; mysql8 之后…

leetcode97. 交错字符串(动态规划-java)

交错字符串 leetcode97. 交错字符串题目描述解题思路代码演示&#xff1a; 动态规划加状态压缩代码演示 动态规划专题 leetcode97. 交错字符串 来源&#xff1a;力扣&#xff08;LeetCode&#xff09; 链接&#xff1a;https://leetcode.cn/problems/interleaving-string 题目描…

线性代数高级--矩阵的秩--SVD分解定义--SVD分解的应用

目录 矩阵的秩 概念 k阶子式 矩阵的秩的定义 矩阵的秩的性质 SVD分解 概念 注意 SVD的分解过程 SVD分解的应用 矩阵的秩 概念 矩阵的秩是线性代数中的一个重要概念&#xff0c;用于描述矩阵的行&#xff08;或列&#xff09;向量的线性无关程度。矩阵的秩可以通过…

chatgpt赋能python:Python遍历0到100的使用场景及方法

Python遍历0到100的使用场景及方法 Python是一种简洁、高效的脚本语言&#xff0c;广泛用于各种领域的开发。本文介绍Python遍历0到100的使用场景以及方法&#xff0c;旨在帮助读者更加了解Python的强大之处。 遍历0到100的背景和意义 遍历0到100是一种常见的问题&#xff0…

网络安全合规-银行业数据治理架构体系搭建(一)

为引导银行业金融机构加强数据治理&#xff0c;充分发挥数据价值&#xff0c;全面向高质量发展转变&#xff0c;银监会于2018年发布了《银行业金融机构数据治理指引》&#xff0c;主要内容如下&#xff1a; 近年来银行业金融机构在业务快速发展过程中&#xff0c;积累了客户数…

JavaScript 手写代码 第六期(重写数组方法三) 用于遍历的方法

文章目录 1. 为什么要手写代码&#xff1f;2. 手写代码2.1 forEach2.1.1 基本使用2.1.2 手写实现 2.2 map2.2.1 基本使用2.2.2 手写实现 2.3 filter2.3.1 基本使用2.3.2 手写实现 2.4 every2.4.1 基本使用2.4.2 手写实现 2.5 some2.5.1 基本使用2.5.2 手写实现 2.6 reduce2.6.1…