当前位置:   article > 正文

数据结构之链表(LinkedList详解)

linkedlist

 

文章目录

  • 一、什么是LinkedList?
  • 二、LinkedList的使用
  • 三、LinkedList自实现
  • 四、链表实现逆序打印的两种方式(递归和非递归)
  • 五、ArrayList和LinkedList有什么区别?

一、什么是LinkedList?

LinkedList的底层是 双向链表结构(链表后面介绍),由于链表没有将元素存储在连续的空间中,元素存储在单独的节点中,然后通过引用将节点连接起来了,因此在在任意位置插入或者删除元素时,不需要搬移元素,效率比较高。
 
在集合框架中,LinkedList也实现了List接口,具体如下:
d7695e27e19e41c0af85476fdb249112.png
1. LinkedList实现了 List接口
2. LinkedList的底层使用了 双向链表
3. LinkedList没有实现RandomAccess接口,因此LinkedList 不支持随机访问
4. LinkedList的任意位置插入和删除元素时效率比较高,时间复杂度为O(1)
 

二、LinkedList的使用

构造方法:

方法解释
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 java.util.ArrayList<>();
  5. list2.add("JavaSE");
  6. list2.add("JavaWeb");
  7. list2.add("JavaEE");
  8. // 使用ArrayList构造LinkedList
  9. List<String> list3 = new LinkedList<>(list2);
  10. }

 LinkedList的常用方法:

方法解释
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 lastIndexOf(Object o)
返回最后一个 o 的下标
List<E> subList(int fromIndex, int toIndex)
截取部分 list

LinkedList的遍历:(foreach遍历、使用迭代器遍历---正向遍历、使用反向迭代器---反向遍历

  1. LinkedList<String> list = new LinkedList<>();
  2. list.add("javaSE");
  3. list.add("javaWeb");
  4. list.add("javaEE");
  5. // foreach遍历
  6. for (String x: list) {
  7. System.out.print(x + " ");
  8. }
  9. // 使用迭代器遍历---正向遍历
  10. ListIterator<String> list1 = list.listIterator();
  11. while (list1.hasNext()){
  12. System.out.print(list1.next()+" ");
  13. }
  14. // 使用反向迭代器---反向遍历
  15. ListIterator<String> lis2 = list.listIterator(list.size());
  16. while (lis2.hasPrevious()){
  17. System.out.print(lis2.previous()+" ");
  18. }

三、LinkedList自实现

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

四、链表实现逆序打印的两种方式(递归和非递归)

递归逆序打印:

  1. public void display(ListNode head) {
  2. if(head == null) {
  3. return;
  4. }
  5. if(head.next == null) {
  6. System.out.print(head.val+" ");
  7. return;
  8. }
  9. display(head.next);
  10. System.out.print(head.val+" ");
  11. }

非递归逆序打印(用栈实现):

  1. public void display(ListNode head) {
  2. if (head == null) {
  3. return;
  4. }
  5. Stack<ListNode> stack = new Stack<>();
  6. ListNode cur = head;
  7. while (cur != null) {
  8. stack.push(cur);
  9. cur = cur.next;
  10. }
  11. while (!stack.empty()) {
  12. ListNode ret = stack.pop();
  13. System.out.print(ret.val+" ");
  14. }
  15. }

 

五、ArrayList和LinkedList有什么区别?

 

ArrayList实质是顺序表,底层是一个数组。LinkedList实质是一个链表。

他们都具有增删查改的功能,但是在实现方式上有区别。比如在插入元素的时候,ArrayList往0位置上插入一个元素,就需把整个数组整体往后移动,时间复杂度为O(N)。而LinkedList只需要修改指向就可以了,时间复杂度为O(1)。但是ArrayList可以支持随机访问,时间复杂度为O(1),所以一般情况下ArrayList顺序表适合频繁根据下标位置访问,LinkedList比较适合插入和删除比较频繁的情况。

从存储上来说,ArrayList顺序表在物理上和逻辑上都是连续的,但是在扩容的时候,可能会造成空间的浪费。而LinkedList在物理上不一定是连续的,在逻辑上是连续的,可以做到随用随取。

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

 

 

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

闽ICP备14008679号