双向链表的应用实例
管理单向链表的缺点分析:
- 单向链表,查找的方向只能是一个方向,而双向链表可以向前或者向后查找。
- 单向链表不能自我删除,需要靠辅助节点 ,而双向链表,则可以自我删除,所以前面我们单链表删除节点时,总是找到 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. }