链表是一种物理存储单元上非连续、非顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针链接次序实现的。
链表由一系列节点组成,节点可以在运行时动态生成。
每个结点包括两个部分:

  • 存储数据元素的数据域
  • 存储下一个结点地址的指针域。

相比于线性表顺序结构,操作复杂。由于不必须按顺序存储,链表在插入的时候可以达到O(1)的复杂度,比另一种线性表顺序表快得多,但是查找一个节点或者访问特定编号的节点则需要O(n)的时间,而线性表和顺序表相应的时间复杂度分别是O(logn)和O(1)。

例题

206. 反转链表

给你单链表的头节点 head ,请你反转链表,并返回反转后的链表。 :::info 示例:
输入: 1->2->3->4->5->NULL
输出: 5->4->3->2->1->NULL ::: 进阶:
你可以迭代或递归地反转链表。你能否用两种方法解决这道题?

思路

迭代

nxt记录下一个节点,cur表示当前节点,prev表示上一个节点。
不断遍历节点,将当前节点cur指向前一个结点prev,然后将cur/prev分别向后移动,直到cur为空。
最后返回prev即可。

  1. var reverseList = function(head) {
  2. if(!head) return head
  3. let prev = null , curr = head
  4. while(curr){
  5. // 暂存当前节点的下一节点
  6. const nxt = curr.next
  7. // 当前节点指向上一节点
  8. curr.next = prev
  9. // 将上一节点往后移动到当前节点
  10. prev = curr
  11. // 将当前节点移动到下一节点
  12. curr = nxt
  13. }
  14. return prev
  15. };

递归

采用递归的方法,即不断递归到链表的倒数第二个节点。
然后在回退时,将当前节点的下一个节点指向为当前节点。 :::info n_1→…→_nk−1→nknk+1→…→nm→∅
将 nk+1的下一个节点指向nk:
n_1→…→_nk−1→nknk+1←…←nm ::: 最后注意的是要将 n1的下一个节点设置为空,以防出现环。

  1. var reverseList = function(head) {
  2. if (!head || !head.next) return head;
  3. let curHead = reverseList(head.next);
  4. head.next.next = head;
  5. head.next = null;
  6. return curHead;
  7. };

92. 反转链表 II

给你单链表的头指针 head 和两个整数 left 和 right ,其中 left <= right 。请你反转从位置 left 到位置 right 的链表节点,返回 反转后的链表 :::info 输入: 1->2->3->4->5->NULL, left = 2, right = 4
输出: 1->4->3->2->5->NULL :::

思路

找出需要反转的子链表的起点节点leftNode与终点节点rightNode
然后还要记录leftNode的前一个节点pre,和rightNode的后一个节点curr
对子链表进行反转后,拼接链表。
pre节点指向rightNode,然后leftNode节点指向curr即可。
反转链表I 、II - 图1

  1. var reverseBetween = function(head, left, right) {
  2. const dummyNode = new ListNode(-1);
  3. dummyNode.next = head;
  4. let pre = dummyNode;
  5. // 来到 left 节点的前一个节点
  6. for (let i = 0; i < left - 1; i++) {
  7. pre = pre.next;
  8. }
  9. // 来到 right 节点
  10. let rightNode = pre;
  11. for (let i = 0; i < right - left + 1; i++) {
  12. rightNode = rightNode.next;
  13. }
  14. // 切断出一个子链表
  15. let leftNode = pre.next;
  16. let curr = rightNode.next;
  17. pre.next = null;
  18. rightNode.next = null;
  19. // 反转链表的子区间
  20. reverse(leftNode);
  21. // 接回到原来的链表中
  22. pre.next = rightNode;
  23. leftNode.next = curr;
  24. return dummyNode.next;
  25. };
  26. function reverse(head) {
  27. let prev = null
  28. let cur = head
  29. while (cur) {
  30. let next = cur.next
  31. cur.next = prev
  32. prev = cur
  33. cur = next
  34. }
  35. }