当前位置:   article > 正文

Java——LinkedList

Java——LinkedList

1、链表

1.1 链表的概念及结构

链表在逻辑层面上是连续的,在物理层面上不一定是连续的

链表结构可分为,单向或双向、带头或不带头、循环或非循环,组合共计8种

重点:无头单向非循环链表、无头双向链表

1.2 模拟实现无头单向非循环链表

一个链表由若干节点组成,结合 内部类 知识,可将节点类定义在链表类中,成为内部类

  1. public class MySingleLinkedList {
  2. static class ListNode {//该内部类中定义的是节点的属性
  3. public int val;
  4. public ListNode next;
  5. public ListNode(int val) {
  6. this.val = val;
  7. }
  8. }
  9. public ListNode head;//链表的头节点,定义在MySingleLinkedList类中
  10. }

下面以穷举的方式创建链表方便理解(真正创建链表并非如此)

  1. //MySingleLinkedList类
  2. //该方法创建一个链表,头节点为node1,当该方法结束后,变量node1...都会销毁,只剩下头节点为head的链表
  3. public void createdList(){
  4. ListNode node1 = new ListNode(1);
  5. ListNode node2 = new ListNode(2);
  6. ListNode node3 = new ListNode(3);
  7. ListNode node4 = new ListNode(4);
  8. ListNode node5 = new ListNode(5);
  9. node1.next = node2;
  10. node2.next = node3;
  11. node3.next = node4;
  12. node4.next = node5;
  13. this.head = node1;
  14. }

打印链表

  1. //MySingleLinkedList 类
  2. public void display() {
  3. ListNode cur = head; //若直接使用head进行遍历打印,将只能打印一次,再次调用该函数,头节点就不在原来的位置了
  4. while(cur != null) { //注意!此处若写成 cur.next != null 则不会打印最后一个节点
  5. System.out.print(cur.val + " ");
  6. cur = cur.next;
  7. }
  8. }

求链表长度:

  1. //遍历即可
  2. public int size() {
  3. ListNode cur = head;
  4. int count = 0;
  5. while(cur != null) {
  6. cur = cur.next;
  7. count++;
  8. }
  9. return count;
  10. }

头插法:

  1. public void addFirst(int data) {
  2. ListNode newNode = new ListNode(data);
  3. newNode.next = head;
  4. head = newNode;
  5. }

尾插法:

  1. public void addLast(int data) {
  2. ListNode newNode = new ListNode(data);
  3. //不要忘记:判空!
  4. if(head == null) {
  5. head = newNode;
  6. return;
  7. }
  8. ListNode cur = head;
  9. while(cur.next != null) { //此处若写成 cur.next != null 则不会打印最后一个节点
  10. cur = cur.next;
  11. }
  12. cur.next = newNode;
  13. }

在index位置插入

  1. // IndexNotLegalException 异常类
  2. public class IndexNotLegalException extends RuntimeException{
  3. public IndexNotLegalException() {
  4. }
  5. public IndexNotLegalException(String msg) {
  6. super(msg);
  7. }
  8. }
  9. // MySingleLinkedList 类
  10. public void addIndex(int index, int data) {
  11. //1、判断index合法性
  12. try{
  13. checkIndex(index);
  14. }catch(IndexNotLegalException e) {
  15. e.printStackTrace();
  16. }
  17. //2、index == 0 || index == size()
  18. if(index == 0) {
  19. addFirst(data);
  20. return;
  21. }
  22. if(index == size()) {
  23. addLast(data);
  24. return;
  25. }
  26. //3、找到index的前一个位置
  27. ListNode cur = findIndexSubOne(index);
  28. //4、进行连接
  29. ListNode node = new ListNode(data);
  30. node.next = cur.next;
  31. cur.next = node;
  32. }
  33. private void checkIndex(int index) throws IndexNotLegalException{
  34. if(index < 0 || index > size()) {
  35. throw new IndexNotLegalException("index不合法!");
  36. }
  37. }
  38. private ListNode findIndexSubOne(int index) {
  39. int count = 0;
  40. ListNode cur = head;
  41. while(count < index-1) {
  42. cur = cur.next;
  43. count++;
  44. }
  45. return cur;
  46. }

查找关键字key是否包含在链表中

  1. public boolean contains(int key) {
  2. ListNode cur = head;
  3. while(cur != null) {
  4. if(cur.val == key) {
  5. return true;
  6. }
  7. cur = cur.next;
  8. }
  9. return false;
  10. }

删除第一次出现关键字key的节点

  1. public void remove(int key) {
  2. //判空
  3. if(head == null) {
  4. return;
  5. }
  6. //若头节点为key
  7. while(head.val == key) {
  8. head = head.next;
  9. return;
  10. }
  11. ListNode cur = head;
  12. //遍历找到值为key的节点
  13. while(cur.next != null) {
  14. if(cur.next.val == key) {
  15. cur.next = cur.next.next;
  16. return;
  17. }
  18. cur = cur.next;
  19. }
  20. System.out.println("没有找到要删除的数字!");
  21. }

删除所有值为key的节点

  1. public void removeAllKey(int key) {
  2. //判空
  3. if (this.head == null) {
  4. return;
  5. }
  6. //快慢指针
  7. ListNode prev = head;
  8. ListNode cur = head.next;
  9. while(cur != null) {
  10. if(cur.val == key) {
  11. prev.next = cur.next;
  12. }else {
  13. prev = cur;
  14. }
  15. cur = cur.next;
  16. }
  17. //处理头节点,当上述操作完成后,只剩下头节点没有判断
  18. //该方法优于一上来就判断头节点
  19. if(head.val == key) {
  20. head =head.next;
  21. }
  22. }

清空链表

  1. public void clear() {
  2. ListNode cur = head;
  3. while(cur != null) {
  4. ListNode curN = cur.next;
  5. cur.next = null;
  6. cur = curN;
  7. }
  8. head = null;
  9. }

1.3 模拟实现无头双向非循环链表

  1. public class MyLinkedList {
  2. static class ListNode {
  3. public int data;
  4. public ListNode prev;//前驱节点
  5. public ListNode next;//后继节点
  6. public ListNode(int data){
  7. this.data = data;
  8. }
  9. }
  10. public ListNode head;//头节点
  11. public ListNode last;//尾节点
  12. //得到单链表的长度
  13. public int size(){
  14. int count = 0;
  15. ListNode cur = head;
  16. while(cur != null) {
  17. count++;
  18. cur = cur.next;
  19. }
  20. return count;
  21. }
  22. public void display(){
  23. ListNode cur = head;
  24. while(cur != null) {
  25. System.out.print(cur.data + " ");
  26. cur = cur.next;
  27. }
  28. System.out.println();
  29. }
  30. //查找是否包含关键字key是否在单链表当中
  31. public boolean contains(int key){
  32. ListNode cur = head;
  33. while(cur != null) {
  34. if(cur.data == key) {
  35. return true;
  36. }
  37. cur = cur.next;
  38. }
  39. return false;
  40. }
  41. //头插法
  42. public void addFirst(int data){
  43. ListNode node = new ListNode(data);
  44. if(head == null) {
  45. head = last = node;
  46. }else {
  47. head.prev = node;
  48. node.next = head;
  49. head = node;
  50. }
  51. }
  52. //尾插法
  53. public void addLast(int data){
  54. ListNode node = new ListNode(data);
  55. if(head == null) {
  56. head = last = node;
  57. }else {
  58. last.next = node;
  59. node.prev = last;
  60. last = node;
  61. }
  62. }
  63. //任意位置插入,第一个数据节点为0号下标
  64. public void addIndex(int index,int data){
  65. try{
  66. checkIndex(index);
  67. }catch(IndexIllegalException e) {
  68. e.printStackTrace();
  69. }
  70. if(index == 0) {
  71. addFirst(data);
  72. return;
  73. }
  74. if(index == size()) {
  75. addLast(data);
  76. return;
  77. }
  78. ListNode node = new ListNode(data);
  79. ListNode cur = findIndex(index);
  80. node.next = cur;
  81. node.prev = cur.prev;
  82. cur.prev.next = node;
  83. cur.prev = node;
  84. }
  85. private ListNode findIndex(int index) {
  86. ListNode cur = head;
  87. while(index != 0) {
  88. cur = cur.next;
  89. index--;
  90. }
  91. return cur;
  92. }
  93. private void checkIndex(int index) throws IndexIllegalException{
  94. if(index < 0 || index > size()) {
  95. throw new IndexIllegalException("双向链表index不合法!");
  96. }
  97. }
  98. //删除第一次出现关键字为key的节点
  99. public void remove(int key){
  100. ListNode cur = head;
  101. while(cur != null) {
  102. if(cur.data == key) {
  103. if(cur == head) {
  104. head = head.next;
  105. if(head != null) {
  106. head.prev = null;
  107. }else {
  108. last = null;
  109. }
  110. }else if(cur == last) {
  111. cur.prev.next = null;
  112. last = cur.prev;
  113. }else {
  114. cur.prev.next = cur.next;
  115. cur.next.prev = cur.prev;
  116. }
  117. return;
  118. }
  119. cur = cur.next;
  120. }
  121. }
  122. //删除所有值为key的节点
  123. public void removeAllKey(int key){
  124. ListNode cur = head;
  125. while(cur != null) {
  126. if(cur.data == key) {
  127. if(cur == head) {
  128. head = head.next;
  129. if(head != null) {
  130. head.prev = null;
  131. }else {
  132. last = null;
  133. }
  134. }else if(cur == last) {
  135. cur.prev.next = null;
  136. last = cur.prev;
  137. }else {
  138. cur.prev.next = cur.next;
  139. cur.next.prev = cur.prev;
  140. }
  141. }
  142. cur = cur.next;
  143. }
  144. }
  145. public void clear(){
  146. ListNode cur = head.next;
  147. while(cur != null) {
  148. cur = head.next;
  149. head.prev = null;
  150. head.next = null;
  151. head = cur;
  152. }
  153. head = last = null;
  154. }
  155. }

链表遍历方式:

  1. public static void main(String[] args) {
  2. LinkedList<Integer> list = new LinkedList<>();
  3. list.add(1);
  4. list.add(2);
  5. list.add(3);
  6. //直接sout打印
  7. System.out.println(list);
  8. System.out.println("======");
  9. //foreatch循环打印
  10. for(Integer x : list) {
  11. System.out.print(x + " ");
  12. }
  13. System.out.println();
  14. System.out.println("======");
  15. //for循环打印
  16. for (int i = 0; i < list.size(); i++) {
  17. System.out.print(list.get(i) + " ");
  18. }
  19. System.out.println();
  20. System.out.println("======");
  21. //Iterator打印
  22. Iterator<Integer> it = list.iterator();
  23. while(it.hasNext()) {
  24. System.out.print(it.next() + " ");
  25. }
  26. System.out.println();
  27. System.out.println("======");
  28. //ListIterator可以倒着打印
  29. ListIterator<Integer> it3 = list.listIterator(list.size());
  30. while(it3.hasPrevious()) {
  31. System.out.print(it3.previous() + " ");
  32. }
  33. }

运行结果:

2、ArrayList 和 LinkedList 的区别

不同点ArrayListLinkedList
存储空间上逻辑&物理均连续逻辑上连续,物理上不一定连续
随机访问支持,时间复杂度为O(1)不支持,时间复杂度为O(N)
头插需要搬运元素,O(N)只需修改引用的指向,O(1)
插入空间不够时需要扩容没有容量概念
应用场景元素高效存储+频繁访问频繁在任意位置插入删除操作

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

闽ICP备14008679号