数据结构与算法-链表学习笔记

链表的概念

  1. 链表是有序的列表。
  2. 链表是以节点的方式来存储,是链式存储,它在内存中并不是一定是连续的。
  3. 每个节点包含 data 域:存储数据, next 域:指向下一个节点。
  4. 链表分带头节点的链表和没有头节点的链表,根据实际的需求来确定。
  5. 链表优点:数据的删除、插入简单;缺点:数据查找慢

下图为带头节点的单向链表内存示意图:

单向链表

单向链表每个节点的next域指向下一个节点,通过next的链接实现让无数个节点链接成一个链表。

单链表(带头结点) 逻辑结构示意图如下:

下面我们通过一个例子模拟单向链表的基本操作:

创建链表中的数据节点:

/*** 数据节点*/
class HeroNode {public int no;public String name;public String zi;public HeroNode next;public HeroNode(int no, String name, String zi) {this.no = no;this.name = name;this.zi = zi;}@Overridepublic String toString() {return "HeroNode{" + "no=" + no + ", name='" + name + '\'' + ", zi='" + zi + '\'' + '}';}
}

创建模拟链表

/*** 模拟链表类*/
class LinkedList {//创建链表时就创建头,且不可修改public final HeroNode head = new HeroNode(0, "", "");
}

添加节点到链表最后一个位置

public void add(HeroNode heroNode) {HeroNode temp = head;//当节点没有下一个节点时退出循环while (true) {if (temp.next == null) {break;}temp = temp.next;}//循环结束时temp就是最后一个节点temp.next = heroNode;
}

按编号添加节点

public void addByNo(HeroNode heroNode) {//临时节点HeroNode temp = head;//记录上一个节点HeroNode upNode = null;while (true) {//判断是否有相同编号,有就添加失败if (temp.no == heroNode.no) {throw new RuntimeException("链表已有编号相同的数据");}//插入节点编号小于循环目前节点,将节点插入到当前节点前面if (temp.no > heroNode.no) {//插入节点,下一个节点顺移upNode.next = heroNode;heroNode.next = temp;break;}//循环到最后一个节点都没有找到插入点,直接插入到最后。if (temp.next == null) {temp.next = heroNode;break;}//更新临时节点upNode = temp;temp = temp.next;}
}

修改节点信息

public void edit(HeroNode heroNode) {if (heroNode.no == 0) {throw new RuntimeException("0为链表头不支持修改");}//临时节点HeroNode temp = head;//记录上一个节点HeroNode upNode = null;while (true) {//未找到修改编号if (temp.next == null) {throw new RuntimeException("未找到可修改的节点");}//遍历找到编号一致的节点if (temp.no == heroNode.no) {//替换节点和上节点heroNode.next = temp.next;upNode.next = heroNode;break;}//更新临时节点upNode = temp;temp = temp.next;}
}

删除节点

public void delete(int no) {if (no == 0) {throw new RuntimeException("0为链表头无法删除");}//临时节点HeroNode temp = head;//记录上一个节点HeroNode upNode = null;while (true) {//找到删除节点编号if (temp.no == no) {//上节点指向下节点upNode.next = temp.next;break;}//未找到修改编号if (temp.next == null) {throw new RuntimeException("未找到可删除的节点");}//更新临时节点upNode = temp;temp = temp.next;}
}

获取链表中节点个数

public int count() {//临时节点HeroNode temp = head;int count = 0;while (true) {if (temp.next == null) {break;}temp = temp.next;count++;}return count;
}

获取链表倒数第N个节点

public HeroNode getBackwardsNode(int n) {if (n <= 0) {throw new RuntimeException("倒数必须>0");}//临时节点HeroNode temp = head;//获取链表总节点int total = count();if (n > total) {throw new RuntimeException("超出链表长度");}for (int i = 0; i <= (total - n); i++) {temp = temp.next;}return temp;
}

链表反转

public LinkedList reversal() {//创建反转链表LinkedList reversal = new LinkedList();HeroNode reversalTemp = reversal.head;//获取原链表节点个数int count = count();//循环添加链表节点到reversalfor (int i = count; i > 0; i--) {HeroNode temp = head;int index = 0;while (true) {if (index == i) {reversalTemp.next = temp;break;}temp = temp.next;index++;}reversalTemp = reversalTemp.next;}//最后一个节点没有后续节点reversalTemp.next = null;return reversal;
}

从尾到头打印链表(遍历)

public void invertedPrintFor() {//临时HeroNode temp = head;//获取链表节点个数int count = count();for (int i = count; i > 0; i--) {int index = 0;while (true) {if (index == i) {System.out.println(temp);temp = head;break;}temp = temp.next;index++;}}
}

从尾到头打印链表(栈)

public void invertedPrintStack() {//临时链表,头节点不参与加入循环HeroNode temp = head.next;//创建栈对象Stack<HeroNode> stack = new Stack<>();//链表元素添加到栈while (true) {stack.add(temp);if (temp.next == null) {break;}temp = temp.next;}//循环输出栈内的元素,以达到从尾到头的效果while (stack.size() != 0) {HeroNode heroNode = stack.pop();System.out.println(heroNode);}
}

遍历链表

public void forLinkedList() {if (head.next == null) {System.out.println("链表为空");}HeroNode temp = head;while (true) {if (temp.next == null) {break;}temp = temp.next;System.out.println(temp);}
}

双向链表

双向链表与单向链表的区别:单向链表查找的方向只能是一个方向,而双向链表可以向前或者向后查找。

下面我们通过一个例子模拟双向链表的基本操作:

创建数据节点:

/*** 数据节点*/
class HeroNode {public int no;public String name;public String zi;public HeroNode up;public HeroNode next;public HeroNode(int no, String name, String zi) {this.no = no;this.name = name;this.zi = zi;}@Overridepublic String toString() {return "HeroNode{" + "no=" + no + ", name='" + name + '\'' + ", zi='" + zi + '\'' + '}';}
}

创建模拟链表

class LinkedList {//创建链表时就创建头,且不可修改public final HeroNode head = new HeroNode(0, "", "");
}

遍历链表

public void forLinkedList() {if (head.next == null) {System.out.println("链表为空");}HeroNode temp = head;while (true) {if (temp.next == null) {break;}temp = temp.next;System.out.println(temp);}
}

添加节点到最后一个位置

public void add(HeroNode heroNode) {HeroNode temp = head;while (true) {if (temp.next == null) {temp.next = heroNode;heroNode.up = temp;break;}temp = temp.next;}
}

根据编号添加节点

public void addByNo(HeroNode heroNode) {HeroNode temp = head.next;while (true) {if (temp.no == heroNode.no) {throw new RuntimeException("已有编号相同的节点");}if (temp.no > heroNode.no) {//替换上一个节点信息HeroNode up = temp.up;up.next = heroNode;heroNode.up = up;heroNode.next = temp;break;}if (temp.next == null) {temp.next = heroNode;heroNode.up = temp;break;}temp = temp.next;}
}

修改节点

public void update(HeroNode heroNode) {HeroNode temp = head.next;while (true) {if (temp.next == null) {throw new RuntimeException("未找到修改的节点");}if (temp.no == heroNode.no) {temp.name = heroNode.name;temp.zi = heroNode.zi;break;}}
}

删除节点

public void delete(int no) {HeroNode temp = head.next;while (true) {if (temp.no == no) {HeroNode up = temp.up;HeroNode next = temp.next;up.next = next;if (next!=null){next.up = up;}break;}if (temp.next == null) {throw new RuntimeException("未找到删除的节点");}temp = temp.next;}
}

示例完整代码

单向链表

public class OneLinkedList {public static void main(String[] args) {//创建链表LinkedList list = new LinkedList();//创建节点HeroNode heroNode1 = new HeroNode(1, "刘备", "玄德");HeroNode heroNode2 = new HeroNode(2, "关羽", "云长");HeroNode heroNode3 = new HeroNode(3, "张飞", "翼德");HeroNode heroNode4 = new HeroNode(4, "赵云", "子龙");HeroNode heroNode5 = new HeroNode(5, "马超", "孟起");//添加节点到链表末尾list.add(heroNode1);list.add(heroNode2);list.add(heroNode3);list.add(heroNode4);list.add(heroNode5);//循环节点list.forLinkedList();System.out.println("----------------------------");
//        list.addByNo(new HeroNode(6, "赵云", "子龙"));
//        list.edit(new HeroNode(0, "赵飞", "字符"));
//        list.delete(0);
//        list.forLinkedList();
//        System.out.println(list.count());
//        HeroNode backwardsNode = list.getBackwardsNode(0);
//        list.reversal().forLinkedList();
//        list.invertedPrintFor();list.invertedPrintStack();}
}/*** 模拟链表类*/
class LinkedList {//创建链表时就创建头,且不可修改public final HeroNode head = new HeroNode(0, "", "");/*** 添加节点到最后一个位置*/public void add(HeroNode heroNode) {HeroNode temp = head;//当节点没有下一个节点时退出循环while (true) {if (temp.next == null) {break;}temp = temp.next;}//循环结束时temp就是最后一个节点temp.next = heroNode;}/*** 按编号添加节点*/public void addByNo(HeroNode heroNode) {//临时节点HeroNode temp = head;//记录上一个节点HeroNode upNode = null;while (true) {//判断是否有相同编号,有就添加失败if (temp.no == heroNode.no) {throw new RuntimeException("链表已有编号相同的数据");}//插入节点编号小于循环目前节点,将节点插入到当前节点前面if (temp.no > heroNode.no) {//插入节点,下一个节点顺移upNode.next = heroNode;heroNode.next = temp;break;}//循环到最后一个节点都没有找到插入点,直接插入到最后。if (temp.next == null) {temp.next = heroNode;break;}//更新临时节点upNode = temp;temp = temp.next;}}/*** 修改节点*/public void edit(HeroNode heroNode) {if (heroNode.no == 0) {throw new RuntimeException("0为链表头不支持修改");}//临时节点HeroNode temp = head;//记录上一个节点HeroNode upNode = null;while (true) {//未找到修改编号if (temp.next == null) {throw new RuntimeException("未找到可修改的节点");}//遍历找到编号一致的节点if (temp.no == heroNode.no) {//替换节点和上节点heroNode.next = temp.next;upNode.next = heroNode;break;}//更新临时节点upNode = temp;temp = temp.next;}}/*** 删除节点*/public void delete(int no) {if (no == 0) {throw new RuntimeException("0为链表头无法删除");}//临时节点HeroNode temp = head;//记录上一个节点HeroNode upNode = null;while (true) {//找到删除节点编号if (temp.no == no) {//上节点指向下节点upNode.next = temp.next;break;}//未找到修改编号if (temp.next == null) {throw new RuntimeException("未找到可删除的节点");}//更新临时节点upNode = temp;temp = temp.next;}}/*** 获取链表中节点个数*/public int count() {//临时节点HeroNode temp = head;int count = 0;while (true) {if (temp.next == null) {break;}temp = temp.next;count++;}return count;}/*** 获取链表倒数第N个节点** @param n 倒数第N个* @return*/public HeroNode getBackwardsNode(int n) {if (n <= 0) {throw new RuntimeException("倒数必须>0");}//临时节点HeroNode temp = head;//获取链表总节点int total = count();if (n > total) {throw new RuntimeException("超出链表长度");}for (int i = 0; i <= (total - n); i++) {temp = temp.next;}return temp;}/*** 链表反转*/public LinkedList reversal() {//创建反转链表LinkedList reversal = new LinkedList();HeroNode reversalTemp = reversal.head;//获取原链表节点个数int count = count();//循环添加链表节点到reversalfor (int i = count; i > 0; i--) {HeroNode temp = head;int index = 0;while (true) {if (index == i) {reversalTemp.next = temp;break;}temp = temp.next;index++;}reversalTemp = reversalTemp.next;}//最后一个节点没有后续节点reversalTemp.next = null;return reversal;}/*** 从尾到头打印链表(遍历)*/public void invertedPrintFor() {//临时HeroNode temp = head;//获取链表节点个数int count = count();for (int i = count; i > 0; i--) {int index = 0;while (true) {if (index == i) {System.out.println(temp);temp = head;break;}temp = temp.next;index++;}}}/*** 从尾到头打印链表(栈)*/public void invertedPrintStack() {//临时链表,头节点不参与加入循环HeroNode temp = head.next;//创建栈对象Stack<HeroNode> stack = new Stack<>();//链表元素添加到栈while (true) {stack.add(temp);if (temp.next == null) {break;}temp = temp.next;}//循环输出栈内的元素,以达到从尾到头的效果while (stack.size() != 0) {HeroNode heroNode = stack.pop();System.out.println(heroNode);}}/*** 遍历链表*/public void forLinkedList() {if (head.next == null) {System.out.println("链表为空");}HeroNode temp = head;while (true) {if (temp.next == null) {break;}temp = temp.next;System.out.println(temp);}}
}/*** 数据节点*/
class HeroNode {public int no;//名称public String name;public String zi;public HeroNode next;public HeroNode(int no, String name, String zi) {this.no = no;this.name = name;this.zi = zi;}@Overridepublic String toString() {return "HeroNode{" + "no=" + no + ", name='" + name + '\'' + ", zi='" + zi + '\'' + '}';}
}

双向链表

package dataStructure.linkedList;
import java.util.Stack;public class TwoLinkedList {public static void main(String[] args) {LinkedList list = new LinkedList();list.add(new HeroNode(1, "曹操", "孟德"));list.add(new HeroNode(2, "刘备", "玄德"));list.add(new HeroNode(4, "张飞", "翼德"));list.addByNo(new HeroNode(3, "关羽", "云长"));list.addByNo(new HeroNode(5, "赵云", "子龙"));list.update(new HeroNode(1, "马超", "孟起"));list.delete(5);list.forLinkedList();}
}/*** 模拟链表类*/
class LinkedList {//创建链表时就创建头,且不可修改public final HeroNode head = new HeroNode(0, "", "");/*** 遍历链表*/public void forLinkedList() {if (head.next == null) {System.out.println("链表为空");}HeroNode temp = head;while (true) {if (temp.next == null) {break;}temp = temp.next;System.out.println(temp);}}/*** 添加节点到最后一个位置*/public void add(HeroNode heroNode) {HeroNode temp = head;while (true) {if (temp.next == null) {temp.next = heroNode;heroNode.up = temp;break;}temp = temp.next;}}/*** 根据编号添加节点*/public void addByNo(HeroNode heroNode) {HeroNode temp = head.next;while (true) {if (temp.no == heroNode.no) {throw new RuntimeException("已有编号相同的节点");}if (temp.no > heroNode.no) {//替换上一个节点信息HeroNode up = temp.up;up.next = heroNode;heroNode.up = up;heroNode.next = temp;break;}if (temp.next == null) {temp.next = heroNode;heroNode.up = temp;break;}temp = temp.next;}}/*** 修改节点*/public void update(HeroNode heroNode) {HeroNode temp = head.next;while (true) {if (temp.next == null) {throw new RuntimeException("未找到修改的节点");}if (temp.no == heroNode.no) {temp.name = heroNode.name;temp.zi = heroNode.zi;break;}}}/*** 删除节点*/public void delete(int no) {HeroNode temp = head.next;while (true) {if (temp.no == no) {HeroNode up = temp.up;HeroNode next = temp.next;up.next = next;if (next!=null){next.up = up;}break;}if (temp.next == null) {throw new RuntimeException("未找到删除的节点");}temp = temp.next;}}
}/*** 数据节点*/
class HeroNode {public int no;public String name;public String zi;public HeroNode up;public HeroNode next;public HeroNode(int no, String name, String zi) {this.no = no;this.name = name;this.zi = zi;}@Overridepublic String toString() {return "HeroNode{" + "no=" + no + ", name='" + name + '\'' + ", zi='" + zi + '\'' + '}';}
}

参考

该笔记基于《尚硅谷-数据结构与算法》教程

数据结构与算法-链表学习笔记相关推荐

  1. 【数据结构与算法】学习笔记——第一章 绪论1

    ✔前言: 新的专栏开启啦. 持续更新~ 关注我,我们一起学习

  2. 【数据结构与算法】学习笔记-《算法笔记》-7

    查找元素 找x #include <cstdio> #include <cstring> #include <cmath> using namespace std; ...

  3. 算法训练营学习笔记1

    算法训练营学习笔记 贪心算法 心算法总是做出当前最好的选择,期望通过局部最优选择得到全局最优的解决方案.从问题的初始解开始,一步歩地做出当前最好的选择,逐步逼近问题的目标,尽可能得到最优解: 贪心本质 ...

  4. 数据结构与算法深入学习_我最喜欢的免费课程,用于深入学习数据结构和算法...

    数据结构与算法深入学习 by javinpaul 由javinpaul Data structures and algorithms are some of the most essential to ...

  5. 数据结构与算法的学习——思维的学习与高屋建瓴

    数据结构与算法的学习--思维的学习与高屋建瓴 一.算法思维的练习 二.练习过程 1.是什么(WHat) 2.怎么用(How) 三.进阶思考 1.栈的思考 2.树的问题 3.关于递归 (1)排列组合问题 ...

  6. 数据结构与算法——从零开始学习(一)基础概念篇

    系列文章 第一章:基础知识 第二章:线性表 第三章:栈和队列 第四章:字符串和数组 第五章:树和二叉树 第六章:图 第七章:排序算法 前言 数据结构:是指相互之间存在一种或多种特定关系的数据元素的集合 ...

  7. Interview之AI:人工智能领域岗位求职面试—人工智能算法工程师知识框架及课程大纲(AI基础之数学基础/数据结构与算法/编程学习基础、ML算法简介、DL算法简介)来理解技术交互流程

    Interview之AI:人工智能领域岗位求职面试-人工智能算法工程师知识框架及课程大纲(AI基础之数学基础/数据结构与算法/编程学习基础.ML算法简介.DL算法简介)来理解技术交互流程 目录 一.A ...

  8. 一夜登顶GitHub!字节内网数据结构与算法刷题笔记,看完直呼卧槽

    网络上流传着一句段子"程序员两条腿,一条是算法,一条是英文,想跑的更远,这两条腿都不能弱".英文,我们暂且不谈,我们先来谈谈算法. 算法之难,在于将精巧的逻辑,通过合适的数据结构, ...

  9. 王道数据结构与算法:完整笔记

    王道数据结构与算法:完整笔记 文章目录 数据结构笔记 第一章 绪论 1.1 基本概念 1.2 数据结构三要素 1.3 算法的概念 1.4 算法效率的度量 第二章 线性表 2.1 线性表的定义和基本操作 ...

最新文章

  1. Too many connections解决方法
  2. 云原生应用实现规范 - 初识 Operator
  3. Ubuntu返回到Gnome经典桌面!
  4. 使用Jupyter notebook,为什么按下ctrl+enter后,没有输出,也没有报错,而是一直出现“*”呢?
  5. C# Datatable排序与取前几行数据
  6. html5伪类效果延缓,CSS3实现伪类hover离开时平滑过渡效果示例
  7. 布局管理器android,Android课程---布局管理器之相对布局(一)
  8. 【C++深度剖析教程15】经典问题解析之关于string的疑问
  9. 百度刷新世界级权威DeepFake防伪数据集榜单记录,成绩超越SOTA
  10. 计算机等级考试一级宝典,计算机等级考试一级通关宝典.doc
  11. c语言枪战游戏代码,FPS射击游戏《林海雪原》完整源代码
  12. oracle ebs bug,ORACLE EBS 价目表的导入效能-存储过程BUG
  13. 如何设计简单的网站Favicon图标?ICO图标制作
  14. zabbix查询历史数据
  15. python爬虫爬取豆瓣电影评分排行榜前n名的前n页影评
  16. 阿里云python中文社区_一文详解如何用 python 做中文分词-阿里云开发者社区
  17. 甲骨文一键修改root密码
  18. Oxyplot实时绘图学习笔记(上)
  19. python文献知识图谱可视化_知识图谱可视化工具(知识图谱可视化python)
  20. 傲慢与偏见:程序员非科班出身就得不到重用?

热门文章

  1. ResultMessage<T>
  2. 2021 SLAM会议论文汇总
  3. SpringBoot2.x集成分布式搜索引擎Elasticsearch
  4. 《JavaScript高级程序设计 (第3版)》学习笔记14:chapter_5 - 5 Function类型
  5. 成为一个积极主动的项目经理
  6. 47个市场营销基本概念
  7. 星空银河html,银河星空拍摄的前期后期
  8. 品牌企业出海,如何抓住独立站热潮
  9. android wifi智能车,基于 Android 的智能 Wifi 遥控电动滑板车
  10. IBOX NFT 数字藏品价格 监控 工具 科技