• 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 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 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 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)
    插入空间不够时需要扩容没有容量概念
    应用场景元素高效存储+频繁访问频繁在任意位置插入删除操作

  • 相关阅读:
    11 结构型模式- 代理模式
    【Linux operation 42】Linux 系统的时间
    IEDA refactor的用法
    【20221114】【每日一题】复原IP地址
    使用Webpack打包TS代码
    leetcode:126. 单词接龙 II
    Eolink征文活动---Eolink API文档服务的天才产品
    shell 学习笔记
    WSL2安装历程
    强化学习 补充笔记(TD算法、Q学习算法、SARSA算法、多步TD目标、经验回放、高估问题、对决网络、噪声网络)
  • 原文地址:https://blog.csdn.net/Yuan_o_/article/details/139603275