前序遍歷和中序遍歷唯一確定一顆二叉樹


---恢復內容開始---

問題描述

如果給出了遍歷二叉樹的前序序列和中序序列,則可以構造出唯一的一顆二叉樹。

基本要求

已知一棵二叉樹的前序序列和中序序列,試設計完成下列任務的一個算法:

(1).構造一顆二叉樹

(2).證明構造正確(即分撥兒以前序和中序遍歷該樹,將得到的結果

與給出的序列進行比較)

(3).對該二叉樹進行后序遍歷,輸出后序遍歷序列

(4).用凹入法輸出該二叉樹

測試數據

前序序列為ABDEGCFHIJ,中序序列為DBGEAHFIJC                                                                             

 

代碼思路

1.確定樹的根節點,樹根是當前樹中所有元素在前序遍歷中最先出現的元素。

2.求解樹的子樹,找出根節點在中序遍歷中的位置,根左邊的所有元素就是左子樹,根右邊的所有元素就是右子樹。若根節點左邊或右邊為空,則該方向子樹為空;若根節點左邊和右邊都為空,則根節點已經為葉子節點。

3.遞歸求解樹,將左子樹和右子樹分別看成一棵二叉樹,重復1、2、3步,直到所有的節點完成定位。

 

源代碼

/*
1.確定樹的根節點,樹根是當前樹中所有元素在前序遍歷中最先出現的元素。
2.求解樹的子樹,找出根節點在中序遍歷中的位置,根左邊的所有元素就是左子樹,根右邊的所有元素就是右子樹。若根節點左邊或右邊為空,則該方向子樹為空;若根節點左邊和右邊都為空,則根節點已經為葉子節點。
3.遞歸求解樹,將左子樹和右子樹分別看成一棵二叉樹,重復1、2、3步,直到所有的節點完成定位。
*/

#include<iostream>
#include<algorithm>
#include<string>
#include<cstring>
using namespace std;

const int maxint = 10000;
char ch1[maxint], ch2[maxint]; //前序序列,中序序列
int length; //二叉樹結點的個數
struct tree {
    char name;
    struct tree *leftchild;
    struct tree *rightchild;
};

//訪問函數
void vis(char name) {
    cout << name;
}

//初始化
void init(struct tree **root){
    *root = (struct tree *)malloc(sizeof(struct tree));
    (*root)->leftchild = NULL;
    (*root)->rightchild = NULL;
}

//創建左子樹
struct tree *build_ltree(struct tree *h,char name) {
    struct tree *p, *t;
    if (h == NULL) return NULL;
    t = h->leftchild;
    p= (struct tree*)malloc(sizeof(struct tree));
    p->name = name;
    p->leftchild = t;
    p->rightchild = NULL;
    h->leftchild = p;
    return h->leftchild;
}

//創建右子樹
struct tree *build_rtree(struct tree *h, char name) {
    struct tree *p, *t;
    if (h == NULL) return NULL;
    t = h->rightchild;
    p = (struct tree*)malloc(sizeof(struct tree));
    p->name = name;
    p->leftchild = NULL;
    p->rightchild = t;
    h->rightchild = p;
    return h->rightchild;
}

//凹入法打印二叉樹
void print_tree(struct tree *t, int n) {
    if (t == NULL) return;
    print_tree(t->rightchild, n + 1);
    for (int i = 0; i < n - 1; i++) cout << "      ";
    if (n > 0) {
        cout<<"***";
        cout << t->name << endl;
    }
    print_tree(t->leftchild, n + 1);
}

//前序遍歷
void preorder(struct tree *t, void vis(char name)) {
    if (t != NULL) {
        vis(t->name);
        preorder(t->leftchild, vis);
        preorder(t->rightchild, vis);
    }
    
}

//中序遍歷
void inorder(struct tree *t, void vis(char name)) {
    if (t != NULL) {
        inorder(t->leftchild, vis);
        vis(t->name);
        inorder(t->rightchild, vis);
    }
}

//后序遍歷
void postorder(struct tree *t, void vis(char name)) {
    if (t != NULL) {
        postorder(t->leftchild, vis);
        postorder(t->rightchild, vis);
        vis(t->name);
    }
}


//尋找對應中序序列中和前序序列相對應的結點的位置
int bfs(char ch[],char name) {
    int i(0);
    while (ch[i] != name) ++i;
    return i;
}

//找到左子樹的位置
int seek_left(int flag[], int t){
    int temp;
    temp = t;
    while (flag[temp] != 1 && temp >= 0)
        temp--;
    if (flag[temp] == 1)
        return temp;
    else return -1;
}
//找到右子樹的位置
int seek_right(int flag[], int t)
{
    int temp;
    temp = t;
    while (flag[temp] != 1 && temp <= 10000)
        temp++;
    if (flag[temp] == 1)
        return temp;
    else return -1;
}

int main() {
    while (1) {
        cout << "          ***************唯一確定一顆二叉樹***************" << endl;
        cout << "          *                                              *" << endl;
        cout << "          *    給定前序序列和中序序列唯一確定一顆二叉樹  *" << endl;
        cout << "          *                                              *" << endl;
        cout << "          ************************************************" << endl;
        struct tree *root; //定義根節點
        init(&root);        //創建根節點
        struct tree *node_tree[maxint]; //二叉樹中的結點
        int flag[maxint];   //標記數組
        int left, right;
        memset(flag, 0, sizeof flag);  //標記數組全部賦值為0
        cout << "請輸入前序序列:";
        cin >> ch1;
        cout << "請輸入中序序列:";
        cin >> ch2;
        length = strlen(ch1);
        char node;  //前序序列中的結點
        int num;    //中序序列中對應前序序列結點的位置
        for (int i = 0; i < length; ++i) {
            node = ch1[i];
            num = bfs(ch2, node);
            left = seek_left(flag, num);    //找到左子樹位置
            right = seek_right(flag, num);  //找到右子樹位置
            if (left == -1 && right == -1) {  //第一次的時候肯定會執行這個條件后面的語句
                node_tree[num] = build_ltree(root, node);
                flag[num] = 1;
            }
            else if (left != -1 && node_tree[left]->rightchild == NULL) {
                node_tree[num] = build_rtree(node_tree[left], node);
                flag[num] = 1;
            }
            else if (right != -1 && node_tree[right]->leftchild == NULL) {
                node_tree[num] = build_ltree(node_tree[right], node);
                flag[num] = 1;
            }
        }
        cout << "此二叉樹的結構是:" << endl << endl;
        print_tree(root, 0);
        cout << "此二叉樹的前序序列為:";
        preorder(root->leftchild, vis);
        cout << endl;
        cout << "此二叉樹的中序序列為:";
        inorder(root->leftchild, vis);
        cout << endl;
        cout << "此二叉樹的后序序列為:";
        postorder(root->leftchild, vis);
        cout << endl << endl << endl;
    }
    
    return 0;
}

 

效果圖

 

總結

斷更一個月后,重新寫博。呃呃呃呃呃,最近狀態慢慢的調整過來了,加油吧!

下周去訓練!!!

---恢復內容結束---


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM