近期在学习数据结构的东西,基于ES6标准,写了一些自定义结构类javascript
数据结构:Typescript版本前端
class Stack { constructor() { this.count = 0; this.items = {}; } push(element) { this.items[this.count] = element; this.count++; } pop() { if (this.isEmpty()) { return undefined; } this.count--; const result = this.items[this.count]; delete this.items[this.count]; return result; } peek() { if (this.isEmpty()) { return undefined; } return this.items[this.count - 1]; } isEmpty() { return this.count === 0; } size() { return this.count; } clear() { /* while (!this.isEmpty()) { this.pop(); } */ this.items = {}; this.count = 0; } toString() { if (this.isEmpty()) { return ''; } let objString = `${this.items[0]}`; for (let i = 1; i < this.count; i++) { objString = `${objString},${this.items[i]}`; } return objString; } }
push(el or els): 添加元素,只添加到栈顶(能够是一个或多个) pop: 移除元素,遵循栈原则,移除最后添加的元素,并返回溢出的元素 peek: 返回栈顶的元素 isEmpty: 栈是否为空 clear: 清空栈 size: 栈的元素个数 toString: 转换栈内容为字符串
栈实现:字符串括号匹配java
场景:电脑打印文件,添加进入队列的文件按前后顺序打印node
class Queue { constructor() { this.count = 0; this.lowestCount = 0; this.items = {}; } enqueue(element) { this.items[this.count] = element; this.count++; } dequeue() { if (this.isEmpty()) { return undefined; } const result = this.items[this.lowestCount]; delete this.items[this.lowestCount]; this.lowestCount++; return result; } peek() { if (this.isEmpty()) { return undefined; } return this.items[this.lowestCount]; } isEmpty() { return this.size() === 0; } clear() { this.items = {}; this.count = 0; this.lowestCount = 0; } size() { return this.count - this.lowestCount; } toString() { if (this.isEmpty()) { return ''; } let objString = `${this.items[this.lowestCount]}`; for (let i = this.lowestCount + 1; i < this.count; i++) { objString = `${objString},${this.items[i]}`; } return objString; } }
enqueue(el or els): 添加元素到队列,只能向队列尾部添加(能够是一个或多个) dequeue: 移除队列第一项,队列最早放入的数据,返回被移除的元素 peek: 返回第一个添加的元素 isEmpty: 队列是否为空 clear: 清空队列 size: 队列的元素个数 toString: 输出队列元素转换的字符串
场景:电影院排队,一我的刚买了票,须要再询问一些简单信息,能够直接回到队伍头部;在队伍末尾的人若是不想看电影,能够直接离开队伍数据库
class Deque { constructor() { this.count = 0; this.lowestCount = 0; this.items = {}; } addFront(element) { if (this.isEmpty()) { this.addBack(element); } else if (this.lowestCount > 0) { this.lowestCount--; this.items[this.lowestCount] = element; } else { for (let i = this.count; i > 0; i--) { this.items[i] = this.items[i - 1]; } this.count++; this.items[0] = element; } } addBack(element) { this.items[this.count] = element; this.count++; } removeFront() { if (this.isEmpty()) { return undefined; } const result = this.items[this.lowestCount]; delete this.items[this.lowestCount]; this.lowestCount++; return result; } removeBack() { if (this.isEmpty()) { return undefined; } this.count--; const result = this.items[this.count]; delete this.items[this.count]; return result; } peekFront() { if (this.isEmpty()) { return undefined; } return this.items[this.lowestCount]; } peekBack() { if (this.isEmpty()) { return undefined; } return this.items[this.count - 1]; } isEmpty() { return this.size() === 0; } clear() { this.items = {}; this.count = 0; this.lowestCount = 0; } size() { return this.count - this.lowestCount; } toString() { if (this.isEmpty()) { return ''; } let objString = `${this.items[this.lowestCount]}`; for (let i = this.lowestCount + 1; i < this.count; i++) { objString = `${objString},${this.items[i]}`; } return objString; } }
addFront(el): 在双端队列前端添加新元素 addBack(el): 在双端队列后端添加新元素 removeFront: 从双端队列前端移除第一个元素 removeBack: 从双端队列后端移除第一个元素 peekFront: 返回双端队列的前端第一个元素 peekBack: 返回双端队列的后端第一个元素 isEmpty: 双端队列是否为空 clear: 清空双端队列 size: 双端队列元素个数 toString: 转换为字符串输出
循环队列:击鼓传花;双端队列:回文检查segmentfault
场景:火车,每节车都是链表元素,车间的连接就是指针数组
// 链表元素节点 Node { constructor(element, next) { this.element = element; this.next = next; } } function defaultEquals(a, b) { return a === b; }
LinkedList { constructor(equalsFn = defaultEquals) { this.equalsFn = equalsFn; this.count = 0; this.head = undefined; } push(element) { const node = new Node(element); let current; if (this.head == null) { // catches null && undefined this.head = node; } else { current = this.head; while (current.next != null) { current = current.next; } current.next = node; } this.count++; } getElementAt(index) { if (index >= 0 && index <= this.count) { let node = this.head; for (let i = 0; i < index && node != null; i++) { node = node.next; } return node; } return undefined; } insert(element, index) { if (index >= 0 && index <= this.count) { const node = new Node(element); if (index === 0) { const current = this.head; node.next = current; this.head = node; } else { const previous = this.getElementAt(index - 1); node.next = previous.next; previous.next = node; } this.count++; return true; } return false; } removeAt(index) { if (index >= 0 && index < this.count) { let current = this.head; if (index === 0) { this.head = current.next; } else { const previous = this.getElementAt(index - 1); current = previous.next; previous.next = current.next; } this.count--; return current.element; } return undefined; } remove(element) { const index = this.indexOf(element); return this.removeAt(index); } indexOf(element) { let current = this.head; for (let i = 0; i < this.size() && current != null; i++) { if (this.equalsFn(element, current.element)) { return i; } current = current.next; } return -1; } isEmpty() { return this.size() === 0; } size() { return this.count; } getHead() { return this.head; } clear() { this.head = undefined; this.count = 0; } toString() { if (this.head == null) { return ''; } let objString = `${this.head.element}`; let current = this.head.next; for (let i = 1; i < this.size() && current != null; i++) { objString = `${objString},${current.element}`; current = current.next; } return objString; } }
push(el): 向链表尾部添加元素 insert(el, position): 向链表特定位置添加元素 getElementAt(index): 返回链表特定位置元素,若是不存在,返回undefined remove: 返回链表移除一个元素 indexOf: 返回元素在链表索引,不存在元素返回-1 removeAt(position): 从链表特定位置删除元素 isEmpty: 链表是否为空 size: 链表的元素个数 toString: 转换输出字符串
DoublyNode extends Node { constructor(element, next, prev) { super(element, next); this.prev = prev; } }
DoublyLinkedList extends LinkedList { constructor(equalsFn = defaultEquals) { super(equalsFn); this.tail = undefined; } push(element) { const node = new DoublyNode(element); if (this.head == null) { this.head = node; this.tail = node; // NEW } else { // attach to the tail node // NEW this.tail.next = node; node.prev = this.tail; this.tail = node; } this.count++; } insert(element, index) { if (index >= 0 && index <= this.count) { const node = new DoublyNode(element); let current = this.head; if (index === 0) { if (this.head == null) { // NEW this.head = node; this.tail = node; // NEW } else { node.next = this.head; this.head.prev = node; // NEW this.head = node; } } else if (index === this.count) { // last item NEW current = this.tail; current.next = node; node.prev = current; this.tail = node; } else { const previous = this.getElementAt(index - 1); current = previous.next; node.next = current; previous.next = node; current.prev = node; // NEW node.prev = previous; // NEW } this.count++; return true; } return false; } removeAt(index) { if (index >= 0 && index < this.count) { let current = this.head; if (index === 0) { this.head = this.head.next; // if there is only one item, then we update tail as well //NEW if (this.count === 1) { // {2} this.tail = undefined; } else { this.head.prev = undefined; } } else if (index === this.count - 1) { // last item //NEW current = this.tail; this.tail = current.prev; this.tail.next = undefined; } else { current = this.getElementAt(index); const previous = current.prev; // link previous with current's next - skip it to remove previous.next = current.next; current.next.prev = previous; // NEW } this.count--; return current.element; } return undefined; } indexOf(element) { let current = this.head; let index = 0; while (current != null) { if (this.equalsFn(element, current.element)) { return index; } index++; current = current.next; } return -1; } getHead() { return this.head; } getTail() { return this.tail; } clear() { super.clear(); this.tail = undefined; } toString() { if (this.head == null) { return ''; } let objString = `${this.head.element}`; let current = this.head.next; while (current != null) { objString = `${objString},${current.element}`; current = current.next; } return objString; } inverseToString() { if (this.tail == null) { return ''; } let objString = `${this.tail.element}`; let previous = this.tail.prev; while (previous != null) { objString = `${objString},${previous.element}`; previous = previous.prev; } return objString; } }
push(el): 向链表尾部添加元素 insert(el, position): 向链表特定位置添加元素 getElementAt(index): 返回链表特定位置元素,若是不存在,返回undefined remove: 返回链表移除一个元素 indexOf: 返回元素在链表索引,不存在元素返回-1 removeAt(position): 从链表特定位置删除元素 isEmpty: 链表是否为空 size: 链表的元素个数 toString: 转换输出字符串 新增方法: getHead: 返回双链表第一个元素节点 getTail: 返回双链表最后一个元素节点 inverseToString: 返回双链表倒叙字符串
CircularLinkedList extends LinkedList { constructor(equalsFn = defaultEquals) { super(equalsFn); } push(element) { const node = new Node(element); let current; if (this.head == null) { this.head = node; } else { current = this.getElementAt(this.size() - 1); current.next = node; } // set node.next to head - to have circular list node.next = this.head; this.count++; } insert(element, index) { if (index >= 0 && index <= this.count) { const node = new Node(element); let current = this.head; if (index === 0) { if (this.head == null) { // if no node in list this.head = node; node.next = this.head; } else { node.next = current; current = this.getElementAt(this.size()); // update last element this.head = node; current.next = this.head; } } else { const previous = this.getElementAt(index - 1); node.next = previous.next; previous.next = node; } this.count++; return true; } return false; } removeAt(index) { if (index >= 0 && index < this.count) { let current = this.head; if (index === 0) { if (this.size() === 1) { this.head = undefined; } else { const removed = this.head; current = this.getElementAt(this.size() - 1); this.head = this.head.next; current.next = this.head; current = removed; } } else { // no need to update last element for circular list const previous = this.getElementAt(index - 1); current = previous.next; previous.next = current.next; } this.count--; return current.element; } return undefined; } }
push(el): 向链表尾部添加元素 insert(el, position): 向链表特定位置添加元素 removeAt(position): 从链表特定位置删除元素
const Compare = { LESS_THAN: -1, BIGGER_THAN: 1, EQUALS: 0 }; function defaultCompare(a, b) { if (a === b) { return Compare.EQUALS; } return a < b ? Compare.LESS_THAN : Compare.BIGGER_THAN; }
SortedLinkedList extends LinkedList { constructor(equalsFn = defaultEquals, compareFn = defaultCompare) { super(equalsFn); this.equalsFn = equalsFn; this.compareFn = compareFn; } push(element) { if (this.isEmpty()) { super.push(element); } else { const index = this.getIndexNextSortedElement(element); super.insert(element, index); } } insert(element, index = 0) { if (this.isEmpty()) { return super.insert(element, index === 0 ? index : 0); } const pos = this.getIndexNextSortedElement(element); return super.insert(element, pos); } getIndexNextSortedElement(element) { let current = this.head; let i = 0; for (; i < this.size() && current; i++) { const comp = this.compareFn(element, current.element); if (comp === Compare.LESS_THAN) { return i; } current = current.next; } return i; } }
push(el): 向链表尾部添加元素 insert(el, position): 向链表特定位置添加元素 getIndexNextSortedElement(el): 返回元素在有序链表的位置,实际位置index+1;若是不存在,返回最后一个元素位置
场景:无序惟一数据结构
class Set { constructor() { this.items = {}; } add(element) { if (!this.has(element)) { this.items[element] = element; return true; } return false; } delete(element) { if (this.has(element)) { delete this.items[element]; return true; } return false; } has(element) { return Object.prototype.hasOwnProperty.call(this.items, element); } values() { return Object.values(this.items); } union(otherSet) { const unionSet = new Set(); this.values().forEach(value => unionSet.add(value)); otherSet.values().forEach(value => unionSet.add(value)); return unionSet; } intersection(otherSet) { const intersectionSet = new Set(); const values = this.values(); const otherValues = otherSet.values(); let biggerSet = values; let smallerSet = otherValues; if (otherValues.length - values.length > 0) { biggerSet = otherValues; smallerSet = values; } smallerSet.forEach(value => { if (biggerSet.includes(value)) { intersectionSet.add(value); } }); return intersectionSet; } difference(otherSet) { const differenceSet = new Set(); this.values().forEach(value => { if (!otherSet.has(value)) { differenceSet.add(value); } }); return differenceSet; } isSubsetOf(otherSet) { if (this.size() > otherSet.size()) { return false; } let isSubset = true; this.values().every(value => { if (!otherSet.has(value)) { isSubset = false; return false; } return true; }); return isSubset; } isEmpty() { return this.size() === 0; } size() { return Object.keys(this.items).length; } clear() { this.items = {}; } toString() { if (this.isEmpty()) { return ''; } const values = this.values(); let objString = `${values[0]}`; for (let i = 1; i < values.length; i++) { objString = `${objString},${values[i].toString()}`; } return objString; } }
add(el): 向集合添加一个新元素 delete(el): 从集合移除一个元素 has(el): 集合是否包含元素 clear: 清空集合 size: 集合元素个数 values: 返回包含集合全部值的数组 isEmpty: 集合是否为空 toString: 转换集合值为字符串 union(set): 并集 intersection(set): 交集 difference(set): 差集 isSubsetOf(set): 子集
并集:new Set([...setA, ...setB])
交集:new Set([...setA].filter(x => setB.has(x)))
补集:new Set([...setA].filter(x => !setBhas(x)))
ide
class ValuePair { constructor(key, value) { this.key = key; this.value = value; } toString() { return `[#${this.key}: ${this.value}]`; } } function defaultToString(item) { if (item === null) { return 'NULL'; } else if (item === undefined) { return 'UNDEFINED'; } else if (typeof item === 'string' || item instanceof String) { return `${item}`; } return item.toString(); }
class Dictionary { constructor(toStrFn = defaultToString) { this.toStrFn = toStrFn; this.table = {}; } set(key, value) { if (key != null && value != null) { const tableKey = this.toStrFn(key); this.table[tableKey] = new ValuePair(key, value); return true; } return false; } get(key) { const valuePair = this.table[this.toStrFn(key)]; return valuePair == null ? undefined : valuePair.value; } hasKey(key) { return this.table[this.toStrFn(key)] != null; } remove(key) { if (this.hasKey(key)) { delete this.table[this.toStrFn(key)]; return true; } return false; } values() { return this.keyValues().map(valuePair => valuePair.value); } keys() { return this.keyValues().map(valuePair => valuePair.key); } keyValues() { return Object.values(this.table); } forEach(callbackFn) { const valuePairs = this.keyValues(); for (let i = 0; i < valuePairs.length; i++) { const result = callbackFn(valuePairs[i].key, valuePairs[i].value); if (result === false) { break; } } } isEmpty() { return this.size() === 0; } size() { return Object.keys(this.table).length; } clear() { this.table = {}; } toString() { if (this.isEmpty()) { return ''; } const valuePairs = this.keyValues(); let objString = `${valuePairs[0].toString()}`; for (let i = 1; i < valuePairs.length; i++) { objString = `${objString},${valuePairs[i].toString()}`; } return objString; } }
set(key, value): 向字典添加新元素,若是key存在,value会覆盖当前已经存在的值 get(key): 获取当前key的value remove(key): 使用key来删除对应字典内的键值对 hasKey(key): 是否在字典中存在当前key对应的键值对 clear: 清空字典 size: 返回字典的元素个数 isEmpty: 字典是否为空 toString: 转换字典键值对为字符串 keys: 字典全部键名,输出为数组 values: 字典全部键值对的值,输出为数组 keyValues: 字典全部的[键, 值]对 forEach(cb): 迭代字典全部元素,cb是回调函数,有两个参数:key和value。在回调函数返回false停止循环
场景:数据库建索引;javascript内部使用散列表来表示每一个对象
class ValuePair { constructor(key, value) { this.key = key; this.value = value; } toString() { return `[#${this.key}: ${this.value}]`; } } function defaultToString(item) { if (item === null) { return 'NULL'; } else if (item === undefined) { return 'UNDEFINED'; } else if (typeof item === 'string' || item instanceof String) { return `${item}`; } return item.toString(); }
class HashTable { constructor(toStrFn = defaultToString) { this.toStrFn = toStrFn; this.table = {}; } // 建立散列表值 djb2HashCode(key) { const tableKey = this.toStrFn(key); let hash = 5381; for (let i = 0; i < tableKey.length; i++) { hash = (hash * 33) + tableKey.charCodeAt(i); } return hash % 1013; } hashCode(key) { return this.djb2HashCode(key); } put(key, value) { if (key != null && value != null) { const position = this.hashCode(key); this.table[position] = new ValuePair(key, value); return true; } return false; } get(key) { const valuePair = this.table[this.hashCode(key)]; return valuePair == null ? undefined : valuePair.value; } remove(key) { const hash = this.hashCode(key); const valuePair = this.table[hash]; if (valuePair != null) { delete this.table[hash]; return true; } return false; } getTable() { return this.table; } isEmpty() { return this.size() === 0; } size() { return Object.keys(this.table).length; } clear() { this.table = {}; } toString() { if (this.isEmpty()) { return ''; } const keys = Object.keys(this.table); let objString = `{${keys[0]} => ${this.table[keys[0]].toString()}}`; for (let i = 1; i < keys.length; i++) { objString = `${objString},{${keys[i]} => ${this.table[keys[i]].toString()}}`; } return objString; } }
put(key, value): 向散列表增长元素 remove(key): 键值在散列表中移除值 get(key): 键值检索特定的值 loseloseHashCode(key): 散列函数 hashCode(key): 返回键名对应的键值对数据 getTable: 返回散列表 isEmpty: 散列表是否为空 size: 散列表元素个数 clear: 清空散列表 toString: 转换键值对为字符串
通常散列表对于重复的生成散列值会覆盖数据,也就是返回的是相同散列值最后添加那个元素。分离连接在每一个散列值位置建立一个链表来储存元素,不会覆盖
class ValuePair { constructor(key, value) { this.key = key; this.value = value; } toString() { return `[#${this.key}: ${this.value}]`; } } function defaultToString(item) { if (item === null) { return 'NULL'; } else if (item === undefined) { return 'UNDEFINED'; } else if (typeof item === 'string' || item instanceof String) { return `${item}`; } return item.toString(); }
class HashTableSeparateChaining { constructor(toStrFn = defaultToString) { this.toStrFn = toStrFn; this.table = {}; } // 建立散列表值 djb2HashCode(key) { const tableKey = this.toStrFn(key); let hash = 5381; for (let i = 0; i < tableKey.length; i++) { hash = (hash * 33) + tableKey.charCodeAt(i); } return hash % 1013; } hashCode(key) { return this.djb2HashCode(key); } put(key, value) { if (key != null && value != null) { const position = this.hashCode(key); if (this.table[position] == null) { // 单向链表 this.table[position] = new LinkedList(); } this.table[position].push(new ValuePair(key, value)); return true; } return false; } get(key) { const position = this.hashCode(key); const linkedList = this.table[position]; if (linkedList != null && !linkedList.isEmpty()) { let current = linkedList.getHead(); while (current != null) { if (current.element.key === key) { return current.element.value; } current = current.next; } } return undefined; } remove(key) { const position = this.hashCode(key); const linkedList = this.table[position]; if (linkedList != null && !linkedList.isEmpty()) { let current = linkedList.getHead(); while (current != null) { if (current.element.key === key) { linkedList.remove(current.element); if (linkedList.isEmpty()) { delete this.table[position]; } return true; } current = current.next; } } return false; } isEmpty() { return this.size() === 0; } size() { let count = 0; Object.values(this.table).forEach(linkedList => { count += linkedList.size(); }); return count; } clear() { this.table = {}; } getTable() { return this.table; } toString() { if (this.isEmpty()) { return ''; } const keys = Object.keys(this.table); let objString = `{${keys[0]} => ${this.table[keys[0]].toString()}}`; for (let i = 1; i < keys.length; i++) { objString = `${objString},{${keys[i]} => ${this.table[ keys[i] ].toString()}}`; } return objString; } }
方法使用同通常散列表方法,重写了put、get、remove方法
也是为了处理通常散列表覆盖值的问题,线性是由于不建立额外的数据结构,直接储存在表中
class HashTableLinearProbing { constructor(toStrFn = defaultToString) { this.toStrFn = toStrFn; this.table = {}; } // 建立散列表值 djb2HashCode(key) { const tableKey = this.toStrFn(key); let hash = 5381; for (let i = 0; i < tableKey.length; i++) { hash = (hash * 33) + tableKey.charCodeAt(i); } return hash % 1013; } hashCode(key) { return this.djb2HashCode(key); } put(key, value) { if (key != null && value != null) { const position = this.hashCode(key); if (this.table[position] == null) { this.table[position] = new ValuePair(key, value); } else { let index = position + 1; while (this.table[index] != null) { index++; } this.table[index] = new ValuePair(key, value); } return true; } return false; } get(key) { const position = this.hashCode(key); if (this.table[position] != null) { if (this.table[position].key === key) { return this.table[position].value; } let index = position + 1; while (this.table[index] != null && this.table[index].key !== key) { index++; } if (this.table[index] != null && this.table[index].key === key) { return this.table[position].value; } } return undefined; } remove(key) { const position = this.hashCode(key); if (this.table[position] != null) { if (this.table[position].key === key) { delete this.table[position]; this.verifyRemoveSideEffect(key, position); return true; } let index = position + 1; while (this.table[index] != null && this.table[index].key !== key) { index++; } if (this.table[index] != null && this.table[index].key === key) { delete this.table[index]; this.verifyRemoveSideEffect(key, index); return true; } } return false; } verifyRemoveSideEffect(key, removedPosition) { const hash = this.hashCode(key); let index = removedPosition + 1; while (this.table[index] != null) { const posHash = this.hashCode(this.table[index].key); if (posHash <= hash || posHash <= removedPosition) { this.table[removedPosition] = this.table[index]; delete this.table[index]; removedPosition = index; } index++; } } isEmpty() { return this.size() === 0; } size() { return Object.keys(this.table).length; } clear() { this.table = {}; } getTable() { return this.table; } toString() { if (this.isEmpty()) { return ''; } const keys = Object.keys(this.table); let objString = `{${keys[0]} => ${this.table[keys[0]].toString()}}`; for (let i = 1; i < keys.length; i++) { objString = `${objString},{${keys[i]} => ${this.table[ keys[i] ].toString()}}`; } return objString; } }
使用方法同通常散列表方法
原生Map使用方式:
const map = new Map(); map.set('whh', 'whh@163.com'); map.set('lsd', 'lsd@163.com'); map.set('lbb', 'lbb@163.com'); console.log(map.has('whh')); // true console.log(map.size); // 3 console.log(map.keys()); // {"whh", "lsd", "lbb"} console.log(map.values()); // {"whh@163.com", "lsd@163.com", "lbb@163.com"} console.log(map.get('lsd')); // "lsd@163.com"
Map类的values和keys方法返回的是Iterator,不是键值对构成的数组。size是属性,不是方法,删除元素用delete(key)
这两个类是Map和Set的弱化版本:
一、这两个类没有entries、keys和values等方法; 二、只能用对象做为键; 三、建立这两个类主要是为了性能,没有强引用键,使得js的垃圾回收能够直接清除入口; 四、没有entries、keys和values等方法,实例不知道原始类内部状况,能够用来封装类的私有属性
一种特殊的操做树和图结构的方法,递归迭代
递归引发的栈溢出问题
递归引发的重复计算问题
非顺序数据结构,父级节点下能够有多个或者零个子节点
父级节点下最多两个子节点
class Node { constructor(key) { this.key = key; this.left = null; this.right = null; } } function defaultCompare(a, b) { if (a === b) { return Compare.EQUALS; } return a < b ? Compare.LESS_THAN : Compare.BIGGER_THAN; }
const Compare = { LESS_THAN: -1, BIGGER_THAN: 1, EQUALS: 0 }; class BinarySearchTree { constructor(compareFn = defaultCompare) { this.compareFn = compareFn; this.root = undefined; } insert(key) { // special case: first key if (this.root == null) { this.root = new Node(key); } else { this.insertNode(this.root, key); } } insertNode(node, key) { if (this.compareFn(key, node.key) === Compare.LESS_THAN) { if (node.left == null) { node.left = new Node(key); } else { this.insertNode(node.left, key); } } else if (node.right == null) { node.right = new Node(key); } else { this.insertNode(node.right, key); } } getRoot() { return this.root; } search(key) { return this.searchNode(this.root, key); } searchNode(node, key) { if (node == null) { return false; } if (this.compareFn(key, node.key) === Compare.LESS_THAN) { return this.searchNode(node.left, key); } else if (this.compareFn(key, node.key) === Compare.BIGGER_THAN) { return this.searchNode(node.right, key); } return true; } inOrderTraverse(callback) { this.inOrderTraverseNode(this.root, callback); } inOrderTraverseNode(node, callback) { if (node != null) { this.inOrderTraverseNode(node.left, callback); callback(node.key); this.inOrderTraverseNode(node.right, callback); } } preOrderTraverse(callback) { this.preOrderTraverseNode(this.root, callback); } preOrderTraverseNode(node, callback) { if (node != null) { callback(node.key); this.preOrderTraverseNode(node.left, callback); this.preOrderTraverseNode(node.right, callback); } } postOrderTraverse(callback) { this.postOrderTraverseNode(this.root, callback); } postOrderTraverseNode(node, callback) { if (node != null) { this.postOrderTraverseNode(node.left, callback); this.postOrderTraverseNode(node.right, callback); callback(node.key); } } min() { return this.minNode(this.root); } minNode(node) { let current = node; while (current != null && current.left != null) { current = current.left; } return current; } max() { return this.maxNode(this.root); } maxNode(node) { let current = node; while (current != null && current.right != null) { current = current.right; } return current; } remove(key) { this.root = this.removeNode(this.root, key); } removeNode(node, key) { if (node == null) { return undefined; } if (this.compareFn(key, node.key) === Compare.LESS_THAN) { node.left = this.removeNode(node.left, key); return node; } else if (this.compareFn(key, node.key) === Compare.BIGGER_THAN) { node.right = this.removeNode(node.right, key); return node; } // key is equal to node.item // handle 3 special conditions // 1 - a leaf node // 2 - a node with only 1 child // 3 - a node with 2 children // case 1 if (node.left == null && node.right == null) { node = undefined; return node; } // case 2 if (node.left == null) { node = node.right; return node; } else if (node.right == null) { node = node.left; return node; } // case 3 const aux = this.minNode(node.right); node.key = aux.key; node.right = this.removeNode(node.right, aux.key); return node; } }
insert(key):插入新的键 getRoot:返回根节点 search(key):查找键,返回true和false inOrderTraverse:中序遍历节点 perOrderTraverse:先序遍历节点 postOrderTraverse:后序遍历节点 min:树中最小的键 max:树中最大的键 remove(key):删除键