1. 链表对象

  1. // 定义 HeroNode2 , 每个 HeroNode 对象就是一个节点
  2. class HeroNode {
  3. public String no;
  4. public String name;
  5. public String nickname;
  6. public HeroNode next; // 指向下一个节点, 默认为 null
  7. public HeroNode pre; // 指向前一个节点, 默认为 null
  8. // 构造器
  9. public HeroNode(String no, String name, String nickname) {
  10. this.no = no;
  11. this.name = name;
  12. this.nickname = nickname;
  13. }
  14. // 为了显示方法,我们重新 toString
  15. @Override
  16. public String toString() {
  17. return "HeroNode [no=" + no + ", name=" + name + ", nickname=" + nickname + "]";
  18. }
  19. }

2. 对链表对象进行操作

  1. // 创建一个双向链表的类
  2. class DoubleLinkedList {
  3. // 先初始化一个头节点, 头节点不要动, 不存放具体的数据
  4. private HeroNode head = new HeroNode("0", "", "");
  5. //定义双向链表的尾节点
  6. private HeroNode last;
  7. // 返回头节点
  8. public HeroNode getHead() {
  9. return head;
  10. }
  11. // 遍历双向链表的方法
  12. // 显示链表[遍历]
  13. public List<uhjcTreeDetailVO> list() {
  14. List<uhjcTreeDetailVO> list = new ArrayList<>();
  15. // 判断链表是否为空
  16. if (head.next == null) {
  17. System.out.println("链表为空");
  18. return null;
  19. }
  20. // 因为头节点,不能动,因此我们需要一个辅助变量来遍历
  21. HeroNode temp = head.next;
  22. while (true) {
  23. // 判断是否到链表最后
  24. if (temp == null) {
  25. break;
  26. }
  27. // 设置
  28. uhjcTreeDetailVO uhjcTreeDetailVO = new uhjcTreeDetailVO();
  29. uhjcTreeDetailVO.setNodeId(temp.name);
  30. uhjcTreeDetailVO.setNextNodeId(temp.nickname);
  31. list.add(uhjcTreeDetailVO);
  32. // 输出节点的信息
  33. System.out.println(temp);
  34. // 将 temp 后移, 一定小心
  35. temp = temp.next;
  36. }
  37. return list;
  38. }
  39. // 添加一个节点到双向链表的最后.
  40. public void addLast(HeroNode heroNode) {
  41. // 因为 head 节点不能动,因此我们需要一个辅助遍历 temp
  42. HeroNode temp = head;
  43. // 遍历链表,找到最后
  44. while (true) {
  45. // 找到链表的最后
  46. if (temp.next == null) {
  47. break;
  48. }
  49. // 如果没有找到最后, 将将 temp 后移
  50. temp = temp.next;
  51. }
  52. // 当退出 while 循环时,temp 就指向了链表的最后
  53. // 形成一个双向链表
  54. temp.next = heroNode;
  55. heroNode.pre = temp;
  56. }
  57. //头插法
  58. public void addFirst(HeroNode heroNode) {
  59. //定义一个用作插入的节点
  60. //1.假设双向链表为空
  61. if (this.head == null) {
  62. this.head = heroNode;
  63. this.last = heroNode;
  64. } else {
  65. //2.双向链表不为空的情况下
  66. //不懂请看上面的图解,就很简单了
  67. heroNode.next = this.head;
  68. this.head.pre = heroNode;
  69. this.head = heroNode;
  70. }
  71. }
  72. //在任意位置插入
  73. public void addIndex(int index, HeroNode heroNode) {//形参index为插入元素位置,data为插入的数值
  74. //定义一个用作插入的节点
  75. HeroNode cur = this.head;//定义一个cur用作遍历双向链表
  76. //1、判断插入位置的合法性
  77. if (index < 0 || index > size()) {
  78. System.out.println("插入位置不合法!!!");
  79. return;
  80. }
  81. //2、假设插入位置为头结点的情况下,即就是头插法
  82. if (index == 0) {
  83. addFirst(heroNode);//调用头插法代码
  84. return;
  85. }
  86. //3、假设插入位置为尾结点的情况下,即就是尾插法
  87. if (index == size()) {
  88. addLast(heroNode);//调用尾插法代码
  89. return;
  90. }
  91. //4、在中间任意位置的情况下
  92. while (index != 0) {
  93. cur = cur.next;
  94. index--;
  95. }
  96. //不懂请看上面的图解,就很简单了
  97. //核心代码
  98. heroNode.next = cur;
  99. heroNode.pre = cur.pre;
  100. cur.pre = heroNode;
  101. heroNode.pre.next = heroNode;
  102. }
  103. //在任意位置查询
  104. public HeroNode findIndex(int index) {
  105. //定义一个用作查询的节点
  106. HeroNode cur = this.head;//定义一个cur用作遍历双向链表
  107. //1、判断插入位置的合法性
  108. if (index < 0 || index > size()) {
  109. System.out.println("查询位置不合法!!!");
  110. return null;
  111. }
  112. //2、判断是否为头部
  113. if (index == 0) {
  114. return this.head;
  115. }
  116. //3、判断是否为尾部
  117. if (index == size()) {
  118. return this.last;
  119. }
  120. //4、在中间任意位置的情况下
  121. while (index != 0) {
  122. cur = cur.next;
  123. index--;
  124. }
  125. return cur;
  126. }
  127. //求双向链表的长度(之后addIndex代码会用到)
  128. public int size() {
  129. int count = 0;
  130. HeroNode cur = this.head;
  131. while (cur != null) {
  132. count++;
  133. cur = cur.next;
  134. }
  135. return count;
  136. }
  137. // 修改一个节点的内容, 可以看到双向链表的节点内容修改和单向链表一样
  138. // 只是 节点类型改成 HeroNode2
  139. public void update(HeroNode newHeroNode) {
  140. // 判断是否空
  141. if (head.next == null) {
  142. System.out.println("链表为空~");
  143. return;
  144. }
  145. // 找到需要修改的节点, 根据 no 编号
  146. // 定义一个辅助变量
  147. HeroNode temp = head.next;
  148. boolean flag = false; // 表示是否找到该节点
  149. while (true) {
  150. if (temp == null) {
  151. break; // 已经遍历完链表
  152. }
  153. if (newHeroNode.no.equals(temp.no)) {
  154. // 找到
  155. flag = true;
  156. break;
  157. }
  158. temp = temp.next;
  159. }
  160. // 根据 flag 判断是否找到要修改的节点
  161. if (flag) {
  162. temp.name = newHeroNode.name;
  163. temp.nickname = newHeroNode.nickname;
  164. } else { // 没有找到
  165. System.out.printf("没有找到 编号 %d 的节点,不能修改\n", newHeroNode.no);
  166. }
  167. }
  168. // 从双向链表中删除一个节点,
  169. // 说明
  170. // 1 对于双向链表,我们可以直接找到要删除的这个节点
  171. // 2 找到后,自我删除即可
  172. public void del(String no) {
  173. // 判断当前链表是否为空
  174. if (head.next == null) {
  175. // 空链表
  176. System.out.println("链表为空,无法删除");
  177. return;
  178. }
  179. HeroNode temp = head.next;
  180. // 辅助变量(指针)
  181. boolean flag = false;
  182. // 标志是否找到待删除节点的
  183. while (true) {
  184. if (temp == null) { // 已经到链表的最后
  185. break;
  186. }
  187. if (temp.no == no) {
  188. // 找到的待删除节点的前一个节点temp
  189. flag = true;
  190. break;
  191. }
  192. temp = temp.next; // temp 后移,遍历
  193. }
  194. // 判断 flag
  195. if (flag) { // 找到
  196. // 可以删除
  197. temp.next = temp.next.next;
  198. //[单向链表]
  199. temp.pre.next = temp.next;
  200. // 这里我们的代码有问题?
  201. // 如果是最后一个节点,就不需要执行下面这句话,否则出现空指针
  202. if (temp.next != null) {
  203. temp.next.pre = temp.pre;
  204. }
  205. } else {
  206. System.out.printf("要删除的 %d 节点不存在\n", no);
  207. }
  208. }
  209. }

3. 测试

  1. public class DoubleLinkedListDemo {
  2. public static void main(String[] args) {
  3. // 测试
  4. System.out.println("双向链表的测试");
  5. // 先创建节点\
  6. HeroNode hero1 = new HeroNode("1", "1", "0");
  7. HeroNode hero2 = new HeroNode("2", "2", "玉麒麟");
  8. HeroNode hero3 = new HeroNode("3", "吴用", "智多星");
  9. HeroNode hero4 = new HeroNode("4", "林冲", "豹子头");
  10. // 创建一个双向链表
  11. DoubleLinkedList doubleLinkedList = new DoubleLinkedList();
  12. doubleLinkedList.addLast(hero1);
  13. doubleLinkedList.addLast(hero2);
  14. doubleLinkedList.addLast(hero3);
  15. doubleLinkedList.addLast(hero4);
  16. doubleLinkedList.list();
  17. // 修改
  18. HeroNode newHeroNode = new HeroNode("4", "公孙胜", "入云龙");
  19. doubleLinkedList.update(newHeroNode);
  20. System.out.println("修改后的链表情况");
  21. List<uhjcTreeDetailVO> list = doubleLinkedList.list();
  22. list.forEach(uhjcTreeDetailVO -> {
  23. });
  24. // 删除
  25. doubleLinkedList.del("3");
  26. System.out.println("删除后的链表情况~~");
  27. doubleLinkedList.list();
  28. // 随机插入
  29. System.out.println("随机插入");
  30. doubleLinkedList.addIndex(1, hero3);
  31. doubleLinkedList.list();
  32. // 查询指定节点
  33. System.out.println("随机查询");
  34. HeroNode index = doubleLinkedList.findIndex(1);
  35. System.out.println(index.toString());
  36. }
  37. }