当前位置: 首页 > news >正文

链表的核心思想

链表的核心思想

1. 数组转化为单链表

class ListNode {int val;ListNode next;ListNode(int x) {val = x};
}// 将数组转化为一个单链表
ListNode createLinkedList(int[] arr) {if (arr == null || arr.length == 0) {return null;}ListNode head = new ListNode(arr[0]);ListNode cur = head;for(int i = 1; i < arr.length; i++) {cur.next = new ListNode(arr[i]);cur = cur.next;}return head;
}

代码疑难点

cur.next = new ListNode(arr[i]); // 把新建的节点接到当前节点后面cur = cur.next; // 当前指针移动到下一个节点去	

2. 单链表的头插

// 创建一个单链表
ListNode head = createLinkedList(new int[]{1, 2, 3, 4, 5});
// 在单链表前面进行头插
ListNode cur = new ListNode(int[0]); // 创建一个新节点
cur.next = head;
head = cur;

代码疑难点

1 -> 2 -> 3 -> 4 -> 5
cur.next = head; // 将新节点指向了1这个节点,这个节点也就是 head
// 变成了 0 -> 1 -> 2 -> 3 -> 4 -> 5 // 此时,head 指针还停留在 1 这个节点上
head = cur; // 将 head 指针走向了 0 这个位置

3. 单链表的尾插

// 创建一条单链表
ListNode head = createLinkedList(new int[]{1, 2, 3, 4, 5});
// 在链表的尾部插入一个数字6
ListNode p = head; // 一般另起一个指针来进行遍历,不使用原来的头结点
// 首先,得将指针移动到链表尾部
while (p.next != null) {p = p.next;
}
// 1 -> 2 -> 3 -> 4 -> 5 // 现在 p 指针指向了 5 数字
p.next = new ListNode(6);// 这样就完成了:1 -> 2 -> 3 -> 4 -> 5 -> 6

代码疑难点

// 为什么 while(p != null || p.next != null) 不是这个?而是只需要p.next != null 即可?
// 原因就是:如果 head != null ,p 一定不会等于 null,最终会停在尾节点。

4. 在单链表中间插入新元素

// 创建一条单链表
ListNode head = createLinkedList(new int[]{1, 2, 3, 4, 5});
// 在坐标3中插入一个数字66
ListNode p = head;
for (int i = 0; i < 2; i++) {p = p.next;
}
// 创建一个新节点
ListNode newNode = new ListNode(66);
newNode.next = p.next;
// 插入新节点
p.next = newNode;// 最终变成了 1 -> 2 -> 3 -> 66 -> 4 -> 5

代码疑点

// 创建一个新节点
ListNode newNode = new ListNode(66);
newNode.next = p.next; // p.next 指向了4这个数字,66 -> 4
// 插入新节点
p.next = newNode; // p 的下一个节点指向了 newNode 变成了:3 -> 66 // 最终变成了 1 -> 2 -> 3 -> 66 -> 4 -> 5

5. 在单链表中删除元素

// 创建一个单链表
ListNode head = new ListNode(new int[]{1, 2, 3, 4, 5};
// 删除第 4 个节点,要操作前驱节点
ListNode p = head;
// 走到要删除节点的前驱节点,也就是3这个节点
for (int i = 0; i < 2; i++) {p = p.next; // 往下走
}
// 删除也就是不连接 4 这个节点得了
p.next = p.next.next; // 3 的下一个下一个节点 -> 是 5// 现在链表:1 -> 2 -> 3 -> 5

注意点:【删除】就是:将要删除的节点的前驱节点 -> 连接其后驱节点

6. 在单链表尾部删除元素

// 创建一个单链表
ListNode head = createLinkedList(new int[]{1, 2, 3, 4, 5});
// 在尾部删除元素:找到倒数第二个元素
ListNode p = head;
while(p.next.next != null) {p = p.next; // 往下走
}
// 走到这个状态:p 指向了 4
// 不指向 5 了,以 4 为结尾好了
p.next = null;// 现在链表变成了 1 -> 2 -> 3 -> 4

7. 在单链表头部删除元素

// 这个更简单,头节点往下走一步好了,这样就把头节点删掉了
// 创建一个单链表
ListNode head = createLinkedList(new int[]{1, 2, 3, 4, 5});
// 头节点往下走一步
head = head.next;// 现在变成:2 -> 3 -> 4 -> 5

不过,读者会不会有一个疑问:前面的 1 应该还会指向 2 ,会不会造成内存泄漏?

答案是不会。旧的头节点指向别的节点没有关系,只要没有其他节点指向这个旧的头结点即可,这样,旧的头节点就会被垃圾回收收掉。

8. 双链表的基本操作

// 创建一条双链表
// 创建节点
class DoublyListNode {int val;DoublyListNode prev, next;DoublyListNode(int x) {val = x};
}
DoublyListNode createDoublyLinkedList(int arr) {// 判断if (arr == null || arr.length == 0) {return null;}// new 一个头节点DoublyListNode head = new DoublyListNode(arr[0]);DoublyListNode cur = head;// 开始创建链表for (int i = 1; i < arr.length; i++) {// 双向链表,最重要的是双向DoublyListNode newNode = new DoublyListNode(arr[i]);cur.next = newNode; // cur -> newNodenewNode.prev = cur; // cur <- newNodecur = cur.next; // cur 指针往下走}return head;
}

9. 双链表的遍历/查找/修改

// 创建一条双链表
DoublyListNode head = createDoublyLinkedList(new arr[]{1, 2, 3, 4, 5});
DoublyListNode tail = null;// 从头节点向后遍历链表
for (DoublyListNode cur = head; cur != null; cur = cur.next) {System.out.println(cur.val);tail = cur; // 尾节点跟随 cur 指针的步伐
}
// 从尾节点向前遍历链表
for (DoublyListNode cur = tail; cur  != null; cur = cur.prev) {System.out.println(cur.val);
}

10. 在双链表头部插入元素

// 创建一条双链表
DoublyListNode head = createDoublyLinkedList(new arr[]{1, 2, 3, 4, 5});
// 先 new 一个节点 0
DoublyListNode newNode = new DoublyListNode(0);
newNode.next = head; // 0 -> 1
head.prev = newNode; // 0 <- 1
head = newNode; // head 往 newNode 走,因为 head 得变成头节点,原本 head 在 1 的位置,不符合规则,所以跑回 0 这个位置// 结果变成:0 -> 1 -> 2 -> 3 -> 4 -> 5

11. 在双链表尾部插入一个新元素

// 创建一条双链表
DoublyListNode head = createDoublyLinkedList(new int[]{1, 2, 3, 4, 5});
DoublyListNode tail = head;// 先走到链表的尾部
while (tail.next != null) {tail = tail.next;
}
// 现在 tail 指针指向了 5 这个位置
// new 一个新的节点 6
DoublyListNode newNode = new DoublyListNode(6);
tail.next = newNode; // tail -> newNode
newNode.prev = tail; // tail <- newNode
// 现在 tail 还是指向 5
tail = newNode; // tail 顾名思义,是尾节点的意思,所以得指向 6,所以,就往 newNode 这挪,最终 tail 就指向 6// 现在链表变成了 1 -> 2 -> 3 -> 4 -> 5 -> 6

12. 在双链表中间插入新元素

在双链表指定位置插入节点,需要调整该位置的前驱节点和后续节点的指针。

比如下面的例子,把元素 66 插入到索引 3(第 4 个节点)的位置:

// 创建一条双链表
DoublyListNode head = createDoublyLinkedList(new int[]{1, 2, 3, 4, 5});
DoublyListNode cur = head;
// 想要在索引 3(第 4 个节点)插入元素
// cur 得走到 索引 3 的前一个位置:索引 2
for (int i = 0; i < 2; i++) {cur = cur.next;
}
// new 一个新节点 66
DoublyListNode newNode = new DoublyListNode(66);
// 得呈现一个这个状态:cur -> newNode -> cur.next
newNode.next = cur.next; // newNode -> cur.next
cur.next = newNode; // cur -> newNode// 双链表,讲究一个双向
cur.next.prev = newNode; // newNode <- cur.next
newNode,prev = cur; // cur <- newNode// 现在链表变成了 1 -> 2 -> 3 -> 66 -> 4 -> 5

13. 在双链表中删除一个节点

在双链表中删除元素,得调整要删除元素的前驱节点以及其后续节点的指针:

// 创建一条双链表
DoublyListNode head = createDoublyLinkedList(new int[]{1, 2, 3, 4, 5});
// 删除第 4 个节点
// 先找到第 3 个节点
DoublyListNode cur = head;
for (int i = 0; i < 2; i++) {cur = cur.next;
}
// 现在 cur 指针指向了 3
DoublyListNode toDelete = cur.next; // toDelete 节点指向 4
// 只需要将 toDelete 的前驱节点 -> 后续节点,跳过 toDelete 就好了
cur.next = toDelete.next; // cur -> toDelete.next
toDelete.next.prev = cur; // cur <- toDelete.next
// 把 toDelete 的前后指针都去置为 null (可选,一个好习惯)
toDelete.next = null;
toDelete.prev = null;// 现在链表变成了 1 -> 2 -> 3 -> 5

14. 在双链表头部删除元素

删除双链表需要调整头节点的指向

// 创建一条双链表
DoublyListNode head = createDoublyLinkedList(new int[]{1, 2, 3, 4, 5});// 删除头节点,让 head 往下走一个步即可
DoublyListNode toDelete = head;
head = head.next;
// 现在 head 已经指向了 2
head.prev = null; // 将 2 的前驱节点置为空//清除已删除节点的指针
toDelete.next = null;// 现在链表变成了 2 -> 3 -> 4 -> 5

15. 在双链表尾部删除元素

在单链表中,由于缺乏前驱节点,所以只能遍历到尾节点的前一个节点,再进行操作,也就是:cur.next.next != null 操作它的 next 指针才能将尾节点删掉。但在双链表中,由于每个节点都存储其自身的前驱节点的指针,所以,在双链表中,可以直接操作尾节点,也就是:cur.next != null ,把自己从链表中摘掉。

// 创建一条双链表
DoublyListNode head = createDoublyLinkedList(new int[]{1, 2, 3, 4, 5});
// 删除尾节点 5
DoublyListNode cur = head;
while (cur.next != null) {cur = cur.next;
}
// 现在 cur 走到了 5 这个位置
cur.prev.next = null; // cur.prev 指向的是 4  4 的 next 就是 5 所以把 5 给断掉了cur.prev = null; // 把被删结点的指针都断开是个好习惯(可选)// 现在链表变成了 1 -> 2 -> 3 -> 4
http://www.dtcms.com/a/414882.html

相关文章:

  • Matlab通过GUI实现点云的坡度滤波(附最简版)
  • GESP8级——AT_icpc2013spring_e 最小生成树题解
  • Qt窗口与对话框开发指南
  • 湖北平台网站建设哪家好有经验的邵阳网站建设
  • 33.Linux iCSCI 服务
  • 国内优秀网页设计网站网站建设流程共有几个阶段
  • 基于物联网的个人健康管理系统(论文+源码)
  • 一个网站可以做几个关键词网站建设济南
  • Linux日志分析入门:使用grep和awk发现服务器异常访问
  • 435. 无重叠区间
  • 2025制造业研发流程提效指南:从审批卡顿到协同闭环,3类系统选型全解析
  • 文件夹随机分配 把文件夹随机分配到指定的文件夹中
  • 104.二叉树的最大深度(二叉树算法题)
  • 宿迁做网站的怎样制作h5
  • 电子商务网站建设结业论文seo教程seo官网优化详细方法
  • 使用 Three.js 和本地 Draco Loader 高效加载压缩 GLB 模型
  • Nginx-Proxy-Manager配置SSL泛域名证书教程
  • 图的遍历:从深度优先到广度优先
  • Java数据结构:ArrayList与顺序表1
  • C语言实战项目:贪吃蛇(1)
  • 鸿蒙应用开发之ArkTs集成AI大模型与Markdown流式渲染教程(API 20)
  • 网站建设服务器环境配置关于网站开发的网店计划书范文
  • LeetCode-hot100——将有序数组转换为二叉搜索树
  • 网站速度对seo的影响修改wordpress登录背景图片
  • Kimi 灰度测试 OK Computer,AI 从 “问答” 迈入 “执行” 新阶段​
  • 什么是 mmap?
  • 民宿客用网络升级方案:从传统到现代化的跃迁
  • 湖南省住房和城乡建设厅老网站做网站分为竞价和优化
  • 品牌创意网站建设韩国手机网站模板
  • 力扣3679. 使库存平衡的最少丢弃次数