二叉查詢樹(二叉排序樹)學習筆記
本文轉載自:http://blog.csdn.net/qq_37887537/article/details/75647670
在學習資料結構的時候,除了基本的之外的,還有許多樹像是二叉搜尋樹,2-3樹,紅黑樹等等。
也曾經學習過二叉樹,以及前序排列中序排列後序排列等等,但是一直無緣使用它!
排序有快速排序,歸併排序,查詢有二分法,甚至直接遍歷查詢,二叉樹的使用很少。那二叉樹究竟是幹什麼的呢?
進行了一番粗淺的研究,我們學習的經典二叉樹,僅僅當他是一種資料結構是不行的,他還是一種程式設計思想,例如解決揹包問題(後面進行學習),在考試和麵試中使用較多。
而實際場景使用上,用的最多的是二叉平衡樹,有種特殊的二叉平衡樹就是紅黑樹
那麼二叉樹有什麼優點?
大家看到最多的是這麼說的,二叉排序樹是一種比較有用的折中方案:
陣列的搜尋比較方便,可以直接使用下標,但刪除或者插入就比較麻煩了,而連結串列與之相反,刪除和插入都比較簡單,但是查詢很慢,這自然也與這兩種資料結構的儲存方式有關,陣列是取一段相連的空間,而連結串列是每建立一個節點便取一個節點所需的空間,只是使用指標進行連線,空間上並不是連續的。而二叉樹就既有連結串列的好處,又有陣列的優點。
二叉樹的分類,瞭解一下
滿二叉樹:從高到低,除了葉節點外,所以節點左右節點都存在。
完全二叉樹:比滿二叉樹少幾個葉節點,從左向右放子節點。
平衡二叉樹:空樹或者它的左右兩個子樹的高度差的絕對值不超過1,並且左右兩個子樹也都是平衡樹。
二叉搜尋樹:空樹或者二叉樹的所有節點比他的左子節點大,比他的右子節點小。
紅黑樹:不僅是具有二叉搜尋樹的屬性,還具有平衡樹的屬性,有序且子樹差不超過1,顏色規則:根節點和特殊節點(即葉節點下面兩個虛無的節點和未填寫的節點)是黑的,紅節點的左右子節點是黑的,最重要的是對於每個節點,從該節點到子孫葉節點的所有路徑包含相同數目的黑節點。
今天就學習一下最簡單的二叉排序樹
二叉排序樹又叫二叉查詢樹或者二叉搜尋樹
1)若左子樹不空,則左子樹上所有結點的值均小於它的根節點的值;
2)若右子樹不空,則右子樹上所有結點的值均大於它的根結點的值
3)左、右子樹也分別為二叉排序樹
這種特殊的結構二叉樹,採用中序遍歷(左根右)即可獲得一個有序陣列。
在網上找到的一個基礎圖形:
前序遍歷(根-左-右):ABDGHECKFIJ
中序遍歷(左-根-右):GDHBEAKCIJF
後序便利(左-右-根):GHDEBKJIFCA
二叉搜尋樹的資料關係:G<D<H<B<E<A<K<C<I<J<F
實現方法也比較乾淨利落
void PreOrderTraverse(BiTree root) // 先序遍歷
{
if(root){
printf("%d",root->value);
PreOrderTraverse(root->lchild);
PreorderTraverse(root->rchild);
}
}
void InOrderTraverse(BiTree root) // 中序遍歷
{
if(root){
InOrderTraverse(root->lchild);
printf("%d",root->value);
InOrderTraverse(root->rchild);
}
}
void PostOrderTraverse(BiTree root) // 後序遍歷
{
if(root){
PostOrderTraverse(root->lchild);
PostOrderTraverse(root->rchild);
printf("%d",root->value);
}
}
接著就是關於建立一個二叉搜尋樹的過程,這裡沒有將相同的數字遮蔽掉:
#include <iostream>
using namespace std;
// BST的節點
typedef struct node{
node( int element, node *lt, node *rt)
: key{ element }, lChild{ lt }, rChild{ rt } { }
int key;
struct node *lChild;
struct node *rChild;
}Node, *BST;
// 在給定的BST中插入節點,其資料域為element,使之稱為新的BST
bool BSTInsert(BST &p, int element){
if(p==nullptr){
p = new Node(element,nullptr,nullptr);
return true;
}
// if(element == p->key) // BST中不能有相等的值,不註釋掉會遮蔽掉相同的樹
// return false;
// 遞迴
if(element < p->key)
return BSTInsert(p->lChild, element);
else
return BSTInsert(p->rChild, element);
}
// 先序遍歷(根-左-右)
void preOrderTraverse(BST T){
if(T){
cout << T->key << ends;
preOrderTraverse(T->lChild);
preOrderTraverse(T->rChild);
}
}
// 中序遍歷(左-根-右)
void inOrderTraverse(BST T){
if(T){
inOrderTraverse(T->lChild);
cout << T->key << ends;
inOrderTraverse(T->rChild);
}
}
// 後序遍歷(左-右-根)
void postOrderTraverse(BST T){
if(T){
postOrderTraverse(T->lChild);
postOrderTraverse(T->rChild);
cout << T->key << ends;
}
}
int main(){
int a[13] = {4,5,2,1,0,12,3,7,6,8,5,4,7};
int n = 13;
BST T = nullptr;
int i;
for(i=0;i<n;++i){
BSTInsert(T, a[i]);
}
inOrderTraverse(T);
cout << endl;
BSTInsert(T,11);
inOrderTraverse(T);
cout << endl;
return 0;
}