双向链表
单双链表的一些比较
- 单向链表,查找的方向只能是一个方向,而双向链表可以向前或者向后查找。
- 单向链表不能自我删除,需要靠辅助节点,而双向链表,则可以自我删除,所以前面我们单链表删除时节点,总是找到temp,temp是待删除节点的前一个节点.
分析思路和代码实现
双向链表的遍历,添加,修改,删除的操作思路,代码实现
- 遍历方式和单链表一样,只是可以向前,也可以向后查找
- 添加 (默认添加到双向链表的最后)
- 先找到双向链表的最后这个节点
- temp.next = newHeroNode
- newHeroNode.pre = temp
- 修改 思路和 原来的单向链表一样.
- 删除
- 因为是双向链表,因此,我们可以实现自我删除某个节点
- 直接找到要删除的这个节点,比如temp
- temp.pre.next = temp.next
- temp.next.pre = temp.pre;
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164
| public class DoubleLinkedListDemo {
public static void main(String[] args) { System.out.println("双向链表的测试"); HeroNode2 hero1 = new HeroNode2(1, "宋江", "及时雨"); HeroNode2 hero2 = new HeroNode2(2, "卢俊义", "玉麒麟"); HeroNode2 hero3 = new HeroNode2(3, "吴用", "智多星"); HeroNode2 hero4 = new HeroNode2(4, "林冲", "豹子头"); DoubleLinkedList doubleLinkedList = new DoubleLinkedList(); doubleLinkedList.add(hero1); doubleLinkedList.add(hero2); doubleLinkedList.add(hero3); doubleLinkedList.add(hero4); doubleLinkedList.list(); HeroNode2 newHeroNode = new HeroNode2(4, "公孙胜", "入云龙"); doubleLinkedList.update(newHeroNode); System.out.println("修改后的链表情况"); doubleLinkedList.list(); doubleLinkedList.del(3); System.out.println("删除后的链表情况~~"); doubleLinkedList.list(); } }
class DoubleLinkedList { private HeroNode2 head = new HeroNode2(0, "", ""); public HeroNode2 getHead() { return head; } public void list() { if (head.next == null) { System.out.println("链表为空"); return; } HeroNode2 temp = head.next; while (true) { if (temp == null) { break; } System.out.println(temp); temp = temp.next; } } public void add(HeroNode2 heroNode) { HeroNode2 temp = head; while (true) { if (temp.next == null) { break; } temp = temp.next; } temp.next = heroNode; heroNode.pre = temp; } public void update(HeroNode2 newHeroNode) { if (head.next == null) { System.out.println("链表为空~"); return; } HeroNode2 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; } HeroNode2 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 HeroNode2 { public int no; public String name; public String nickname; public HeroNode2 next; public HeroNode2 pre; public HeroNode2(int no, String name, String nickname) { this.no = no; this.name = name; this.nickname = nickname; } @Override public String toString() { return "HeroNode [no=" + no + ", name=" + name + ", nickname=" + nickname + "]"; } }
|
单向环形链表
Josephu(约瑟夫、约瑟夫环) 问题
Josephu 问题为:设编号为1,2,…n的n个人围坐一圈,约定编号为k(1<=k<=n)的人从1开始报数,数到m 的那个人出列,它的下一位又从1开始报数,数到m的那个人又出列,依次类推,直到所有人出列为止,由此产生一个出队编号的序列。
用一个不带头结点的循环链表来处理Josephu问题:先构成一个有n个结点的单循环链表,然后由k结点起从1开始计数,计到m时,对应结点从链表中删除,然后再从被删除结点的下一个结点又从1开始计数,直到最后一个结点从链表中删除算法结束。
例:
n = 5 , 即有5个人 。
k = 1, 从第一个人开始报数。
m = 2, 数2下。
使用环形单向链表来解决 Josephu问题
- 先创建第一个节点, 让 first 指向该节点,并形成环形,当前节点为curBoy
- 后面当我们每创建一个新的节点,就把该节点,加入到已有的环形链表中即可.将新的节点称为boy,将curboy.next = boy;boy.next=first;curBoy = boy;
- 先让一个辅助指针(变量) curBoy,指向first节点
- 然后通过一个while循环遍历 该环形链表即可 。当 curBoy.next == first 结束遍历
n = 5 , 即有5个人
k = 1, 从第一个人开始报数
m = 2, 数2下
- 需求创建一个辅助指针(变量) helper , 事先应该指向环形链表的最后这个节点.
补充: 小孩报数前,先让 first 和 helper 移动 k - 1次
- 当小孩报数时,让first 和 helper 指针同时 的移动 m - 1 次
- 这时就可以将first 指向的小孩节点 出圈
first = first .next;
helper.next = first
原来first 指向的节点就没有任何引用,就会被回收
出圈的顺序
2->4->1->5->3
代码实现
节点类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| 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; } }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94
| 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()); } }
|
1 2 3 4 5 6 7 8 9 10 11 12 13
| public class Josepfu { public static void main(String[] args) { CircleSingleLinkedList circleSingleLinkedList = new CircleSingleLinkedList(); circleSingleLinkedList.addBoy(125); circleSingleLinkedList.showBoy(); circleSingleLinkedList.countBoy(10, 20, 125); } }
|