1. 程式人生 > >二叉樹的用途之一二叉搜尋樹

二叉樹的用途之一二叉搜尋樹

    在學習資料結構的時候,也曾經學習過二叉樹,以及前序排列、中序排列、後序排列等等,但是一直無緣使用它!

二叉樹可以幹什麼?

    排序有快速排序,歸併排序,查詢有二分法,甚至直接遍歷查詢,二叉樹的使用很少。

實際場景使用上,用的最多的是二叉平衡樹,有種特殊的二叉平衡樹就是紅黑樹,Java集合中的TreeSet和TreeMap,C++STL中的set,map以及LInux虛擬記憶體的管理,都是通過紅黑樹去實現的,還有哈弗曼樹編碼方面的應用,以及B-Tree,B+-Tree在檔案系統中的應用。當然二叉查詢樹可以用來查詢和排序

二叉樹的分類

    滿二叉樹:從高到低,除了葉節點外,所以節點左右節點都存在。

    完全二叉樹:比滿二叉樹少幾個葉節點,從左向右放子節點。

    平衡二叉樹:空樹或者它的左右兩個子樹的高度差的絕對值不超過1,並且左右兩個子樹也都是平衡樹。

    二叉搜尋樹:空樹或者二叉樹的所有節點比他的左子節點大,比他的右子節點小。

    紅黑樹:不僅是具有二叉搜尋樹的屬性,還具有平衡樹的屬性,有序且子樹差不超過1,顏色規則:根節點和特殊節點(即葉節點下面兩個虛無的節點和未填寫的節點)是黑的,紅節點的左右子節點是黑的,最重要的是對於每個節點,從該節點到子孫葉節點的所有路徑包含相同數目的黑節點。

    二叉樹在搜尋上的優勢

    陣列的搜尋比較方便,可以直接使用下標,但刪除或者插入就比較麻煩了,而連結串列與之相反,刪除和插入都比較簡單,但是查詢很慢,這自然也與這兩種資料結構的儲存方式有關,陣列是取一段相連的空間,而連結串列是每建立一個節點便取一個節點所需的空間,只是使用指標進行連線,空間上並不是連續的。而二叉樹就既有連結串列的好處,又有陣列的優點。

今天就學習一下最簡單的二叉排序樹

1.定義:

二叉排序樹又叫二叉查詢樹或者二叉搜尋樹,它首先是一個二叉樹,而且必須滿足下面的條件:

1)若左子樹不空,則左子樹上所有結點的值均小於它的根節點的值;

2)若右子樹不空,則右子樹上所有結點的值均大於它的根結點的值

3)左、右子樹也分別為二叉排序樹

2.二叉樹的遍歷:

在網上找到的一個遍歷示意圖:


圖1 遍歷示意圖

前序遍歷(根-左-右):ABDGHECKFIJ
中序遍歷(左-根-右):GDHBEAKCIJF
後序便利(左-右-根):GHDEBKJIFCA

結合定義可以知道,二叉搜尋樹的資料大小關係為:G<D<H<B<E<A<K<C<I<J<F,即中序遍歷

順序。

小結:從建立好的二叉搜尋樹,我們可以直接使用中序遍歷得到排序。

3.二叉樹的程式碼實現:

    有了思路,程式碼實現的方式很多,以下就是很經典的一種實現,多多思考把握吧。

#include <iostream>
using namespace std;

/*BST的結點*/
typedef struct node
{
    int key;
    struct node *lChild, *rChild;
}Node, *BST;

/*在給定的BST中插入結點,其資料域為element, 使之稱為新的BST*/
bool BSTInsert(BST &p, int element)
{
    if(NULL == p) // 空樹
    {
        p = new Node;
        p->key = element;
        p->lChild = p->rChild = NULL;
        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 << " ";
        preOrderTraverse(T->lChild);
        preOrderTraverse(T->rChild);
    }
}

/*中序遍歷*/
void inOrderTraverse(BST T)
{
    if(T)
    {
        inOrderTraverse(T->lChild);
        cout << T->key << " ";
        inOrderTraverse(T->rChild);
    }
}
/*後序遍歷*/
void postOrderTraverse(BST T)
{
    if(T)
    {
        inOrderTraverse(T->lChild);
        inOrderTraverse(T->rChild);
        cout << T->key << " ";
    }
}
int main()
{
    int a[13] = {4, 5, 2, 1, 0, 9, 3, 7, 6, 8,5,4,7};
    int n = 13;
    BST T;
    T = NULL;
    int i;
    for(i = 0; i < n; i++)
    {
        BSTInsert(T, a[i]);
    }
    inOrderTraverse(T);
    cout << endl;


    return 0;
}