当前位置:   article > 正文

基于Java的链表 常见使用方法_java使用链表的方式

java使用链表的方式

一、链表
链表(Linked list)是一种常见的基础数据结构,是一种线性表,但是并不会按线性的顺序存储数据,而是在每一个节点里存到下一个节点的指针(Pointer)。由于不必须按顺序存储,链表在插入的时候可以达到O(1)的复杂度,比另一种线性表顺序表快得多,但是查找一个节点或者访问特定编号的节点则需要O(n)的时间,而顺序表相应的时间复杂度分别是O(logn)和O(1)。

1.单向链表
单向链表,它包含两个域,一个信息域和一个指针域。信息域用来存储链表中要存放的值,指针域则指向下一个节点。这个链接指向列表中的下一个节点,而最后一个节点则指向一个空值。其结构图如下:


2、双向链表
双向链表在单链表的基础上,每个节点新增了一个指针域,用来指向前一个节点。其结构图如下:


二、链表的基本操作
首先创建一个LinkedList类。

0.链表节点的对象
创建一个ListNode类,包含两个属性,一个为链表节点的值,另一个为下一个节点的地址。
创建size属性记录链表长度

  1. public class LinkedList {
  2. //定义节点
  3. static class ListNode {
  4. int val; // 链表存储的值
  5. ListNode next; // 指针,指向下一个节点
  6. ListNode() {
  7. }
  8. ListNode(int val) {
  9. this.val = val;
  10. }
  11. ListNode(int val, ListNode next) {
  12. this.val = val;
  13. this.next = next;
  14. }
  15. }
  16. int size; // 链表长度
  17. ListNode headNode; //链表头结点
  18. ListNode dummyHead = new ListNode(0);
  19. }

1.头插法
头插法,即在链表首部添加一个节点作为新的头结点。
首先要新建一个ListNode 对象作为要插入的节点,然后根据情况进行操作。如果当前链表为空链表,则将该节点直接作为头结点即可创建一个链表;如果当前链表不是空链表,则将要插入的节点的next指针指向原本的头节点。

  1. public void headInsertion(int val) {
  2. ListNode newListNode = new ListNode(); // 新建一个对象,即为要插入的节点
  3. newListNode.val = val; // 对节点存入要插入的值
  4. if (headNode == null) { //头结点为空即是个空链表,头结点直接指向要插入的节点即可
  5. headNode = newListNode;
  6. } else {
  7. newListNode.next = headNode; // 要插入的节点应放在第一个,所以它的下一个节点指向head
  8. headNode = newListNode; // 插入后新插入的节点是新的头结点
  9. }
  10. size ++;
  11. }

2.任意位置插入节点
insert方法为在任意位置插入节点,参数中的index为插入节点的位置,val为插入节点的值,如果index等于0,则和头插法过程相同。否则,需要先找到前一个节点, 将该节点的next指针指向前一个节点next指向的节点,然后再将前一个节点指向该节点。
插入过程图解如下:
(1)创建要插入的节点对象

(2)current节点指向next节点

(3)previous节点指向current节点,完成插入


   

  1. public void insert(int index, int val) {
  2. if (index > size) {
  3. System.out.println("越界");
  4. return;
  5. }
  6. ListNode newListNode = new ListNode(); // 存放添加元素的链表节点
  7. newListNode.val = val;
  8. if (index == 0) { // 插入到第0位,和头插法相同
  9. if (headNode == null) {
  10. headNode = newListNode;
  11. } else {
  12. newListNode.next = headNode;
  13. headNode = newListNode;
  14. }
  15. size ++;
  16. } else {
  17. ListNode prevNode = headNode; // 创建一个指向头结点的指针
  18. for (int i = 0; i < index-1; i++) {
  19. prevNode = prevNode.next; // 用该指针找到要添加元素位置的前一个
  20. }
  21. newListNode.next = prevNode.next; // 添加的节点的next指针指向要添加位置的下一个
  22. prevNode.next = newListNode; //前一个节点的next指针指向添加的节点
  23. size ++;
  24. }
  25. }

3.尾插法
先找到原先最后一个节点,然后将其next指向要插入的节点即可。

  1. public void tailInsertion(int val) {
  2. ListNode newListNode = new ListNode();
  3. newListNode.val = val;
  4. ListNode prevNode = headNode; // 创建一个指向头结点的指针
  5. for (int i = 0; i < size-1; i++) {
  6. prevNode = prevNode.next;// 用该指针找到要最后一个节点的前一个节点
  7. }
  8. newListNode.next = prevNode.next;
  9. prevNode.next = newListNode;
  10. size ++;
  11. }

4.删除第index个元素
找到第index-1个节点,将其直接指向第index+1个节点即可。需要注意空链表或者越界情况。
删除过程图解如下:
(1)找到要删除的节点对象current

(2)previous指针指向next节点即可删除。

  1. public void deleteByIndex(int index) {
  2. if (index > size) {
  3. System.out.println("越界");
  4. return;
  5. }
  6. if (headNode == null) {
  7. System.out.println("空链表");
  8. } else {
  9. if (index == 0) { // 删除第一个元素,直接把头结点指向第二个元素即可
  10. headNode = headNode.next;
  11. size --;
  12. } else {
  13. ListNode prevNode = headNode; // 创建一个指向头结点的指针
  14. for (int i = 0; i < index-1; i++) {
  15. prevNode = prevNode.next; // 用该指针找到要删除元素位置的前一个
  16. }
  17. System.out.println("delete:"+prevNode.next.val);
  18. // 要删除的元素的前一个节点的next指针指向下一个节点,完成删除
  19. prevNode.next = prevNode.next.next;
  20. size --;
  21. }
  22. }
  23. }

5.删除val元素
删除值为val的节点,以此遍历找到值为val的节点,并对其删除即可。

  1. public void deleteByValue(int val) {
  2. if (headNode == null) {
  3. System.out.println("空链表");
  4. } else {
  5. while(val == headNode.val){// 如果头结点是要删除的元素
  6. headNode = headNode.next;
  7. size --;
  8. }
  9. ListNode prevNode = headNode; // 创建指针,指向被操作的节点的前一位
  10. ListNode currentNode = headNode; // 创建指针,指向被操作的节点
  11. while(prevNode != null && currentNode != null){
  12. if(currentNode.val == val) {
  13. prevNode.next = currentNode.next;
  14. size--;
  15. } else {
  16. prevNode = currentNode;
  17. }
  18. currentNode = currentNode.next;
  19. }
  20. }
  21. }

 6.获取第index节点的值
遍历找到即可。

  1. public void getElum(int index) {
  2. if (index > size) {
  3. System.out.println("越界");
  4. return;
  5. }
  6. ListNode currentNode = headNode;
  7. for (int i = 0; i < index; i++) {
  8. currentNode = currentNode.next;
  9. }
  10. int result = currentNode.val;
  11. System.out.println(result);
  12. }

7.将第Index个节点的值修改为val
找到第index节点,修改val即可。

  1. public void update(int index, int val) {
  2. if (index > size) {
  3. System.out.println("越界");
  4. return;
  5. }
  6. ListNode currentNode = headNode;
  7. for (int i = 0; i < index; i++) {
  8. currentNode = currentNode.next;
  9. }
  10. currentNode.val = val;
  11. }

8.创建一个链表

  1. // 创建一个链表 1->2
  2. public void creatLinkList() {
  3. ListNode node1 = new ListNode();
  4. node1.val = 2;
  5. ListNode node2 = new ListNode();
  6. node2.val = 1;
  7. node1.next = node2;
  8. headNode = node1;
  9. size++;
  10. size++;
  11. }

9.按顺序打印链表

  1. public void display(){
  2. ListNode current = headNode;
  3. while(current != null){
  4. System.out.print(current.val);
  5. if (current.next != null) {
  6. System.out.print("->");
  7. }
  8. current = current.next;
  9. }
  10. System.out.println();
  11. }


三、最终代码展示(包含测试)

  1. package linkedList;
  2. public class SingleLinkedList {
  3. //定义节点
  4. static class ListNode {
  5. int val; // 链表存储的值
  6. ListNode next; // 指针,指向下一个节点
  7. ListNode() {
  8. }
  9. ListNode(int val) {
  10. this.val = val;
  11. }
  12. ListNode(int val, ListNode next) {
  13. this.val = val;
  14. this.next = next;
  15. }
  16. }
  17. int size; // 链表长度
  18. ListNode headNode; //链表头结点
  19. // ListNode dummyHead = new ListNode(0);
  20. public SingleLinkedList() {
  21. headNode = null;
  22. size = 0;
  23. }
  24. //头插法
  25. public void headInsertion(int val) {
  26. ListNode newListNode = new ListNode(); // 新建一个对象,即为要插入的节点
  27. newListNode.val = val; // 对节点存入要插入的值
  28. if (headNode == null) { //头结点为空即是个空链表,头结点直接指向要插入的节点即可
  29. headNode = newListNode;
  30. } else {
  31. newListNode.next = headNode; // 要插入的节点应放在第一个,所以它的下一个节点指向head
  32. headNode = newListNode; // 插入后新插入的节点是新的头结点
  33. }
  34. size ++;
  35. }
  36. //头插法(使用虚拟头结点的方法)
  37. // public void headInsertionVirtual(int val) {
  38. // ListNode dummyHead = new ListNode(0, this.head);
  39. // ListNode newListNode = new ListNode();
  40. // newListNode.val = val;
  41. // ListNode currentNode = dummyHead;
  42. // currentNode.val = val;
  43. // currentNode.next = dummyHead.next;
  44. // size ++;
  45. // }
  46. //任意位置插入
  47. public void insert(int index, int val) {
  48. if (index > size) {
  49. System.out.println("越界");
  50. return;
  51. }
  52. ListNode newListNode = new ListNode(); // 存放添加元素的链表节点
  53. newListNode.val = val;
  54. if (index == 0) { // 插入到第0位,和头插法相同
  55. if (headNode == null) {
  56. headNode = newListNode;
  57. } else {
  58. newListNode.next = headNode;
  59. headNode = newListNode;
  60. }
  61. size ++;
  62. } else {
  63. ListNode prevNode = headNode; // 创建一个指向头结点的指针
  64. for (int i = 0; i < index-1; i++) {
  65. prevNode = prevNode.next; // 用该指针找到要添加元素位置的前一个
  66. }
  67. newListNode.next = prevNode.next; // 添加的节点的next指针指向要添加位置的下一个
  68. prevNode.next = newListNode; //前一个节点的next指针指向添加的节点
  69. size ++;
  70. }
  71. }
  72. //尾插法
  73. public void tailInsertion(int val) {
  74. ListNode newListNode = new ListNode();
  75. newListNode.val = val;
  76. ListNode prevNode = headNode; // 创建一个指向头结点的指针
  77. for (int i = 0; i < size-1; i++) {
  78. prevNode = prevNode.next;// 用该指针找到要最后一个节点的前一个节点
  79. }
  80. newListNode.next = prevNode.next;
  81. prevNode.next = newListNode;
  82. size ++;
  83. }
  84. //删除第index个元素
  85. public void deleteByIndex(int index) {
  86. if (index > size) {
  87. System.out.println("越界");
  88. return;
  89. }
  90. if (headNode == null) {
  91. System.out.println("空链表");
  92. } else {
  93. if (index == 0) { // 删除第一个元素,直接把头结点指向第二个元素即可
  94. headNode = headNode.next;
  95. size --;
  96. } else {
  97. ListNode prevNode = headNode; // 创建一个指向头结点的指针
  98. for (int i = 0; i < index-1; i++) {
  99. prevNode = prevNode.next; // 用该指针找到要删除元素位置的前一个
  100. }
  101. System.out.println("delete:"+prevNode.next.val);
  102. // 要删除的元素的前一个节点的next指针指向下一个节点,完成删除
  103. prevNode.next = prevNode.next.next;
  104. size --;
  105. }
  106. }
  107. }
  108. //删除val元素
  109. public void deleteByValue(int val) {
  110. if (headNode == null) {
  111. System.out.println("空链表");
  112. } else {
  113. while(val == headNode.val){// 如果头结点是要删除的元素
  114. headNode = headNode.next;
  115. size --;
  116. }
  117. ListNode prevNode = headNode; // 创建指针,指向被操作的节点的前一位
  118. ListNode currentNode = headNode; // 创建指针,指向被操作的节点
  119. while(prevNode != null && currentNode != null){
  120. if(currentNode.val == val) {
  121. prevNode.next = currentNode.next;
  122. size--;
  123. } else {
  124. prevNode = currentNode;
  125. }
  126. currentNode = currentNode.next;
  127. }
  128. }
  129. }
  130. public void getElum(int index) {
  131. if (index > size) {
  132. System.out.println("越界");
  133. return;
  134. }
  135. ListNode currentNode = headNode;
  136. for (int i = 0; i < index; i++) {
  137. currentNode = currentNode.next;
  138. }
  139. int result = currentNode.val;
  140. System.out.println(result);
  141. }
  142. public void update(int index, int val) {
  143. if (index > size) {
  144. System.out.println("越界");
  145. return;
  146. }
  147. ListNode currentNode = headNode;
  148. for (int i = 0; i < index; i++) {
  149. currentNode = currentNode.next;
  150. }
  151. currentNode.val = val;
  152. }
  153. // 创建一个链表 1->2
  154. public void creatLinkList() {
  155. ListNode node1 = new ListNode();
  156. node1.val = 2;
  157. ListNode node2 = new ListNode();
  158. node2.val = 1;
  159. node1.next = node2;
  160. headNode = node1;
  161. size++;
  162. size++;
  163. }
  164. //打印链表
  165. public void display(){
  166. ListNode current = headNode;
  167. while(current != null){
  168. System.out.print(current.val);
  169. if (current.next != null) {
  170. System.out.print("->");
  171. }
  172. current = current.next;
  173. }
  174. System.out.println();
  175. }
  176. public static void main(String[] args) {
  177. SingleLinkedList singleLinkedList = new SingleLinkedList();
  178. singleLinkedList.creatLinkList();
  179. singleLinkedList.headInsertion(5);
  180. singleLinkedList.headInsertion(8);
  181. singleLinkedList.headInsertion(9);
  182. singleLinkedList.headInsertion(5);
  183. singleLinkedList.display();
  184. singleLinkedList.insert(0,3);
  185. singleLinkedList.insert(0,3);
  186. singleLinkedList.insert(2,3);
  187. singleLinkedList.insert(2,3);
  188. singleLinkedList.insert(2,7);
  189. singleLinkedList.display();
  190. singleLinkedList.tailInsertion(1);
  191. singleLinkedList.display();
  192. singleLinkedList.deleteByIndex(1);
  193. singleLinkedList.display();
  194. singleLinkedList.deleteByValue(3);
  195. singleLinkedList.display();
  196. singleLinkedList.getElum(0);
  197. singleLinkedList.update(1, 6);
  198. singleLinkedList.display();
  199. }
  200. }

                                     感谢大家的阅读,觉得有所帮助的朋友点点关注点点赞!

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/空白诗007/article/detail/823037
推荐阅读
相关标签
  

闽ICP备14008679号