• 数据结构之链表(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 c)
    使用其他集合容器中元素构造List
    1. public static void main(String[] args) {
    2. // 构造一个空的LinkedList
    3. List list1 = new LinkedList<>();
    4. List list2 = new java.util.ArrayList<>();
    5. list2.add("JavaSE");
    6. list2.add("JavaWeb");
    7. list2.add("JavaEE");
    8. // 使用ArrayList构造LinkedList
    9. List list3 = new LinkedList<>(list2);
    10. }

     LinkedList的常用方法:

    方法解释
    boolean add(E e)
    尾插 e
    void add(int index, E element)
    将 e 插入到 index 位置
    boolean addAll(Collection 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 subList(int fromIndex, int toIndex)
    截取部分 list

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

    1. LinkedList 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 list1 = list.listIterator();
    11. while (list1.hasNext()){
    12. System.out.print(list1.next()+" ");
    13. }
    14. // 使用反向迭代器---反向遍历
    15. ListIterator 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 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)
    插入
    空间不够时需要扩容
    没有容量的概念
    应用场景
    元素高效存储+频繁访问
    任意位置插入和删除频繁

     

     

  • 相关阅读:
    从0到1设计通用数据大屏搭建平台
    [附源码]Python计算机毕业设计钓鱼爱好者交流平台
    git详细教程
    阿里云一面:并发场景下的底层细节 - 伪共享问题
    基于C++的云安全主动防御系统客户端服务端设计
    设计模式介绍
    Marin说PCB之Coilcraft&Bourns POC 电感的性能对比
    最新下载:Paragon NTFS for Mac 15【软件附加安装教程】
    OpenHarmony实战开发-Web自定义长按菜单案例。
    分布式文件系统和对象存储魔力象限,右上角都有谁?
  • 原文地址:https://blog.csdn.net/crazy_xieyi/article/details/126991783