【數(shù)據(jù)結(jié)構(gòu)】——二叉樹的遍歷算法

題目要求

編寫程序普监,用先序遞歸遍歷法(或輸入先序及中序遞歸遍歷結(jié)點訪問序列)建立二叉樹的二叉鏈表存儲結(jié)構(gòu)贵试,計算并輸出二叉樹的結(jié)點總數(shù)以及樹的高度;然后輸出其先序凯正、中序毙玻、后序以及層次遍歷結(jié)點訪問次序。其中層次遍歷的實現(xiàn)需使用循環(huán)隊列廊散。二叉樹結(jié)點數(shù)據(jù)類型建議選用字符類型桑滩。

數(shù)據(jù)結(jié)構(gòu)設(shè)計

采用C++的模板類运准,創(chuàng)建隊列。每個隊列對象中缭受,elem指針用來建立長度為n的數(shù)組胁澳,n表示隊列的容量,front表示隊頭指針米者,rear表示隊尾指針胰丁,c表示隊列中當(dāng)前元素的個數(shù)。
采用結(jié)構(gòu)體建立二叉樹喂分,其中锦庸,data表示數(shù)據(jù)域,lchild表示左指針妻顶,rchild表示右指針酸员,BiT表示二叉樹結(jié)構(gòu)體指針類型變量蜒车,BiTNode表示二叉樹結(jié)構(gòu)體類型變量。

算法設(shè)計簡要描述

  1. 先序遍歷建立二叉樹:遞歸調(diào)用函數(shù)幔嗦,不斷讀取字符酿愧,依次建立左子樹和右子樹,當(dāng)讀取到‘#’字符時邀泉,返回NULL指針嬉挡,最終返回根結(jié)點指針。
  2. 先序和中序遍歷結(jié)點訪問序列建立二叉樹:
    a. 先由先序序列求得根節(jié)點汇恤;
    b. 再由根節(jié)點在中序序列中的位置庞钢,知:它之前的訪問的結(jié)點為其左子樹結(jié)點,它之后訪問的為其右子樹結(jié)點因谎;
    c. 遞歸應(yīng)用a基括,b兩條。

程序代碼

#include <conio.h>
#include <iostream>
using namespace std;
typedef char ElemTp;
#define MAX 20
template <typename T>
class Queue                         //模板類:隊列
{
public:
    Queue();                        //默認(rèn)構(gòu)造函數(shù)
    Queue(int n);                   //構(gòu)造函數(shù)财岔,調(diào)用函數(shù)createQueue(int n)风皿,創(chuàng)建長度為n的隊列
    ~Queue();                       //虛構(gòu)函數(shù)
    int createQueue(int n);         //創(chuàng)建長度為n的隊列
    int empty();                    //判斷隊列是否為空
    int full();                     //判斷隊列是否為滿
    int enQueue(T e);               //元素e入隊
    int dlQueue(T &e);              //元素出隊,保存在e中
private:
    T *elem;                        //建立長度為n的數(shù)組
    int n;                          //隊列容量
    int front;                      //隊頭指針
    int rear;                       //隊尾指針
    int c;                          //隊列當(dāng)前元素個數(shù)
};
typedef struct node
{
    ElemTp data;                    //數(shù)據(jù)域
    struct node *lchild,            //左指針
        *rchild;                    //右指針
}*BiT,BiTNode;
 
void visit(BiT e)                   //訪問函數(shù)      
{
    if (e->data != NULL)            //輸出二叉樹的數(shù)據(jù)域
        cout << e->data << "  ";
}
void preorder(BiT bt)               //先序遍歷二叉樹
{
    if (bt)
    {
        visit(bt);                  //訪問根節(jié)點
        preorder(bt->lchild);       //遞歸調(diào)用遍歷左子樹
        preorder(bt->rchild);       //遞歸調(diào)用遍歷右子樹
    }
}
void midorder(BiT bt)               //中序遍歷二叉樹
{
    if (bt)
    {
        midorder(bt->lchild);       //遞歸調(diào)用遍歷左子樹
        visit(bt);                  //訪問根節(jié)點
        midorder(bt->rchild);       //遞歸調(diào)用遍歷右子樹
    }
}
void lasorder(BiT bt)               //后序遍歷二叉樹
{
    if (bt)
    {
        lasorder(bt->lchild);       //遞歸調(diào)用遍歷左子樹
        lasorder(bt->rchild);       //遞歸調(diào)用遍歷右子樹
        visit(bt);                  //訪問根節(jié)點
    }
}
void layertravel(BiT bt)            //層次遍歷二叉樹
{
    if (bt == NULL)
        return;
    Queue<BiT> q(MAX);              //建立隊列
    q.enQueue(bt);                  //根節(jié)點入隊
    while (!q.empty())
    {
        q.dlQueue(bt);              //根節(jié)點出隊
        visit(bt);                  //訪問根節(jié)點
        if (bt->lchild)
            q.enQueue(bt->lchild);  //左子樹不空匠璧,訪問左子樹
        if (bt->rchild)
            q.enQueue(bt->rchild);  //右子樹不空桐款,訪問右子樹
    }
}
BiT crtPreBT()                      //先序遞歸遍歷建立二叉樹算法
{
    BiT bt;
    char ch;
    ch = getchar();
    if (ch == '#')                  //讀到‘#’返回NULL指針
        return NULL;
    bt = new BiTNode();             //建立新的二叉樹結(jié)點
    bt->data = ch;
    bt->lchild = crtPreBT();        //遞歸建立左子樹
    bt->rchild = crtPreBT();        //遞歸建立右子樹
    return bt;
}
BiT crtPreMidBT(char *pr, int &i, char *mi, int u, int v)  //先序及中序遞歸遍歷結(jié)點訪問序列建立二叉樹算法
{
    BiT bt;
    int k;
    if (u > v)
        return NULL;
    bt = new BiTNode();                     
    bt->data = pr[i++];              //pr[i]為子樹根節(jié)點
    for (k = u; k <= v; k++)         //mi[u...v]為子樹中序序列
    {
        if (mi[k] == bt->data)       //查找根節(jié)點在中序序列中的位置
            break;
    }
    bt->lchild = crtPreMidBT(pr, i, mi, u, k - 1);  //遞歸建立左子樹
    bt->rchild = crtPreMidBT(pr, i, mi, k + 1, v);  //遞歸建立右子樹
    return bt;
}
int height(BiT bt)                   //計算二叉樹的高度
{
    int hl, hr;
    if (!bt)
        return 0;
    hl = height(bt->lchild);         //遞歸計算左子樹的高度
    hr = height(bt->rchild);         //遞歸計算右子樹的高度
    return (hl > hr) ? (hl + 1) : (hr + 1);       //返回整個二叉樹的高度(左、右子樹高度較大的值加一)
}
int nodeNum(BiT bt)                  //計算二叉樹的總結(jié)點數(shù)
{
    int nl, nr;
    if (!bt)
        return 0;
    nl = nodeNum(bt->lchild);        //遞歸計算左子樹的結(jié)點數(shù)  
    nr = nodeNum(bt->rchild);        //遞歸計算右子樹的結(jié)點數(shù)
    return nl + nr + 1;              //返回整個二叉樹的結(jié)點數(shù)(左夷恍、右子樹結(jié)點數(shù)之和加一)
}
void choose(BiT &bt)                 //選擇建立二叉樹的方式
{
    char num, pre[MAX], mid[MAX];
    int i = 0, u = 0, v;
    cout << "請選擇建立二叉樹的方式:  " << endl;
    cout << "1.   先序遍歷建立二叉樹" << endl;
    cout << "2.   先序和中序遍歷建立二叉樹" << endl;
    num = _getch();
    switch (num)
    {
    case '1':                        //先序遍歷建立二叉樹
    {
        cout << "您選擇了第一種方式." << endl;
        cout << "請輸入先序遍歷的字符序列: " << endl;
        bt = crtPreBT();
    }   break;
    case '2':                        //先序和中序遍歷建立二叉樹
    {
        cout << "您選擇了第二種方式." << endl;
        cout << "請輸入先序遍歷的字符序列: " << endl;
        cin.getline(pre, MAX);
        cout << "請輸入中序遍歷的字符序列: " << endl;
        cin.getline(mid, MAX);
        v = strlen(mid) - 1;
        bt = crtPreMidBT(pre, i, mid, u, v);
    }   break;
    }
}
template<typename T>
Queue<T>::Queue()                           
{
    front = rear = -1;
    c = 0;
}
template<typename T>
Queue<T>::Queue(int n)                          
{
    createQueue(n);
}
template<typename T>
Queue<T>::~Queue()
{
    c = 0;
    front = rear = -1;
    delete[]elem;
}
template<typename T>
int Queue<T>::createQueue(int n)
{
    if (n <= 0)
        return 0;
    this->n = n;
    c = 0;
    front = rear = -1;
    elem = new T[n];
    if (!elem)
        return 0;
    return 1;
}
template<typename T>
int Queue<T>::empty()
{
    return c == 0;
}
template<typename T>
int Queue<T>::full()
{
    return c == n;
}
template<typename T>
int Queue<T>::enQueue(T e)
{
    if (c == n)
        return 0;                       //隊滿魔眨,入隊失敗
    rear = (rear + 1) % n;
    elem[rear] = e;
    c++;
    return 1;                           //入隊成功返回1
}
template<typename T>
int Queue<T>::dlQueue(T & e)
{
    if (c == 0)
        return 0;                       //隊空,出隊失敗
    front = (front + 1) % n;
    e = elem[front];
    c--;
    return 1;                           //出隊成功返回1
}
int main()
{
    int h, num;
    BiT bt;
    choose(bt);
    h = height(bt);
    cout << "二叉樹的高度是: " << h << endl;
    num = nodeNum(bt);
    cout << "二叉樹的總結(jié)點數(shù)是: " << num << endl;
    cout << "先序遍歷結(jié)點訪問次序: " << endl;
    preorder(bt);
    cout << endl;
    cout << "中序遍歷結(jié)點訪問次序: " << endl;
    midorder(bt);
    cout << endl;
    cout << "后序遍歷結(jié)點訪問次序: " << endl;
    lasorder(bt);
    cout << endl;
    cout << "層次遍歷結(jié)點訪問次序: " << endl;
    layertravel(bt);
    cout << endl;
    return 0;
}

示例

(1)程序輸入
先序序列:abc##de#g##f###
程序輸出
二叉樹的高度是:5
二叉樹的總結(jié)點數(shù)是:7
先序遍歷:a b c d e g f
中序遍歷:c b e g d f a
后序遍歷:c g e f d b a
層次遍歷:a b c d e f g


(2)程序輸入
先序序列:ABCDEFG
中序序列:CBEDAFG
程序輸出
二叉樹的高度是:4
二叉樹的總結(jié)點數(shù)是:7
先序遍歷:A B C D E F G
中序遍歷:C B E D A F G
后序遍歷:C E D B G F A
層次遍歷:A B F C D G E

(3)程序輸入
先序序列:ABDF####C#E#G#H##
程序輸出
二叉樹的高度是:5
二叉樹的總結(jié)點數(shù)是:8
先序遍歷:A B D F C E G H
中序遍歷:F D B A C E G H
后序遍歷:F D B H G E C A
層次遍歷:A B C D E F G H

(4)程序輸入
先序序列:#
程序輸出
二叉樹的高度是:0
二叉樹的總結(jié)點數(shù)是:0

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末酿雪,一起剝皮案震驚了整個濱河市遏暴,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌指黎,老刑警劉巖拓挥,帶你破解...
    沈念sama閱讀 216,591評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異袋励,居然都是意外死亡侥啤,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,448評論 3 392
  • 文/潘曉璐 我一進(jìn)店門茬故,熙熙樓的掌柜王于貴愁眉苦臉地迎上來盖灸,“玉大人,你說我怎么就攤上這事磺芭×扪祝” “怎么了?”我有些...
    開封第一講書人閱讀 162,823評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長徙垫。 經(jīng)常有香客問我讥裤,道長,這世上最難降的妖魔是什么姻报? 我笑而不...
    開封第一講書人閱讀 58,204評論 1 292
  • 正文 為了忘掉前任己英,我火速辦了婚禮,結(jié)果婚禮上吴旋,老公的妹妹穿的比我還像新娘损肛。我一直安慰自己,他們只是感情好荣瑟,可當(dāng)我...
    茶點故事閱讀 67,228評論 6 388
  • 文/花漫 我一把揭開白布治拿。 她就那樣靜靜地躺著,像睡著了一般笆焰。 火紅的嫁衣襯著肌膚如雪劫谅。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,190評論 1 299
  • 那天嚷掠,我揣著相機(jī)與錄音同波,去河邊找鬼。 笑死叠国,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的戴尸。 我是一名探鬼主播粟焊,決...
    沈念sama閱讀 40,078評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼孙蒙!你這毒婦竟也來了项棠?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,923評論 0 274
  • 序言:老撾萬榮一對情侶失蹤挎峦,失蹤者是張志新(化名)和其女友劉穎香追,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體坦胶,經(jīng)...
    沈念sama閱讀 45,334評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡透典,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,550評論 2 333
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了顿苇。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片峭咒。...
    茶點故事閱讀 39,727評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖纪岁,靈堂內(nèi)的尸體忽然破棺而出凑队,到底是詐尸還是另有隱情,我是刑警寧澤幔翰,帶...
    沈念sama閱讀 35,428評論 5 343
  • 正文 年R本政府宣布漩氨,位于F島的核電站西壮,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏叫惊。R本人自食惡果不足惜款青,卻給世界環(huán)境...
    茶點故事閱讀 41,022評論 3 326
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望赋访。 院中可真熱鬧可都,春花似錦、人聲如沸蚓耽。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,672評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽步悠。三九已至签杈,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間鼎兽,已是汗流浹背答姥。 一陣腳步聲響...
    開封第一講書人閱讀 32,826評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留谚咬,地道東北人鹦付。 一個月前我還...
    沈念sama閱讀 47,734評論 2 368
  • 正文 我出身青樓,卻偏偏與公主長得像择卦,于是被迫代替她去往敵國和親敲长。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,619評論 2 354