【簡介】
二叉查詢樹是一種資料結構,它支援多種動態集合操作。
在二叉查詢樹上執行的基本操作的時間與樹的高度成正比。對於一棵含有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.根節點...
演算法系列之二叉樹
資料結構中有一種結構是樹,不過一般我們常見的是樹中的一種特殊型別 二叉樹。二叉樹簡單來說就是每個節點最多有兩個子節點。如果每個節點都有兩個子節點,那麼我們稱這種二叉樹為滿二叉樹。還有一種二叉樹,其葉子節點都在最底下兩層,最後一層葉子節點都靠左排列,並且除了最後一層,其他層的葉子節點都要達到最大,這種...