单链表

数组和链表都是线性的数据存储结构的基础,栈和队列都是线性存储结构的应用。

众所周知,数组是一种连续的存储线性结构,元素的类型是相同的,大小相等。但是数组的存取速度快。不过好像数组的有点好像就只有这个,相反,数组的缺点就是一大摞:数组不能改变初始化后的大小插入和删除元素效率低下,而且需要预先分配一定量的连续的内存。相比之下,链表是离散存储线性结构。每个单链表节点都只有两个指针(数据指针、下个节点的地址指针),彼此通过指针相连。。单链表的这些特性就决定了它不受磁盘空间限制插入删除元素效率较高,唯一的缺点就是读写很慢。

  • 单链表的首节点没有前驱节点,尾节点没有后续节点,首节点储存着下个节点的地址,下个节点也存储着下个节点的地址,依次类推,尾节点的下个节点地址为空。(详细可见下图)

基本操作

  • 惯例,先创建一个节点类,并定义数据域和指针域:
/*** 节点* @author huaian**/
public class Node {// node dataint data;// next node Node nextNode;// 构造函数public Node(int data) {super();this.data = data;}
}
  • 单链表的基本操作有以下这几种:
方法名 描述
append() 向链表的尾节点添加一个节点
getData() 取出当前节点数据的值
isLast() 判断是否是最后一个节点
remove(int index) 删除指定索引的节点(index >= 1)
1)追加节点
  • 向链表的尾节点添加一个节点
    – ① 先用最简单的方法来追加节点,简单到直接贴代码(为了方便操作,多谢一个 next() 方法来获取下一个节点):
/*** 在末尾添加节点* @param node 待添加节点*/
public void append(Node node) {this.nextNode = node;
}/*** 获取下一个节点* @return 下一个节点*/
public Node next() {return this.nextNode;
}

– ② 追加节点的功能已经写完,现在调用一下:

// 创建一个节点
Node node01 = new Node(1);
// 追加节点 4 5 6
node01.append(new Node(4));
node01.next().append(new Node(5));
node01.next().next().append(new Node(6));

– ③通过上述代码我们可以看到,每次追加代码只能用过调用 next() 来获取下一个节点,非常麻烦。能不能 append() 自行判断下个节点是否为最后一个节点,上层调用只管追加就行?那肯定是可以,于是改了一下以上代码,见下:

/*** 追加节点* @param node 待添加的node*/
public void append(Node node) {// 获取当前节点Node currentNode = this;while (true) {// 获取下一个节点Node nextNode = currentNode.nextNode;// 判断是否是最后一个节点if (nextNode == null) {break;}currentNode = nextNode;}// 添加节点currentNode.nextNode = node;
}

– ④ 这样修改之后就可以这样添加元素,上层调用就只管 append ,无需获取下一个节点再添加节点。于是乎调用就变成了这样:

// 向 node01 添加元素
node01.append(new Node(4));
node01.append(new Node(5));
node01.append(new Node(6));

– ⑤ 其实我们还可以再改一下,使得可以链式调用 append(),把 append() 返回当前节点便可:

/*** 追加节点* @param node 待添加的node*/
public Node append(Node node) {// 获取当前节点Node currentNode = this;while (true) {// 获取下一个节点Node nextNode = currentNode.nextNode;// 判断是否是最后一个节点if (nextNode == null) {break;}currentNode = nextNode;}// 添加节点currentNode.nextNode = node;return this;
}

– ⑥ 链式调用如下:

// 链式调用
node01.append(new Node(4)).append(new Node(5)).append(new Node(6));
  • 那么,单链表添加节点的功能到这里就完成了。
2)获取数据
  • 这个功能也比较简单,只需要把当前的数据域的值返回便可,这里就不累赘了,直接贴代码:
/*** 获取当前节点的数据* @return*/
public int getData() {return this.data;
}
3)判断是否是最后一个节点
  • 这个功能也比较简单,只需要判断当前的节点的指针域是否为空便可,这里就不累赘了,直接贴代码:
/*** 判断当前节点是否为空* @return */
public boolean isLast() {return nextNode == null;
}
4)删除某一节点

这个功能就有点绕了,成功的把自己也给绕进去了。不过还好憋出来了。

  • 删除某一节点,核心思想就是:把存储当前节点的指针域,改为存储当前节点的下一个节点便可。
  • 主要的难点是:因为单链表,当前节点只有下一个节点的指针域,无法获取前一个节点的信息。
  • 实现思路:
    – ① 获取当前链表和该链表的长度
    – ② 找到待删除索引的下标的节点 current 的前一个节点 prev
    – ③ 把 prev 的指针域链到 current 的下一个节点
    – ④ 添加相关的有效性检查
  • 代码实现:
/*** 删除指定索引下标的元素* @param index 索引* @return 新的链表*/
public Node remove(int index) {Node headNode = this;Node currentNode = headNode;Node preNode = null;// 索引越界或者当前节点不存在则抛出异常if (index > size || index <= 0) {throw new IndexOutOfBoundsException(index);}int count = 1;// 找到待删除节点的前一个节点while (!currentNode.isLast() && count < index) {preNode = currentNode;currentNode = currentNode.nextNode;count++;}if (preNode == null && index == count) {headNode = currentNode.nextNode;} else {preNode.nextNode = currentNode.nextNode;}size--;return headNode;
}

完整代码

因为代码是演进的,可能在某个功能会出现阅读困难的问题,在这里贴上完整代码,方便查阅。

  • 完整代码:
/*** 节点* * @author huaian**/
public class Node {// node dataint data;// next nodeNode nextNode;// node sizeint size;public Node() {super();size = 0;}public Node(int data) {super();this.data = data;size++;}/*** 追加节点* * @param node 待添加的node*/public Node append(Node node) {// 获取当前节点Node currentNode = this;while (true) {// 获取下一个节点Node nextNode = currentNode.nextNode;// 判断是否是最后一个节点if (nextNode == null) {break;}currentNode = nextNode;}// 添加节点currentNode.nextNode = node;size++;return this;}/*** 删除指定索引下标的元素* @param index 索引* @return 新的链表*/public Node remove(int index) {Node headNode = this;Node currentNode = headNode;Node preNode = null;// 索引越界或者当前节点不存在则抛出异常if (index > size || index <= 0) {throw new IndexOutOfBoundsException(index);}int count = 1;// 找到待删除节点的前一个节点while (!currentNode.isLast() && count < index) {preNode = currentNode;currentNode = currentNode.nextNode;count++;}if (preNode == null && index == count) {headNode = currentNode.nextNode;} else {preNode.nextNode = currentNode.nextNode;}size--;return headNode;}/*** 获取下一个节点* * @return 下一个节点*/public Node next() {return this.nextNode;}/*** 获取当前节点的数据* * @return 节点数据*/public int getData() {return this.data;}/*** 判断当前节点是否是最后一个节点* * @return 是否为最后一个节点*/public boolean isLast() {return nextNode == null;}/*** 链表节点数* * @return 节点数*/public int size() {return size;}/*** 判空* * @return 是否为空链表*/public boolean isEmpty() {return size == 0;}
}

总结

  • 其实链表在数据结构的内容中还是占有很大的比重的,但是关乎于指针的东西还是比较复制,不过幸好我们用的是 Java 语言,在 C 语言中,实现上述代码,还是要有一定的理解能力的。有人说 Java 的数据结构是没有灵魂的(其实是我说的)。因为 Java 没有指针,C/C++ 才有指针。数据结构学的是思想,锻炼的是思维,与语言的关系不大,所以关于语言这一块,可以按照个人喜好来选择。

  • 本来这篇文章还要憋很久才能出来,但是!!!今天(20190922)情况特殊,打个篮球还把脚给崴了,得去敷药,今天就写到这吧。后续会慢慢补上。
  • 20190923 更,下课回来继续补充,不知道是怎么滴,浑身痛,躺了两个小时还是爬起来写,结果 remove 有点绕,结果把自己给绕进去了。后面问了下同学,捋了一下思路,还是憋出来了。

觉得不错,请留下你们的赞。谢谢。如果有任何问题可以,私信我,欢迎学习交流。
  • 惯例放一下座右铭:
    人若无名,专心练剑!

Java 数据结构 --- 单链表相关推荐

  1. java数据结构 - 单链表(腾讯面试题实现单链表反转)

    直接上实现代码 //单链表的反转public static void reverseList(HeroNode head){//如果当前链表为空,或只有一个节点,无需反转if (head.next = ...

  2. Java数据结构之链表(单链表)

    文章目录 一.链表 概念 结构 二.无头单链表 图解 代码实现 特点 三.带头单链表 为何引入带头单链表 代码实现 注意 提示:以下是本篇文章正文内容,Java系列学习将会持续更新 一.链表 概念 链 ...

  3. 20175330 数据结构-单链表(选做)

    要求 参见附件,补充MyList.java的内容,提交运行结果截图(全屏) 课下推送代码到码云 ``` public class MyList {     public static void mai ...

  4. php链表和联表的区别,PHP_浅谈PHP链表数据结构(单链表),链表:是一个有序的列表,但 - phpStudy...

    浅谈PHP链表数据结构(单链表) 链表:是一个有序的列表,但是它在内存中是分散存储的,使用链表可以解决类似约瑟夫问题,排序问题,搜索问题,广义表 单向链表,双向链表,环形链表 PHP的底层是C,当一个 ...

  5. php mysql 链表_浅谈PHP链表数据结构(单链表)

    链表:是一个有序的列表,但是它在内存中是分散存储的,使用链表可以解决类似约瑟夫问题,排序问题,搜索问题,广义表 单向链表,双向链表,环形链表 PHP的底层是C,当一个程序运行时,内存分成五个区(堆区, ...

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

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

  7. 数据结构——单链表的C++实现

    数据结构--单链表的C++实现 \qquad单链表的创建.求长度.查找.插入和删除的C++实现. #include<iostream> using namespace std;//1.定义 ...

  8. python 单链表是否有回路_(Python3)数据结构--单链表之判断链表是否有环

    前言 有Python基础 有数据结构单链表基础,没接触过的可以看下面链接 https://blog.csdn.net/sf9898/article/details/104946291 原理和实现 有一 ...

  9. 数据结构 —— 单链表(超详细图解 接口函数实现)

    系列文章目录 数据结构 -- 顺序表 数据结构 -- 单链表 数据结构 -- 双向链表 数据结构 -- 队列 数据结构 -- 栈 数据结构 -- 堆 数据结构 -- 二叉树 数据结构 -- 八大排序 ...

  10. C语言数据结构单链表链表

    数据结构–单链表 学习了顺序表,我们发现顺序表在向里面存放数据的时候很麻烦,比如我们要使用头插法存放一个数据到顺序表的时候,我们要将整个表都向后挪一位,这个操作就让人很难受.那么有没有一种结构可以让我 ...

最新文章

  1. 分布式平台下的HS(High-Security) --Apache Shiro API(介绍)
  2. JavaScript 学习笔记 之事件
  3. 假设一个半衰期为0的对象
  4. php extract 变量覆盖,extract变量覆盖
  5. Python库引用import多种用法及比较
  6. 获取指定某一天的00:00—23:59
  7. 大数据、AI“武装”企业服务:风控、检索、安全
  8. 深度学习(27)随机梯度下降五: 单输出感知机梯度
  9. openfire消息通知推送_微信小游戏内测「订阅消息」能力,这是召回用户的「大杀器」吗?...
  10. Activiti 流程查询出的结果封装为 JSON 时出现的异常
  11. 数据库半年回顾:国外波澜不惊,国内势如破竹
  12. idea中配置Springboot热部署
  13. 1.4信息系统基础-软件构件技术知识
  14. Linux终端下翻页操作
  15. 在SQL Server中的数据库之间复制表的六种不同方法
  16. 纯前端控件集 WijmoJS 2018V2发布,提供可视化设计器,在React、Vue和Angular中的更易用...
  17. 学习笔记-----usart串口调试助手一直打印00的解决方案
  18. mysql passwor authen_mysql5.7 的 user表的密码字段从 password 变成了 authentication_string
  19. Oracle 递归查询详解
  20. ubuntu 关闭系统自动更新

热门文章

  1. python 分类_python如何分类这样子的数据?
  2. 复习c语言深度剖析(14)—单引号和双引号
  3. 7-10 1.3.1 混合牛奶 (80分)
  4. 水果电商推广:一个桃子的爆棚营销实战
  5. php判断手机访问代码分享
  6. ros_demo系列——smach
  7. (5)机械臂URDF文件制作
  8. 【华为OD统一考试B卷 | 100分】N个选手比赛前三名、比赛(C++ Java JavaScript Python)
  9. 关于【中孚计算机终端保密检查系统】的卸载
  10. 如何用代码控制浏览器下载知乎大v的粉丝数据?