// 单向链表 /** * 链表节点 */ export class ListNode { [x: string]: any; constructor(data: any) { this.data = data; // 数据 this.next = null; // 指向下一个节点的指针 } // 转数组 toArr() { const arr = []; let p = this; while (p) { arr.push(p.data); p = p.next; } return arr; } } /** * 链表类 * 通常使用"head"作为链表的入口,这个"head"是对链表中第一个节点的引用, * 而链表的最后一个节点指向null, * 如果是空链表,链表的引用就是null */ export class LinkedList { [x: string]: any; // 果未传递"head"节点,则它将初始化为 null constructor(head: any = null) { // this.head = head; if (head) { this.head = new ListNode(head); } else { this.head = null; } } // 添加节点 add(data: any) { const newNode = new ListNode(data); const currNode = this.getLast(); if (currNode) { // 将最后一个节点的指针指向新的节点 currNode.next = newNode; } else { this.head = newNode; } } // 查找节点 find(data: any) { let currNode = this.head; // 从头部开始找 while (currNode && currNode.data !== data) { // 如果不相等,则指针指向下一个节点继续比较 currNode = currNode.next; } return currNode; } // 插入节点 // target:链表中存在的节点值 // data:要插入的节点值 // data插入的位置在target的后面 insert(target: any, data: any) { const tagNode = this.find(target); if (!tagNode) return; // 如果目标节点不存在,则返回 const newNode = new ListNode(data); newNode.next = tagNode.next; // 1 先将新节点的指针->指向目标节点的next tagNode.next = newNode; // 2 再将目标节点的指针指向->新节点 // 注意顺序不要反了,不然目标节点与新节点的指针会相互循环指向下去 } // 删除节点 remove(data: any) { const tarNode = this.find(data); if (!tarNode) return; // 删除的节点不存在,就返回 if (this.head.data === data) { // 如果是头节点 console.warn('单链表的头节点不允删除'); return; } // 方法一 // 找到要删除节点的前一个节点(例如叫A节点) // 还是从头开始找 let currNode = this.head; // 如果A节点的下一个指针指向的节点值等于我们要删除的节点值,那么这个节点就是我们要找的 while (currNode && currNode.next && currNode.next.data !== data) { currNode = currNode.next; } // 然后把A节点的next指向->删除节点的next currNode.next = tarNode.next; // // 方法二 // // 此方法不能删除最后一个节点 // // 将要删除节点的值修改为它的下一个节点的值 // if (tarNode.next) { // tarNode.data = tarNode.next.data; // tarNode.next = tarNode.next.next; // } } // 链表反向 reverse() { if (this.head === null || this.head.next === null) { return this.head; } let p = this.head; let n = null; while (p) { const nextNode = p.next; p.next = n; n = p; p = nextNode; } const newList = new LinkedList(); newList.head = n; return newList; } // 返回链表中的节点数 size() { let count = 0; let node = this.head; while (node) { count++; node = node.next; } return count; } // 清空链表 clear() { this.head = null; } // 返回链表的最后一个节点 getLast() { let lastNode = this.head; if (lastNode) { while (lastNode.next) { lastNode = lastNode.next; } } return lastNode; } // 返回链表的第一个节点 getFirst() { return this.head; } // 返回上一个节点 getLastNode(data: any) { const currNode = this.find(data); if (currNode) { // 如果头节点 if (data === this.head.data) { return null; } else { let currNode = this.head; while (currNode && currNode.next && currNode.next.data !== data) { currNode = currNode.next; } return currNode; } } else { return null; } } // 返回下一个节点 getNextNode(data: any) { const currNode = this.find(data); if (currNode) { return currNode.next; } else { return null; } } // 返回链表的中间节点 // 如果有两个中间节点,则返回第二个节点 getMiddle() { // 用两个指针,快指针走两步,慢指针走一步 // 当快指针到终点时,慢指针正好在中间 let fast = this.head; let low = this.head; while (fast && fast.next) { fast = fast.next.next; low = low.next; } return low; } // 转数组 toArr() { let p = this.head; const arr = []; while (p) { arr.push(p.data); p = p.next; } return arr; } } /** * 合并两个升序链表 */ export const mergeTwoLists = function (list1: any, list2: any) { let p1 = list1.head || null; let p2 = list2.head || null; const newList = new LinkedList('head'); let p3 = newList.head; while (p1 && p2) { // 把更小的放到p3,p3向后移动,小的那个也向后移动 if (p1.data > p2.data) { p3.next = p2; p2 = p2.next; } else { p3.next = p1; p1 = p1.next; } p3 = p3.next; } p3.next = p1 ? p1 : p2; // while (p1) { // p3.next = p1; // p3 = p3.next; // p1 = p1.next; // } // while (p2) { // p3.next = p2; // p3 = p3.next; // p2 = p2.next; // } return newList.head.next; }; /** * 合并两个升序链表 递归法 */ export const mergeByRecursion = function (list1: any, list2: any) { const p1 = list1 ? list1.head || list1 : null; const p2 = list2 ? list2.head || list2 : null; if (p1 === null) { return p2; } if (p2 === null) { return p1; } if (p1.data < p2.data) { p1.next = mergeByRecursion(p1.next, p2); return p1; } else { p2.next = mergeByRecursion(p2.next, p1); return p2; } }; /** * 两数相加 */ export const addTwoNumbers = function (l1: any, l2: any) { let p1 = l1.head || null; let p2 = l2.head || null; const list3 = new ListNode('head'); let p3 = list3; let step = 0; while (p1 || p2) { const sum = (p1?.data || 0) + (p2?.data || 0) + step; const targetNum = sum % 10; // 当前位的值 p3.next = new ListNode(targetNum); p1 = p1?.next || null; p2 = p2?.next || null; p3 = p3.next; step = Math.floor(sum / 10); // 下一次的进位数 if (p1 == null && p2 == null && step !== 0) { p3.next = new ListNode(step); } } return list3.next; }; /** * 移除链表元素 */ export const removeElements = function (head: any, val: any) { // 方法一 迭代 // let p = head; // while (p) { // if (p.next?.data === val) { // p.next = p.next.next || null; // } else { // if (p.next) { // p = p.next; // } else { // p = null; // } // } // } // if (head?.data === val) { // head = head.next || null; // } // return head; // 方法二 递归 if (head === null) { return null; } head.next = removeElements(head.next, val); return head.data === val ? head.next : head; };