演算法系列之六 二叉查詢樹

2021-06-26 16:40:32 字數 4235 閱讀 9385

【簡介】

二叉查詢樹是一種資料結構,它支援多種動態集合操作。

在二叉查詢樹上執行的基本操作的時間與樹的高度成正比。對於一棵含有n個節點的完全二叉樹,這些操作的最壞情況執行時間為o(n)。

【結構體】

一棵二叉查詢樹按二叉樹結構來組織的。

// 二叉查詢樹節點

struct treenode

};

【性質】

設x為二叉查詢樹上的乙個節點。

如果y是x的左子樹中的乙個節點,則y->val 小於等於 x->val。

如果y是x的右子樹中的乙個節點,則y->val 大於等於 x->val。

【輸出】

根據二叉查詢樹的性質,我們可以用中序遞迴遍歷演算法按排列順序輸出樹中的所有關鍵字。

// 中序遍歷輸出二叉查詢樹

void inorder(treenode* root)//if

inorder(root->left);

cout

}

【插入】

// 插入

void treeinsert(treenode*& root,int val)//if

treenode *pre = null;

treenode *p = root;

// 尋找插入位置

while(p)//if

// 沿右子樹方向下降

else//else

}//while

// 父節點

node->parent = pre;

// 左子結點處插入

if(val < pre->val)//if

// 右子結點處插入

else//else

}

treeinsert從根節點開始,並沿樹下降。

指標p跟蹤了這條路徑,而pre始終指向p的父節點。初始化後while迴圈是這兩個指標沿樹下降,根據val和p->val的比較結果,可以決定向左還是向右轉。

直到p成為null為止。這個null所佔的位置就是我們像插入的位置。

其特點是:樹的結構通常不是一次生成的,而是在查詢過程中,當樹中不存在關鍵字

等於給定值的節點

時再進行插入。

新插入的結點一定是乙個新新增的葉子節點

,並且是查詢不成功時查詢路徑

上訪問的最後乙個結點的左孩子或右孩子結點。

【查詢】

【遞迴演算法】

返回指向包含關鍵字val的節點(如果存在的)的指標,否則返回null

// 查詢

treenode* treesearch(treenode* root,int val)//if

// 左子樹查詢

if(val < root->val)//if

// 右子樹查詢

else//else

}

如果root是一棵空樹,搜尋失敗,直接返回null。

如果root不是空樹:

對碰到的每乙個節點p,都要進行比較val和p->val,如果兩個關鍵字相同,則查詢結束。

如果val小於p->val,則繼續查詢p的左子樹,如果val大於等於p->val,則繼續查詢p的右子樹。

【非遞迴演算法】

// 非遞迴查詢

treenode* treesearch2(treenode* root,int val)//if

treenode *p = root;

while(p && val != p->val)//if

// 右子樹查詢

else//else

}//while

return p;

}

【最大元素】

要查詢二叉樹中具有最大關鍵字的元素,只要從根節點開始,沿著各節點的right指標查詢下去,直到遇到null為止。

// 最大元素

treenode* treemaxnum(treenode *root)//while

return p;

}

【最小元素】

要查詢二叉樹中具有最小關鍵字的元素,只要從根節點開始,沿著各節點的left指標查詢下去,直到遇到null為止。

// 最小元素

treenode* treeminnum(treenode *root)//while

return p;

}

【前驅和後繼】

即具有大於x->val中的關鍵字中的最小的那個節點。

根據二叉查詢樹的性質得知,不用任何的比較,就可以找到某個節點的後繼。對於二叉查詢樹的某個節點x,下面的**返回其後繼(如果存在的話)

,或者返回null(如果x具有樹中最大關鍵字的某個節點)

// 後繼

treenode* treesuccessor(treenode* node)//if

// 右子樹為空,後繼為最低祖先節點

treenode *pre = node->parent;

treenode *cur = node;

// y是xd的最低祖先節點且y的左兒子也是x的祖先

while(pre != null && cur == pre->right)//while

return pre;

}

求某個節點的後繼,需要考慮兩種情況:

(1)如果節點的右子樹非空,則x的後繼即右子樹中的最左節點。可以通過呼叫treeminnum獲取。

(2)如果節點的右子樹為空,則x有乙個後繼y,則y是x的最低祖先節點,且y的左兒子也是x的祖先。

對於高度為h的一棵二叉查詢樹,時間執行為o(h)。

【刪除】

在刪除node的過程中需要考慮三種情況:

(1)如果node沒有子女,則直接刪除node節點,使null成為node父節點的子女。

(2)如果節點node只有乙個子女,則可以通過在其子節點與父節點之間建立一條鏈來刪除node。

(3)如果節點node有兩個子女,先刪除node節點的後繼y(它沒有左子女),再用y的內容來代替node的內容。

// 刪除(返回被刪除的節點)

treenode* treedelete(treenode *root,treenode *node)//if

// 有兩個子女則刪除node節點的後繼節點

else//esle

//2.刪除節點的子女(至多有乙個子女)

treenode *childnode = null;

if(deletenode->left)//if

else//else

// 3.刪除

if(childnode)//if

// 刪除節點為根節點

if(deletenode->parent == null)//if

else//if

// 刪除節點是父節點的右子結點

else//else

}//else

// 4.如果刪除的是後繼節點,將deletenode內容複製給node

if(deletenode->val != node->val)//if

return deletenode;

}

第一步先確定要刪除的節點deletenode。該節點或者是輸入節點node(如果node至多有只有乙個子女),或者是node節點的後繼(如果node有兩個子女)。

第二步找到刪除節點deletenode的子女。刪除節點只有乙個子女,或者是左子女或者是右子女或者是null。

第三步刪除節點deletenode。先修改一下刪除節點子女的父指標。如果刪除節點是根節點,root = childnode。

如果刪除節點不是根節點,稍微有點複雜。

第四步判斷刪除節點是否是後繼節點,如果是後繼節點,還需要將deletenode內容複製到node中,從而覆蓋先前內容。

Leetcode演算法系列六(二分查詢與二叉查詢樹)

預備知識 二分查詢基礎知識 例1 插入位置 easy 二分查詢 例2 區間查詢 medium 二分查詢 例3 旋轉陣列查詢 medium 二分查詢 預備知識 二叉查詢 排序 樹基礎知識 例4 二叉查詢樹編碼與解碼 medium 例5 逆序數 hard 二叉查詢樹應用 搜尋插入位置 給定乙個排序陣列和...

演算法精解(六) 二叉樹

二叉樹是一種將結點按照層次結構組織起來的資料結構,每個結點最多只有兩個與它直接關聯的子節點。類似於細胞 一樣,1 2,2 4,4 8.先序遍歷 1,訪問根節點,2.左節點,3.右節點 屬於深度優先遍歷 中序遍歷 1.訪問左節點,2.根節點,3.右節點 後序遍歷 1.訪問左節點,2.右節點,3.根節點...

演算法系列之二叉樹

資料結構中有一種結構是樹,不過一般我們常見的是樹中的一種特殊型別 二叉樹。二叉樹簡單來說就是每個節點最多有兩個子節點。如果每個節點都有兩個子節點,那麼我們稱這種二叉樹為滿二叉樹。還有一種二叉樹,其葉子節點都在最底下兩層,最後一層葉子節點都靠左排列,並且除了最後一層,其他層的葉子節點都要達到最大,這種...