標籤:max rip print blog insert sso ini turn 中序遍曆
* 什麼是二叉搜尋樹?其形式就是二叉樹,對於每個節點x,其左子樹的值<=x.value,右子樹的值>=x.value。
* 對於二叉搜尋樹,我們可以使用中序遍曆,得到樹上從小到大所有的元素。時間複雜度平均為O(n)。
function inorderTreeWalk(x) { if(x!== null) { inorderTreeWalk(x.left); print(x.key); inorderTreeWalk(x.right); } }
* 當我們想要查詢二叉搜尋樹中某個關鍵字應該怎麼做呢?由於二叉搜尋樹左子樹和右子樹的特點,我們很容易寫出:
function treeSearch(x,k) { //最開始x代表根節點 if(x === null || x.key === k) { return x; } if(k < x.key) { return treeSearch(x.left, k); } else { return treeSearch(x.right, k); }}
我們還可以寫出迴圈版本(一般比遞迴更高效):
function treeSearch(x, k) { while(x !== null || k !== x.key) { if(k < x.key) { x = x.left; } else { x = x.right; } } return x;}
* 我們很容易可以找到二叉搜尋樹中的最小元素和最大元素,其尋找時間複雜度為O(lgn):
function treeMinimum(x) { while(x.left !== null) { x = x.left; } return x;}function treeMaximum(x) { while(x.right !== null) { x = x.right; } return x;}
* 有時候我們需要按中序遍曆尋找二叉搜尋樹某個節點的後繼和前驅。分析二叉搜尋樹性質可知,如果該節點右子樹不為空白,則它的後繼應該是右子樹中的最小元素;若右子樹為空白,則該節點的後繼應該是其雙親有左子樹的父節點。前驅則與其對稱.時間複雜度O(lgn):
function treeSuccessor(x) { //後繼尋找 if(x.right !== null) { return treeMinimum(x.right); } else { let y = x.parent; while(y !== null && x === y.right) { x = y; y = y.parent; } return y; }}function treeSuccessor(x) { //前驅尋找 if(x.left !== null) { return treeMaximum(x.left); } else { let y = x.parent; while(y !== null && x === y.left) { x = y; y = y.parent; } return y; }}
* 接下來我們還想要對二叉搜尋樹實現插入和刪除操作。
1、插入相對比較簡單,我們只要遍曆二叉樹把值插入到合適的位置就行了。
function treeInsert(tree, newNode) { let y = null; while(tree !== null) { y = tree; if(newNode.key < tree.key) { tree = tree.left; } else { tree = tree.right; } } newNode.parent = y; if(y === null) { // 樹為空白 tree.root = newNode; } else { if(newNode.key < y.key) { y.left = newNode; } else { y.right = newNode; } }}
2、刪除操作相對較複雜。假如刪除z節點,我們考慮三種情況:z沒有子節點、z有一個子節點、z有兩個子節點。
第一種情況:z沒有子節點,則直接刪除z,修改父節點屬性,用null代替z。
第二種情況:z只有一個子節點,則用子節點代替z。
第三種情況:z有兩個子節點,我們需要找到z的後繼y,y肯定在z的右子樹並且沒有左孩子,當y恰好是z的右子節點,則直接用y替代z,並留下y的右孩子;否則先用y的右子節點替代y,再用y替代z。
function transplant(tree, u, v) { //子樹替換父節點方法 if(u.p === null) { tree.root = v; } else if(u === u.parent.left) { u.parent.left = v; } else { u.parent.right = v; } if(v !== null) { v.parent = u.parent; }}function treeDelete(tree, z) { if(z.left === null) { transplant(tree, z, z.right); } else if(z.right === null) { transplant(tree, z, z.left); } else { let y = treeMinimum(z.right); if(y.parent !== z) { transplant(tree, y, y.right); y.right = z.right; y.right.parent = y; } transplant(tree, z, y); y.left = z.left; y.left.parent = y; }}
二叉搜尋樹JavaScript實現