二叉樹練習(一):從字符串構建二叉樹和使用字符串輸出二叉樹

前言

如標題所言,本次要實現是使用類似 “A(B(C),D(,E))” 這樣的字符串構建、輸出二叉樹的代碼,其實這種表示方式就是廣義表的表示方式,有些書上也叫括號表示法。

這種表示法的規則是:以字符來表示結點,結點後緊跟的括號表示此結點的孩子結點,例如樹 “A(B,C)”,若孩子結點後面還有孩子結點,也按照此方法遞歸表示。兄弟結點之間使用逗號分隔。

需要注意的是,如果結點A後面只有一個左孩子B,那麼表示成這樣 “A(B)”,而如果結點A後面只有一個右孩子B,則是“A(,B)”。

理解清楚概念能夠更好地幫助我們理清寫代碼的邏輯。

 

寫碼

首先定義樹的結點結構和一些基礎的方法:

#include <iostream>
#include <algorithm>

using namespace std;

//樹節點定義,寫了一個簡單的構造函數
struct Node
{
    char data;
    Node *lchild;
    Node *rchild;
    Node(char c = '\0') : data(c), lchild(NULL), rchild(NULL) {}
};


//銷燬二叉樹
void destroy(Node *p)
{
    if (!p)
        return;
    destroy(p->lchild);
    destroy(p->rchild);
    delete p;
}

int main()
{

    
    return 0;
}

這裏要注意的是樹的銷燬函數,必須是這種類似後序遍歷的寫法,遍歷完左右孩子再delete父節點。

 

 

從字符串構建二叉樹

直接上代碼,關鍵的地方都寫註釋裏了:

Node *createTree(string &s)
{
    Node *root = NULL;    //最後要返回的樹根結點
    Node *cur = NULL;    //當前節點
    stack<Node *> stk;    //輔助棧
    //flag用來標記當前節點是父節點的哪個孩子,左孩子還是右孩子
    int flag = 0;    // 1 -> lchild, 2 -> rchild, 0 -> nothing
    for (char c : s)
    {
        switch (c)
        {
        case '(':    //遇到左括號意味着當前的cur結點有孩子結點,入棧並標記下一個孩子應該是此結點的左孩子
            if (!cur)
                cout << "error" << endl;
            stk.push(cur);
            flag = 1;
            break;

        case ')':    //表示該結點的孩子已經處理完畢,出棧該結點
            stk.pop();
            break;

        case ',':    //遇到逗號表示下一個結點應是一個右孩子結點,使用flag標記
            flag = 2;
            break;

        default:    //遇到字符的情況,創建節點並判斷該節點是上一個節點的左孩子還是右孩子
            cur = new Node(c);
            if (!root)    //根爲空,當前的cur就是根結點
                root = cur;
            if (flag == 1)
                stk.top()->lchild = cur;
            else if (flag == 2)
                stk.top()->rchild = cur;
            flag = 0;

            break;
        }
    }
    return root;    //最後返回根結點
}

 

以字符串形式輸出二叉樹

代碼挺簡單的,要解釋的也都寫註釋裏了:

void print(Node *p)
{
    if (!p)    //p爲空直接返回
        return;
    cout << p->data;    //能執行到這裏說明p不空,輸出p的data
    if (p->lchild || p->rchild)    //如果有孩子結點再處理
    {
        cout << "(";    //有孩子結點,輸出左括號
        print(p->lchild);    //這裏直接遞歸,如果左孩子爲空會直接返回,不空會遞歸輸出
        if (p->rchild)    //有右孩子則輸出逗號並遞歸輸出右孩子的孩子
        {
            cout << ",";
            print(p->rchild);
        }
        cout << ")";    //最後輸出右括號
    }
}

 

完整代碼

加了前中後序遍歷來驗證二叉樹是否正確構建,由於遞歸輸出無法處理最後的換行,就寫了個teaverse函數處理換行

#include <iostream>
#include <string>
#include <algorithm>
#include <stack>

using namespace std;

struct Node
{
    char data;
    Node *lchild;
    Node *rchild;

    Node(char c = '\0') : data(c), lchild(NULL), rchild(NULL) {}
};

Node *createTree(string &s)
{

    Node *root = NULL;
    Node *cur = NULL;
    stack<Node *> stk;
    int flag = 0; // 1 -> lchild, 2 -> rchild, 0 -> nothing
    for (char c : s)
    {
        switch (c)
        {
        case '(':
            if (!cur)
                cout << "error" << endl;
            stk.push(cur);
            flag = 1;
            break;

        case ')':
            stk.pop();
            break;

        case ',':
            flag = 2;
            break;

        default:
            cur = new Node(c);
            if (!root)
                root = cur;
            if (flag == 1)
                stk.top()->lchild = cur;
            else if (flag == 2)
                stk.top()->rchild = cur;
            flag = 0;

            break;
        }
    }
    return root;
}

void print(Node *p)
{
    if (!p)
        return;
    cout << p->data;
    if (p->lchild || p->rchild)
    {
        cout << "(";
        print(p->lchild);
        if (p->rchild)
        {
            cout << ",";
            print(p->rchild);
        }
        cout << ")";
    }
}

void preorder(Node *p)
{
    if (!p)
        return;
    cout << p->data << " ";
    preorder(p->lchild);
    preorder(p->rchild);
}

void inorder(Node *p)
{
    if (!p)
        return;
    inorder(p->lchild);
    cout << p->data << " ";
    inorder(p->rchild);
}

void postorder(Node *p)
{
    if (!p)
        return;
    postorder(p->lchild);
    postorder(p->rchild);
    cout << p->data << " ";
}

void destory(Node *p)
{
    if (!p)
        return;
    destory(p->lchild);
    destory(p->rchild);
    delete p;
}

void traverse(void(tFunc)(Node *p), Node *root)
{
    tFunc(root);
    cout << endl;
}

int main()
{
    Node *root = NULL;
    string s = "A(B(D,G),C(H,F))";
    cout << s << endl;
    root = createTree(s);
    traverse(preorder, root);
    traverse(inorder, root);
    traverse(postorder, root);
    print(root);
    destory(root);
    return 0;
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章