数据结构 栈 栈是一个一个**==后进先出==**的数据结构 TypeScript 版数据结构
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 interface IStack <T> { push (element : T): void ; pop (): T | undefined ; peek (): T; isEmpty (): boolean ; size (): number ; toString (): string ; } class Stack <T = any > implements IStack <T> { list : T[]; constructor ( ) { this .list = []; } push (element : T ) { this .list .push (element); } pop (): T | undefined { return this .list .pop (); } peek (): T { return this .list [this .list .length - 1 ]; } isEmpty (): boolean { return this .list .length <= 0 ? true : false ; } size (): number { return this .list .length ; } toString (): string { return this .list .join (" " ); } }
十进制转二进制 1 2 3 4 5 6 7 8 9 10 11 12 13 const stack = new Stack <number >();function transform (num : number ) { while (num >= 1 ) { stack.push (num % 2 ); num = Math .floor (num / 2 ); } let result = "" ; while (!stack.isEmpty ()) { result += stack.pop (); } return result; }
有效的括号 给定一个只包括 '('
,')'
,'{'
,'}'
,'['
,']'
的字符串 s
,判断字符串是否有效。
有效字符串需满足:
左括号必须用相同类型的右括号闭合。
左括号必须以正确的顺序闭合。
每个右括号都有一个对应的相同类型的左括号。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 function isValid (s : string ): boolean { const stack = new Stack <string >(); for (let i = 0 ; i < s.length ; i++) { const flag = s[i]; if (flag === "(" ) { stack.push (")" ); } else if (flag === "{" ) { stack.push ("}" ); } else if (flag === "[" ) { stack.push ("]" ); } else { if (flag !== stack.pop ()) return false ; } } return stack.isEmpty (); }
队列 队列和栈相反是一个==先进先出==的一个数据结构
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 interface IQueue <T> { enqueue (element : T): void ; dequeue (): T | undefined ; front (): T; isEmpty (): boolean ; size (): number ; } export default class Queue <T = any > implements IQueue <T> { list : T[] = []; enqueue (element : T ) { this .list .push (element); } dequeue (): T | undefined { return this .list .shift (); } front (): T { return this .list [0 ]; } isEmpty (): boolean { return this .list .length <= 0 ? true : false ; } size (): number { return this .list .length ; } }
击鼓传花 几个朋友一起玩一个游戏,围成一圈,开始数数,数到某个数字的人自动淘汰。使用 TypeScript 实现一个函数传入玩家的名字和数到什么数字淘汰,并返回胜利的玩家。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 function hotPotato (arr : string [], num : number ) { const queue = new Queue <string >(); for (const item of arr) { queue.enqueue (item); } while (queue.size () !== 1 ) { for (let i = 1 ; i < num; i++) { queue.enqueue (queue.dequeue ()!); } queue.dequeue (); } return queue.front (); }
优先级队列 每个元素都分配一个数字来标记其优先级,优先级小的排在前面
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 class QueueElement <T> { element : T; priority : number ; constructor (element : T, priority : number ) { this .element = element; this .priority = priority; } } class priorityQueue <T = any > { list : QueueElement <T>[] = []; length : number = 0 ; enqueue (element : T, priority : number ) { const queueElement = new QueueElement <T>(element, priority); if (this .isEmpty ()) { this .list .push (queueElement); } else if (queueElement.priority > this .list [this .length - 1 ].priority ) { this .list .splice (this .length , 0 , queueElement); } else { for (let i = 0 ; i < this .length ; i++) { if (queueElement.priority < this .list [i].priority ) { this .list .splice (i, 0 , queueElement); break ; } } } this .length ++; } dequeue ( ) { if (this .length <= 0 ) throw new Error ("stack is empty" ); this .length --; return this .list .shift (); } front ( ) { if (this .isEmpty ()) return null ; return this .list [0 ]; } isEmpty ( ) { return this .length <= 0 ? true : false ; } size ( ) { return this .length ; } }
单项链表 不同于数组,链表在内存中的空间不必是连续的,链表的每个元素由一个储存元素本身的节点 和指向下一个元素的指针 构成。
链表的优势:
链表中的元素在内存中不必是连续的空间 ,可以充分利用计算机的内存,实现灵活的内存动态管理 。
链表不必在创建时就确定大小 ,并且大小可以无限地延伸 下去。
链表在插入和删除 数据时,时间复杂度 可以达到 O(1),相对数组效率高很多。
链表的缺点:
链表访问任何一个位置的元素时,都需要从头开始访问 (无法跳过第一个元素访问任何一个元素)。
无法通过下标值直接访问元素,需要从头开始一个个访问,直到找到对应的元素。
虽然可以轻松地到达下一个节点 ,但是回到前一个节点 是很难的。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 class Node <T> { element : T; next : Node <T> | null ; constructor (element : any ) { this .element = element; this .next = null ; } } class LinkList <T = any > { head : Node <T> | null ; length : number ; constructor ( ) { this .head = null ; this .length = 0 ; } append (element : T ) { const node = new Node <T>(element); if (this .head === null ) { this .head = node; } else { let current = this .head ; while (current.next !== null ) { current = current.next ; } current.next = node; } this .length ++; } get (position : number ) { if (position < 0 || position > this .length - 1 ) { throw new Error ("position is error" ); } let i = 0 ; let current = this .head ; while (i !== position) { current = current!.next ; i++; } return current; } insert (position : number , element : T ) { if (position < 0 || position > this .length ) { throw new Error ("position is error" ); } const node = new Node <T>(element); if (position === 0 && this .length !== 0 ) { const firstNode = this .head ; this .head = node; node.next = firstNode; } else if (position === 0 && this .length === 0 ) { this .append (element); } else { let current = this .get (position - 1 ); node.next = current!.next ; current!.next = node; } this .length ++; } indexOf (element : any ) { let i = 0 ; let current = this .head ; while (i !== this .length ) { if (current!.element === element) { return i; } else { current = current!.next ; i++; } } return -1 ; } update (position : number , element : T ) { const current = this .get (position); current!.element = element; } removeAt (position : number ) { if (position < 0 || position > this .length - 1 ) { throw new Error ("position is error" ); } if (position === 0 ) { this .head = this .head !.next ; } else { let frontNode = this .get (position - 1 ); frontNode!.next = frontNode!.next !.next ; } this .length --; } remove (element : any ) { if (this .indexOf (element) === -1 ) { throw new Error ("element is not fount" ); } let position = this .indexOf (element); this .removeAt (position); } isEmpty ( ) { return this .length === 0 ; } size ( ) { return this .length ; } }
删除链表中的节点 有一个单链表的 head,我们想删除它其中的一个节点 node。
给你一个需要删除的节点 node 。你将 无法访问 第一个节点 head。
链表的所有值都是 唯一的,并且保证给定的节点 node 不是链表中的最后一个节点。
删除给定的节点。注意,删除节点并不是指从内存中删除它。这里的意思是:
给定节点的值不应该存在于链表中。
链表中的节点数应该减少 1。
node 前面的所有值顺序相同。
node 后面的所有值顺序相同。
来源:力扣(LeetCode) 链接:https://leetcode.cn/problems/delete-node-in-a-linked-list
1 2 3 4 5 6 7 8 9 10 11 12 class ListNode { val : number ; next : ListNode | null ; constructor (val?: number , next?: ListNode | null ) { this .val = val === undefined ? 0 : val; this .next = next === undefined ? null : next; } } function deleteNode (node : ListNode | null ): void { node!.val = node!.next !.val ; node!.next = node!.next !.next ; }
反转链表 循环方式 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 class ListNode { val : number ; next : ListNode | null ; constructor (val?: number , next?: ListNode | null ) { this .val = val === undefined ? 0 : val; this .next = next === undefined ? null : next; } } function reverseList (head : ListNode | null ): ListNode | null { if (head === null || head.next === null ) return head; let newHead : ListNode | null = null ; while (head) { let current : any = head.next ; head.next = newHead; newHead = head; head = current; } return newHead; }
递归方式 1 2 3 4 5 6 7 8 9 10 11 12 13 function reverseList (head : ListNode | null ): ListNode | null { if (head === null || head.next === null ) return head; const newHead = reverseList (head?.next ); head.next .next = head; head.next = null ; return newHead; }
双向链表 双向链表 :既可以从头遍历到尾 ,又可以从尾遍历到头 。也就是说链表连接的过程是双向 的,它的实现原理是:一个节点既有向前连接的引用 ,也有一个向后连接的引用 。
双向链表的缺点:
每次在插入或删除 某个节点时,都需要处理四个引用,而不是两个,实现起来会困难些;
相对于单向链表,所占内存空间更大 一些;
但是,相对于双向链表的便利性而言,这些缺点微不足道。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 class Node <T> { element : T; next : Node <T> | null ; prev : Node <T> | null ; constructor (element : T ) { this .element = element; this .next = null ; this .prev = null ; } } class DoublyLinkList <T = any > { head : Node <T> | null ; tail : Node <T> | null ; length : number ; constructor ( ) { this .head = null ; this .tail = null ; this .length = 0 ; } append (element : T ) { const node = new Node <T>(element); if (this .length === 0 ) { this .head = this .tail = node; } else { let current = this .head ; while (current!.next !== null ) { current = current!.next ; } node.prev = current; current!.next = this .tail = node; } this .length ++; } get (position : number ) { if (position < 0 || position > this .length - 1 ) { throw new Error ("position is error" ); } let i = 0 ; let current = this .head ; while (i !== position) { current = current!.next ; i++; } return current; } insert (position : number , element : T ) { if (position < 0 || position > this .length ) { throw new Error ("position is error" ); } const node = new Node (element); if (this .length === 0 && position === 0 ) { this .append (element); } else if (this .length !== 0 && position === 0 ) { node.next = this .head !.next ; this .head !.prev = this .head = node; } else if (position === this .length ) { node.prev = this .tail ; this .tail !.next = this .tail = node; } else { const frontNode = this .get (position - 1 ); node.next = frontNode!.next ; node.prev = frontNode; frontNode!.next !.prev = frontNode!.next = node; } this .length ++; } indexOf (element : T ) { let i = 0 ; let current = this .head ; while (i !== this .length ) { if (current!.element === element) { return i; } else { current = current!.next ; i++; } } return -1 ; } update (position : number , element : T ) { const current = this .get (position); current!.element = element; } removeAt (position : number ) { if (position < 0 || position > this .length - 1 ) { throw new Error ("position is error" ); } const current = this .get (position); if (position === 0 ) { current!.next !.prev = null ; this .head = current!.next ; current!.next = null ; } else if (position === this .length - 1 ) { current!.prev !.next = null ; this .tail = current!.prev ; current!.prev = null ; } else { current!.next !.prev = current!.prev ; current!.prev !.next = current!.next ; } this .length --; } remove (element : T ) { if (this .indexOf (element) === -1 ) { throw new Error ("element is not fount" ); } let position = this .indexOf (element); this .removeAt (position); } isEmpty ( ) { return this .length === 0 ? true : false ; } size ( ) { return this .length ; } }
哈希表 哈希表通常是基于数组 实现的,但是相对于数组,它存在更多优势:
哈希表可以提供非常快速的插入-删除-查找操作 ;
无论多少数据,插入和删除值都只需要非常短的时间,即 O(1)的时间级。实际上,只需要几个机器指令 即可完成;
哈希表的速度比树还要快 ,基本可以瞬间查找到想要的元素。但是相对于树来说编码要简单得多。
哈希表同样存在不足之处:
哈希表中的数据是没有顺序 的,所以不能以一种固定的方式(比如从小到大 )来遍历其中的元素。
通常情况下,哈希表中的 key 是不允许重复 的,不能放置相同的 key,用于保存不同的元素。
树 二叉搜索树(插入) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 class Node <T> { value : T; constructor (element : any ) { this .value = element; } } class TreeNode <T> extends Node <T> { left : TreeNode <T> | null = null ; right : TreeNode <T> | null = null ; } class BSTree <T> { private root : TreeNode <T> | null = null ; insert (number : T ) { const newNode = new TreeNode <T>(number ); if (!this .root ) { this .root = newNode; } else { this .insertNode (this .root , newNode); } } private insertNode (node : TreeNode <T>, newNode : TreeNode <T> ) { if (node.value > newNode.value ) { if (node.left === null ) { node.left = newNode; } else { this .insertNode (node.left , newNode); } } else { if (node.right === null ) { node.right = newNode; } else { this .insertNode (node.right , newNode); } } } }
二叉搜索树(遍历) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 class Node <T> { value : T; constructor (element : any ) { this .value = element; } } class TreeNode <T> extends Node <T> { left : TreeNode <T> | null = null ; right : TreeNode <T> | null = null ; } class BSTree <T> { private root : TreeNode <T> | null = null ; preOrderTraverse ( ) { this .PreOrderTraverseNode (this .root ); } PreOrderTraverseNode (node : TreeNode <T> | null ) { if (node) { console .log (node); this .PreOrderTraverseNode (node.left ); this .PreOrderTraverseNode (node.right ); } } inOrderTraverse ( ) { this .PreOrderTraverseNode (this .root ); } inOrderTraverseNode1 (node : TreeNode <T> | null ) { if (node) { this .PreOrderTraverseNode (node.left ); console .log (node); this .PreOrderTraverseNode (node.right ); } } postOrderTraverse ( ) { this .PreOrderTraverseNode (this .root ); } postOrderTraverseNode1 (node : TreeNode <T> | null ) { if (node) { this .PreOrderTraverseNode (node.left ); this .PreOrderTraverseNode (node.right ); console .log (node); } } leaverOrderTraverse ( ) { if (!this .root ) return ; const queue : TreeNode <T>[] = []; queue.unshift (this .root ); while (queue.length !== 0 ) { const node = queue.pop (); console .log (node?.value ); if (node?.left ) { queue.unshift (node!.left ); } if (node?.right ) { queue.unshift (node!.right ); } } } }
二叉搜索树(最值和搜索) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 class Node<T> { value: T; constructor(element: any) { this.value = element; } } class TreeNode<T> extends Node<T> { left: TreeNode<T> | null = null right: TreeNode<T> | null = null } class BSTree<T> { private root: TreeNode<T> | null = null // 获取最大值 getMaxValue(): T | null { if (!this.root) return null let maxNode = this.root while (maxNode?.right !== null) { maxNode = maxNode!.right } return maxNode.value } // 获取最小值 getMinValue(): T | null { if (!this.root) return null let maxNode = this.root while (maxNode?.left !== null) { maxNode = maxNode!.left } return maxNode.value } // 查找树中是否有指定节点 search(value: T): boolean { let current = this.root while (current) { if (current.value === value) return true if (current.value > value) { current = current.left } else { current = current.right } } return false } }
二叉搜索树(删除) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 class Node <T> { value : T; constructor (element : any ) { this .value = element; } } class TreeNode <T> extends Node <T> { left : TreeNode <T> | null = null ; right : TreeNode <T> | null = null ; } class BSTree <T> { private root : TreeNode <T> | null = null ; searchNode (value : T ) { let current = this .root ; let parent : TreeNode <T> | null = null ; let flag : "left" | "right" = "left" ; while (current) { if (current.value === value) return { current, parent, flag }; parent = current; if (current.value > value) { current = current.left ; flag = "left" ; } else { current = current.right ; flag = "right" ; } } return null ; } private getSuccessor (delNode : TreeNode <T> ) { let current = delNode.right ; let successor : TreeNode <T> | null = null ; while (current) { successor = current; current = current.left ; } successor!.left = delNode.left ; if (successor !== delNode.right ) { const { parent } = this .searchNode (successor!.value )!; parent!.left = successor!.right ; successor!.right = delNode.right ; } return successor!; } delete (value : T ) { if (!this .search (value)) return ; const { current : deleteNode, parent : deleteParentNode, flag, } = this .searchNode (value)!; if (!deleteNode.left && !deleteNode.right ) { if (deleteNode === this .root ) { this .root = null ; } else { deleteParentNode![flag] = null ; } } else if (deleteNode.right === null ) { if (deleteNode === this .root ) { this .root = deleteNode.left ; } else { deleteParentNode![flag] = deleteNode.left ; } } else if (deleteNode.left === null ) { if (deleteNode === this .root ) { this .root = deleteNode.right ; } else { deleteParentNode![flag] = deleteNode.right ; } } else { const successor = this .getSuccessor (deleteNode); if (deleteNode === this .root ) { this .root = successor; } else if (flag === "left" ) { deleteParentNode!.left = successor; } else { deleteParentNode!.right = successor; } } } }
完整代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 class Node <T> { value : T; constructor (element : any ) { this .value = element; } } class TreeNode <T> extends Node <T> { left : TreeNode <T> | null = null ; right : TreeNode <T> | null = null ; } class BSTree <T> { private root : TreeNode <T> | null = null ; insert (number : T ) { const newNode = new TreeNode <T>(number ); if (!this .root ) { this .root = newNode; } else { this .insertNode (this .root , newNode); } } private insertNode (node : TreeNode <T>, newNode : TreeNode <T> ) { if (node.value > newNode.value ) { if (node.left === null ) { node.left = newNode; } else { this .insertNode (node.left , newNode); } } else { if (node.right === null ) { node.right = newNode; } else { this .insertNode (node.right , newNode); } } } preOrderTraverse ( ) { this .PreOrderTraverseNode (this .root ); } PreOrderTraverseNode (node : TreeNode <T> | null ) { if (node) { console .log (node); this .PreOrderTraverseNode (node.left ); this .PreOrderTraverseNode (node.right ); } } inOrderTraverse ( ) { this .PreOrderTraverseNode (this .root ); } inOrderTraverseNode1 (node : TreeNode <T> | null ) { if (node) { this .PreOrderTraverseNode (node.left ); console .log (node); this .PreOrderTraverseNode (node.right ); } } postOrderTraverse ( ) { this .PreOrderTraverseNode (this .root ); } postOrderTraverseNode (node : TreeNode <T> | null ) { if (node) { this .PreOrderTraverseNode (node.left ); this .PreOrderTraverseNode (node.right ); console .log (node); } } leaverOrderTraverse ( ) { if (!this .root ) return ; const queue : TreeNode <T>[] = []; queue.unshift (this .root ); while (queue.length !== 0 ) { const node = queue.pop (); console .log (node?.value ); if (node?.left ) { queue.unshift (node!.left ); } if (node?.right ) { queue.unshift (node!.right ); } } } getMaxValue (): T | null { if (!this .root ) return null ; let maxNode = this .root ; while (maxNode?.right !== null ) { maxNode = maxNode!.right ; } return maxNode.value ; } getMinValue (): T | null { if (!this .root ) return null ; let maxNode = this .root ; while (maxNode?.left !== null ) { maxNode = maxNode!.left ; } return maxNode.value ; } search (value : T): boolean { let current = this .root ; while (current) { if (current.value === value) return true ; if (current.value > value) { current = current.left ; } else { current = current.right ; } } return false ; } searchNode (value : T ) { let current = this .root ; let parent : TreeNode <T> | null = null ; let flag : "left" | "right" = "left" ; while (current) { if (current.value === value) return { current, parent, flag }; parent = current; if (current.value > value) { current = current.left ; flag = "left" ; } else { current = current.right ; flag = "right" ; } } return null ; } private getSuccessor (delNode : TreeNode <T> ) { let current = delNode.right ; let successor : TreeNode <T> | null = null ; while (current) { successor = current; current = current.left ; } successor!.left = delNode.left ; if (successor !== delNode.right ) { const { parent } = this .searchNode (successor!.value )!; parent!.left = successor!.right ; successor!.right = delNode.right ; } return successor!; } delete (value : T ) { if (!this .search (value)) return ; const { current : deleteNode, parent : deleteParentNode, flag, } = this .searchNode (value)!; if (!deleteNode.left && !deleteNode.right ) { if (deleteNode === this .root ) { this .root = null ; } else { deleteParentNode![flag] = null ; } } else if (deleteNode.right === null ) { if (deleteNode === this .root ) { this .root = deleteNode.left ; } else { deleteParentNode![flag] = deleteNode.left ; } } else if (deleteNode.left === null ) { if (deleteNode === this .root ) { this .root = deleteNode.right ; } else { deleteParentNode![flag] = deleteNode.right ; } } else { const successor = this .getSuccessor (deleteNode); if (deleteNode === this .root ) { this .root = successor; } else if (flag === "left" ) { deleteParentNode!.left = successor; } else { deleteParentNode!.right = successor; } } } }
图 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 verteces : T[] = [] adList : Map <T, T[]> = new Map () addvertex (vertex : T ) { this .verteces .push (vertex) this .adList .set (vertex, []) } addEdge (v1 : T, v2 : T ) { this .adList .get (v1)?.push (v2) this .adList .get (v2)?.push (v1) } bfs ( ) { if (this .verteces .length === 0 ) return const queue : T[] = [] queue.push (this .verteces [0 ]) const visited = new Set <T>() visited.add (this .verteces [0 ]) while (queue.length ) { const vertex = queue.shift ()! console .log (vertex) const neighbors = this .adList .get (vertex) if (!neighbors) continue for (const nei of neighbors) { if (!visited.has (nei)) { visited.add (nei) queue.push (nei) } } } } dfs ( ) { if (this .verteces .length === 0 ) return const stack : T[] = [] stack.push (this .verteces [0 ]) const visited = new Set <T>() visited.add (this .verteces [0 ]) while (stack.length ) { const vertex = stack.pop ()! console .log (vertex) const neighbors = this .adList .get (vertex) if (!neighbors) continue for (let i = neighbors.length - 1 ; i > 0 ; i--) { const nei = neighbors[i] visited.add (nei) stack.push (nei) } } } }
堆结构