ES6的JavaScript数据结构实现之链表
目的:ES6标准下的JS数据结构的一些实现代码。(作为记录和启发)
内容:链表和双向链表,循环链表,有序链表。(未完成,待继续)
所有源码在我的Github上(如果觉得不错记得给星鼓励我哦):ES6的JavaScript数据结构实现之链表
一、基础数据结构
1、链表
1 class Node { 2 constructor(element, next) { 3 this.element = element; 4 this.next = next; 5 } 6 } 7 8 function defaultEquals(a, b) { 9 return a === b; 10 } 11 12 class LinkedList { 13 constructor(equalsFn = defaultEquals) { 14 this.equalsFn = equalsFn; 15 this.count = 0; 16 this.head = undefined; 17 } 18 19 push(element){ 20 const node = new Node(element); 21 let current; 22 if (this.head == null){ 23 this.head = node; 24 } else { 25 current = this.head; 26 while (current.next != null) { 27 current = current.next; 28 } 29 current.next = node; 30 } 31 this.count++; 32 } 33 34 getElementAt(index) { 35 if (index >= 0 && index <= this.count) { 36 let node = this.head; 37 for (let i = 0; i < index && node != null; i++) { 38 node = node.next; 39 } 40 return node; 41 } 42 return undefined; 43 } 44 45 insert(element, index) { 46 if (index >= 0 && index <= this.count) { 47 const node = new Node(element); 48 if (index ==0 ) { 49 const current = this.head; 50 node.next = current; 51 this.head = node; 52 } else { 53 const previous = this.getElementAt(index - 1); 54 node.next = previous.next; 55 previous.next = node; 56 } 57 this.count++; 58 return true; 59 } 60 return false; 61 } 62 63 removeAt(index) { 64 if (index >= 0 && index < this.count) { 65 let current = this.head; 66 if (index == 0) { 67 this.head = current.next; 68 }else { 69 const previous = this.getElementAt(index - 1); 70 current = previous.next; 71 previous.next = current; 72 73 } 74 this.count--; 75 return current.element; 76 } 77 return undefined; 78 } 79 80 remove(element) { 81 const index = this.indexOf(element); 82 return this.removeAt(index); 83 } 84 85 indexOf(element) { 86 let current = this.head; 87 for (let i = 0; i < this.count && current != null; i++) { 88 if (this.equalsFn(element, current.element)) { 89 return i; 90 } 91 current = current.next; 92 } 93 return -1; 94 } 95 96 isEmpty() { 97 return this.size() === 0; 98 } 99 100 size() { 101 return this.count; 102 } 103 104 getHead() { 105 return this.head; 106 } 107 108 clear() { 109 this.head = undefined; 110 this.count = 0; 111 } 112 113 toString() { 114 if (this.head == null) { 115 return ''; 116 } 117 let objString = `${this.head.element}`; 118 let current = this.head.next; 119 for (let i = 1; i < this.size() && current != null; i++) { 120 objString = `${objString},${current.element}`; 121 current = current.next; 122 } 123 return objString; 124 } 125 } 126 127 128 const list = new LinkedList(); 129 130 console.log(list); 131 list.push(15); 132 console.log(list); 133 list.push(10); 134 list.push(5); 135 console.log(list); 136 list.removeAt(1); 137 console.log(list); 138 list.insert(4,1); 139 console.log(list); 140 console.log(list.indexOf(15)); 141 console.log(list.indexOf(1)); 142 list.remove(15); 143 console.log(list); 144 145 LinkedList
2、双向链表
1 class DoublyNode extends Node { 2 constructor(element, next, prev) { 3 super(element, next); 4 this.prev = prev 5 } 6 } 7 8 class DoublyLinkedList extends LinkedList { 9 constructor(equalsFn = defaultEquals) { 10 super (equalsFn); 11 this.tail = undefined; 12 } 13 push(element) { 14 const node = new DoublyNode(element); 15 if (this.head == null) { 16 this.head = node; 17 this.tail = node; // NEW 18 } else { 19 // attach to the tail node // NEW 20 this.tail.next = node; 21 node.prev = this.tail; 22 this.tail = node; 23 } 24 this.count++; 25 } 26 insert(element, index) { 27 if (index >= 0 && index <= this.count) { 28 const node = new DoublyNode(element); 29 let current = this.head; 30 if (index == 0 ) { 31 if(this.head == null) { 32 this.head = node; 33 this.tail = node; 34 } else { 35 node.next = this.head; 36 this.head.prev = node; 37 this.head = node; 38 } 39 } else if (index === this.count) { 40 current = this.tail; 41 current.next = node; 42 node.prev = current; 43 this.tail = node; 44 } else { 45 const previous = this.getElementAt(index - 1); 46 current = previous.next; 47 node.next = current; 48 previous.next = node; 49 current.prev = node; 50 node.prev = previous; 51 } 52 this.count++; 53 return true; 54 } 55 return false; 56 } 57 removeAt(index) { 58 if (index >= 0 && index < this.count) { 59 let current = this.head; 60 if (index === 0) { 61 this.head = this.head.next; 62 if (this.count === 1) { 63 this.tail = undefined; 64 } else { 65 this.head.prev = undefined; 66 } 67 } else if (index === this.count - 1) { 68 current = this.tail; 69 this.tail = current.prev; 70 this.tail.next = undefined; 71 } else { 72 current = this.getElementAt(index); 73 const previous = current.prev; 74 previous.next = current.next; 75 current.next.prev = previous; 76 } 77 this.count--; 78 return current.element; 79 } 80 return undefined; 81 } 82 indexOf(element) { 83 let current = this.head; 84 let index = 0; 85 while (current != null) { 86 if (this.equalsFn(element, current.element)) { 87 return index; 88 } 89 index++; 90 current = current.next; 91 } 92 return -1; 93 } 94 getHead() { 95 return this.head; 96 } 97 getTail() { 98 return this.tail; 99 } 100 clear() { 101 super.clear(); 102 this.tail = undefined; 103 } 104 toString() { 105 if (this.head == null) { 106 return ''; 107 } 108 let objString = `${this.head.element}`; 109 let current = this.head.next; 110 while (current != null) { 111 objString = `${objString},${current.element}`; 112 current = current.next; 113 } 114 return objString; 115 } 116 inverseToString() { 117 // if (this.tail == null) { 118 // return ''; 119 // } 120 let objString = `${this.tail.element}`; 121 let previous = this.tail.prev; 122 while (previous != null) { 123 objString = `${objString},${previous.element}`; 124 previous = previous.prev; 125 } 126 return objString; 127 } 128 } 129 130 131 const list = new DoublyLinkedList(); 132 list.push(20); 133 console.log(list); 134 list.push(19); 135 list.push(18); 136 console.log(list); 137 list.insert(15, 1); 138 console.log(list); 139 list.removeAt(1); 140 console.log(list); 141 console.log(list.toString()); 142 console.log(list.inverseToString());
3、循环链表(以扩展上述普通链表Linkedlist为例)
1 class CircularLinkedList extends LinkedList { 2 constructor(equalsFn = defaultEquals) { 3 super(equalsFn); 4 } 5 push(element) { 6 const node = new Node(element); 7 let current; 8 if (this.head == null) { 9 this.head = node; 10 } else { 11 current = this.getElementAt(this.size() - 1); 12 current.next = node; 13 } 14 // set node.next to head - to have circular list 15 node.next = this.head; 16 this.count++; 17 } 18 insert(element, index) { 19 if (index >= 0 && index <= this.count) { 20 const node = new Node(element); 21 let current = this.head; 22 if (index === 0) { 23 if (this.head == null) { 24 // if no node in list 25 this.head = node; 26 node.next = this.head; 27 } else { 28 node.next = this.head; 29 current = this.getElementAt(this.size()); 30 // update last element 31 this.head = node; 32 current.next = this.head; 33 } 34 } else { 35 const previous = this.getElementAt(index - 1); 36 node.next = previous.next; 37 previous.next = node; 38 } 39 this.count++; 40 return true; 41 } 42 return false; 43 } 44 removeAt(index) { 45 if (index >= 0 && index < this.count) { 46 let current = this.head; 47 if (index === 0) { 48 if (this.size() === 1) { 49 this.head = undefined; 50 } else { 51 const removed = this.head; 52 current = this.getElementAt(this.size() - 1); 53 this.head = this.head.next; 54 current.next = this.head; 55 current = removed; 56 } 57 } else { 58 // no need to update last element for circular list 59 const previous = this.getElementAt(index - 1); 60 current = previous.next; 61 previous.next = current.next; 62 } 63 this.count--; 64 return current.element; 65 } 66 return undefined; 67 } 68 } 69 70 71 const list = new CircularLinkedList(); 72 73 list.push(20); 74 console.log(list); 75 list.push(19); 76 list.push(18); 77 console.log(list); 78 list.insert(15, 0); 79 console.log(list); 80 list.removeAt(0); 81 console.log(list);
4、有序链表
1 class Node { 2 constructor(element, next) { 3 this.element = element; 4 this.next = next; 5 } 6 } 7 8 function defaultEquals(a, b) { 9 return a === b; 10 } 11 12 const Compare = { 13 LESS_THAN: -1, 14 BIGGER_THAN: 1, 15 EQUALS: 0 16 }; 17 18 function defaultCompare(a, b) { 19 if (a === b) { 20 return Compare.EQUALS; 21 } 22 return a < b ? Compare.LESS_THAN : Compare.BIGGER_THAN; 23 } 24 class SortedLinkedList extends LinkedList { 25 constructor(equalsFn = defaultEquals, compareFn = defaultCompare) { 26 super(equalsFn); 27 this.equalsFn = equalsFn; 28 this.compareFn = compareFn; 29 } 30 push(element) { 31 if (this.isEmpty()) { 32 super.push(element); 33 } else { 34 const index = this.getIndexNextSortedElement(element); 35 super.insert(element, index); 36 } 37 } 38 insert(element, index = 0) { 39 if (this.isEmpty()) { 40 return super.insert(element, index === 0 ? index : 0); 41 } 42 const pos = this.getIndexNextSortedElement(element); 43 return super.insert(element, pos); 44 } 45 getIndexNextSortedElement(element) { 46 let current = this.head; 47 let i = 0; 48 for (; i < this.size() && current; i++) { 49 const comp = this.compareFn(element, current.element); 50 if (comp === Compare.LESS_THAN) { 51 return i; 52 } 53 current = current.next; 54 } 55 return i; 56 } 57 } 58 59 const list = new SortedLinkedList(); 60 for (let i = 5; i > 0; i--) { 61 list.push(i); 62 } 63 console.log(list); 64 list.insert(1); 65 console.log(list);
Talk is cheap, code the code.