【數據結構】——二叉樹的遍歷算法

題目要求

編寫程序,用先序遞歸遍歷法(或輸入先序及中序遞歸遍歷結點訪問序列)創建二叉樹的二叉鏈表存儲結構,計算並輸出二叉樹的結點總數以及樹的高度;而後輸出其先序、中序、後序以及層次遍歷結點訪問次序。其中層次遍歷的實現需使用循環隊列。二叉樹結點數據類型建議選用字符類型。node

數據結構設計

採用C++的模板類,建立隊列。每一個隊列對象中,elem指針用來創建長度爲n的數組,n表示隊列的容量,front表示隊頭指針,rear表示隊尾指針,c表示隊列中當前元素的個數。
採用結構體創建二叉樹,其中,data表示數據域,lchild表示左指針,rchild表示右指針,BiT表示二叉樹結構體指針類型變量,BiTNode表示二叉樹結構體類型變量。ios

算法設計簡要描述

  1. 先序遍歷創建二叉樹:遞歸調用函數,不斷讀取字符,依次創建左子樹和右子樹,當讀取到‘#’字符時,返回NULL指針,最終返回根結點指針。
  2. 先序和中序遍歷結點訪問序列創建二叉樹:
    a. 先由先序序列求得根節點;
    b. 再由根節點在中序序列中的位置,知:它以前的訪問的結點爲其左子樹結點,它以後訪問的爲其右子樹結點;
    c. 遞歸應用a,b兩條。

程序代碼

#include <conio.h>
#include <iostream>
using namespace std;
typedef char ElemTp;
#define MAX 20
template <typename T>
class Queue                         //模板類:隊列
{
public:
    Queue();                        //默認構造函數
    Queue(int n);                   //構造函數,調用函數createQueue(int n),建立長度爲n的隊列
    ~Queue();                       //虛構函數
    int createQueue(int n);         //建立長度爲n的隊列
    int empty();                    //判斷隊列是否爲空
    int full();                     //判斷隊列是否爲滿
    int enQueue(T e);               //元素e入隊
    int dlQueue(T &e);              //元素出隊,保存在e中
private:
    T *elem;                        //創建長度爲n的數組
    int n;                          //隊列容量
    int front;                      //隊頭指針
    int rear;                       //隊尾指針
    int c;                          //隊列當前元素個數
};
typedef struct node
{
    ElemTp data;                    //數據域
    struct node *lchild,            //左指針
        *rchild;                    //右指針
}*BiT,BiTNode;
 
void visit(BiT e)                   //訪問函數      
{
    if (e->data != NULL)            //輸出二叉樹的數據域
        cout << e->data << "  ";
}
void preorder(BiT bt)               //先序遍歷二叉樹
{
    if (bt)
    {
        visit(bt);                  //訪問根節點
        preorder(bt->lchild);       //遞歸調用遍歷左子樹
        preorder(bt->rchild);       //遞歸調用遍歷右子樹
    }
}
void midorder(BiT bt)               //中序遍歷二叉樹
{
    if (bt)
    {
        midorder(bt->lchild);       //遞歸調用遍歷左子樹
        visit(bt);                  //訪問根節點
        midorder(bt->rchild);       //遞歸調用遍歷右子樹
    }
}
void lasorder(BiT bt)               //後序遍歷二叉樹
{
    if (bt)
    {
        lasorder(bt->lchild);       //遞歸調用遍歷左子樹
        lasorder(bt->rchild);       //遞歸調用遍歷右子樹
        visit(bt);                  //訪問根節點
    }
}
void layertravel(BiT bt)            //層次遍歷二叉樹
{
    if (bt == NULL)
        return;
    Queue<BiT> q(MAX);              //創建隊列
    q.enQueue(bt);                  //根節點入隊
    while (!q.empty())
    {
        q.dlQueue(bt);              //根節點出隊
        visit(bt);                  //訪問根節點
        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();             //創建新的二叉樹結點
    bt->data = ch;
    bt->lchild = crtPreBT();        //遞歸創建左子樹
    bt->rchild = crtPreBT();        //遞歸創建右子樹
    return bt;
}
BiT crtPreMidBT(char *pr, int &i, char *mi, int u, int v)  //先序及中序遞歸遍歷結點訪問序列創建二叉樹算法
{
    BiT bt;
    int k;
    if (u > v)
        return NULL;
    bt = new BiTNode();                     
    bt->data = pr[i++];              //pr[i]爲子樹根節點
    for (k = u; k <= v; k++)         //mi[u...v]爲子樹中序序列
    {
        if (mi[k] == bt->data)       //查找根節點在中序序列中的位置
            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)                  //計算二叉樹的總結點數
{
    int nl, nr;
    if (!bt)
        return 0;
    nl = nodeNum(bt->lchild);        //遞歸計算左子樹的結點數  
    nr = nodeNum(bt->rchild);        //遞歸計算右子樹的結點數
    return nl + nr + 1;              //返回整個二叉樹的結點數(左、右子樹結點數之和加一)
}
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 << "二叉樹的總結點數是: " << num << endl;
    cout << "先序遍歷結點訪問次序: " << endl;
    preorder(bt);
    cout << endl;
    cout << "中序遍歷結點訪問次序: " << endl;
    midorder(bt);
    cout << endl;
    cout << "後序遍歷結點訪問次序: " << endl;
    lasorder(bt);
    cout << endl;
    cout << "層次遍歷結點訪問次序: " << endl;
    layertravel(bt);
    cout << endl;
    return 0;
}

示例

(1)程序輸入
先序序列:abc##de#g##f###
程序輸出
二叉樹的高度是:5
二叉樹的總結點數是: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
image.png
(2)程序輸入
先序序列:ABCDEFG
中序序列:CBEDAFG
程序輸出
二叉樹的高度是:4
二叉樹的總結點數是: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
image.png
(3)程序輸入
先序序列:ABDF####C#E#G#H##
程序輸出
二叉樹的高度是:5
二叉樹的總結點數是: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
image.png
(4)程序輸入
先序序列:#
程序輸出
二叉樹的高度是:0
二叉樹的總結點數是:0
image.pngc++

相關文章
相關標籤/搜索