数据分散的存储在物理空间中,通过一根线保存着它们之间的逻辑关系,这种存储结构称为链式存储结构
    实际上,就是每一个结点存放一个元素和一个指向下一个结点的引用(C语言里面是指针,Java中就是对象的引用,代表下一个结点对象)

    image.png
    利用这种思想,我们再来尝试实现上面的抽象类,从实际的代码中感受!

    比较:顺序表和链表的优异?

    顺序表优缺点:

    • 访问速度快,随机访问性能高
    • 插入和删除的效率低下,极端情况下需要变更整个表
    • 不易扩充,需要复制并重新创建数组

    链表优缺点:

    • 插入和删除效率高,只需要改变连接点的指向即可
    • 动态扩充容量,无需担心容量问题
    • 访问元素需要依次寻找,随机访问元素效率低下

    链表只能指向后面,能不能指向前面呢?双向链表!


    栈和队列实际上就是对线性表加以约束的一种数据结构,如果前面的线性表的掌握已经ok,那么栈和队列就非常轻松了!
    手动实现一个int链表

    1. package com.linkedlist;
    2. public class Node {
    3. private int data;// 结点数据
    4. private Node next;// 下一个结点
    5. public Node(int data) {
    6. this.data = data;
    7. }
    8. public int getData() {
    9. return data;
    10. }
    11. public void setData(int data) {
    12. this.data = data;
    13. }
    14. public Node getNext() {
    15. return next;
    16. }
    17. public void setNext(Node next) {
    18. this.next = next;
    19. }
    20. }
    1. package com.linkedlist;
    2. import java.util.Hashtable;
    3. public class LinkedListOperator {
    4. private Node head = null;// 头结点
    5. // 在链表的末尾增加一个结点
    6. private void addNode(int data) {
    7. Node newNode = new Node(data);
    8. if (head == null) {
    9. head = newNode;
    10. return;
    11. }
    12. Node temp = head;
    13. while (temp.getNext() != null) {
    14. temp = temp.getNext();
    15. }
    16. temp.setNext(newNode);
    17. }
    18. // 打印链表结点
    19. private void printLink() {
    20. Node curNode = head;
    21. while (curNode != null) {
    22. System.out.println(curNode.getData());
    23. curNode = curNode.getNext();
    24. }
    25. System.out.println("===========");
    26. }
    27. // 求链表长度
    28. private int getLength() {
    29. int len = 0;
    30. Node curNode = head;
    31. while (curNode != null) {
    32. len++;
    33. curNode = curNode.getNext();
    34. }
    35. return len;
    36. }
    37. // 删除某一个结点
    38. private boolean delNode(int index) {
    39. if (index < 1) {
    40. return false;
    41. }
    42. if (index == 1) {
    43. head = head.getNext();
    44. return true;
    45. }
    46. Node preNode = head;
    47. Node curNode = head.getNext();
    48. int n = 1;
    49. while (curNode.getNext() != null) {
    50. if (n == index) {
    51. preNode.setData(curNode.getData());
    52. preNode.setNext(curNode.getNext());
    53. return true;
    54. }
    55. preNode = preNode.getNext();
    56. curNode = curNode.getNext();
    57. n++;
    58. }
    59. if (curNode.getNext() == null) {
    60. preNode.setNext(null);
    61. }
    62. return false;
    63. }
    64. // 链表排序:选择排序法,从小到大
    65. private void sortList() {
    66. Node curNode = head;
    67. while (curNode != null) {
    68. Node nextNode = curNode.getNext();
    69. while (nextNode != null) {
    70. if (curNode.getData() > nextNode.getData()) {
    71. int temp = curNode.getData();
    72. curNode.setData(nextNode.getData());
    73. nextNode.setData(temp);
    74. }
    75. nextNode = nextNode.getNext();
    76. }
    77. curNode = curNode.getNext();
    78. }
    79. }
    80. // 去掉重复元素
    81. private void distinctLink() {
    82. Hashtable<Integer, Integer> map = new Hashtable<Integer, Integer>();
    83. Node curNode = head;
    84. Node preNode = null;
    85. while (curNode != null) {
    86. if (map.containsKey(curNode.getData())) {
    87. preNode.setData(curNode.getData());
    88. preNode.setNext(curNode.getNext());
    89. } else {
    90. map.put(curNode.getData(), 1);
    91. preNode = curNode;
    92. }
    93. curNode = curNode.getNext();
    94. }
    95. }
    96. // 返回倒数第k个结点,定义两个指针,第一个指针向前移动K-1次,之后两个指针同时前进,
    97. // 当第一个指针到达末尾时,第二个指针所在的位置即为倒数第k个结点
    98. private Node getReverNode(int k) {
    99. if (k < 1) {
    100. return null;
    101. }
    102. Node first = head;
    103. Node second = head;
    104. for (int i = 0; i < k - 1; i++) {
    105. first = first.getNext();
    106. }
    107. while (first.getNext() != null) {
    108. first = first.getNext();
    109. second = second.getNext();
    110. }
    111. return second;
    112. }
    113. // 反转链表
    114. private void reserveLink() {
    115. Node preNode = null;
    116. Node curNode = head;
    117. Node tempNode = null;
    118. while (curNode != null) {
    119. tempNode = curNode.getNext();
    120. curNode.setNext(preNode);
    121. preNode = curNode;
    122. curNode = tempNode;
    123. }
    124. head = preNode;
    125. }
    126. // 寻找链表的中间结点
    127. private Node getMiddleNode() {
    128. Node slowNode = head;
    129. Node quickNode = head;
    130. while (slowNode.getNext() != null && quickNode.getNext() != null) {
    131. slowNode = slowNode.getNext();
    132. quickNode = quickNode.getNext().getNext();
    133. }
    134. return slowNode;
    135. }
    136. // 判断链表是否有环
    137. private boolean isRinged() {
    138. if (head == null) {
    139. return false;
    140. }
    141. Node slowNode = head;
    142. Node quickNode = head;
    143. while (slowNode.getNext() != null && quickNode.getNext() != null) {
    144. slowNode = slowNode.getNext();
    145. quickNode = quickNode.getNext().getNext();
    146. if (slowNode.getData() == quickNode.getData()) {
    147. return true;
    148. }
    149. }
    150. return false;
    151. }
    152. // 删除指定结点
    153. private boolean delNode(Node node) {
    154. if (node.getNext() == null) {
    155. return false;// 在不知道头结点的情况下,没法删除单链表的尾结点
    156. }
    157. node.setData(node.getNext().getData());
    158. node.setNext(node.getNext().getNext());
    159. return true;
    160. }
    161. // 判断两个链表是否相交:相交的链表的尾结点相同
    162. private boolean isCross(Node n1, Node n2) {
    163. while (n1.getNext() != null) {
    164. n1 = n1.getNext();
    165. }
    166. while (n2.getNext() != null) {
    167. n2 = n2.getNext();
    168. }
    169. if (n1.getData() == n2.getData()) {
    170. return true;
    171. }
    172. return false;
    173. }
    174. // 求相交链表的起始点
    175. private Node getFirstCrossNode(LinkedListOperator l1, LinkedListOperator l2) {
    176. int len = l1.getLength() - l2.getLength();
    177. Node n1 = l1.head;
    178. Node n2 = l2.head;
    179. if (len > 0) {
    180. for (int i = 0; i < len; i++) {
    181. n1 = n1.getNext();
    182. }
    183. } else {
    184. for (int i = 0; i < len; i++) {
    185. n2 = n2.getNext();
    186. }
    187. }
    188. while (n1.getData() != n2.getData()) {
    189. n1 = n1.getNext();
    190. n2 = n2.getNext();
    191. }
    192. return n1;
    193. }
    194. public static void main(String[] args) {
    195. LinkedListOperator llo = new LinkedListOperator();
    196. llo.addNode(10);
    197. llo.addNode(4);
    198. llo.addNode(6);
    199. llo.addNode(8);
    200. llo.printLink();
    201. // llo.delNode(4);
    202. // llo.sortList();
    203. // llo.distinctLink();
    204. // System.out.println(llo.getReverNode(3).getData());
    205. // llo.reserveLink();
    206. // System.out.println(llo.getMiddleNode().getData());
    207. // System.out.println(llo.isRinged());
    208. llo.delNode(llo.head.getNext().getNext());
    209. llo.printLink();
    210. }
    211. }