模拟链表

  1. class Node {
  2. constructor(value) {
  3. this.value = value;
  4. this.next = null;
  5. }
  6. }
  7. class LinkedList {
  8. constructor() {
  9. this.length = 0;
  10. this.head = null;
  11. }
  12. equalsFn(a, b) {
  13. return a === b;
  14. }
  15. }

功能

  1. push(element):向链表尾部添加一个新元素。
  2. insert(element, position):向链表的特定位置插入一个新元素。
  3. getElementAt(index):返回链表中特定位置的元素。如果链表中不存在这样的元素,则返回undefined。
  4. remove(element):从链表中移除一个元素。
  5. indexOf(element):返回元素在链表中的索引。如果链表中没有该元素则返回-1。
  6. removeAt(position):从链表的特定位置移除一个元素。
  7. isEmpty():如果链表中不包含任何元素,返回true,如果链表长度大于0 则返回false。
  8. size():返回链表包含的元素个数,与数组的length 属性类似。
  9. toString():返回表示整个链表的字符串。由于列表项使用了Node 类,就需要重写继承自JavaScript 对象默认的toString 方法,让其只输出元素的值。

push

  1. push(val) {
  2. let newNode = new Node(val);
  3. let curr;
  4. if (!this.head) { // 刚开始链表为空,就把这个设置为head
  5. this.head = newNode;
  6. } else {
  7. curr = this.head;
  8. while (curr.next) { // 一直找到链表末尾
  9. curr = curr.next;
  10. }
  11. curr.next = newNode;
  12. }
  13. this.length++;
  14. }

removeAt

链表 - 图1

  1. removeAt(index) {
  2. if (index < this.length && index >= 0) {
  3. let curr = this.head;
  4. if (index === 0) {
  5. this.head = curr.next;
  6. } else {
  7. // 找到index前一个后停止,下一个就是要删除的结点
  8. for (let i = 1; i < index; i++) {
  9. curr = curr.next;
  10. }
  11. let beRemove = curr.next;
  12. // 改变要被删除结点的上一个结点的指向
  13. curr.next = beRemove.next;
  14. this.length--;
  15. return beRemove;
  16. }
  17. }
  18. }

getElementAt

  1. getElementAt(index) {
  2. if (index < this.length && index >= 0) {
  3. let curr = this.head;
  4. if (index === 0) return curr;
  5. else {
  6. for (let i = 1; i <= index; i++) {
  7. curr = curr.next;
  8. }
  9. return curr;
  10. }
  11. }
  12. }

重写removeAt

  1. removeAt(index) {
  2. let curr = this.getElementAt(index - 1);
  3. curr.next = curr.next.next;

insert

链表 - 图2

  1. insert(index, value) {
  2. let newNode = new Node(value);
  3. if (index < this.length && index >= 0) {
  4. let curr = this.head;
  5. if (index === 0) { // index 为0,改变头结点指向就行了
  6. this.head = newNode;
  7. this.head.next = curr;
  8. } else {
  9. // 找到插入位置的前一个,
  10. for (let i = 1; i < index; i++) {
  11. curr = curr.next;
  12. }
  13. let nextNode = curr.next;
  14. curr.next = newNode;
  15. newNode.next = nextNode;
  16. }
  17. this.length++;
  18. }
  19. }

indexOf

  1. indexOf(value) {
  2. let curr = this.head; // 存入head
  3. if (this.equalsFn(curr.value, value)) {
  4. return 0;
  5. }
  6. for (let i = 1; i < this.length; i++) {
  7. curr = curr.next;
  8. if (this.equalsFn(curr.value, value)) {
  9. return i;
  10. }
  11. }
  12. return -1;
  13. }

removeValue

  1. removeValue(value) {
  2. let curr = this.head;
  3. let prev = null;
  4. if (this.equalsFn(curr.value, value)) {
  5. this.head = curr.next;
  6. this.length--;
  7. }
  8. for (let i = 1; i < this.length; i++) {
  9. prev = curr;
  10. curr = curr.next;
  11. if (this.equalsFn(curr.value, value)) {
  12. prev.next = curr.next;
  13. this.length--;
  14. }
  15. }
  16. return undefined;
  17. }

toString

  1. toString() {
  2. let objString = "";
  3. let curr = this.head;
  4. if (!curr) {
  5. return objString;
  6. } else {
  7. objString = `${curr.value}`;
  8. for (let i = 1; i < this.length; i++) {
  9. curr = curr.next;
  10. objString = `${objString}, ${curr.value}`;
  11. }
  12. return objString;
  13. }
  14. }

完整代码

  1. class Node {
  2. constructor(value) {
  3. this.value = value;
  4. this.next = null;
  5. }
  6. }
  7. class LinkedList {
  8. constructor() {
  9. this.length = 0;
  10. this.head = null;
  11. }
  12. equalsFn(a, b) {
  13. return a === b;
  14. }
  15. push(val) {
  16. let newNode = new Node(val);
  17. let curr;
  18. if (!this.head) { // 刚开始链表为空,就把这个设置为head
  19. this.head = newNode;
  20. } else {
  21. curr = this.head;
  22. while (curr.next) { // 一直找到链表末尾
  23. curr = curr.next;
  24. }
  25. curr.next = newNode;
  26. }
  27. this.length++;
  28. }
  29. removeAt(index) {
  30. let curr = this.getElementAt(index - 1);
  31. curr.next = curr.next.next;
  32. }
  33. getElementAt(index) {
  34. if (index < this.length && index >= 0) {
  35. let curr = this.head;
  36. if (index === 0) return curr;
  37. else {
  38. for (let i = 1; i <= index; i++) {
  39. curr = curr.next;
  40. }
  41. return curr;
  42. }
  43. }
  44. }
  45. insert(index, value) {
  46. let newNode = new Node(value);
  47. if (index < this.length && index >= 0) {
  48. let curr = this.head;
  49. if (index === 0) { // index 为0,改变头结点指向就行了
  50. this.head = newNode;
  51. this.head.next = curr;
  52. } else {
  53. // 找到插入位置的前一个,
  54. for (let i = 1; i < index; i++) {
  55. curr = curr.next;
  56. }
  57. let nextNode = curr.next;
  58. curr.next = newNode;
  59. newNode.next = nextNode;
  60. }
  61. this.length++;
  62. } else {
  63. throw "索引值错误";
  64. }
  65. }
  66. indexOf(value) {
  67. let curr = this.head; // 存入head
  68. if (this.equalsFn(curr.value, value)) {
  69. return 0;
  70. }
  71. for (let i = 1; i < this.length; i++) {
  72. curr = curr.next;
  73. if (this.equalsFn(curr.value, value)) {
  74. return i;
  75. }
  76. }
  77. return -1;
  78. }
  79. removeValue(value) {
  80. let curr = this.head;
  81. let prev = null;
  82. if (this.equalsFn(curr.value, value)) {
  83. this.head = curr.next;
  84. this.length--;
  85. }
  86. for (let i = 1; i < this.length; i++) {
  87. prev = curr;
  88. curr = curr.next;
  89. if (this.equalsFn(curr.value, value)) {
  90. prev.next = curr.next;
  91. this.length--;
  92. }
  93. }
  94. return undefined;
  95. }
  96. toString() {
  97. let objString = "";
  98. let curr = this.head;
  99. if (!curr) {
  100. return objString;
  101. } else {
  102. objString = `${curr.value}`;
  103. for (let i = 1; i < this.length; i++) {
  104. curr = curr.next;
  105. objString = `${objString}, ${curr.value}`;
  106. }
  107. return objString;
  108. }
  109. }
  110. getHead() {
  111. return this.head;
  112. }
  113. isEmpty() {
  114. return this.length === 0 ? true : false;
  115. }
  116. size() {
  117. return this.length;
  118. }
  119. }
  120. let linkedList = new LinkedList();
  121. linkedList.push("a");
  122. linkedList.push("b");
  123. linkedList.push("c");
  124. // linkedList.removeAt(1);
  125. linkedList.insert(1, "aa");
  126. console.log(linkedList.getElementAt(2));
  127. console.log(linkedList.indexOf("a"));
  128. console.log(linkedList.removeValue("c"));
  129. console.log(linkedList.size());
  130. console.log(linkedList.isEmpty());
  131. console.log(linkedList);
  132. console.log(linkedList.toString());

题目

lc237:删除链表中的结点

  1. var deleteNode = function(node) {
  2. node.val = node.next.val;
  3. node.next = node.next.next;
  4. };

206. 反转链表

  1. 双指正法
  2. 最开始p1指向head,p2指向前一个null
  3. 改变p1.next,主意首先保存temp = p1.next;
  4. 改变p2 = p1,p1 = temp,双指针向前移动,直到p1为null
  5. 返回p2,此时p2为新的head
    1. var reverseList = function(head) {
    2. let p1 = head;
    3. let p2 = null;
    4. while(p1) {
    5. const temp = p1.next;
    6. p1.next = p2;
    7. p2 = p1;
    8. p1 = temp;
    9. }
    10. return p2;
    11. };

2. 两数相加

  1. var addTwoNumbers = function (l1, l2) {
  2. const l3 = new ListNode(0);
  3. let p1 = l1, p2 = l2;
  4. let p3 = l3;
  5. let carry = 0; // 上一步的进位
  6. while(p1 || p2) {
  7. const val1 = p1 ? p1.val : 0;
  8. const val2 = p2 ? p2.val : 0;
  9. const x = val1 + val2 + carry;
  10. carry = Math.floor(x / 10);
  11. p3.next = new ListNode(x % 10);
  12. if (p1) p1 = p1.next;
  13. if (p2) p2 = p2.next;
  14. p3 = p3.next;
  15. }
  16. if (carry) {
  17. p3.next = new ListNode(carry)
  18. }
  19. return l3.next;
  20. };

83. 删除排序链表中的重复元素

  1. var deleteDuplicates = function(head) {
  2. let p = head;
  3. while(p && p.next) {
  4. if (p.val === p.next.val) {
  5. p.next = p.next.next;
  6. } else {
  7. p = p.next;
  8. }
  9. }
  10. return head;
  11. };

141. 环形链表

快慢指针

  1. var hasCycle = function(head) {
  2. let p1 = head;
  3. let p2 = head;
  4. while(p1 && p2 && p2.next) {
  5. p1 = p1.next;
  6. p2 = p2.next.next;
  7. if (p1 === p2) {
  8. return true
  9. }
  10. }
  11. return false
  12. };

利用链表获取JSON的结点值

  1. const json = {
  2. a: { b: { c: 1 } },
  3. d: { e: 2 },
  4. };
  5. // 写出结点的路径
  6. const path = ["a", "b", "c"];
  7. let p = json;
  8. path.forEach(k => {
  9. p = p[k];
  10. });
  11. console.log(p)