二叉搜索樹(遞歸實(shí)現(xiàn))

#include <iostream>
#include <queue>
#include <cassert>

using namespace std;

template <typename Key, typename Value>
class BST{

private:
    struct Node{
        Key key;
        Value value;
        Node *left;
        Node *right;

        Node(Key key, Value value){
            this->key = key;
            this->value = value;
            this->left = this->right = NULL;
        }

        Node(Node *node){
            this->key = node->key;
            this->value = node->value;
            this->left = node->left;
            this->right = node->right;
        }
    };

    Node *root;
    int count;

public:
    BST(){
        root = NULL;
        count = 0;
    }
    ~BST(){
        destroy( root );
    }

    int size(){
        return count;
    }

    bool isEmpty(){
        return count == 0;
    }


int main() {

    srand(time(NULL));
    BST<int,int> bst = BST<int,int>();

    int n = 10000;
    for( int i = 0 ; i < n ; i ++ ){
        int key = rand()%n;
        // 為了后續(xù)測試方便,這里value值取和key值一樣
        int value = key;
        //cout<<key<<" ";
        bst.insert(key,value);
    }

    // test remove
    // remove elements in random order
    int order[n];
    for( int i = 0 ; i < n ; i ++ )
        order[i] = i;
    shuffle( order , n );

    for( int i = 0 ; i < n ; i ++ )
        if( bst.contain( order[i] )){
            bst.remove( order[i] );
            cout<<"After remove "<<order[i]<<" size = "<<bst.size()<<endl;
        }

    return 0;
}

1. 插入insert

public:
void insert(Key key, Value value){
     root = insert(root, key, value);
}

private:
// 向以node為根的二叉搜索樹中,插入節(jié)點(diǎn)(key, value)
// 返回插入新節(jié)點(diǎn)后的二叉搜索樹的根
Node* insert(Node *node, Key key, Value value){

    if( node == NULL ){      // 如果節(jié)點(diǎn)為空,就在此節(jié)點(diǎn)處加入x信息
        count ++;
        return new Node(key, value);
    }

    if( key == node->key )  
        node->value = value;  //如果相等,就把頻率加1
    else if( key < node->key )
        node->left = insert( node->left , key, value);  // 如果x小于節(jié)點(diǎn)的值,就繼續(xù)在節(jié)點(diǎn)的左子樹中插入x
    else    // key > node->key    
        node->right = insert( node->right, key, value);  // 如果x大于節(jié)點(diǎn)的值,就繼續(xù)在節(jié)點(diǎn)的右子樹中插入x

    return node;
}

2. 包含contain

bool contain(Key key){
    return contain(root, key);
}

// 查看以node為根的二叉搜索樹中是否包含鍵值為key的節(jié)點(diǎn)
bool contain(Node* node, Key key){

    if( node == NULL )
        return false;

    if( key == node->key )
        return true;
    else if( key < node->key )
        return contain( node->left , key );
    else // key > node->key
        return contain( node->right , key );
}

3. 搜索search

Value* search(Key key){
    return search( root , key );
}

// 在以node為根的二叉搜索樹中查找key所對應(yīng)的value
Value* search(Node* node, Key key){

    if( node == NULL )
        return NULL;

    if( key == node->key )
        return &(node->value);
    else if( key < node->key )
        return search( node->left , key );
    else // key > node->key
        return search( node->right, key );
}

4. 遍歷

  • 前序遍歷preOrder
void preOrder(){
    preOrder(root);
}

// 對以node為根的二叉搜索樹進(jìn)行前序遍歷
void preOrder(Node* node){

    if( node != NULL ){
        cout<<node->key<<endl;
        preOrder(node->left);
        preOrder(node->right);
    }
}
  • 中序遍歷inOrder
void inOrder(){
    inOrder(root);
}

// 對以node為根的二叉搜索樹進(jìn)行中序遍歷
void inOrder(Node* node){

    if( node != NULL ){
        inOrder(node->left);
        cout<<node->key<<endl;
        inOrder(node->right);
    }
}
  • 后序遍歷postOrder
void postOrder(){
    postOrder(root);
}

// 對以node為根的二叉搜索樹進(jìn)行后序遍歷
void postOrder(Node* node){

    if( node != NULL ){
        postOrder(node->left);
        postOrder(node->right);
        cout<<node->key<<endl;
    }
}
  • 層序遍歷levelOrder
void levelOrder(){

    queue<Node*> q;
    q.push(root);
    while( !q.empty() ){

        Node *node = q.front();
        q.pop();

        cout<<node->key<<endl;

        if( node->left )
            q.push( node->left );
        if( node->right )
            q.push( node->right );
    }
}

5. 尋找最小/大鍵值

Key minimum(){
    assert( count != 0 );
    Node* minNode = minimum( root );
    return minNode->key;
}

// 在以node為根的二叉搜索樹中,返回最小鍵值的節(jié)點(diǎn)
Node* minimum(Node* node){
    if( node->left == NULL )
        return node;

    return minimum(node->left);
}
Key maximum(){
    assert( count != 0 );
    Node* maxNode = maximum(root);
    return maxNode->key;
}

// 在以node為根的二叉搜索樹中,返回最大鍵值的節(jié)點(diǎn)
Node* maximum(Node* node){
    if( node->right == NULL )
        return node;

    return maximum(node->right);
}

6. 從二叉樹中刪除最小/大值所在節(jié)點(diǎn)

void removeMin(){
    if( root )
        root = removeMin( root );
}

// 刪除掉以node為根的二分搜索樹中的最小節(jié)點(diǎn)
// 返回刪除節(jié)點(diǎn)后新的二分搜索樹的根
Node* removeMin(Node* node){

    if( node->left == NULL ){

        Node* rightNode = node->right;
        delete node;
        count --;
        return rightNode;
    }

    node->left = removeMin(node->left);
    return node;
}
void removeMax(){
    if( root )
        root = removeMax( root );
}

// 刪除掉以node為根的二分搜索樹中的最大節(jié)點(diǎn)
// 返回刪除節(jié)點(diǎn)后新的二分搜索樹的根
Node* removeMax(Node* node){

    if( node->right == NULL ){

        Node* leftNode = node->left;
        delete node;
        count --;
        return leftNode;
    }

    node->right = removeMax(node->right);
    return node;
}

7. 刪除remove

void remove(Key key){
    root = remove(root, key);
}

// 刪除掉以node為根的二分搜索樹中鍵值為key的節(jié)點(diǎn)
// 返回刪除節(jié)點(diǎn)后新的二分搜索樹的根
Node* remove(Node* node, Key key){

    if( node == NULL )
        return NULL;

    if( key < node->key ){
        node->left = remove( node->left , key );
        return node;
    }
    else if( key > node->key ){
        node->right = remove( node->right, key );
        return node;
    }
    else{   // key == node->key

        if( node->left == NULL ){
            Node *rightNode = node->right;
            delete node;
            count --;
            return rightNode;
        }

        if( node->right == NULL ){
            Node *leftNode = node->left;
            delete node;
            count--;
            return leftNode;
        }

        // node->left != NULL && node->right != NULL
        Node *successor = new Node(minimum(node->right));
        count ++;

        successor->right = removeMin(node->right);
        successor->left = node->left;

        delete node;
        count --;

        return successor;
    }
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末蚁署,一起剝皮案震驚了整個(gè)濱河市匕积,隨后出現(xiàn)的幾起案子亭病,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,386評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異,居然都是意外死亡枪狂,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,142評論 3 394
  • 文/潘曉璐 我一進(jìn)店門宋渔,熙熙樓的掌柜王于貴愁眉苦臉地迎上來州疾,“玉大人,你說我怎么就攤上這事皇拣⊙媳停” “怎么了?”我有些...
    開封第一講書人閱讀 164,704評論 0 353
  • 文/不壞的土叔 我叫張陵氧急,是天一觀的道長颗胡。 經(jīng)常有香客問我,道長吩坝,這世上最難降的妖魔是什么毒姨? 我笑而不...
    開封第一講書人閱讀 58,702評論 1 294
  • 正文 為了忘掉前任,我火速辦了婚禮钉寝,結(jié)果婚禮上弧呐,老公的妹妹穿的比我還像新娘闸迷。我一直安慰自己,他們只是感情好俘枫,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,716評論 6 392
  • 文/花漫 我一把揭開白布腥沽。 她就那樣靜靜地躺著,像睡著了一般崩哩。 火紅的嫁衣襯著肌膚如雪巡球。 梳的紋絲不亂的頭發(fā)上言沐,一...
    開封第一講書人閱讀 51,573評論 1 305
  • 那天邓嘹,我揣著相機(jī)與錄音,去河邊找鬼险胰。 笑死汹押,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的起便。 我是一名探鬼主播棚贾,決...
    沈念sama閱讀 40,314評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼榆综!你這毒婦竟也來了妙痹?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,230評論 0 276
  • 序言:老撾萬榮一對情侶失蹤鼻疮,失蹤者是張志新(化名)和其女友劉穎怯伊,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體判沟,經(jīng)...
    沈念sama閱讀 45,680評論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡耿芹,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,873評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了挪哄。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片吧秕。...
    茶點(diǎn)故事閱讀 39,991評論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖迹炼,靈堂內(nèi)的尸體忽然破棺而出砸彬,到底是詐尸還是另有隱情,我是刑警寧澤斯入,帶...
    沈念sama閱讀 35,706評論 5 346
  • 正文 年R本政府宣布砂碉,位于F島的核電站,受9級特大地震影響咱扣,放射性物質(zhì)發(fā)生泄漏绽淘。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,329評論 3 330
  • 文/蒙蒙 一闹伪、第九天 我趴在偏房一處隱蔽的房頂上張望沪铭。 院中可真熱鬧壮池,春花似錦、人聲如沸杀怠。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,910評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽赔退。三九已至橙依,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間硕旗,已是汗流浹背窗骑。 一陣腳步聲響...
    開封第一講書人閱讀 33,038評論 1 270
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留漆枚,地道東北人创译。 一個(gè)月前我還...
    沈念sama閱讀 48,158評論 3 370
  • 正文 我出身青樓,卻偏偏與公主長得像墙基,于是被迫代替她去往敵國和親软族。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,941評論 2 355

推薦閱讀更多精彩內(nèi)容

  • 背景 一年多以前我在知乎上答了有關(guān)LeetCode的問題, 分享了一些自己做題目的經(jīng)驗(yàn)残制。 張土汪:刷leetcod...
    土汪閱讀 12,745評論 0 33
  • 二叉查找樹(Binary Sort Tree) 我們之前所學(xué)到的列表立砸,棧等都是一種線性的數(shù)據(jù)結(jié)構(gòu),今天我們將學(xué)習(xí)計(jì)...
    Cryptic閱讀 5,008評論 1 19
  • 概述 在分析樹形結(jié)構(gòu)之前初茶,先看一下樹形結(jié)構(gòu)在整個(gè)數(shù)據(jù)結(jié)構(gòu)中的位置 當(dāng)然颗祝,沒有圖,現(xiàn)在還沒有足夠的水平去分析圖這種太...
    wustor閱讀 2,057評論 0 3
  • 基本概念:每個(gè)節(jié)點(diǎn)的子樹最多為2個(gè)的樹纺蛆。 幾個(gè)基本性質(zhì): 1吐葵、二叉樹第i層上的結(jié)點(diǎn)數(shù)目最多為 2^(i-1) (i...
    知城閱讀 306評論 0 0
  • 小白兔因?yàn)閻圩兂闪诵⌒?從前有一個(gè)小熊,撿到了一個(gè)貝殼桥氏。他說:“這是我的耳朵温峭。”他每天都把貝殼掛在頭上字支,叮鈴鈴凤藏,叮...
    思茲念茲閱讀 486評論 0 1