如下代碼所有原創手寫。node
非遞歸實現:數組
class Node {
constructor(value, next) {
this.value = value;
this.next = next;
}
}
class LinkedList{
constructor() {
this.dummyHead = new Node(null, null);
this.size = 0;
}
//在指定索引處插入一個Node類型的節點
add(index, newNode) {
if(index > this.size || index < 0)
throw new Error('索引非法');
let pre = this.dummyHead;
for(let i = 0; i < index; i++) {
pre = pre.next;
}
newNode.next = pre.next;
pre.next = newNode;
this.size++;
}
//在鏈表頭增長節點
addFirst(newNode) {
this.add(0, newNode);
}
//在鏈表尾增長節點
addLast(newNode) {
this.add(size, newNode);
}
//刪除一個索引爲index的節點
remove(index) {
if(index >= this.size || index < 0)
throw new Error('索引非法');
let pre = this.dummyHead;
for (let i = 0; i < index; i++) {
pre = pre.next;
}
let delNode = pre.next;
pre.next = delNode.next;
delNode.next = null;
this.size--;
}
removeFirst() {
this.remove(0);
}
removeLast() {
this.remove(this.size - 1);
}
//刪除值爲value的節點
removeElement(value) {
let pre = this.dummyHead;
//找到待刪除節點的前一個節點
while (pre.next != null) {
if (pre.next.value == value)
break;
pre = pre.next;
}
if (pre.next != null) {
let cur = pre.next;
pre.next = cur.next;
cur.next = null;
this.size--;
return cur;
}
return null;
}
contains(value) {
let cur = this.dummyHead.next;
while(cur != null) {
if(cur.value === value) {
return true;
}
cur = cur.next;
}
return false;
}
getSize() {
return this.size;
}
isEmpty() {
return this.size == 0;
}
toString() {
let cur = this.dummyHead.next;
let str = "";
while (cur != null){
str += cur.value + "->";
cur = cur.next;
}
str += "null";
return str;
}
}
function test() {
let n1 = new Node(1, null);
let n2 = new Node(4, null);
let n3 = new Node(3, null);
let n4 = new Node(2, null);
let list = new LinkedList();
list.addFirst(n1);
list.addFirst(n2);
list.addFirst(n3);
list.addFirst(n4);
console.log("鏈表初始化:", list.toString());
list.remove(3);
console.log("刪除第3個元素後爲:", list.toString());
list.removeElement(3);
console.log("刪除值爲3的元素後爲:", list.toString());
console.log("鏈表元素個數:", list.getSize());
}
test();
複製代碼
測試結果:函數
下面是遞歸方法的實現,會有一些繞,可是並非太難理解,但願你們耐心看下來:post
class Node {
constructor(value, next) {
this.value = value;
this.next = next;
}
}
class LinkedList{
constructor() {
this.dummyHead = new Node(null, null);
this.size = 0;
}
//在指定索引處插入一個Node類型的節點,遞歸寫法
add(index, newNode) {
if(index > this.size || index < 0)
throw new Error('索引非法');
let pre = this.dummyHead;
pre.next = this._add(index, pre.next, newNode, 0);
this.size++;
}
_add(index, cur, newNode, depth) {
//遞歸深度達到索引值時,即當前的cur指向第index個元素時,咱們作一些處理
//讓函數返回插入的節點,即讓第index-1個元素的next指向了要插入的節點,如下遞歸寫法均爲同理
if (index == depth) {
newNode.next = cur;
return newNode;
}
cur.next = this._add(index, cur.next, newNode, depth + 1);
return cur;
}
//在鏈表頭增長節點
addFirst(newNode) {
this.add(0, newNode);
}
//在鏈表尾增長節點
addLast(newNode) {
this.add(size, newNode);
}
//刪除一個索引爲index的節點,遞歸寫法
remove(index) {
if(index >= this.size || index < 0)
throw new Error('索引非法');
let pre = this.dummyHead;
pre.next = this._remove(index, pre.next, 0);
this.size--;
}
_remove(index, cur, depth) {
if (index === depth) {
let nextNode = cur.next;
cur.next = null;
return nextNode;
}
cur.next = this._remove(index, cur.next, depth + 1);
return cur;
}
removeFirst() {
this.remove(0);
}
removeLast() {
this.remove(this.size - 1);
}
//刪除值爲value的節點, 遞歸寫法
removeElement(value) {
let pre = this.dummyHead;
pre.next = this._removeElement(pre.next, value);
}
_removeElement(cur, value) {
if(cur.value === value) {
let nextNode = cur.next;
cur.next = null;
this.size--;
return nextNode;
}
cur.next = this._removeElement(cur.next, value);
return cur;
}
contains(value) {
let cur = this.dummyHead.next;
while(cur != null) {
if(cur.value === value) {
return true;
}
cur = cur.next;
}
return false;
}
getSize() {
return this.size;
}
isEmpty() {
return this.size == 0;
}
toString() {
let cur = this.dummyHead.next;
let str = "";
while (cur != null){
str += cur.value + "->";
cur = cur.next;
}
str += "null";
return str;
}
}
function test() {
let n1 = new Node(1, null);
let n2 = new Node(4, null);
let n3 = new Node(3, null);
let n4 = new Node(2, null);
let list = new LinkedList();
list.addFirst(n1);
list.addFirst(n2);
list.addFirst(n3);
list.addFirst(n4);
console.log("鏈表初始化:", list.toString());
list.remove(3);
console.log("刪除第3個元素後爲:", list.toString());
list.removeElement(3);
console.log("刪除值爲3的元素後爲:", list.toString());
console.log("鏈表元素個數:", list.getSize());
}
test();
複製代碼
測試結果:測試
能夠看到,遞歸方法的結果和非遞歸是徹底同樣的,說明遞歸的實現沒有問題。ui
在二分搜索樹中,任何的節點的值大於左孩子節點,並且小於右孩子節點。this
如今來實現其中全部的方法,其中三種順序的遍歷都有遞歸和非遞歸的方式:spa
class Node{
constructor(value, left, right) {
this.value = value;
this.left = left || null;
this.right = right || null;
this.isVisited = false;
}
}
class BST{
constructor() {
this.root = null;
this.size = 0;
}
getSize() {
return this.size;
}
isEmpty() {
return this.size === 0;
}
add(value) {
this.root = this._add(this.root, value);
}
_add(node, value) {
if(node == null) {
let newNode = new Node(value);
this.size++;
return newNode;
}
if(value < node.value)
node.left = this._add(node.left, value);
if(value > node.value)
node.right = this._add(node.right, value);
//等於的狀況不作處理
return node;
}
contains(value) {
return this._contains(this.root, value);
}
_contains(node, value) {
if(node == null)
return false;
if(value < node.value)
return this._contains(node.left, value);
else if(value > node.value)
return this._contains(node.right, value);
else if(value === node.value)
return true;
}
//先序遍歷 遞歸方式
preOrder() {
this._preOrder(this.root);
}
_preOrder(node) {
if(node == null)
return;
console.log(node.value);
this._preOrder(node.left);
this._preOrder(node.right);
}
//先序遍歷 非遞歸方式
preOrderNR() {
//這裏須要用到棧,js數組的push和pop就能知足
let stack = [];
let p = this.root;
while(!stack.length || p != null) {
while(p != null) {
stack.push(p);
console.log(p.value);
p = p.left;
}
let q = stack.pop();
p = q.right;
}
}
//中序遍歷 遞歸方式
inOrder() {
this._inOrder(this.root);
}
_inOrder(node) {
if(node == null)
return;
this._inOrder(node.left);
console.log(node.value);
this._inOrder(node.right);
}
//中序遍歷 非遞歸方式
inOrderNR() {
//這裏一樣須要用到棧,js數組的push和pop就能知足
let stack = [];
let p = this.root;
while(stack.length || p != null) {
while(p != null) {
stack.push(p);
p = p.left;
}
let q = stack.pop();
console.log(q.value);
p = q.right;
}
}
//後序遍歷 遞歸方式
postOrder() {
this._postOrder(this.root);
}
_postOrder(node) {
if(node == null)
return;
this._inOrder(node.left);
this._inOrder(node.right);
console.log(node.value);
}
//後序遍歷 非遞歸方式
postOrderNR() {
//這裏一樣也須要用到棧,js數組的push和pop就能知足
let stack = [];
let p = this.root;
while(stack.length || p != null) {
while(p != null) {
stack.push(p);
p = p.left;
}
//拿到棧頂元素
let peek = stack[stack.length - 1];
if(peek.right != null && !peek.right.isVisited)
p = peek.right;
else{
let q = stack.pop();
console.log(q.value);
q.isVisited = true;
}
}
}
//層序遍歷
levelOrder() {
//須要用到隊列,用js數組的shift和push就能知足
let queue = [];
queue.push(this.root);
while(queue.length) {
let cur = queue.shift();
console.log(cur.value);
if(cur.left != null)
queue.push(cur.left);
if(cur.right != null)
queue.push(cur.right);
}
}
//找到BST節點中的最小值
minimum() {
return this._minimum(this.root).value;
}
_minimum(node) {
if(node.left == null) {
return node;
}
return this._minimum(node.left);
}
maximum() {
return this._maximum(this.root).value;
}
_maximum(node) {
if(node.right == null) {
return node;
}
return this._maximum(node.right);
}
removeMin() {
let ret = this.minimum(this.root);
this.root = this._removeMin(this.root);
return ret;
}
_removeMin(node) {
if(node.left == null) {
let right = node.right;
node.right = null;
this.size--;
return right;
}
node.left = this._removeMin(node.left);
return node;
}
removeMax() {
let ret = this.maximum(this.root);
this.root = this._removeMax(this.root);
return ret;
}
_removeMax(node) {
if(node.right == null) {
let left = node.left;
node.left = null;
this.size--;
return left;
}
node.right = this._removeMax(node.right);
return node;
}
remove(value) {
this.root = this._remove(this.root, value);
return value;
}
_remove(node, value) {
if(value <node.value) {
node.left = this._remove(node.left);
return node;
} else if(value > node.value){
node.right = this._remove(node.right);
return node;
} else {
//要開始刪除了
if(node.left == null) {
let right = node.right;
node.right = null;
this.size--;
return right;
}
if(node.right == null) {
let left = node.left;
node.left = null;
this.size--;
return left;
}
//最小的後繼節點
let successor = this._minimum(node.right);
successor.right = this._removeMin(node.right);
successor.left = node.left;
node.left = node.right = null;
this.size--;
return successor;
}
}
toString() {
this._generateBST(this.root, 0);
}
//先序遍歷打印樹的結構
_generateBST(node, depth){
if(node == null){
console.log(this._generateDepthString(depth), "null");
return;
}
console.log(this._generateDepthString(depth), node.value);
this._generateBST(node.left, depth+1);
this._generateBST(node.right, depth+1);
}
_generateDepthString(depth) {
let str = "";
for(let i = 0; i < depth; i++) {
str += "--"
}
return str;
}
}
function test() {
let bst = new BST();
bst.add(2);
bst.add(6);
bst.add(5);
bst.add(3);
bst.add(7);
// console.log("先序遍歷");
// bst.preOrder();
// bst.preOrderNR();
// console.log("中序遍歷");
// bst.inOrder();
// bst.inOrderNR();
// console.log("後序遍歷");
// bst.postOrder();
// bst.postOrderNR();
// console.log("層序遍歷");
// bst.levelOrder();
// console.log("最大值", bst.maximum());
// console.log("最小值", bst.minimum());
// console.log(bst.contains(2));//true
// console.log(bst.removeMin());
// console.log(bst.removeMax());
console.log(bst.remove(6));
bst.toString();
}
test();
複製代碼
堆的結構實現以下:debug
class MaxHeap{
constructor(arr = [], compare = null) {
this.data = arr;
this.size = arr.length;
this.compare = compare || function(a, b){return a - b > 0};
}
getSize() {
return this.size;
}
isEmpty() {
return this.size === 0;
}
_swap(i, j) {
[this.data[i], this.data[j]] = [this.data[j], this.data[i]];
}
_parent(index) {
return Math.floor((index - 1) / 2);
}
_leftChild(index) {
return 2 * index + 1;
}
_rightChild(index) {
return 2 * index + 2;
}
_siftUp(k) {
while(k > 0 && this.data[k] > this.data[this._parent(k)]){
this._swap(k, this._parent(k));
k = this._parent(k);
}
}
_siftDown(k) {
while(this._leftChild(k) < this.size) {
let j = this._leftChild(k);
debugger;
if(this._rightChild(k) < this.size &&
this.compare(this.data[this._rightChild(k)], this.data[j])){
j++;
}
if(this.data[k] >= this.data[j])
return;
this._swap(k, j);
k = j;
}
}
//增長元素
add(value) {
this.data.push(value);
this.size++;
this._siftUp(this.getSize() - 1);
}
findMax() {
if(this.getSize() === 0)
return;
return this.data[0];
}
extractMax() {
let ret = this.findMax();
this._swap(0, this.getSize() - 1);
this.data.pop();
this.size--;
this._siftDown(0);
return ret;
}
toString() {
console.log(this.data);
}
}
module.exports = MaxHeap;
複製代碼
所謂優先隊列,就是每次出隊的時候,老是出隊列中權值最高的元素。code
如今能夠用堆來輕易地實現:
const MaxHeap = require('./maxHeap');
class PriorityQueue {
constructor() {
this.maxHeap = new MaxHeap();
}
getSize() {
return this.maxHeap.getSize();
}
isEmpty() {
return this.maxHeap.isEmpty();
}
getFront() {
return this.maxHeap.findMax();
}
enqueue(e) {
return this.maxHeap.add(e);
}
dequeue() {
return this.maxHeap.extractMax();
}
}
let pq = new PriorityQueue();
pq.enqueue(1);
pq.enqueue(3);
pq.enqueue(6);
pq.enqueue(2);
pq.enqueue(62);
console.log(pq.dequeue());
複製代碼