diff --git a/code/linked-list/book/LinkedList.ts b/code/linked-list/book/LinkedList.ts index 0644c7b..431638a 100644 --- a/code/linked-list/book/LinkedList.ts +++ b/code/linked-list/book/LinkedList.ts @@ -4,11 +4,11 @@ import { type LinkedListInterface } from './type'; export default class LinkedList implements LinkedListInterface { count: number; - head: null | LinkedNode; + head: undefined | LinkedNode; eqFn: (a: T, b: T) => boolean; constructor(eq = defaultEquals) { this.count = 0; - this.head = null; + this.head = undefined; this.eqFn = eq; } @@ -23,20 +23,40 @@ export default class LinkedList implements LinkedListInterface { } current.next = node; } - this.count++; } - // @ts-ignore insert(element: T, position: number) { - // @ts-ignore - const node = new LinkedListNode(element); - - this.count++; + if (position >= 0 && position <= this.count) { + const node = new LinkedNode(element); + if (position == 0) { + let c = this.head; + node.next = c; + this.head = node; + } else { + const pre = this.getElementAt(position - 1); + if (pre) { + const next = pre.next; + pre.next = node; + node.next = next; + } + } + this.count++; + return true; + } return false; } - // @ts-ignore getElementAt(index: number) { + if (index >= 0 && index < this.count) { + let current = this.head; + for (let i = 0; i < this.count; i++) { + if (i === index) { + break; + } + current = current?.next; + } + return current; + } return undefined; } @@ -50,42 +70,45 @@ export default class LinkedList implements LinkedListInterface { } removeAt(index: number) { - if (index >= 0 && index < this.count) { - let prev = this.head; - let i = 0; - while (prev?.next != null) { - if (i === index) { - break; - } - prev = prev.next; - i++; + if (index === 0) { + if (typeof this.head !== 'undefined') { + let c = this.head; + this.head = this.head.next; + this.count--; + return c.val; } - - const target = prev?.next; - - if (prev && prev.next && target) { - prev.next = target.next; + } else { + const prev = this.getElementAt(index - 1); + let current = prev?.next; + if (prev) { + prev.next = current?.next; + this.count--; + return current?.val; } - this.count--; - return target?.val; } - return; + return undefined; } + isEmpty() { return this.size() === 0; } size() { return this.count; } + toString() { - const arr: T[] = []; - let c = this.head; - while (c?.next !== null) { - c?.val && arr.push(c.val); - // @ts-ignore - c = c?.next; + if (!this.head) { + return ''; + } + let result = `${this.head?.val}`; + let current: LinkedNode | undefined = this.head; + for (let i = 1; i < this.count; i++) { + current = current?.next; + if (current) { + result += `,${current.val}`; + } } - return arr.join(','); + return result; } } diff --git a/code/linked-list/book/LinkedNode.ts b/code/linked-list/book/LinkedNode.ts index 94ac7e6..f4497c2 100644 --- a/code/linked-list/book/LinkedNode.ts +++ b/code/linked-list/book/LinkedNode.ts @@ -3,9 +3,9 @@ */ export class LinkedNode { val: T; - next: null | LinkedNode; + next: undefined | LinkedNode; constructor(v: T) { this.val = v; - this.next = null; + this.next = undefined; } } diff --git a/code/linked-list/book/type.ts b/code/linked-list/book/type.ts index 3f0f180..b51a60a 100644 --- a/code/linked-list/book/type.ts +++ b/code/linked-list/book/type.ts @@ -1,3 +1,5 @@ +import { LinkedNode } from "./LinkedNode"; + export interface LinkedListInterface { /** * 添加一个节点 @@ -19,7 +21,7 @@ export interface LinkedListInterface { * @param index * @returns */ - getElementAt: (index: number) => T | undefined; + getElementAt: (index: number) => LinkedNode | undefined; /** * 从链表中移除一个元素 diff --git a/code/linked-list/test/LinkedList.test.ts b/code/linked-list/test/LinkedList.test.ts index fc45ed7..ae83f91 100644 --- a/code/linked-list/test/LinkedList.test.ts +++ b/code/linked-list/test/LinkedList.test.ts @@ -8,231 +8,40 @@ describe('LinkedList', () => { it('should append node to linked list', () => { const linkedList = new LinkedList(); - - expect(linkedList.head).toBeNull(); - + expect(linkedList.head).toBeUndefined(); linkedList.push(1); linkedList.push(2); - expect(linkedList.toString()).toBe('1,2'); - // expect(linkedList.tail.next).toBeNull(); }); - // it('should prepend node to linked list', () => { - // const linkedList = new LinkedList(); - - // linkedList.prepend(2); - // expect(linkedList.head.toString()).toBe('2'); - // expect(linkedList.tail.toString()).toBe('2'); - - // linkedList.append(1); - // linkedList.prepend(3); - - // expect(linkedList.toString()).toBe('3,2,1'); - // }); - - // it('should insert node to linked list', () => { - // const linkedList = new LinkedList(); - - // linkedList.insert(4, 3); - // expect(linkedList.head.toString()).toBe('4'); - // expect(linkedList.tail.toString()).toBe('4'); - - // linkedList.insert(3, 2); - // linkedList.insert(2, 1); - // linkedList.insert(1, -7); - // linkedList.insert(10, 9); - - // expect(linkedList.toString()).toBe('1,4,2,3,10'); - // }); - - // it('should delete node by value from linked list', () => { - // const linkedList = new LinkedList(); - - // expect(linkedList.delete(5)).toBeNull(); - - // linkedList.append(1); - // linkedList.append(1); - // linkedList.append(2); - // linkedList.append(3); - // linkedList.append(3); - // linkedList.append(3); - // linkedList.append(4); - // linkedList.append(5); - - // expect(linkedList.head.toString()).toBe('1'); - // expect(linkedList.tail.toString()).toBe('5'); - - // const deletedNode = linkedList.delete(3); - - // expect(deletedNode.value).toBe(3); - // expect(linkedList.toString()).toBe('1,1,2,4,5'); - - // linkedList.delete(3); - // expect(linkedList.toString()).toBe('1,1,2,4,5'); - - // linkedList.delete(1); - // expect(linkedList.toString()).toBe('2,4,5'); - - // expect(linkedList.head.toString()).toBe('2'); - // expect(linkedList.tail.toString()).toBe('5'); - - // linkedList.delete(5); - // expect(linkedList.toString()).toBe('2,4'); - - // expect(linkedList.head.toString()).toBe('2'); - // expect(linkedList.tail.toString()).toBe('4'); - - // linkedList.delete(4); - // expect(linkedList.toString()).toBe('2'); - - // expect(linkedList.head.toString()).toBe('2'); - // expect(linkedList.tail.toString()).toBe('2'); - - // linkedList.delete(2); - // expect(linkedList.toString()).toBe(''); - // }); - - // it('should delete linked list tail', () => { - // const linkedList = new LinkedList(); - - // linkedList.append(1); - // linkedList.append(2); - // linkedList.append(3); - - // expect(linkedList.head.toString()).toBe('1'); - // expect(linkedList.tail.toString()).toBe('3'); - - // const deletedNode1 = linkedList.deleteTail(); - - // expect(deletedNode1.value).toBe(3); - // expect(linkedList.toString()).toBe('1,2'); - // expect(linkedList.head.toString()).toBe('1'); - // expect(linkedList.tail.toString()).toBe('2'); - - // const deletedNode2 = linkedList.deleteTail(); - - // expect(deletedNode2.value).toBe(2); - // expect(linkedList.toString()).toBe('1'); - // expect(linkedList.head.toString()).toBe('1'); - // expect(linkedList.tail.toString()).toBe('1'); - - // const deletedNode3 = linkedList.deleteTail(); - - // expect(deletedNode3.value).toBe(1); - // expect(linkedList.toString()).toBe(''); - // expect(linkedList.head).toBeNull(); - // expect(linkedList.tail).toBeNull(); - // }); - - // it('should delete linked list head', () => { - // const linkedList = new LinkedList(); - - // expect(linkedList.deleteHead()).toBeNull(); - - // linkedList.append(1); - // linkedList.append(2); - - // expect(linkedList.head.toString()).toBe('1'); - // expect(linkedList.tail.toString()).toBe('2'); - - // const deletedNode1 = linkedList.deleteHead(); - - // expect(deletedNode1.value).toBe(1); - // expect(linkedList.toString()).toBe('2'); - // expect(linkedList.head.toString()).toBe('2'); - // expect(linkedList.tail.toString()).toBe('2'); - - // const deletedNode2 = linkedList.deleteHead(); - - // expect(deletedNode2.value).toBe(2); - // expect(linkedList.toString()).toBe(''); - // expect(linkedList.head).toBeNull(); - // expect(linkedList.tail).toBeNull(); - // }); - - // it('should be possible to store objects in the list and to print them out', () => { - // const linkedList = new LinkedList(); - - // const nodeValue1 = { value: 1, key: 'key1' }; - // const nodeValue2 = { value: 2, key: 'key2' }; - - // linkedList.append(nodeValue1).prepend(nodeValue2); - - // const nodeStringifier = (value) => `${value.key}:${value.value}`; - - // expect(linkedList.toString(nodeStringifier)).toBe('key2:2,key1:1'); - // }); - - // it('should find node by value', () => { - // const linkedList = new LinkedList(); - - // expect(linkedList.find({ value: 5 })).toBeNull(); - - // linkedList.append(1); - // expect(linkedList.find({ value: 1 })).toBeDefined(); - - // linkedList.append(2).append(3); - - // const node = linkedList.find({ value: 2 }); - - // expect(node.value).toBe(2); - // expect(linkedList.find({ value: 5 })).toBeNull(); - // }); - - // it('should find node by callback', () => { - // const linkedList = new LinkedList(); - - // linkedList - // .append({ value: 1, key: 'test1' }) - // .append({ value: 2, key: 'test2' }) - // .append({ value: 3, key: 'test3' }); - - // const node = linkedList.find({ - // callback: (value) => value.key === 'test2', - // }); + it('should removeAt node by index linked list', () => { + const linkedList = new LinkedList(); + linkedList.push(1); + linkedList.push(2); - // expect(node).toBeDefined(); - // expect(node.value.value).toBe(2); - // expect(node.value.key).toBe('test2'); - // expect(linkedList.find({ callback: (value) => value.key === 'test5' })).toBeNull(); - // }); + linkedList.removeAt(1); + expect(linkedList.toString()).toBe('1'); + }); - // it('should create linked list from array', () => { - // const linkedList = new LinkedList(); - // linkedList.fromArray([1, 1, 2, 3, 3, 3, 4, 5]); - // expect(linkedList.toString()).toBe('1,1,2,3,3,3,4,5'); - // }); - // it('should convert to array', () => { - // const linkedList = new LinkedList(); - // linkedList.append(1); - // linkedList.append(2); - // linkedList.append(3); - // expect(linkedList.toArray().join(',')).toBe('1,2,3'); - // }); + it('should getElementAt by index linked list', () => { + const linkedList = new LinkedList(); + linkedList.push(1); + linkedList.push(2); - // it('should reverse linked list', () => { - // const linkedList = new LinkedList(); + const v = linkedList.getElementAt(1); + expect(v?.val).toBe(2); + }); - // // Add test values to linked list. - // linkedList.append(1).append(2).append(3); - // expect(linkedList.toString()).toBe('1,2,3'); - // expect(linkedList.head.value).toBe(1); - // expect(linkedList.tail.value).toBe(3); + it('should insert by index linked list', () => { + const linkedList = new LinkedList(); + linkedList.push(1); + linkedList.push(2); - // // Reverse linked list. - // linkedList.reverse(); - // expect(linkedList.toString()).toBe('3,2,1'); - // expect(linkedList.head.value).toBe(3); - // expect(linkedList.tail.value).toBe(1); + linkedList.insert(4, 1); + expect(linkedList.toString()).toBe('1,4,2'); + }); - // // Reverse linked list back to initial state. - // linkedList.reverse(); - // expect(linkedList.toString()).toBe('1,2,3'); - // expect(linkedList.head.value).toBe(1); - // expect(linkedList.tail.value).toBe(3); - // }); }); diff --git a/docs/zh/guide/book/linkedList.mdx b/docs/zh/guide/book/linkedList.mdx deleted file mode 100644 index fbbb6e4..0000000 --- a/docs/zh/guide/book/linkedList.mdx +++ /dev/null @@ -1,12 +0,0 @@ -# 第6章 链表 - -链表是一种物理存储单元上非连续、非顺序的存储结构。数据元素的逻辑顺序通过指针链接实现。链表是由一系列结点组成。 -特点是:添加和删除都比较方便。但是访问比较耗时。 - -## 种类 - -链表主要分为以下几种: - -- 单向链表 -- 双向链表 -- 循环链表 diff --git a/modern.config.ts b/modern.config.ts index cf78ebb..19cde3f 100644 --- a/modern.config.ts +++ b/modern.config.ts @@ -43,7 +43,7 @@ function getSidebarConfig(lang: 'zh' | 'en') { getLink('/guide/book/chap3'), getLink('/guide/book/chap4'), getLink('/guide/book/chap5'), - getLink('/guide/book/linkedList'), + getLink('/guide/book/chap6'), getLink('/guide/book/recursive'), getLink('/guide/book/heap'), getLink('/guide/book/chap13'),