課程設(shè)計(jì)——非遞歸實(shí)現(xiàn)二叉樹的三種遍歷算法及創(chuàng)建排序二叉樹

本次課程設(shè)計(jì)主要含三部分內(nèi)容,并且每一部分內(nèi)容獨(dú)立為一個(gè)小的課程設(shè)計(jì)

1.二叉樹的建立及其非遞歸的先序悠瞬、中序昵骤、后序遍歷;
2.二叉樹的層序遍歷
3.排序二叉樹的創(chuàng)建及中序遍歷輸出

  • 首先我們來(lái)實(shí)現(xiàn)第一小部分的內(nèi)容交惯,先序遞歸構(gòu)建二叉樹并按非遞歸的方法對(duì)其進(jìn)行先序次泽、中序和后序遍歷。

接下來(lái)我們用下面這顆二叉樹作為我們示例進(jìn)行演示席爽,我們示例二叉樹長(zhǎng)這樣:

圖1 示例二叉樹

在前序遍歷生成二叉樹中意荤,我們用‘#’表示結(jié)點(diǎn)為NULL,因此前序遍歷生成二叉樹時(shí)的輸入序列應(yīng)該為:"abd#h##k##cef##g##m##"只锻。通過(guò)CreateTree()函數(shù)我們就建立起了一顆如上圖所示的二叉樹玖像,然后就可以愉快的開始各種遍歷測(cè)試了,具體代碼如下:

#include<stdio.h>
#include<stdlib.h>

typedef struct treeNode{
    char data;
    struct treeNode*rchild, *lchild;
}TreeNode;

char str[] = "abd#h##k##cef##g##m##";
int pos = 0;

void CreateTree(TreeNode** T)
{//前序遞歸創(chuàng)建二叉樹
    char ch;
    //scanf("%c", &ch);//讀入字符
    ch = str[pos++];
    if (ch == '#')//.代表空子樹
        *T = NULL;
    else
    {
        *T = (TreeNode *)malloc(sizeof(TreeNode));
        if (!(*T))
        {
            printf("開辟內(nèi)存失敗\n");
            exit(1);
        }
        (*T)->data = ch;//給T賦值
        CreateTree(&(*T)->lchild);//給左子樹賦值
        CreateTree(&(*T)->rchild);//給右子樹賦值
    }
}

void preorderTraversal(TreeNode* root)
{
    if (!root)
        return;

    TreeNode* stack[10]; int top = -1;
    stack[++top] = root;

    while (top > -1)
    {
        TreeNode* temp = stack[top--];
        printf("%c ", temp->data);
        
        if (temp->rchild)
            stack[++top] = temp->rchild;
        if (temp->lchild)
            stack[++top] = temp->lchild;
    }

}
void midorderTraversal(TreeNode* root)
{//中序非遞歸遍歷二叉樹

    TreeNode *stack[10]; int top = -1;
    TreeNode *p = root;
    while (p != NULL || top > -1)
    {
        while (p != NULL)
        {
            stack[++top] = p;
            p = p->lchild;
        }
        if (top > -1)
        {
            p = stack[top];
            printf("%c ", p->data);
            --top;
            p = p->rchild;
        }
    }

}

typedef struct tempNode{
    TreeNode* btnode;
    bool isFirst;
}TempNode;
void postorderTraversal(TreeNode* root)
{//后續(xù)非遞歸遍歷二叉樹
    TempNode *stack[10]; int top = -1;
    TreeNode *p = root;
    TempNode *temp;
    while (p != NULL || top > -1)
    {
        while (p != NULL) //沿左子樹一直往下搜索齐饮,直至出現(xiàn)沒(méi)有左子樹的結(jié)點(diǎn)
        {
            TempNode *tempNode = new TempNode;
            tempNode->btnode = p;
            tempNode->isFirst = true;
            stack[++top] = tempNode;
            p = p->lchild;
        }
        if (top > -1)
        {
            temp = stack[top--];
            if (temp->isFirst == true)   //表示是第一次出現(xiàn)在棧頂
            {
                temp->isFirst = false;
                stack[++top] = temp;
                p = temp->btnode->rchild;
            }
            else  //第二次出現(xiàn)在棧頂
            {
                printf("%c ", temp->btnode->data);
                p = NULL;
            }
        }
    }
}

int choice()
{
    printf("*********歡迎來(lái)到二叉樹非遞歸遍歷演示界面************\n");
    printf("0-退出\n");
    printf("1-顯示前序非遞歸遍歷結(jié)果\n");
    printf("2-顯示中序非遞歸遍歷結(jié)果\n");
    printf("3-顯示后序非遞歸遍歷結(jié)果\n");

    int n;
    printf("請(qǐng)選擇:"); scanf("%d", &n);
    return n;
}

int main()
{
    //freopen("data.txt", "r", stdin);
    TreeNode* root;
    CreateTree(&root);
    int n;
    while (1)
    {
        n = choice();
        if (!(n >= 0 && n <= 3))
        {
            printf("菜單選擇錯(cuò)誤");
            continue;
        }
        if (n == 0)break;
        switch (n)
        {
        case 1:printf("前序遍歷結(jié)果:");
            preorderTraversal(root); break;
        case 2: printf("中序遍歷結(jié)果:");
            midorderTraversal(root);
            break;
        case 3:
            printf("\n后序遍歷結(jié)果:");
            postorderTraversal(root);
            break;
        }
        putchar('\n');
        system("pause"); system("cls");
    }
}//運(yùn)行結(jié)果ok 2019年5月26日15:36:55

以上代碼的運(yùn)行結(jié)果為:


圖2 前序遍歷
圖3 中序遍歷
圖4 后續(xù)遍歷

通過(guò)比較我在圖1中手動(dòng)遍歷的結(jié)果與程序運(yùn)行之后的結(jié)果捐寥,可以看到我們的代碼給出了正確的結(jié)果。


  • 接下來(lái)我們?cè)倮^續(xù)第二個(gè)小設(shè)計(jì)——二叉樹的層序遍歷祖驱,這部分內(nèi)容比較簡(jiǎn)單握恳,沒(méi)什么好講述的直接貼代碼好了,代碼如下:
#include<stdio.h>
#include<stdlib.h>
#include<stack>
using namespace std;

typedef struct treeNode{
    char data;
    struct treeNode*rchild, *lchild;
}TreeNode;

void CreateTree(TreeNode** T)
{//前序遞歸創(chuàng)建二叉樹
    char ch;
    scanf("%c", &ch);//讀入字符
    if (ch == '#')//.代表空子樹
        *T = NULL;
    else
    {
        *T = (TreeNode *)malloc(sizeof(TreeNode));
        if (!(*T))
        {
            printf("開辟內(nèi)存失敗\n");
            exit(1);
        }
        (*T)->data = ch;//給T賦值
        CreateTree(&(*T)->lchild);//給左子樹賦值
        CreateTree(&(*T)->rchild);//給右子樹賦值
    }
}

void levelorderTraversal(TreeNode*root)
{//二叉樹從左至右捺僻,從上至下層次遍歷
    int front, rear;
    TreeNode*que[10];
    front = rear = 0;
    TreeNode*q;
    if (root)
    {
        rear = (rear + 1) % 10;
        que[rear] = root;
        while (front != rear)
        {
            front = (front + 1) % 10;
            q = que[front];
            printf("%c ", q->data);
            if (q->lchild)
            {
                rear = (rear + 1) % 10;
                que[rear] = q->lchild;
            }
            if (q->rchild)
            {
                rear = (rear + 1) % 10;
                que[rear] = q->rchild;
            }
        }
    }
}


int main()
{
    freopen("data.txt", "r", stdin);
    TreeNode* root;
    CreateTree(&root);

    printf("層序遍歷結(jié)果:");
    levelorderTraversal(root);

    putchar('\n');
}//運(yùn)行結(jié)果ok2019年5月26日14:37:20

這是一個(gè)完整可以執(zhí)行出結(jié)果的代碼睡互,不過(guò)我們重定義了標(biāo)準(zhǔn)輸入為“data.txt”,因此運(yùn)行這段代碼之前你需要在程序所在的文件夾內(nèi)創(chuàng)建名為“data.txt”的文件陵像,并將"abd#h##k##cef##g##m##"寫入該文件保存(字符串不含引號(hào))就珠,然后程序就可以直接從“data.txt”文本中讀入二叉樹的數(shù)據(jù),并將按層序遍歷的結(jié)果輸出醒颖。演示結(jié)果為:


圖5 層序遍歷結(jié)果

  • 完成了第二個(gè)關(guān)于層序遍歷的小任務(wù)妻怎,再讓我們來(lái)看最后一個(gè)與排序二叉樹有關(guān)的小任務(wù)。
    該任務(wù)比較簡(jiǎn)單泞歉,要求我們首先生成一顆二叉排序樹逼侦,然后對(duì)其進(jìn)行中序遍歷匿辩,輸出遞增序列。由于中序遍歷我們?cè)谌蝿?wù)一中已經(jīng)完成了榛丢,因此只需要構(gòu)建一個(gè)能生成二叉排序樹的函數(shù)就可以了铲球,這里我們采用遞歸的方式來(lái)實(shí)現(xiàn),具體代碼如下:
#include<stdio.h>
#include<stdlib.h>
#include<time.h>

typedef struct treeNode{
    int data;
    struct treeNode*rchild, *lchild;
}TreeNode;

bool CreateTree(TreeNode** root, int data)
{//二叉排序樹創(chuàng)建
    if ((*root) == NULL)    //如果為空晰赞,則創(chuàng)建一個(gè)節(jié)點(diǎn)
    {
        *root = (TreeNode *)malloc(sizeof(TreeNode));
        (*root)->data = data; ( *root)->lchild = (*root)->rchild = NULL;    //該節(jié)點(diǎn)為根節(jié)點(diǎn)稼病,左孩子和右孩子指針均置空
        return true;
    }
    else if (data == (*root)->data) //如果存在,則返回false
        return false;
    else if (data < (*root)->data)  //如果被插入數(shù)據(jù)較小掖鱼,則插入到左子樹
        return CreateTree(&((*root)->lchild), data);
    else    //如果被插入數(shù)據(jù)較大然走,則插入到右子數(shù)
        return CreateTree(&((*root)->rchild), data);
}

void midorderTraversal(TreeNode* root)
{//中序非遞歸遍歷二叉樹
    
    TreeNode *stack[10]; int top = -1;
    TreeNode *p = root;
    while (p != NULL ||  top > -1)
    {
        while (p != NULL)
        {
            stack[++top] = p;
            p = p->lchild;
        }
        if (top > -1)
        {
            p = stack[top];
            printf("%d ", p->data);
            --top;
            p = p->rchild;
        }
    }

}



int main()
{
    
    TreeNode* root = NULL;
    int data;
    srand((unsigned)time(NULL));
    printf("依次保存在排序樹中的值:");
    for (int i = 0; i < 10;)
    {//通過(guò)隨機(jī)生成數(shù)字建立二叉排序樹
        data = rand() % 20;
        
        if (CreateTree(&root, data))
        {
            printf("%d ", data);
            ++i;
        }
    }
    
    printf("\n中序遍歷結(jié)果:");
    midorderTraversal(root);

    putchar('\n');
}//運(yùn)行結(jié)果ok 2019年5月26日14:57:05

我們采用在main()函數(shù)中隨機(jī)生成0-19之間的數(shù)字的方式來(lái)構(gòu)建二叉排序樹,樹中的結(jié)點(diǎn)一共有10個(gè)戏挡,并且要求結(jié)點(diǎn)之間沒(méi)有重復(fù)的值芍瑞。隨機(jī)函數(shù)生成的值及排序結(jié)果輸出如下圖:
圖6 二叉排序樹演示結(jié)果
  • 感想:本次課程設(shè)計(jì)比較簡(jiǎn)單,但是它一次性的總結(jié)了二叉樹的創(chuàng)建褐墅、非遞歸先序拆檬、中序、后序及層序遍歷妥凳,對(duì)掌握二叉樹的遍歷方法比較全面系統(tǒng)竟贯,因此有必要進(jìn)行總結(jié),方便下次使用的時(shí)候直接參考或者拷貝代碼猾封。最后該課程設(shè)計(jì)也涉及了少量的二叉排序樹的知識(shí)澄耍,但是還不夠全面,對(duì)二叉排序樹的查找和結(jié)點(diǎn)刪除等相對(duì)復(fù)雜的點(diǎn)沒(méi)有過(guò)多涉及晌缘,以后還需要補(bǔ)充這方面的知識(shí)齐莲。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市磷箕,隨后出現(xiàn)的幾起案子选酗,更是在濱河造成了極大的恐慌,老刑警劉巖岳枷,帶你破解...
    沈念sama閱讀 217,406評(píng)論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件芒填,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡空繁,警方通過(guò)查閱死者的電腦和手機(jī)殿衰,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,732評(píng)論 3 393
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)盛泡,“玉大人闷祥,你說(shuō)我怎么就攤上這事“了校” “怎么了凯砍?”我有些...
    開封第一講書人閱讀 163,711評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵箱硕,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我悟衩,道長(zhǎng)剧罩,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,380評(píng)論 1 293
  • 正文 為了忘掉前任座泳,我火速辦了婚禮惠昔,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘钳榨。我一直安慰自己舰罚,他們只是感情好纽门,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,432評(píng)論 6 392
  • 文/花漫 我一把揭開白布薛耻。 她就那樣靜靜地躺著,像睡著了一般赏陵。 火紅的嫁衣襯著肌膚如雪饼齿。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,301評(píng)論 1 301
  • 那天蝙搔,我揣著相機(jī)與錄音缕溉,去河邊找鬼。 笑死吃型,一個(gè)胖子當(dāng)著我的面吹牛证鸥,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播勤晚,決...
    沈念sama閱讀 40,145評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼枉层,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了赐写?” 一聲冷哼從身側(cè)響起鸟蜡,我...
    開封第一講書人閱讀 39,008評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎挺邀,沒(méi)想到半個(gè)月后揉忘,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,443評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡端铛,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,649評(píng)論 3 334
  • 正文 我和宋清朗相戀三年泣矛,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片禾蚕。...
    茶點(diǎn)故事閱讀 39,795評(píng)論 1 347
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡您朽,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出夕膀,到底是詐尸還是另有隱情虚倒,我是刑警寧澤美侦,帶...
    沈念sama閱讀 35,501評(píng)論 5 345
  • 正文 年R本政府宣布,位于F島的核電站魂奥,受9級(jí)特大地震影響菠剩,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜耻煤,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,119評(píng)論 3 328
  • 文/蒙蒙 一具壮、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧哈蝇,春花似錦棺妓、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,731評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至吠勘,卻和暖如春性芬,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背剧防。 一陣腳步聲響...
    開封第一講書人閱讀 32,865評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工植锉, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人峭拘。 一個(gè)月前我還...
    沈念sama閱讀 47,899評(píng)論 2 370
  • 正文 我出身青樓俊庇,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親鸡挠。 傳聞我的和親對(duì)象是個(gè)殘疾皇子辉饱,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,724評(píng)論 2 354

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