一篇总结Java链表(单链表、循环链表和双向链表)

什么是Java链表?链表,是Java中的一种重要的链式数据结构。
众所周知,我们日常用手机电脑收发信息,下载视频和软件,都要进行数据的传输。这些数据都要以一种特定的数据结构来进行传输和存储,否则数据将会是一串毫无意义的0和1,无法生成我们想要的文件。一般来说有两种最常见的基本数据结构,一种是线性结构的数组,一种是链式结构的链表。有关数组的内容会在另一篇文章中介绍,这里我们主要来介绍一下链表的内容。
链表
链表(Linked list)是一种线性表,但是并不会按线性的顺序存储数据,而是在每一个节点里存到下一个节点的地址。所谓链表,在存储器中不是一条连续的数据段,而是一群通过指针首尾相连的数据节点的集合。每一个节点包含一部分数据,并且包含指向其他节点的指针。通过这些指针,这些存储在不同物理位置的、包含数据的节点连在了一起,形成了一个像是锁链一样的链表。相比而言,链表是比数组更加方便的数据结构。这主要体现在链表和数组的数据增加和删除方面。当增加或删除数据时,数组需要将特定数据增删后创建一个新的数组,并将修改后的数组复制进去;而链表则只需要改动需要增删的数据的前后指针就可以实现数据的修改,不需要变动整个链表。可以看看下面这个图,说明了两者的区别。

节点
上面我们说过,链表是由一连串的节点构成的,而节点是由数据和指针构成的。通过指针的变化和连接,可以将众多的节点串联起来,并且可以形成很多不同类型的链表。常见的链表有单链表,循环链表,双向链表和双向循环链表。

单链表
单链表是较为简单的链表,单链表的指针指向同一方向的下一个元素。在单链表中,有两个特殊的节点,头节点和尾节点。头节点(也叫根节点)是单链表中的第一个节点,是单链表中的关键节点。通过头节点,我们可以将指针指向头节点,遍历整个单链表,来实现增删改查等操作。这样操作可以防止链表为空(链表若为空,则头节点指针域为null),并且可以保持对单链表操作的统一性(从头节点开始遍历),简化操作减少bug。尾节点是单链表中的最后一个节点,它的指针指向一个空的地址null(没有下一个节点了)。在单链表的操作中,我们可以通过定义尾节点的指针来实现不同的方法。

循环链表
循环链表的结构与单链表类似,不同之处在于单链表的尾节点指向一个null空地址,而循环链表的尾节点指针指向了头节点。这样,就形成了一个首尾相连的环形结构的链表。循环链表适合用来处理环形结构的数据。

双向链表
双向链表是一种可以双向遍历的链表,它的指针可以指向前后两个方向的节点。双向链表拥有头节点和尾节点,可以从头节点进入链表进行操作。与单链表不同的是,双向链表拥有两个指针地址,多了一个指向前一节点的引用地址。双向链表的优点是,在操作链表中的上一节点时可以通过前指针直接向前遍历,而无需从头节点开始重新遍历,提高了链表的效率。其缺点是比单链表结构多了一个指针地址,会占用更多的内存来进行存储。

双向循环链表
双向循环链表是循环链表与双向链表的结合,每个节点拥有前后指针,并且尾节点指向头节点形成循环。可以用来灵活处理环形结构的数据。

单链表的代码实现
在了解了单链表的原理后,我们来通过代码实现单链表的增删改查功能,以及反转链表和输出链表。
创建链表类及节点
在单链表中,我们首先要定义链表中最基础的节点元素。如上图所示,节点中包括两个属性,指针next和数据data。同时,我们可以在创建时定义链表的头节点、尾节点和链表长度。

public class LinkList {public Node root = null; //定义头节点,默认为空public Node tail;  //定义尾节点public int length; //定义链表长度public class Node{ //声明节点类public int data; //定义数据对象public Node next = null; //定义指针,默认为空public Node(int data) {this.data = data; } //重写构造方法,初始化节点
}

添加节点
实现添加节点功能,我们主要有两种思路:头部添加和尾部添加。两种处理方式大同小异,但最终生成的链表顺序会不同。首先要排除头节点为空的情况,然后基于头节点来进行数据的添加。
尾部添加
尾部添加/顺序插入/有头插入都是同一个功能,是指将链表中插入的第一个元素设置为头节点,并且将之后添加的元素依次置于头节点之后,形成一个正顺序的链表。插入的第一个节点为头节点,新插入的节点为尾节点。如下图所示,1、2、3分别是插入节点的次序。

代码实现如下。

public void addTail(int x){Node newNode = new Node(x); //定义新节点if (root == null){ //若头节点为空,则头节点为新节点root = newNode;tail = newNode;}else{tail.next = newNode;//新节点指向尾节点后续tail = newNode;}length++;//顺手统计一下链表长度……
}

头部添加
与尾部添加相反,头部添加是每次添加新数据时将新添加的数据作为头部节点,使得新节点一直处于链表头部。通过头部添加的链表,生成的数据是逆序的。下图是添加的逻辑。

代码实现如下。

public void addHead(int x){Node newNode = new Node(x);if (root == null){root = newNode;}else{newNode.next = root;// 将新节点的指针指向头节点root = newNode; //将新数据赋给头节点}   length++;
}

获取链表长度
在添加节点方法时,我们已经递增length变量得到了链表的长度,但我们还需要定义一个方法来获得链表的长度。

public int getLength(){return length;}

删除节点
删除节点的逻辑:将待删除节点的前一节点的指针指向待删除节点的后一节点,跳过当前待删除节点,使其自动被内存回收,实现节点删除。看图。

接下来我们用代码来实现。实现删除时要考虑到删除头节点的情况,可以直接将头节点指向下一节点来跳过头节点并返回来删除它。代码如下。

public boolean delete(int x){if(x<0||x>length-1){//排除不合法删除System.out.println("删除错误,超出链表范围");return false;}if(x == 0){//删除头节点时,头节点指向下一节点root = root.next;length--;return true;}Node preNode = root;//指定头节点为前节点Node curNode = preNode.next;//声明当前待删除节点int i = 1;while (curNode != null) {if (i == x) {//寻找待删除节点,遍历直到i=输入值preNode.next = curNode.next; //待删除节点的前节点指向后节点length--;//链表长度-1}preNode = preNode.next;//当前节点和前节点同时后移curNode = curNode.next;i++;}return true;
}

根据下标查找节点
使用for循环遍历链表,直到指定位置后停止循环,输出当前节点的数据。

public int searchByOrder(int x){Node curNode = root;if(x<0 || x>length){System.out.println("输入错误,超出链表限值");return 000;}for (int i=1;i<=x-1;i++){curNode = curNode.next;}return curNode.data;
}

根据内容查找节点
使用while循环遍历链表,找到相同内容的节点后返回true,表示链表中存在该数据。

public boolean searchByContent(int x){Node curNode = root;while (curNode != null) {if (curNode.data == x) {return true; //数据相同时返回true} else {curNode = curNode.next; //否则继续寻找}}return false; //要注意在while循环外返回false
}

查询具体数据在链表中的节点数量
与上一个方法相似,在while循环遍历中增加了一个变量,在找到指定内容时作为统计数据返回。并且继续遍历,直到遍历完整个链表为止。

public int SearchAndCount(int x){Node curNode = root;int i = 0;//统计节点数量while (curNode != null){if(curNode.data == x){i++;//符合条件的节点+1curNode = curNode.next;//继续循环}else{curNode = curNode.next;如果不符合也要循环}}return i;//将统计值返回
}

反转链表
链表反转的主要逻辑是将指针反转并将节点后移,遍历后实现反转。需要注意的是,在反转指针前需要保存下一节点,以免指针反转后指空。代码如下。

public void reverse() {Node curNode = root;Node preNode = null;while (curNode != null){Node nextNode = curNode.next; //保存下一节点curNode.next = preNode;//指针反转preNode = curNode; //前节点后移curNode = nextNode;//现节点后移}root = preNode;
}

打印链表
链表打印就比较简单了,将链表从头遍历并打印出来。

public void printLink(){Node curNode = root;while (curNode != null){System.out.print(curNode.data+" ");curNode = curNode.next;}System.out.println();
}

双向链表和循环链表的代码实现与单链表有些不同,但我懒得写了……过段时间再更新吧~

一篇讲完Java链表(单链表、循环链表和双向链表)相关推荐

  1. 一篇讲完Java异常及处理

    目录 什么是异常? java是如何处理异常的? 异常的体系结构: 异常的产生和处理: 异常的处理: throwable类中定义了三个查看异常的方法: finally代码块: 什么是异常? 异常是指在程 ...

  2. java实现单链表常见操作,java面试题,java初级笔试题

    写在最前面,我总结出了很多互联网公司的面试题及答案,并整理成了文档,以及各种学习的进阶学习资料,免费分享给大家.扫码加微信好友进[程序员面试学习交流群],免费领取.也欢迎各位一起在群里探讨技术. 一. ...

  3. 链表的基本概念以及java实现单链表-循环链表-双向链表

    前言 线性结构是非常简单且常用的数据结构,而线性表则是一种非常典型的线性结构. 线性表定义 线性表的数据结构 链表 单链表 单链表的定义 单链表的插入和删除 单链表的遍历,清空,判空,获取指定结点 循 ...

  4. java单链表通讯录_[Java教程]用java实现单链表(菜鸟出征)

    [Java教程]用java实现单链表(菜鸟出征) 0 2016-03-24 14:00:06 package code;class Node{ Node next; int data; public ...

  5. java实现单链表的建立(头插法和尾插法)

    单链表 单链表(Single Linked List): 单链表是一种链式存取的数据结构,用一组地址任意(可能连续,也可能不连续)的存储单元存放线性表中的数据元素. 链表中的数据是以结点来表示的,每个 ...

  6. 数据结构之链表--单链表

    Hello,大家好!好久不见了,之前一直在忙于一些琐事,最近半个月内会将数据结构的各种数据结构实现出来,一个挺有意思的东西. 这次我将要介绍的是链表.链表有单链表,单向循环链表,双向链表,双向循环链表 ...

  7. 建立单链表 单链表的插入_单链列表插入

    建立单链表 单链表的插入 All possible cases: 所有可能的情况: Inserting at beginning 开始插入 Inserting at the ending 在末尾插入 ...

  8. 数据结构上机-尾、头插法建立单链表-单链表遍历C语言完整代码实现

    点击此处跳转视频链接:数据结构上机-尾.头插法建立单链表-单链表遍历C语言完整代码实现

  9. Java基础-->一篇讲全Java常用类(详细易懂,建议收藏)

    Java基础–>一篇讲全Java常用类(详细易懂,建议收藏) 文章目录 Java基础-->一篇讲全Java常用类(详细易懂,建议收藏) 1.字符串相关的类 String类 概述 创建Str ...

  10. Java实现单链表反转操作

    单链表是一种常见的数据结构,由一个个节点通过指针方式连接而成,每个节点由两部分组成:一是数据域,用于存储节点数据.二是指针域,用于存储下一个节点的地址.在Java中定义如下: public class ...

最新文章

  1. 利用BP神经网络教计算机识别语音特征信号(代码部分SS)
  2. java抽象类关键字_Java之关键字abstract(抽象类与抽象方法)
  3. CTO 写的低级 Bug 再致网站被黑,CEO 的号都被盗了!
  4. 洛克人红色思考型机器人叫什么_稻船敬二新企划《红色灰烬》 依然是机器人风格...
  5. 经常被问到的十个 Java 面试题?你Get了吗?
  6. 推荐系统和搜索引擎的关系
  7. CuteChat for Community Server 2.0 beta 3!
  8. sqlite字段类型说明
  9. 微软紧急修复FIP-FS中的 “Year 2022” 漏洞
  10. 打印Activity任务栈脚本:adb shell dumpsys activity
  11. android技术服务,Android Service学习之本地服务
  12. ad怎么导入cad的外形尺寸_CAD文件导入AD09
  13. vfp报表纸张设置_vfp教程之Visual Foxpro生成任意打印字段报表的实现
  14. DirectX11 SDK 下载地址
  15. 连接服务器显示句柄无效,win10打印机句柄无效怎么解决?_网站服务器运行维护,win10,打印机,句柄无效...
  16. 使用python进行数据清洗常用的库_用于格式化和数据清理的便捷Python库
  17. 19、L298N 电机驱动板
  18. ubuntu远程访问win7登录后语言为繁体字的解决办法
  19. c语言零基础入门(经验总结)
  20. 最大似然函数及其求解

热门文章

  1. 解决:Please either set ERLANG_HOME to point to your Erlang installation or place the RabbitMQ server d
  2. 关于min max 函数凹凸性,以及报童模型中期望库存,期望缺货量的性质
  3. 这些solidworks工程图模板知识你都知道吗?
  4. 沙龙回顾|你pick的程序小哥可以C位出道了吗?(内含PPT和演讲稿福利哦!)...
  5. 罗技 连点 脚本_拳头与罗技G展开合作 将推出《英雄联盟》主题外设--新闻中心...
  6. logback简介及引入方法
  7. flask +layUI+ ajax 上传图片
  8. HDR中HLG与PQ曲线的互转
  9. PHP:解析url和查询参数query
  10. 基于单片机设计的遥控数字音量控制D类功率放大器设计