[數(shù)據(jù)結(jié)構(gòu)]C++實現(xiàn)二叉樹及其遍歷

溫故而知新垂睬。本文將回顧二叉搜索樹的基本知識,并用C++將它的三種depth-first search: 前序遍歷辰斋、中序遍歷和后序遍歷退子,以及一種breath first search: 層序遍歷算法分別實現(xiàn)出來。

1. BST的結(jié)構(gòu)

首先切端,我們先定義樹的結(jié)構(gòu):

struct node
{
    int data;
    node *leftchild;
    node *rightchild;
    node(int val)
    {
        data = val;
        leftchild = NULL;
        rightchild = NULL;
    }
};

接下來彻坛,我們實現(xiàn)基本的插入節(jié)點操作。根據(jù)BST的特點,要求保持節(jié)點之間的有序性昌屉,即左節(jié)點<根節(jié)點<右節(jié)點钙蒙。首先找到新節(jié)點的插入位置,再將其插入即可怠益。

void insert(node* root,int val)
{
    node* tmp = new node(val);//創(chuàng)建新節(jié)點
    if(root == NULL)
    {
        root = tmp;
        return;
    }
    node* pre = root;
    while(true)
    {
    
        if(pre->data >= val)
        {
            if(pre->leftchild == NULL)
            {
                pre->leftchild = tmp;
                return;
            }
            pre = pre->leftchild;
        }
        else
        {
            if(pre->rightchild == NULL)
            {
                pre->rightchild = tmp;
                return;
            }
            pre = pre->rightchild;
        }
    }
};

2. 前序仪搔、中序、后序遍歷的遞歸實現(xiàn)

首先明確一下三種遍歷的基本概念:

  • 前序遍歷:根節(jié)點->左子樹->右子樹
  • 中序遍歷:左子樹->根節(jié)點->右子樹
  • 后序遍歷:左子樹->右子樹->根節(jié)點

其中中序遍歷比較特別蜻牢,因為按照中序遍歷BST能夠得到有序的數(shù)列烤咧,這在很多題目中都有所應(yīng)用。

只要理解了三種遍歷的基本概念抢呆,它們的遞歸實現(xiàn)都比較容易寫出煮嫌。

void preordertree(node* root)
{
    if(root == NULL) return;
    if(root!=NULL)
    {
    std::cout << root->data << " ";
    preordertree(root->leftchild);
    preordertree(root->rightchild);
    }
};
void postordertree(node* root)
{
    if(root == NULL) return;
    if(root)
    {
        postordertree(root->leftchild);
        postordertree(root->rightchild);
        std::cout << root->data << " ";
    }
}
void inordertree(node* root)
{
    if(root)
    {
        inordertree(root->leftchild);
        std::cout << root->data << " ";
        inordertree(root->rightchild);
    }
}

3. 前序、中序抱虐、后序遍歷的非遞歸實現(xiàn)

3.1 前序遍歷的非遞歸實現(xiàn)

前序遍歷的非遞歸實現(xiàn)主要需要借助stack昌阿。對于stack中任意一個節(jié)點,先訪問其本身并將其pop出來恳邀,再將其右節(jié)點和左節(jié)點分別壓入棧中即可懦冰。

void iterpreordertree(node* root)
{
    if(root == NULL) return;
    
    std::stack<node *> nstack;
    nstack.push(root);
    
    while(!nstack.empty())
    {
        node* tmp = nstack.top();
        std::cout << tmp->data << " ";
        nstack.pop();
        
        if(tmp->rightchild)
            nstack.push(tmp->rightchild);
        if (tmp->leftchild)
            nstack.push(tmp->leftchild);
    }
    std::cout << std::endl;
}

3.2 中序遍歷的非遞歸實現(xiàn)

中序遍歷的非遞歸實現(xiàn)的主要難點在于:因為首先要尋找到左節(jié)點,訪問完畢后需要回到根節(jié)點谣沸,并轉(zhuǎn)換方向?qū)ふ矣覀?cè)子樹刷钢。這里,我們用一個棧stack和一個節(jié)點cur來追蹤乳附。首先將cur指定為根節(jié)點内地。

  1. 不斷搜尋cur的左子樹,并將中間路過的節(jié)點壓入棧中赋除。
  2. 當(dāng)左子樹搜尋完畢之后阱缓,將cur重新賦值為nstack.top(),訪問過后將其彈出举农。
  3. 轉(zhuǎn)換cur到其右子樹上荆针,并重復(fù)步驟1。
void iterinordertree(node* root)
{
    if(root == NULL) return;
    
    std::stack<node *> nstack;
    node* cur = root;
    
    while(cur || !nstack.empty())
    {
        //if cur is not NULL
        if(cur)
        {
            nstack.push(cur);
            cur = cur->leftchild;
        }
        else{
            cur = nstack.top();
            std::cout << cur->data << " ";
            nstack.pop();
            
            cur = cur->rightchild;
        }
    }
    
    std::cout << std::endl;
}

3.3 后序遍歷的非遞歸實現(xiàn)

后序遍歷的非遞歸實現(xiàn)是三者中最難的颁糟,需要借助兩個stack來實現(xiàn)祭犯。

void iterpostordertree(node* root)
{
    if(root == NULL) return;
    
    std::stack<node *> first,second;
    first.push(root);
    
    while(!first.empty())
    {
        node* tmp = first.top();
        first.pop();
        second.push(tmp);
        
        if(tmp->leftchild)
            first.push(tmp->leftchild);
        if (tmp->rightchild)
            first.push(tmp->rightchild);
    }
    while (!second.empty()) {
        std::cout << second.top()->data << " ";
        second.pop();
    }
    std::cout << std::endl;
}

4. 層序遍歷

層序遍歷利用的是廣度優(yōu)先搜索,利用隊列滚停,每次訪問一層,并將下一層的節(jié)點入隊粥惧。

void breathfirst(node* root)
{
    if(root == NULL) return;
    
    std::queue<node *> nqueue;
    nqueue.push(root);
    
    while (!nqueue.empty()) {
        int n = nqueue.size();
        for(int i = 0; i < n; i++)
        {
            node* cur = nqueue.front();
            std::cout << cur->data << " ";
            nqueue.pop();
            if (cur->leftchild)
                nqueue.push(cur->leftchild);
            if(cur->rightchild)
                nqueue.push(cur->rightchild);
        }
    }
    std::cout << std::endl;
}

以上即是本文的全部內(nèi)容键畴,感謝關(guān)注。

代碼清單: https://github.com/ShulinLiu/DataStructure-Algorithm/blob/master/BasicDataStructure/tree/tree.cpp

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市起惕,隨后出現(xiàn)的幾起案子涡贱,更是在濱河造成了極大的恐慌,老刑警劉巖惹想,帶你破解...
    沈念sama閱讀 216,744評論 6 502
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件问词,死亡現(xiàn)場離奇詭異,居然都是意外死亡嘀粱,警方通過查閱死者的電腦和手機激挪,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,505評論 3 392
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來锋叨,“玉大人垄分,你說我怎么就攤上這事⊥藁牵” “怎么了薄湿?”我有些...
    開封第一講書人閱讀 163,105評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長偷卧。 經(jīng)常有香客問我豺瘤,道長,這世上最難降的妖魔是什么听诸? 我笑而不...
    開封第一講書人閱讀 58,242評論 1 292
  • 正文 為了忘掉前任坐求,我火速辦了婚禮,結(jié)果婚禮上蛇更,老公的妹妹穿的比我還像新娘瞻赶。我一直安慰自己,他們只是感情好派任,可當(dāng)我...
    茶點故事閱讀 67,269評論 6 389
  • 文/花漫 我一把揭開白布砸逊。 她就那樣靜靜地躺著,像睡著了一般掌逛。 火紅的嫁衣襯著肌膚如雪师逸。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,215評論 1 299
  • 那天豆混,我揣著相機與錄音篓像,去河邊找鬼。 笑死皿伺,一個胖子當(dāng)著我的面吹牛员辩,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播鸵鸥,決...
    沈念sama閱讀 40,096評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼奠滑,長吁一口氣:“原來是場噩夢啊……” “哼丹皱!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起宋税,我...
    開封第一講書人閱讀 38,939評論 0 274
  • 序言:老撾萬榮一對情侶失蹤摊崭,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后杰赛,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體呢簸,經(jīng)...
    沈念sama閱讀 45,354評論 1 311
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,573評論 2 333
  • 正文 我和宋清朗相戀三年乏屯,在試婚紗的時候發(fā)現(xiàn)自己被綠了根时。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,745評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡瓶珊,死狀恐怖啸箫,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情伞芹,我是刑警寧澤忘苛,帶...
    沈念sama閱讀 35,448評論 5 344
  • 正文 年R本政府宣布,位于F島的核電站唱较,受9級特大地震影響扎唾,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜南缓,卻給世界環(huán)境...
    茶點故事閱讀 41,048評論 3 327
  • 文/蒙蒙 一胸遇、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧汉形,春花似錦纸镊、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,683評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至岔冀,卻和暖如春凯旭,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背使套。 一陣腳步聲響...
    開封第一講書人閱讀 32,838評論 1 269
  • 我被黑心中介騙來泰國打工罐呼, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人侦高。 一個月前我還...
    沈念sama閱讀 47,776評論 2 369
  • 正文 我出身青樓嫉柴,卻偏偏與公主長得像,于是被迫代替她去往敵國和親奉呛。 傳聞我的和親對象是個殘疾皇子差凹,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,652評論 2 354