欧克!欧克!小刘今天带大家来学习一下链表 ,你要是学不会,你来捶我

文章目录

  • 1、链表(Linked List)介绍
    • 1.1、内存结构
    • 1.2、逻辑结构
    • 1.3、链表特点
  • 2、链表应用场景
    • 2.1、水浒英雄榜
    • 2.2、链表节点定义
    • 2.3、链表定义
    • 2.4、遍历链表
      • 2.4.1、代码思路
      • 2.4.2、代码实现
    • 2.5、尾部插入
      • 2.5.1、代码思路
      • 2.5.2、代码实现
    • 2.6、按顺序插入
      • 2.6.1、代码思路
      • 2.6.2、代码实现
    • 2.7、修改节点信息
      • 2.7.1、代码思路
      • 2.7.2、代码实现
    • 2.8、删除节点
      • 2.8.1、代码思路
      • 2.8.2、代码实现
    • 2.9、总结
  • 3、单链表面试题
    • 3.1、求单链表中有效节点的个数
      • 3.1.1、代码思路
      • 3.1.2、代码实现
    • 3.2、查找单链表中的倒数第 k 个结点
      • 3.2.1、代码思路
      • 3.2.2、代码实现
    • 3.3、单链表的反转
      • 3.3.1、代码思路
      • 3.3.2、代码实现
    • 3.4、单链表的反转(我的代码)
      • 3.4.1、代码思路
      • 3.4.2、代码实现
    • 3.5、从尾到头打印单链表
      • 3.5.1、栈的基本使用
      • 3.5.2、代码思路
      • 3.5.3、代码实现
    • 3.6、合并两个有序的单链表
      • 3.6.1、代码思路
      • 3.6.2、代码实现
    • 3.7、单向链表所有代码
  • 4、双向链表
    • 4.1、与单向链表的比较
    • 4.2、链表节点定义
    • 4.3、链表定义
    • 4.4、链表遍历
      • 4.4.1、代码思路
      • 4.4.2、代码实现
    • 4.5、尾部插入
      • 4.5.1、代码思路
      • 4.5.2、代码实现
    • 4.6、按顺序插入
      • 4.6.1、代码思路
      • 4.6.2、代码实现
    • 4.7、修改节点信息
      • 4.7.1、代码思路
      • 4.7.2、代码实现
    • 4.8、删除节点
      • 4.8.1、代码思路
      • 4.8.2、代码实现
    • 4.9、双向链表测试
      • 4.9.1、测试代码
      • 4.9.2、程序运行结果
    • 4.10、双向链表所有代码
    • 4.11、总结
  • 5、单向环形链表
    • 5.1、单向环形链表应用场景
    • 5.2、单向环形链表图解
    • 5.3、Josephu 问题
    • 5.4、环形链表的构建与遍历
      • 5.4.1、Boy 节点的定义
      • 5.4.2、单向循环链表的定义
      • 5.4.3、构建单向循环链表
        • 1、代码思路
        • 2、代码实现
      • 5.4.4、遍历单向循环链表
        • 1、代码思路
        • 2、代码实现
    • 5.5、解决 Josephu 问题
      • 5.5.1、代码思路
      • 5.5.2、代码实现
    • 5.6、Josephu 问题测试
      • 5.6.1、测试代码
      • 5.6.2、程序运行结果
    • 5.7、Josephu 问题所有代码
    • 5.8、总结

1、链表(Linked List)介绍

1.1、内存结构

  • 内存上来看:链表存储空间 不连续(不像数组)

1.2、逻辑结构

  • 逻辑上来看:链表属于 线性结构

1.3、链表特点

  • 链表是以节点的方式来存储,是 链式存储
  • data 域存放数据,next 域 指向下一个节点
  • 链表分 带头节点的链表和 没有头节点的链表, 根据实际的需求来确定

2、链表应用场景

2.1、水浒英雄榜

  • 使用带 head 头的 单向链表实现【水浒英雄排行榜管理】

2.2、链表节点定义

  • no :英雄编号
  • name :英雄名字
  • nickName :英雄昵称
  • next :指向下一个 HeroNode 节点

class HeroNode {public int no;public String name;public String nickName;public HeroNode next;public HeroNode(int no, String name, String nickname) {this.no = no;this.name = name;this.nickName = nickname;}@Overridepublic String toString() {return "HeroNode [no=" + no + ", name=" + name + ", nickName=" + nickName + "]";}}

2.3、链表定义

  • DummyHead : 头结点不存放数据,仅仅作为当前链表的入口
  • head 字段的值不能改变,一旦改变,就 丢失了整个链表的入口,我们也就无法通过 head 找到链表了

class SingleLinkedList {private HeroNode head = new HeroNode(0, "", "");public HeroNode getHead() {return head;}

2.4、遍历链表

2.4.1、代码思路

  • 定义辅助变量 temp ,相当于一个指针,指向 当前节点
  • 何时遍历完成? temp == null 表明当前节点为 null ,即表示已到链表末尾
  • 如何遍历? temp = temp.next ,每次输出当前节点信息之后,temp 指针后移

2.4.2、代码实现

  • 遍历链表

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

2.5、尾部插入

2.5.1、代码思路

  • 定义辅助变量 temp ,相当于一个指针,指向 当前节点
  • 如何在链表末尾插入节点?
    • 首先需要遍历链表,找到链表最后一个节点,当 temp.next == null时,temp 节点指向链表最后一个节点
    • 然后在 temp 节点之后插入节点即可: *temp.next = heroNode

2.5.2、代码实现

  • 在链表尾部插入节点

public void add(HeroNode heroNode) {HeroNode temp = head;while (true) {if (temp.next == null) {break;}temp = temp.next;}temp.next = heroNode;
}
  • 测试代码
 public static void main(String[] args) {HeroNode hero1 = new HeroNode(1, "宋江", "及时雨");HeroNode hero2 = new HeroNode(2, "卢俊义", "玉麒麟");HeroNode hero3 = new HeroNode(3, "吴用", "智多星");HeroNode hero4 = new HeroNode(4, "林冲", "豹子头");SingleLinkedList singleLinkedList = new SingleLinkedList();singleLinkedList.add(hero1);singleLinkedList.add(hero2);singleLinkedList.add(hero3);singleLinkedList.add(hero4);singleLinkedList.list();}
  • 程序运行结果
HeroNode [no=1, name=宋江, nickName=及时雨]
HeroNode [no=2, name=卢俊义, nickName=玉麒麟]
HeroNode [no=3, name=吴用, nickName=智多星]
HeroNode [no=4, name=林冲, nickName=豹子头]

2.6、按顺序插入

2.6.1、代码思路

  • 定义辅助变量 temp ,相当于一个指针,指向 当前节点
  • 应该如何执行插入?(待插入节点为 heroNode)
    • 首先需要遍历链表,找到链表中编号值比 heroNode.no 大的节点,暂且叫它 biggerNode ,然后把 heroNode 插入到 biggerNode 之前即可
    • 怎么找 biggerNode ?当 temp.next.no > heroNode.no 时,这时 temp.next 节点就是 biggerNode 节点。
    • 为什么是 temp.next 节点?只有找到 temp 节点和 temp.next(biggerNode )节点,才能在 temp 节点和 temp.next 节点之间插入 heroNode 节点
    • 怎么插入?
      • heroNode .next = temp.next;
      • temp.next = heroNode;

2.6.2、代码实现

  • 按照英雄排名的顺序进行插入

public void addByOrder(HeroNode heroNode) {HeroNode temp = head;boolean flag = false;while (true) {if (temp.next == null) {break;}if (temp.next.no > heroNode.no) {break;} else if (temp.next.no == heroNode.no) {flag = true;break;}temp = temp.next;}if (flag) {System.out.printf("准备插入的英雄的编号 %d 已经存在了, 不能加入\n", heroNode.no);} else {heroNode.next = temp.next;temp.next = heroNode;}
}
  • 测试代码
public static void main(String[] args) {HeroNode hero1 = new HeroNode(1, "宋江", "及时雨");HeroNode hero2 = new HeroNode(2, "卢俊义", "玉麒麟");HeroNode hero3 = new HeroNode(3, "吴用", "智多星");HeroNode hero4 = new HeroNode(4, "林冲", "豹子头");SingleLinkedList singleLinkedList = new SingleLinkedList();singleLinkedList.addByOrder(hero1);singleLinkedList.addByOrder(hero4);singleLinkedList.addByOrder(hero2);singleLinkedList.addByOrder(hero3);singleLinkedList.list();
}
  • 程序运行结果
HeroNode [no=1, name=宋江, nickName=及时雨]
HeroNode [no=2, name=卢俊义, nickName=玉麒麟]
HeroNode [no=3, name=吴用, nickName=智多星]
HeroNode [no=4, name=林冲, nickName=豹子头]

2.7、修改节点信息

2.7.1、代码思路

  • 定义辅助变量 temp ,相当于一个指针,指向 当前节点
  • 如何找到指定节点? *temp.no = newHeroNode.no

2.7.2、代码实现

  • 修改指定节点信息

public void update(HeroNode newHeroNode) {if (head.next == null) {System.out.println("链表为空~");return;}HeroNode temp = head.next;boolean flag = false;while (true) {if (temp == null) {break;}if (temp.no == newHeroNode.no) {flag = true;break;}temp = temp.next;}if (flag) {temp.name = newHeroNode.name;temp.nickName = newHeroNode.nickName;} else {System.out.printf("没有找到 编号 %d 的节点,不能修改\n", newHeroNode.no);}
}
  • 测试代码
public static void main(String[] args) {HeroNode hero1 = new HeroNode(1, "宋江", "及时雨");HeroNode hero2 = new HeroNode(2, "卢俊义", "玉麒麟");HeroNode hero3 = new HeroNode(3, "吴用", "智多星");HeroNode hero4 = new HeroNode(4, "林冲", "豹子头");SingleLinkedList singleLinkedList = new SingleLinkedList();singleLinkedList.addByOrder(hero1);singleLinkedList.addByOrder(hero4);singleLinkedList.addByOrder(hero2);singleLinkedList.addByOrder(hero3);HeroNode newHeroNode = new HeroNode(2, "小卢", "玉麒麟~~");singleLinkedList.update(newHeroNode);singleLinkedList.list();
}
  • 程序运行结果
HeroNode [no=1, name=宋江, nickName=及时雨]
HeroNode [no=2, name=小卢, nickName=玉麒麟~~]
HeroNode [no=3, name=吴用, nickName=智多星]
HeroNode [no=4, name=林冲, nickName=豹子头]

2.8、删除节点

2.8.1、代码思路

  • 定义辅助变量 temp ,相当于一个指针,指向 当前节点
  • 如何找到待删除的节点?遍历链表,当 temp.next == no 时,temp.next 节点就是待删除的节点
  • 如何删除? temp = temp.next.next 即可删除 temp.next 节点,该节点没有引用指向它,会被垃圾回收机制回收

2.8.2、代码实现

  • 删除指定节点

public void del(int no) {HeroNode temp = head;boolean flag = false;while (true) {if (temp.next == null) {break;}if (temp.next.no == no) {flag = true;break;}temp = temp.next;}if (flag) {temp.next = temp.next.next;} else {System.out.printf("要删除的 %d 节点不存在\n", no);}
}
  • 测试代码
public static void main(String[] args) {HeroNode hero1 = new HeroNode(1, "宋江", "及时雨");HeroNode hero2 = new HeroNode(2, "卢俊义", "玉麒麟");HeroNode hero3 = new HeroNode(3, "吴用", "智多星");HeroNode hero4 = new HeroNode(4, "林冲", "豹子头");SingleLinkedList singleLinkedList = new SingleLinkedList();singleLinkedList.add(hero1);singleLinkedList.add(hero2);singleLinkedList.add(hero3);singleLinkedList.add(hero4);singleLinkedList.del(1);singleLinkedList.del(4);singleLinkedList.list();
}
  • 程序运行结果
HeroNode [no=2, name=卢俊义, nickName=玉麒麟]
HeroNode [no=3, name=吴用, nickName=智多星]

2.9、总结

  • 遍历链表,执行操作时,判断条件有时候是 temp ,有时候是 temp.next ,Why?

    • 对于插入、删除节点来说,需要知道 当前待操作的节点(heroNode)前一个节点的地址(指针),如果直接定位至当前待操作的节点 heroNode ,那没得玩。。。因为不知道heroNode 前一个节点的地址,无法进行插入、删除操作,所以 while 循环中的条件使用 temp.next 进行判断
    • 对于更新、遍历操作来说,我需要的仅仅就只是当前节点的信息,所以 while 循环中的条件使用 temp进行判断
  • 头结点与首节点
    • 参考资料:https://blog.csdn.net/WYpersist/article/details/80288056
    • 头结点是为了操作的统一与方便而设立的,放在第一个元素结点之前,其数据域一般无意义(当然有些情况下也可存放链表的长度、用做监视哨等等)。
    • 首元结点也就是第一个元素的结点,它是头结点后边的第一个结点。

3、单链表面试题

3.1、求单链表中有效节点的个数

3.1.1、代码思路

  • 求单链表中有效节点的个数:遍历即可

3.1.2、代码实现

  • 求单链表中有效节点的个数

public static int getLength(HeroNode head) {if (head.next == null) {return 0;}int length = 0;HeroNode cur = head.next;while (cur != null) {length++;cur = cur.next;}return length;
}
  • 测试代码
public static void main(String[] args) {HeroNode hero1 = new HeroNode(1, "宋江", "及时雨");HeroNode hero2 = new HeroNode(2, "卢俊义", "玉麒麟");HeroNode hero3 = new HeroNode(3, "吴用", "智多星");HeroNode hero4 = new HeroNode(4, "林冲", "豹子头");SingleLinkedList singleLinkedList = new SingleLinkedList();singleLinkedList.add(hero1);singleLinkedList.add(hero2);singleLinkedList.add(hero3);singleLinkedList.add(hero4);singleLinkedList.list();System.out.println("有效的节点个数=" + getLength(singleLinkedList.getHead()));
}
  • 程序运行结果
HeroNode [no=1, name=宋江, nickName=及时雨]
HeroNode [no=2, name=卢俊义, nickName=玉麒麟]
HeroNode [no=3, name=吴用, nickName=智多星]
HeroNode [no=4, name=林冲, nickName=豹子头]
有效的节点个数=4

3.2、查找单链表中的倒数第 k 个结点

3.2.1、代码思路

  • 查找单链表中的倒数第k个结点 【新浪面试题】

    • 首先,获取整个链表中元素的个数 size
    • 在使用 for 循环定位至倒数第 index(形参) 个节点,返回即可
    • for 循环的条件应如何确定?for (int i = 0; i < x; i++) 中 x 的值应是多少?我们需要定位至倒数第 index 个节点,在 for 循环之前,我们已经定位置首节点,还需再走 (size - index ) 步,定位至倒数第 index 个节点
    • 举例说明:链表中一共有 4 个元素,想要定位至倒数第 2 个节点,那么需要在首节点之后走两步,到达倒数第 2 个节点

3.2.2、代码实现

  • 查找单链表中的倒数第k个结点

public static HeroNode findLastIndexNode(HeroNode head, int index) {if (head.next == null) {return null;}int size = getLength(head);if (index  0 || index > size) {return null;}HeroNode cur = head.next;for (int i = 0; i < size - index; i++) {cur = cur.next;}return cur;
}
  • 测试代码
public static void main(String[] args) {HeroNode hero1 = new HeroNode(1, "宋江", "及时雨");HeroNode hero2 = new HeroNode(2, "卢俊义", "玉麒麟");HeroNode hero3 = new HeroNode(3, "吴用", "智多星");HeroNode hero4 = new HeroNode(4, "林冲", "豹子头");SingleLinkedList singleLinkedList = new SingleLinkedList();singleLinkedList.add(hero1);singleLinkedList.add(hero2);singleLinkedList.add(hero3);singleLinkedList.add(hero4);singleLinkedList.list();HeroNode res = findLastIndexNode(singleLinkedList.getHead(), 2);System.out.println("res=" + res);}
  • 程序运行结果
HeroNode [no=1, name=宋江, nickName=及时雨]
HeroNode [no=2, name=卢俊义, nickName=玉麒麟]
HeroNode [no=3, name=吴用, nickName=智多星]
HeroNode [no=4, name=林冲, nickName=豹子头]
res=HeroNode [no=3, name=吴用, nickName=智多星]

3.3、单链表的反转

3.3.1、代码思路

  • 单链表的反转【腾讯面试题,有点难度】

    • 定义一个新的头结点 reverseHead ,一点一点将链表反转后,再串起来
    • 怎么个串法?
      • 在原链表中每读取一个节点(cur),先保存其下一个节点的地址(next),然后将 cur 节点放在新链表的最前面
      • 然后执行遍历: cur = next ,即指针后移
      • 遍历完成后,新链表即是反转后的链表
    • 如何将 cur 节点插入在新链表的最前面
      • cur.next = reverseHead.next;
      • reverseHead.next = cur;
    • while 循环终止条件? cur == null :已遍历至链表尾部
  • 单链表的翻转可以参考我的这篇博文:https://blog.csdn.net/oneby1314/article/details/107577923

3.3.2、代码实现

  • 单链表的反转

public static void reversetList(HeroNode head) {if (head.next == null || head.next.next == null) {return;}HeroNode cur = head.next;HeroNode next = null;HeroNode reverseHead = new HeroNode(0, "", "");while (cur != null) {next = cur.next;cur.next = reverseHead.next;reverseHead.next = cur;cur = next;}head.next = reverseHead.next;
}
  • 测试代码
public static void main(String[] args) {HeroNode hero1 = new HeroNode(1, "宋江", "及时雨");HeroNode hero2 = new HeroNode(2, "卢俊义", "玉麒麟");HeroNode hero3 = new HeroNode(3, "吴用", "智多星");HeroNode hero4 = new HeroNode(4, "林冲", "豹子头");SingleLinkedList singleLinkedList = new SingleLinkedList();singleLinkedList.add(hero1);singleLinkedList.add(hero2);singleLinkedList.add(hero3);singleLinkedList.add(hero4);System.out.println("原来链表的情况~~");singleLinkedList.list();System.out.println("反转单链表~~");reversetList(singleLinkedList.getHead());singleLinkedList.list();
}
  • 程序运行结果
原来链表的情况~~
HeroNode [no=1, name=宋江, nickName=及时雨]
HeroNode [no=2, name=卢俊义, nickName=玉麒麟]
HeroNode [no=3, name=吴用, nickName=智多星]
HeroNode [no=4, name=林冲, nickName=豹子头]
反转单链表~~
HeroNode [no=4, name=林冲, nickName=豹子头]
HeroNode [no=3, name=吴用, nickName=智多星]
HeroNode [no=2, name=卢俊义, nickName=玉麒麟]
HeroNode [no=1, name=宋江, nickName=及时雨]

3.4、单链表的反转(我的代码)

3.4.1、代码思路

  • 单链表的反转【腾讯面试题,有点难度】

    • 原链表为 cur 指向 next ,反转链表不就是把 next 指向 cur 吗?
    • 由于 next 指向 cur 时,next 将 丢失其下一节点的地址,所以需要先将 nnext 保存起来
    • next ==null 时链表已经反转完毕,最后将头结点指向 cur 节点即可

3.4.2、代码实现

  • 单链表的反转

public static void myReversetList(HeroNode head) {if (head.next == null || head.next.next == null) {return;}HeroNode cur = head.next;HeroNode next = cur.next;cur.next = null;while (next != null) {HeroNode nnext = next.next;next.next = cur;cur = next;next = nnext;}head.next = cur;
}
  • 测试代码
public static void main(String[] args) {HeroNode hero1 = new HeroNode(1, "宋江", "及时雨");HeroNode hero2 = new HeroNode(2, "卢俊义", "玉麒麟");HeroNode hero3 = new HeroNode(3, "吴用", "智多星");HeroNode hero4 = new HeroNode(4, "林冲", "豹子头");SingleLinkedList singleLinkedList = new SingleLinkedList();singleLinkedList.add(hero1);singleLinkedList.add(hero2);singleLinkedList.add(hero3);singleLinkedList.add(hero4);System.out.println("原来链表的情况~~");singleLinkedList.list();System.out.println("反转单链表~~");reversetList(singleLinkedList.getHead());singleLinkedList.list();
}
  • 程序运行结果
原来链表的情况~~
HeroNode [no=1, name=宋江, nickName=及时雨]
HeroNode [no=2, name=卢俊义, nickName=玉麒麟]
HeroNode [no=3, name=吴用, nickName=智多星]
HeroNode [no=4, name=林冲, nickName=豹子头]
反转单链表~~
HeroNode [no=4, name=林冲, nickName=豹子头]
HeroNode [no=3, name=吴用, nickName=智多星]
HeroNode [no=2, name=卢俊义, nickName=玉麒麟]
HeroNode [no=1, name=宋江, nickName=及时雨]

3.5、从尾到头打印单链表

3.5.1、栈的基本使用

  • 测试代码
public static void main(String[] args) {Stack<String> stack = new Stack();stack.add("jack");stack.add("tom");stack.add("smith");while (stack.size() > 0) {System.out.println(stack.pop());}
}
  • 程序运行结果
smith
tom
jack

3.5.2、代码思路

  • 从尾到头打印单链表 【百度,要求方式1:反向遍历 。 方式2:Stack栈】

    • 方式一:先将单链表进行反转操作,然后再遍历输出,问题: 破坏原链表结构,不可取
    • 方式二:遍历链表,去除节点压入栈中,利用栈 先进后出的特点,实现逆序打印

3.5.3、代码实现

  • 从尾到头打印单链表

public static void reversePrint(HeroNode head) {if (head.next == null) {return;}Stack<HeroNode> stack = new Stack<HeroNode>();HeroNode cur = head.next;while (cur != null) {stack.push(cur);cur = cur.next;}while (stack.size() > 0) {System.out.println(stack.pop());}
}
  • 测试代码
public static void main(String[] args) {HeroNode hero1 = new HeroNode(1, "宋江", "及时雨");HeroNode hero2 = new HeroNode(2, "卢俊义", "玉麒麟");HeroNode hero3 = new HeroNode(3, "吴用", "智多星");HeroNode hero4 = new HeroNode(4, "林冲", "豹子头");SingleLinkedList singleLinkedList = new SingleLinkedList();singleLinkedList.add(hero1);singleLinkedList.add(hero2);singleLinkedList.add(hero3);singleLinkedList.add(hero4);System.out.println("原来链表的情况~~");singleLinkedList.list();System.out.println("测试逆序打印单链表, 没有改变链表的结构~~");reversePrint(singleLinkedList.getHead());
}
  • 程序运行结果
原来链表的情况~~
HeroNode [no=1, name=宋江, nickName=及时雨]
HeroNode [no=2, name=卢俊义, nickName=玉麒麟]
HeroNode [no=3, name=吴用, nickName=智多星]
HeroNode [no=4, name=林冲, nickName=豹子头]
测试逆序打印单链表, 没有改变链表的结构~~
HeroNode [no=4, name=林冲, nickName=豹子头]
HeroNode [no=3, name=吴用, nickName=智多星]
HeroNode [no=2, name=卢俊义, nickName=玉麒麟]
HeroNode [no=1, name=宋江, nickName=及时雨]

3.6、合并两个有序的单链表

3.6.1、代码思路

  • 合并两个有序的单链表,合并之后的链表依然有序【课后练习】

3.6.2、代码实现

  • 合并两个有序的单链表,合并之后的链表依然有序
  • 具体讲解见我的一篇博客:https://blog.csdn.net/oneby1314/article/details/107590876

3.7、单向链表所有代码

public class SingleLinkedListDemo {public static void main(String[] args) {HeroNode hero1 = new HeroNode(1, "宋江", "及时雨");HeroNode hero2 = new HeroNode(2, "卢俊义", "玉麒麟");HeroNode hero3 = new HeroNode(3, "吴用", "智多星");HeroNode hero4 = new HeroNode(4, "林冲", "豹子头");SingleLinkedList singleLinkedList = new SingleLinkedList();singleLinkedList.add(hero1);singleLinkedList.add(hero4);singleLinkedList.add(hero2);singleLinkedList.add(hero3);System.out.println("原来链表的情况~~");singleLinkedList.list();System.out.println("反转单链表~~");reversetList(singleLinkedList.getHead());singleLinkedList.list();System.out.println("测试逆序打印单链表, 没有改变链表的结构~~");reversePrint(singleLinkedList.getHead());singleLinkedList.addByOrder(hero1);singleLinkedList.addByOrder(hero4);singleLinkedList.addByOrder(hero2);singleLinkedList.addByOrder(hero3);singleLinkedList.list();HeroNode newHeroNode = new HeroNode(2, "小卢", "玉麒麟~~");singleLinkedList.update(newHeroNode);System.out.println("修改后的链表情况~~");singleLinkedList.list();singleLinkedList.del(1);singleLinkedList.del(4);System.out.println("删除后的链表情况~~");singleLinkedList.list();System.out.println("有效的节点个数=" + getLength(singleLinkedList.getHead()));HeroNode res = findLastIndexNode(singleLinkedList.getHead(), 3);System.out.println("res=" + res);}public static void reversePrint(HeroNode head) {if (head.next == null) {return;}Stack<HeroNode> stack = new Stack<HeroNode>();HeroNode cur = head.next;while (cur != null) {stack.push(cur);cur = cur.next;}while (stack.size() > 0) {System.out.println(stack.pop());}}public static void reversetList(HeroNode head) {if (head.next == null || head.next.next == null) {return;}HeroNode cur = head.next;HeroNode next = null;HeroNode reverseHead = new HeroNode(0, "", "");while (cur != null) {next = cur.next;cur.next = reverseHead.next;reverseHead.next = cur;cur = next;}head.next = reverseHead.next;}public static void myReversetList(HeroNode head) {if (head.next == null || head.next.next == null) {return;}HeroNode cur = head.next;HeroNode next = cur.next;cur.next = null;while (next != null) {HeroNode nnext = next.next;next.next = cur;cur = next;next = nnext;}head.next = cur;}public static HeroNode findLastIndexNode(HeroNode head, int index) {if (head.next == null) {return null;}int size = getLength(head);if (index  0 || index > size) {return null;}HeroNode cur = head.next;for (int i = 0; i < size - index; i++) {cur = cur.next;}return cur;}public static int getLength(HeroNode head) {if (head.next == null) {return 0;}int length = 0;HeroNode cur = head.next;while (cur != null) {length++;cur = cur.next;}return length;}}class SingleLinkedList {private HeroNode head = new HeroNode(0, "", "");public HeroNode getHead() {return head;}public void add(HeroNode heroNode) {HeroNode temp = head;while (true) {if (temp.next == null) {break;}temp = temp.next;}temp.next = heroNode;}public void addByOrder(HeroNode heroNode) {HeroNode temp = head;boolean flag = false;while (true) {if (temp.next == null) {break;}if (temp.next.no > heroNode.no) {break;} else if (temp.next.no == heroNode.no) {flag = true;break;}temp = temp.next;}if (flag) {System.out.printf("准备插入的英雄的编号 %d 已经存在了, 不能加入\n", heroNode.no);} else {heroNode.next = temp.next;temp.next = heroNode;}}public void update(HeroNode newHeroNode) {if (head.next == null) {System.out.println("链表为空~");return;}HeroNode temp = head.next;boolean flag = false;while (true) {if (temp == null) {break;}if (temp.no == newHeroNode.no) {flag = true;break;}temp = temp.next;}if (flag) {temp.name = newHeroNode.name;temp.nickName = newHeroNode.nickName;} else {System.out.printf("没有找到 编号 %d 的节点,不能修改\n", newHeroNode.no);}}public void del(int no) {HeroNode temp = head;boolean flag = false;while (true) {if (temp.next == null) {break;}if (temp.next.no == no) {flag = true;break;}temp = temp.next;}if (flag) {temp.next = temp.next.next;} else {System.out.printf("要删除的 %d 节点不存在\n", no);}}public void list() {if (head.next == null) {System.out.println("链表为空");return;}HeroNode temp = head.next;while (true) {if (temp == null) {break;}System.out.println(temp);temp = temp.next;}}
}class HeroNode {public int no;public String name;public String nickName;public HeroNode next;public HeroNode(int no, String name, String nickname) {this.no = no;this.name = name;this.nickName = nickname;}@Overridepublic String toString() {return "HeroNode [no=" + no + ", name=" + name + ", nickName=" + nickName + "]";}}

4、双向链表

4.1、与单向链表的比较

  • 单向链表, 查找的方向只能是一个方向, 而双向链表可以向前或者向后查找
  • 单向链表不能自我删除, 需要靠辅助节点 , 而双向链表, 则可以 自我删除, 所以前面我们单链表删除时节点, 总是找到 temp ,temp 是待删除节点的 前一个节点(认真体会)

4.2、链表节点定义

  • 在单向链表节点的基础上,增加 pre ,用于指向前一个节点

class HeroNode {public int no;public String name;public String nickname;public HeroNode next;public HeroNode pre;public HeroNode(int no, String name, String nickname) {this.no = no;this.name = name;this.nickname = nickname;}@Overridepublic String toString() {return "HeroNode [no=" + no + ", name=" + name + ", nickname=" + nickname + "]";}}

4.3、链表定义

  • 定义整个链表的头结点,作为链表的入口

class DoubleLinkedList {private HeroNode head = new HeroNode(0, "", "");public HeroNode getHead() {return head;}

4.4、链表遍历

4.4.1、代码思路

  • 定义辅助变量 temp ,相当于一个指针,指向 当前节点 ,用于遍历链表
  • 何时停止 while 循环? temp == null :已经遍历至链表尾部

4.4.2、代码实现


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

4.5、尾部插入

4.5.1、代码思路

  • 定义辅助变量 temp ,相当于一个指针,指向 当前节点
  • 何时停止 while 循环? temp.next == null :temp 节点已经是链表最后一个节点,在 temp 节点之后插入 heroNode 节点即可
  • 如何插入?
    • temp.next 指向新的尾节点 heroNode : temp.next = heroNode;
    • heroNode .pre 指向旧的尾节点 temp : *heroNode.pre = temp;

4.5.2、代码实现

  • 在链表尾部插入节点

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

4.6、按顺序插入

4.6.1、代码思路

  • 定义辅助变量 temp ,相当于一个指针,指向 当前节点
  • 我们将 heroNode 节点插入到 temp 节点之后还是 temp 节点之前?
    • 如果插入到 temp 节点之后:

      • 判断条件: temp.next.no > heroNode.no ,即 temp 的下一个节点的值比 heroNode 节点的值大,所以需要将 heroNode 插入到 temp 节点之后
    • while 循环终止条件:
      • temp.next == null :temp 节点已经是链表的尾节点
      • temp.next.no > heroNode.no :heroNode 节点的值介于 temp 节点的值和 temp 下一个节点的值之间
      • temp.next.no == heroNode.no :heroNode 节点的值等于 temp 下一个节点的值,不能进行插入
    • 如果插入到 temp 节点之前:
      • 判断条件: temp.no > heroNode.no ,即 temp 节点的值比 heroNode 节点的值大,所以需要将 heroNode 插入到 temp 节点之前
      • 存在的问题:如果需要在链表尾部插入 heroNode 节点,即需要在 null 节点之前插入 heroNode 节点, 定位至 null 节点将丢失其前一个节点的信息(除非使用一个变量保存起来),所以跳出循环的判断条件为:temp.next == null
      • 所以我们选取:【插入到 temp 节点之后】方案

4.6.2、代码实现

  • 代码

public void addByOrder(HeroNode heroNode) {HeroNode temp = head;boolean flag = false;while (true) {if (temp.next == null) {break;}if (temp.next.no > heroNode.no) {break;} else if (temp.next.no == heroNode.no) {flag = true;break;}temp = temp.next;}if (flag) {System.out.printf("准备插入的英雄的编号 %d 已经存在了, 不能加入\n", heroNode.no);} else {heroNode.next = temp.next;if(temp.next != null) {temp.next.pre = heroNode;}temp.next = heroNode;heroNode.pre = temp;}
}

4.7、修改节点信息

4.7.1、代码思路

  • 定义辅助变量 temp ,相当于一个指针,指向 当前节点
  • 如何找到指定节点? *temp.no == no

4.7.2、代码实现

  • 修改指定节点的信息

public void update(HeroNode newHeroNode) {if (head.next == null) {System.out.println("链表为空~");return;}HeroNode temp = head.next;boolean flag = false;while (true) {if (temp == null) {break;}if (temp.no == newHeroNode.no) {flag = true;break;}temp = temp.next;}if (flag) {temp.name = newHeroNode.name;temp.nickname = newHeroNode.nickname;} else {System.out.printf("没有找到 编号 %d 的节点,不能修改\n", newHeroNode.no);}
}

4.8、删除节点

4.8.1、代码思路

  • 定义辅助变量 temp ,相当于一个指针,指向 当前节点
  • while 循环的终止条件?由于 temp 节点就是待删除节点,所以终止条件是: temp == null
  • 为何双向链表,可以实现 自我删除?定位至待删除的节点 temp ,由于temp 节点有其前一个节点和后一个节点的信息,所以可实现自我删除
  • 如何删除?
    • temp 的前一个节点的 next 域指向 temp 的后一个节点: temp.pre.next = temp.next;
    • temp 的后一个节点的 pre 域指向 temp 的前一个节点: temp.next.pre = temp.pre;
      • 有个地方需要注意,如果 temp 已经是链表尾节点,temp 已经没有下一个节点
      • 这时只需要将 temp 的前一个节点的 next 指向 null 即可
      • 所以 temp.next.pre = temp.pre; 执行的前提条件是 *temp.next != null

4.8.2、代码实现

  • 删除指定节点

public void del(int no) {if (head.next == null) {System.out.println("链表为空,无法删除");return;}HeroNode temp = head.next;boolean flag = false;while (true) {if (temp == null) {break;}if (temp.no == no) {flag = true;break;}temp = temp.next;}if (flag) {temp.pre.next = temp.next;if (temp.next != null) {temp.next.pre = temp.pre;}} else {System.out.printf("要删除的 %d 节点不存在\n", no);}
}

4.9、双向链表测试

4.9.1、测试代码

public static void main(String[] args) {System.out.println("双向链表的测试");HeroNode hero1 = new HeroNode(1, "宋江", "及时雨");HeroNode hero2 = new HeroNode(2, "卢俊义", "玉麒麟");HeroNode hero3 = new HeroNode(3, "吴用", "智多星");HeroNode hero4 = new HeroNode(5, "林冲", "豹子头");DoubleLinkedList doubleLinkedList = new DoubleLinkedList();doubleLinkedList.add(hero1);doubleLinkedList.add(hero2);doubleLinkedList.add(hero3);doubleLinkedList.add(hero4);doubleLinkedList.list();doubleLinkedList.addByOrder(new HeroNode(4, "Heygo", "Heygogo"));doubleLinkedList.addByOrder(new HeroNode(6, "Oneby", "Onebyone"));System.out.println("按顺序插入后的情况");doubleLinkedList.list();HeroNode newHeroNode = new HeroNode(5, "公孙胜", "入云龙");doubleLinkedList.update(newHeroNode);System.out.println("修改后的链表情况");doubleLinkedList.list();doubleLinkedList.del(3);System.out.println("删除后的链表情况~~");doubleLinkedList.list();
}

4.9.2、程序运行结果

双向链表的测试
HeroNode [no=1, name=宋江, nickname=及时雨]
HeroNode [no=2, name=卢俊义, nickname=玉麒麟]
HeroNode [no=3, name=吴用, nickname=智多星]
HeroNode [no=5, name=林冲, nickname=豹子头]
按顺序插入后的情况
HeroNode [no=1, name=宋江, nickname=及时雨]
HeroNode [no=2, name=卢俊义, nickname=玉麒麟]
HeroNode [no=3, name=吴用, nickname=智多星]
HeroNode [no=4, name=Heygo, nickname=Heygogo]
HeroNode [no=5, name=林冲, nickname=豹子头]
HeroNode [no=6, name=Oneby, nickname=Onebyone]
修改后的链表情况
HeroNode [no=1, name=宋江, nickname=及时雨]
HeroNode [no=2, name=卢俊义, nickname=玉麒麟]
HeroNode [no=3, name=吴用, nickname=智多星]
HeroNode [no=4, name=Heygo, nickname=Heygogo]
HeroNode [no=5, name=公孙胜, nickname=入云龙]
HeroNode [no=6, name=Oneby, nickname=Onebyone]
删除后的链表情况~~
HeroNode [no=1, name=宋江, nickname=及时雨]
HeroNode [no=2, name=卢俊义, nickname=玉麒麟]
HeroNode [no=4, name=Heygo, nickname=Heygogo]
HeroNode [no=5, name=公孙胜, nickname=入云龙]
HeroNode [no=6, name=Oneby, nickname=Onebyone]

4.10、双向链表所有代码

public class DoubleLinkedListDemo {public static void main(String[] args) {System.out.println("双向链表的测试");HeroNode hero1 = new HeroNode(1, "宋江", "及时雨");HeroNode hero2 = new HeroNode(2, "卢俊义", "玉麒麟");HeroNode hero3 = new HeroNode(3, "吴用", "智多星");HeroNode hero4 = new HeroNode(5, "林冲", "豹子头");DoubleLinkedList doubleLinkedList = new DoubleLinkedList();doubleLinkedList.add(hero1);doubleLinkedList.add(hero2);doubleLinkedList.add(hero3);doubleLinkedList.add(hero4);doubleLinkedList.list();doubleLinkedList.addByOrder(new HeroNode(0, "Kobe", "BlackMamba"));doubleLinkedList.addByOrder(new HeroNode(4, "Heygo", "Heygogo"));doubleLinkedList.addByOrder(new HeroNode(6, "Oneby", "Onebyone"));System.out.println("按顺序插入后的情况");doubleLinkedList.list();HeroNode newHeroNode = new HeroNode(5, "公孙胜", "入云龙");doubleLinkedList.update(newHeroNode);System.out.println("修改后的链表情况");doubleLinkedList.list();doubleLinkedList.del(3);System.out.println("删除后的链表情况~~");doubleLinkedList.list();}}class DoubleLinkedList {private HeroNode head = new HeroNode(0, "", "");public HeroNode getHead() {return head;}public void list() {if (head.next == null) {System.out.println("链表为空");return;}HeroNode temp = head.next;while (true) {if (temp == null) {break;}System.out.println(temp);temp = temp.next;}}public void add(HeroNode heroNode) {HeroNode temp = head;while (true) {if (temp.next == null) {break;}temp = temp.next;}temp.next = heroNode;heroNode.pre = temp;}public void addByOrder(HeroNode heroNode) {HeroNode temp = head;boolean flag = false;while (true) {if (temp.next == null) {break;}if (temp.next.no > heroNode.no) {break;} else if (temp.next.no == heroNode.no) {flag = true;break;}temp = temp.next;}if (flag) {System.out.printf("准备插入的英雄的编号 %d 已经存在了, 不能加入\n", heroNode.no);} else {heroNode.next = temp.next;if(temp.next != null) {temp.next.pre = heroNode;}temp.next = heroNode;heroNode.pre = temp;}}public void update(HeroNode newHeroNode) {if (head.next == null) {System.out.println("链表为空~");return;}HeroNode temp = head.next;boolean flag = false;while (true) {if (temp == null) {break;}if (temp.no == newHeroNode.no) {flag = true;break;}temp = temp.next;}if (flag) {temp.name = newHeroNode.name;temp.nickname = newHeroNode.nickname;} else {System.out.printf("没有找到 编号 %d 的节点,不能修改\n", newHeroNode.no);}}public void del(int no) {if (head.next == null) {System.out.println("链表为空,无法删除");return;}HeroNode temp = head.next;boolean flag = false;while (true) {if (temp == null) {break;}if (temp.no == no) {flag = true;break;}temp = temp.next;}if (flag) {temp.pre.next = temp.next;if (temp.next != null) {temp.next.pre = temp.pre;}} else {System.out.printf("要删除的 %d 节点不存在\n", no);}}}class HeroNode {public int no;public String name;public String nickname;public HeroNode next;public HeroNode pre;public HeroNode(int no, String name, String nickname) {this.no = no;this.name = name;this.nickname = nickname;}@Overridepublic String toString() {return "HeroNode [no=" + no + ", name=" + name + ", nickname=" + nickname + "]";}}

4.11、总结

  • 辅助变量 temp ,相当于一个指针,指向 当前节点
  • 如果定位至当前节点会丢失前一个节点的信息,那么我们只能定位至待操作节点的前一个节点:使用 temp.next 进行条件判断

5、单向环形链表

5.1、单向环形链表应用场景

  • Josephu 问题为: 设编号为 1, 2, … n 的 n 个人围坐一圈, 约定编号为 k(1

5.2、单向环形链表图解

5.3、Josephu 问题

  • 用一个不带头结点的循环链表来处理 Josephu 问题: 先构成一个有 n 个结点的 单循环链表, 然后由 k 结点起从 1 开始计数, 计到 m 时, 对应结点从链表中删除, 然后再从被删除结点的下一个结点又从 1 开始计数, 直到最后一个结点从链表中删除算法结束。

5.4、环形链表的构建与遍历

5.4.1、Boy 节点的定义

  • Boy 节点就是个普普通通的单向链表节点

class Boy {private int no;private Boy next;public Boy(int no) {this.no = no;}public int getNo() {return no;}public void setNo(int no) {this.no = no;}public Boy getNext() {return next;}public void setNext(Boy next) {this.next = next;}
}

5.4.2、单向循环链表的定义

  • first 节点为单向循环链表的 首节点,是真实 存放数据的节点,不是头结点

class CircleSingleLinkedList {private Boy first = null;

5.4.3、构建单向循环链表

1、代码思路
  • 长度为 1 的情况:

    • 新创建的 boy 节点即是首节点: first = boy;
    • 自封闭(自己构成环形链表): first.setNext(first);
    • 此时 first 节点既是首节点,也是尾节点,辅助指针也指向 first : curBoy = first;
  • 长度不为 1 的情况:
    • 将 boy 节点添加至环形链表的最后: curBoy.setNext(boy); ,curBoy 节点永远是环形链表的尾节点
    • 构成环形链表(最): boy.setNext(first);
    • 辅助指针后移,指向环形链表的尾节点: *curBoy = boy;

2、代码实现

public void addBoy(int nums) {if (nums < 1) {System.out.println("nums的值不正确");return;}Boy curBoy = null;for (int i = 1; i  nums; i++) {Boy boy = new Boy(i);if (i == 1) {first = boy;first.setNext(first);curBoy = first;} else {curBoy.setNext(boy);boy.setNext(first);curBoy = boy;}}
}

5.4.4、遍历单向循环链表

1、代码思路
  • 定义辅助变量 curBoy ,相当于一个指针,指向 当前节点
  • 何时退出 while 循环?当 curBoy 已经指向环形链表的尾节点: *curBoy.getNext() == first
2、代码实现

public void showBoy() {if (first == null) {System.out.println("没有任何小孩~~");return;}Boy curBoy = first;while (true) {System.out.printf("小孩的编号 %d \n", curBoy.getNo());if (curBoy.getNext() == first) {break;}curBoy = curBoy.getNext();}
}

5.5、解决 Josephu 问题

5.5.1、代码思路

  • 辅助变量 helper :helper 永都指向 环形链表的尾节点,环形链表的尾节点永远都指向首节点,可得出: helper.getNext() == first
  • 如何将 helper 定位至环形链表的尾节点?
    • 初始化时,让 helper = first ,此时 helper 指向环形链表的首节点
    • while 循环终止条件? helper.getNext() == first :此时 helper 已经移动至环形链表的尾节点
  • 如何定位至第 startNo 个节点?如果想要定位至第 2 个节点,那么则需要让 first 和 helper 都移动 1 步,所以让 first 和 helper 都移动 (startNo - 1)步即可
  • 如何数 nums 下?让 first 和 helper 都移动 (nums - 1)步即可
  • 如何实现出圈?
    • 我们需要将 first 指向的节点出圈,first 前一个节点的地址在 helper 中存着(环形链表)
    • 先让 first 后移一步: first = first.getNext;
    • 出圈: helper.setNext(first); ,原来的 first 节点由于没有任何引用,便会被垃圾回收机制回收
  • while 循环终止条件?圈中只剩一人: *helper == first

5.5.2、代码实现


public void countBoy(int startNo, int countNum, int nums) {if (first == null || startNo < 1 || startNo > nums) {System.out.println("参数输入有误, 请重新输入");return;}Boy helper = first;while (true) {if (helper.getNext() == first) {break;}helper = helper.getNext();}for (int j = 0; j < startNo - 1; j++) {first = first.getNext();helper = helper.getNext();}while (true) {if (helper == first) {break;}for (int j = 0; j < countNum - 1; j++) {first = first.getNext();helper = helper.getNext();}System.out.printf("小孩%d出圈\n", first.getNo());first = first.getNext();helper.setNext(first);}System.out.printf("最后留在圈中的小孩编号%d \n", first.getNo());}

5.6、Josephu 问题测试

5.6.1、测试代码

public static void main(String[] args) {CircleSingleLinkedList circleSingleLinkedList = new CircleSingleLinkedList();circleSingleLinkedList.addBoy(5);circleSingleLinkedList.showBoy();circleSingleLinkedList.countBoy(1, 2, 3);
}

5.6.2、程序运行结果

小孩的编号 1
小孩的编号 2
小孩的编号 3
小孩的编号 4
小孩的编号 5
小孩2出圈
小孩4出圈
小孩1出圈
小孩5出圈
最后留在圈中的小孩编号3

5.7、Josephu 问题所有代码

public class Josepfu {public static void main(String[] args) {CircleSingleLinkedList circleSingleLinkedList = new CircleSingleLinkedList();circleSingleLinkedList.addBoy(5);circleSingleLinkedList.showBoy();circleSingleLinkedList.countBoy(1, 2, 3);}}class CircleSingleLinkedList {private Boy first = null;public void addBoy(int nums) {if (nums < 1) {System.out.println("nums的值不正确");return;}Boy curBoy = null;for (int i = 1; i  nums; i++) {Boy boy = new Boy(i);if (i == 1) {first = boy;first.setNext(first);curBoy = first;} else {curBoy.setNext(boy);boy.setNext(first);curBoy = boy;}}}public void showBoy() {if (first == null) {System.out.println("没有任何小孩~~");return;}Boy curBoy = first;while (true) {System.out.printf("小孩的编号 %d \n", curBoy.getNo());if (curBoy.getNext() == first) {break;}curBoy = curBoy.getNext();}}public void countBoy(int startNo, int countNum, int nums) {if (first == null || startNo < 1 || startNo > nums) {System.out.println("参数输入有误, 请重新输入");return;}Boy helper = first;while (true) {if (helper.getNext() == first) {break;}helper = helper.getNext();}for (int j = 0; j < startNo - 1; j++) {first = first.getNext();helper = helper.getNext();}while (true) {if (helper == first) {break;}for (int j = 0; j < countNum - 1; j++) {first = first.getNext();helper = helper.getNext();}System.out.printf("小孩%d出圈\n", first.getNo());first = first.getNext();helper.setNext(first);}System.out.printf("最后留在圈中的小孩编号%d \n", first.getNo());}
}class Boy {private int no;private Boy next;public Boy(int no) {this.no = no;}public int getNo() {return no;}public void setNo(int no) {this.no = no;}public Boy getNext() {return next;}public void setNext(Boy next) {this.next = next;}}

5.8、总结

  • 操作单向链表:对于插入、删除操作,只能定位至待操作节点的前一个节点,如果定位至当前节点,那么其上一个节点的信息便会丢失

数据结构-链表深度刨析相关推荐

  1. 深度刨析VDS链销模式12大优势

    最近最火爆的项目无疑是VDS,以致于山寨FDS出世,FDS宣称"自己是VDS升级版,是BNB公链首批落地项目".而VDS自称链销模式12大优势到底是什么鬼?我们的机会在哪里? 对比 ...

  2. 深度学习之残差网络原理深度刨析

    为什么要加深网络? 深度卷积网络自然的整合了低中高不同层次的特征,特征的层次可以靠加深网络的层次来丰富. 从而,在构建卷积网络时,网络的深度越高,可抽取的特征层次就越丰富. 所以一般我们会倾向于使用更 ...

  3. 什么是联表查询?(深度刨析,建议收藏)

    MySQL十六;联表查询 -- =================联表查询 join========================== -- 查询 参加了考试的同学(学号,姓名,科目编号,分数) S ...

  4. 7-4 平面向量加法 (15 分)---->c语言的深度刨析

    7-4 平面向量加法 (15 分) 本题要求编写程序,计算两个二维平面向量的和向量. 输入格式: 输入在一行中按照"x1​ y1​ x2​ y2​"的格式给出两个二维平面向量v1​ ...

  5. 【玩转c++】多态深度刨析

    多态的概念 多态的概念:通俗来说,就是多种形态, 具体点就是去完成某个行为,当不同的对象去完成时会 产生出不同的状态. 举个例子: 最近为了争夺在线支付市场,支付宝年底经常会做诱人的扫红包-支付-给奖 ...

  6. 快乐学算法or二分查找深度刨析

    目录 零.前言 一.算法思想 二.实现思路 四.源码 零.前言 今天我学习了二分查找(折半查找法),它是用于在有序集合中查找某一元素的便捷算法:算法思想易于理解,很多同学看了就觉得自己会了,但是约易于 ...

  7. FreeRtos学习笔记(11)查找就绪任务中优先级最高任务原理刨析

    FreeRtos学习笔记(11)查找就绪任务中优先级最高任务原理刨析 怎么查找就绪任务中优先级最高的? tasks.c中声明了一个全局变量 uxTopReadyPriority,任务从其他状态进入就绪 ...

  8. zookeeper笔记+源码刨析

    会不断更新!冲冲冲!跳转连接 https://blog.csdn.net/qq_35349982/category_10317485.html zookeeper 1.介绍 Zookeeper 分布式 ...

  9. 网络协议报文理解刨析篇二(再谈Http和Https), 加上TCP/UDP/IP协议分析(理解着学习), 面试官都惊讶你对网络的见解

    目录 前文链接(系列助学, 也为后文学习做铺垫, 可按需读取) 一. 再谈HTTP再理解 二. HTTP对比学习HTTPS HTTP和HTTPS的区别如下: 三.TCP协议  (三次握手四次挥手细节过 ...

最新文章

  1. 微软Win8将有多个版本 四款面向ARM平台
  2. 计算机课四年级说课稿,小学信息技术说课稿
  3. Maven下载、配置环境变量、配置本地仓库、国内镜像源、在IDEA中配置Maven
  4. 基于visual Studio2013解决C语言竞赛题之1027 YN
  5. SDNU 1011.盒子与球(斯特林函数)
  6. 圆心角 圆弧上点坐标_数控加工中心CNC的G02/G03圆弧指令的I、J、与R的区别
  7. Unicode-objects must be encoded before hashing
  8. c++ post请求_Golang GinWeb框架5绑定请求字符串/URI/请求头/复选框/表单类型
  9. pip 安装速度慢解决办法
  10. 第五讲 C#中的异常处理
  11. Multi-Task 多任务学习, 那些你不知道的事
  12. 从移动硬盘安装计算机系统文件,移动硬盘装系统,教您怎么用移动硬盘装系统...
  13. 查看计算机会议 论文,查看计算机视觉会议论文开会的地点
  14. 亲自动手写爬虫系列一、实现一个最简单爬虫
  15. 通过瑞利判据对显微镜物镜进行分辨率研究
  16. 选修课:唐宋词课堂鉴赏笔记01
  17. 2月书讯(下)| 新年到,新书到!
  18. 深入分析Linux虚拟化KVM-Qemu之ARMv8虚拟化
  19. 嵌入式单片机智能药盒设计(含代码)
  20. python大神的成长之路普通话三分钟_三分钟普通话说话30篇-我的成长之路 - 希赛网...

热门文章

  1. oracle一个表空间超出32g,Oracle表空间超出32G的解决方法
  2. 信息学奥赛系列教程:高精度计算
  3. JS学习笔记13-操作内联样式
  4. 如何让mysql榨干电脑性能_榨干多核CPU?这个方法你必须试试!
  5. Oracle 数据库的打开与关闭
  6. 鸿蒙OS应用开发基础之页面的跳转
  7. 虎书学习笔记1:图形学基础数学(集合、映射、逆映、对数、三角学)
  8. 利用XGBoost、Information Value、SHAP寻找“小北极星“指标与分层处理
  9. jquery获取指定元素
  10. valueOf函数详解