当前位置:   article > 正文

详解LinkedList与链表_listnode 与linkedlistnode

listnode 与linkedlistnode

1. ArrayList的缺陷

当在ArrayList任意位置插入或者删除元素时,就需要将后序元素整体往前或者往后搬移,时间复杂度为O(n),效率比较低,因此ArrayList不适合做任意位置插入和删除比较多的场景。

因此:java 集合中又引入了LinkedList,即链表结构。

2. 链表的概念及结构

链表是一种物理存储结构上非连续存储结构,数据元素的逻辑顺序是通过链表中的引用链接次序实现的。

实际中链表的结构非常多样,以下情况组合起来就有8种链表结构:

1. 单向或者双向

2. 带头或者不带头

3. 循环或者非循环

重点掌握两种:

  • 无头单向非循环链表:结构简单,一般不会单独用来存数据。实际中更多是作为其他数据结构的子结构,如 哈希桶、图的邻接表等等。

  • 无头双向链表:在Java的集合框架库中LinkedList底层实现就是无头双向循环链表。

3. 链表的实现

无头单向非循环链表实现

  1. public class MySingleLinkedList {
  2. // 节点内部类
  3. static class ListNode {
  4. public int val;
  5. public ListNode next;
  6. public ListNode(int val) {
  7. this.val = val;
  8. }
  9. }
  10. public ListNode head;// 不初始化,默认为null
  11.     public void dispaly() {
  12. ListNode cur = this.head;
  13. while (cur != null) {
  14. System.out.print(cur.val + " ");
  15. cur = cur.next;
  16. }
  17. System.out.println(" ");
  18. }
  19.     // 得到单链表的长度
  20. public int size() {
  21. int count = 0;
  22. ListNode cur = head;
  23. while (cur != null) {
  24. count++;
  25. cur = cur.next;
  26. }
  27. return count;
  28. }
  29.     // 查找是否包含关键字key是否在单链表当中
  30. public boolean contains(int key) {
  31. ListNode cur = this.head;
  32. while (cur != null) {
  33. if (cur.val == key) {
  34. return true;
  35. }
  36. cur = cur.next;
  37. }
  38. return false;
  39. }
  40. // 头插法
  41. // 先绑定和后面节点的关系
  42. public void addFirst(int data) {
  43. ListNode node = new ListNode(data);
  44. node.next = head;
  45. head = node;
  46. }
  47. // 尾插法
  48. public void addLast(int data) {
  49. ListNode node = new ListNode(data);
  50. ListNode cur = this.head;
  51. if(cur == null) {
  52. this.head = node;
  53. }else {
  54. while (cur.next != null) {
  55. cur = cur.next;
  56. }
  57. //cur已经是尾节点了
  58. cur.next = node;
  59. }
  60. }
  61. // 任意位置插入,第一个数据节点为0号下标
  62. public void addIndex(int index, int data) {
  63. if (index < 0 || index > size()) {
  64. System.out.println("index位置不合法");
  65. throw new IndexWrongFulException("index位置不合法");
  66. }
  67. if (index == 0) {
  68. addFirst(data);
  69. return;
  70. }
  71. if (index == size()) {
  72. addLast(data);
  73. return;
  74. }
  75. // 先走index-1步,找到cur
  76. ListNode cur = findIndexSubOne(index);
  77. ListNode node = new ListNode(data);
  78. //
  79. node.next = cur.next;
  80. cur.next = node;
  81. }
  82.     private ListNode findIndexSubOne(int index) {
  83. ListNode cur = this.head;
  84. while (index - 1 != 0) {
  85. cur = cur.next;
  86. index--;
  87. }
  88. return cur;
  89. }
  90.     // 删除第一次出现关键字为key的节点
  91.     public void remove(int key) {
  92. // 判断链表为空
  93. if (this.head == null) {
  94. return;
  95. }
  96. // 删除头节点
  97. if (this.head.val == key) {
  98. this.head = this.head.next;
  99. return;
  100. }
  101. ListNode cur = findPrevOfKey(key);
  102. if (cur == null) {
  103. System.out.println("没有你要删除的数字");
  104. return;
  105. }
  106. ListNode del = cur.next;
  107. cur.next = del.next;
  108. }
  109.     private ListNode findPrevOfKey(int key) {
  110. ListNode cur = this.head;
  111. while (cur.next != null) {
  112. if (cur.next.val == key) {
  113. return cur;
  114. }
  115. cur = cur.next;
  116. }
  117. return null;
  118. }
  119.     // 删除所有值为key的节点
  120. public void removeAllKey(int key) {
  121. if (this.head == null) {
  122. return;
  123. }
  124. ListNode cur = this.head.next;
  125. ListNode pre = this.head;
  126. while (cur != null) {
  127. if (cur.val == key) {
  128. pre.next = cur.next;
  129. cur = cur.next;
  130. } else {
  131. pre = cur;
  132. cur = cur.next;
  133. }
  134. }
  135. if (this.head.val == key) {
  136. head = head.next;
  137. }
  138. }
  139. public void clear() {
  140. this.head = null;
  141. }

4.什么是LinkedList

LinkedList官方文档

LinkedList的底层是双向链表结构,由于链表没有将元素存储在连续的空间中,元素存储在单独的节点中,然后通过引用将节点连接起来了,因此在在任意位置插入或者删除元素时,不需要搬移元素,效率比较高。

在集合框架中,LinkedList也实现了List接口,具体如下:

【说明】
1. LinkedList实现了List接口
2. LinkedList的底层使用了 双向链表
3. LinkedList 没有实现RandomAccess接口,因此LinkedList 不支持随机访问
4. LinkedList的 任意位置插入和删除元素时效率比较高时间复杂度为O(1)

5.LinkedList的模拟实现

LinkedList底层就是一个双向链表

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

6.LinkedList的使用

6.1LinkedList的构造

LinkedList()

无参构造

public LinkedList(Collection<? extends E> c)

使用其他集合容器中元素构造List

  1. public static void main(String[] args) {
  2. // 构造一个空的LinkedList
  3. List<Integer> list1 = new LinkedList<>();
  4. List<String> list2 = new ArrayList<>();
  5. list2.add("JavaSE");
  6. list2.add("JavaWeb");
  7. list2.add("JavaEE");
  8. // 使用ArrayList构造LinkedList
  9. List<String> list3 = new LinkedList<>(list2);
  10. }

6.2常用方法

方法

解释

boolean add(E e)

尾插e

void add(int index, E element)

将e插入到index位置

boolean addAll(Collection<? extends E> c)

尾插c中的元素

E remove(int index)

删除index位置元素

boolean remove(Object o)

删除遇到的第一个o

E get(int index)

获取下标index位置元素

E set(int index,E element)

将下标index位置元素设置为element

void clear()

清空

boolean contains(Object o)

判断o是否在线性表中

int indexOf(Object o)

返回第一个o所在下标

int lastlndexOf(Object o)

返回最后一个o的下标

List<E> subList(int fromIndex, int tolndex)

截取部分list

  1. public static void main(String[] args) {
  2. LinkedList<Integer> list = new LinkedList<>();
  3. list.add(1); // add(elem): 表示尾插
  4. list.add(2);   //默认尾插
  5. list.add(3);
  6. list.add(4);
  7. list.add(5);
  8. list.add(6);
  9. list.add(7);
  10. System.out.println(list.size());
  11. System.out.println(list);
  12. // 在起始位置插入0
  13. list.add(0, 0); // add(index, elem): 在index位置插入元素elem
  14. System.out.println(list);
  15. list.remove(); // remove(): 删除第一个元素,内部调用的是removeFirst()
  16. list.removeFirst(); // removeFirst(): 删除第一个元素
  17. list.removeLast(); // removeLast(): 删除最后元素
  18. list.remove(1); // remove(index): 删除index位置的元素
  19. System.out.println(list);
  20. // contains(elem): 检测elem元素是否存在,如果存在返回true,否则返回false
  21. if(!list.contains(1)){
  22. list.add(0, 1); //相当于头插
  23.     }
  24. list.add(1);
  25. System.out.println(list);
  26. System.out.println(list.indexOf(1)); // indexOf(elem): 从前往后找到第一个elem的位置
  27. System.out.println(list.lastIndexOf(1)); // lastIndexOf(elem): 从后往前找第一个1的位置
  28. int elem = list.get(0); // get(index): 获取指定位置元素
  29. list.set(0, 100); // set(index, elem): 将index位置的元素设置为elem
  30. System.out.println(list);
  31. // subList(from, to): 用list中[from, to)之间的元素构造一个新的LinkedList返回
  32. List<Integer> copy = list.subList(0, 3);
  33. System.out.println(list);
  34. System.out.println(copy);
  35. list.clear(); // 将list中元素清空
  36. System.out.println(list.size());
  37. }

6.3LinkedList的遍历

  1. public static void main(String[] args) {
  2. LinkedList<Integer> list = new LinkedList<>();
  3. list.add(1); // add(elem): 表示尾插
  4. list.add(2);
  5. list.add(3);
  6. list.add(4);
  7. list.add(5);
  8. list.add(6);
  9. list.add(7);
  10. System.out.println(list.size());
  11. // foreach遍历
  12. for (int e:list) {
  13. System.out.print(e + " ");
  14. }
  15. System.out.println();
  16. // 使用迭代器遍历---正向遍历
  17. ListIterator<Integer> it = list.listIterator();
  18. while(it.hasNext()){
  19. System.out.print(it.next()+ " ");
  20. }
  21. System.out.println();
  22. // 使用反向迭代器---反向遍历
  23. ListIterator<Integer> rit = list.listIterator(list.size());
  24. while (rit.hasPrevious()){
  25. System.out.print(rit.previous() +" ");
  26. }
  27. System.out.println();
  28. }

7.ArrayList和LinkedList的区别

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

闽ICP备14008679号