链表LinkedList
1.单向链表
1.1 定义HeroNode对象
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
| 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; }
@Override public String toString() { return "HeroNode [no=" + no + ", name=" + name + ", nickName=" + nickName + "]"; } }
|
1.2 定义一个单向链表
public void add(HeroNode heroNode);
添加节点的方法
public void addByOrder(HeroNode heroNode);
根据排名将英雄插入到指定位置–如果有这个排名则添加失败–给出提示
public void update(HeroNode newHeroNode);
修改节点的信息
public void showList();
显示链表
public void del(int no);
删除节点的方法
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 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189
| class SingleLinkedList { HeroNode head = new HeroNode(0,"","");
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 showList() { 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 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); } } }
|
1.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 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42
| public class SingleLinkedListDemo {
public static void main(String[] args) {
HeroNode hero1 = new HeroNode(1, "松江", "及时雨"); HeroNode hero2 = new HeroNode(2, "卢俊义","玉麒麟"); HeroNode hero4 = new HeroNode(4, "林冲","豹子头"); SingleLinkedList singleLinkedList = new SingleLinkedList();
singleLinkedList.addByOrder(hero4); singleLinkedList.addByOrder(hero2); singleLinkedList.addByOrder(hero1); System.out.println("修改前的链表"); singleLinkedList.showList(); HeroNode hero5 = new HeroNode(4, "冲冲", "豹子王"); singleLinkedList.update(hero5); System.out.println("修改后的链表"); singleLinkedList.showList(); singleLinkedList.del(1); System.out.println("删除后的数据!"); singleLinkedList.showList(); } }
|
1.4 求单链表中有效节点的个数(新浪面试题 )
求单链表中有效节点的个数(如果该链表带头结点,不统计头结点)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| public static int getLength(HeroNode head) { if(head.next == null) { return 0; } int count = 0; while(head.next != null) { count++; head = head.next; } return count; }
|
1.5 查找链表中的倒数第k个节点(新浪面试题 )
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
| public static HeroNode findLastIndexNode(HeroNode head,int index) { if(head.next == null) { System.out.println("链表为空"); return null; } int length = getLength(head); if(index <=0 || index > length ) { System.out.println("index不规范"); return null; }
HeroNode temp = head.next; for (int i = 0; i < length-index; i++) { temp = temp.next; } return temp; }
|
1.6 单链表的反转(腾讯面试题)
首先先判断该链表是否有数据
判断长度是否大于1
设置reverseHead
遍历链表 取数据 然后 加数据
把head.next = reverseHead.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
| public static void reverseList(HeroNode head) { if(head.next == null || head.next.next == null) { return; } HeroNode cur = head.next; HeroNode next = null; HeroNode reverseHead = new HeroNode(-1,"","");
while(cur!=null) { next = cur.next; cur.next = reverseHead.next; reverseHead.next = cur; cur = next; } head.next = reverseHead.next; }
|
1.7 单向链表的逆序打印(百度面试题)
- 方法一:就是先把单向链表进行反转然后遍历打印,这样存在一个问题:会改变原始的链表结构;
- 方法二:利用栈这个数据结构,将各个节点压入栈,然后利用栈的先进后出的特点来实现;
- 这里我们使用方法二;
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
| public static void reversePrint(HeroNode head) { if(head.next == null) { return; } Stack<HeroNode> stack = new Stack(); HeroNode cur = head.next; while(cur!=null) { stack.add(cur); cur = cur.next; } while(stack.size()>0) { System.out.println(stack.pop()); } }
|
TestStack.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| public class TestStack { public static void main(String[] args) { Stack<String> stack = new Stack(); stack.add("喵喵"); stack.add("喵喵~"); stack.add("喵喵miao~"); while(stack.size()>0) { System.out.println(stack.pop()); } } }
|
2. 双向链表
双向链表的遍历,添加,修改,删除的操作思路
- 遍历方法和单链表一样,只是可以向前,也可以向后查找
- 添加 (默认添加到双向链表的最后)
(1) 先找到双向链表的最后这个节点
(2) temp.next = newHeroNode
(3) newHeroNode.pre = temp;
- 修改思路和原来的单向链表一样.
- 删除
(1) 因为是双向链表,因此,我们可以实现自我删除某个节点
(2) 直接找到要删除的这个节点,比如 temp
(3) temp.pre.next = temp.next
(4) temp.next.pre = temp.pre;
2.1 定义一个HeroNode2对象
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
| 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 "HeroNode2 [no=" + no + ", name=" + name + ", nickName=" + nickName + "]"; } }
|
2.2 定义一个双向链表
public void add(HeroNode heroNode);
添加节点的方法
public void update(HeroNode newHeroNode);
修改节点的信息
public void showList();
显示链表
public void del(int no);
删除节点的方法
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 165 166 167 168 169 170 171 172 173 174 175 176 177
| class DoubleLinkedList{
HeroNode2 head = new HeroNode2(0,"","");
public HeroNode2 getHead() { return head; }
public void showList() { 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); } }
}
|
2.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 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42
|
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.showList();
HeroNode2 newHeroNode2 = new HeroNode2(4, "公孙胜","入云龙"); doubleLinkedList.update(newHeroNode2); System.out.println("修改后的链表情况"); doubleLinkedList.showList(); doubleLinkedList.del(2); System.out.println("删除后的链表"); doubleLinkedList.showList(); } }
|
3. 单向循环链表
3.1 单向环形链表应用场景
Josephu(约瑟夫、约瑟夫环) 问题为:设编号为 1,2,… n 的 n 个人围坐一圈,约定编号为 k(1<=k<=n)的人从 1 开始报数,数到 m 的那个人出列,它的下一位又从 1 开始报数,数到 m 的那个人又出列,依次类推,直到所有人出列为止,由此产生一个出队编号的序列。
用一个不带头结点的循环链表来处理 Josephu 问题:先构成一个有 n 个结点的单循环链表,然后由 k 结点起从 1 开始计数,计到 m 时,对应结点从链表中删除,然后再从被删除结点的下一个结点又从 1 开始计数,直到最后一个结点从链表中删除算法结束。
3.2 创建一个Boy类
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
|
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; }
}
|
3.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 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
|
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(); }
}
}
|
3.4 添加出圈方法
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
|
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());
}
|
3.5 测试
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| public class Josephu {
public static void main(String[] args) {
CircleSingleLinkedList circleSingleLinkedList = new CircleSingleLinkedList(); circleSingleLinkedList.addBoy(5); circleSingleLinkedList.showBoy(); circleSingleLinkedList.countBoy(1, 2, 5);
}
}
|