管理单向链表的缺点分析:
- 单向链表,查找的方向只能是一个方向,而双向链表可以向前或者向后查找。
- 单向链表不能自我删除,需要靠辅助节点 ,而双向链表,则可以自我删除,所以前面我们单链表删除节点时,总是找到 temp,temp 是待删除节点的前一个节点。
双向链表如何完成遍历,添加,修改和删除的思路
1) 遍历 :和单链表一样,只是可以向前,也可以向后查找
2) 添加 (默认添加到双向链表的最后)
(1)先找到双向链表的最后这个节点
(2) temp.next = newNode;
(3) newNode.pre = temp;
3) 修改 思路和原来的单向链表一样
4) 删除
(1) 因为是双向链表,因此,我们可以实现自我删除某个节点
(2) 直接找到要删除的这个节点,比如 temp
temp.pre.next = temp.next;
temp.next.pre = temp.pre;//若删除的是最后一个节点,会有空指针异常
代码实现
1. class doublelinkedlist {
2. //先初始化一个头节点,头节点不能动,不存放具体数据
3. private hero head = new hero(-1, "", "");
4.
5. //添加节点
6. public void add(hero h) {
7. //因为head节点不能动,因此我们需要一个辅助变量temp
8. hero temp = head;
9. //遍历链表,找到最后一个节点
10. while (true) {
11. if (temp.getNext() == null) {
12. break;
13. }
14. //如果没有到最后,将temp后移
15. temp = temp.getNext();
16. }
17. //当退出while循环时,temp就指向了链表的最后
18. //将链表的最后一个节点的next指向要添加的这个节点
19. //将要添加的这个节点的pre指向链表的最后一个节点
20. temp.setNext(h);
21. h.setPre(temp);
22. }
23.
24. //第二种方式在添加英雄时,根据排名将英雄插入到指定位置
25. //(如果有这个排名,则添加失败,并给出提示)
26. public void addByOrder(hero h) {
27. //因为头节点不能动,因此我们仍然通过一个辅助指针(变量)来帮助找到添加的位置
28. hero temp = head;
29. boolean flag = false;// flag 标志添加的编号是否存在,默认为 false
30. while (true) {
31. if (temp.getNext() == null) {//说明 temp 已经在链表的最后
32. break;
33. } else if (temp.getNext().getNum() > h.getNum()) {//位置找到,就在 temp 的后面插入
34. break;
35. } else if (temp.getNext().getNum() == h.getNum()) {//说明希望添加的 heroNode 的编号已然存在
36. flag = true;
37. break;
38. }
39. temp = temp.getNext();//后移,遍历当前链表
40. }
41. if (flag) { //不能添加,说明编号存在
42. System.out.println("添加的序号为" + h.getNum() + "的英雄序号已经存在,添加失败。");
43. return;
44. }
45.
46. //插入到链表中, temp 的后面
47. // (注意,先连两个节点之间的pre和next,再连另外两个节点的pre和next,否则会出错!!)
48. if (temp.getNext() != null) temp.getNext().setPre(h);
49. h.setNext(temp.getNext());//将h与temp的下一个节点相连(pre和next指针)
50.
51. h.setPre(temp);
52. temp.setNext(h);//再将h与temp节点相连(pre和next指针)
53. }
54.
55. //显示链表(遍历)
56. public void show() {
57. //判断链表是否为空
58. if (head.getNext() == null) {
59. System.out.println("show():链表为空。。。。");
60. return;
61. }
62. //因为头节点,不能动,因此我们需要一个辅助变量来遍历
63. hero temp = head.getNext();
64. while (true) {
65. //判断是否到链表最后
66. if (temp == null) {
67. break;
68. }
69. //输出节点的信息
70. System.out.println(temp.toString());
71. //将 temp 后移, 一定小心
72. temp = temp.getNext();
73. }
74. }
75.
76. //修改节点的信息, 根据 no 编号来修改,即 no 编号不能改.
77. //说明
78. //1. 根据 newHeroNode 的 no 来修改即可
79. public void update(hero h) {
80. hero temp = head.getNext();//定义一个辅助变量
81. boolean flag = false;//表示是否找到该节点
82. //判断链表是否空
83. if (head.getNext() == null) {
84. System.out.println("update():链表为空。。。。");
85. return;
86. }
87. //找到需要修改的节点, 根据 num值
88. while (true) {
89. if (temp == null) {
90. break;//已经遍历完链表
91. }
92. if (temp.getNum() == h.getNum()) {
93. flag = true;
94. break;
95. }
96. temp = temp.getNext();
97. }
98. if (flag) {
99. temp.setName(h.getName());
100. temp.setNikname(h.getNikname());
101. } else {//没有找到
102. System.out.printf("没有找到 编号 %d 的节点,不能修改\n", h.getNum());
103. }
104. }
105.
106. //删除节点
107. //思路
108. //1. head 不能动,因此我们需要一个 temp 辅助节点找到待删除节点的前一个节点
109. //2. 双向链表中我们在比较时,是 temp.no 和需要删除的节点的 no 比较
110. public void delete(int n) {
111. if (head.getNext() == null) {
112. System.out.println("delete():链表为空。。。。");
113. return;
114. }
115. hero temp = head.getNext();// 辅助变量(指针)
116. boolean flag = false;// 标志是否找到待删除节点的
117. while (true) {
118. if (temp == null) {//已经到链表的最后
119. break;
120. }
121. if (temp.getNum() == n) {//找到的待删除节点 temp
122. flag = true;
123. break;
124. }
125. temp = temp.getNext();//temp 后移,遍历
126. }
127. if (flag) {
128. temp.getPre().setNext(temp.getNext());
129. if (temp.getNext() != null) {
130. temp.getNext().setPre(temp.getPre());
131. }
132. } else {
133. System.out.printf("没有找到 编号 %d 的节点,不能删除\n", n);
134. }
135. }
136. }