詳細二叉樹實現c++

Andy Dennis發表於2020-12-09

前言

當初學資料結構遺留下來的程式碼。不過程式碼中空指標建議用nullptr, 而不要用0。當初沒有優化。



程式碼

#include <iostream>
#include<stack>
#include<queue>
using namespace std;


//二叉樹結點
template<class T>
struct BinTreeNode
{
    T data;
    BinTreeNode* leftchild, * rightchild;
    BinTreeNode() : leftchild(0), rightchild(0) {}
    BinTreeNode(T x, BinTreeNode* l = 0, BinTreeNode * r = 0) : data(x), leftchild(l), rightchild(r) {}
};

//後序非遞迴遍歷用到的結構
template<class T>
struct stkNode {
    BinTreeNode<T>* ptr;
    int tag; //0代表左,1代表右
    stkNode(BinTreeNode<T>* N = 0) : ptr(N), tag(0) {}
};

template<class T>
class BinaryTree {
public:
    BinaryTree() : root(0) {}
    ~BinaryTree() {}

    //建樹
    void Create();
    void Create(BinTreeNode<T>*& BT, T endValue);
    //刪除樹
    void destroy();
    void destroy(BinTreeNode<T>* subTree);

    //前序,中序,後序遞迴遍歷演算法
    void PreOrder(void(*visti)(BinTreeNode<T>* p)) const;
    void InOrder(void(*visit)(BinTreeNode<T>* p)) const;
    void PostOrder(void (*visit)(BinTreeNode<T>* p)) const;
    //過載前序,中序,後序遞迴排序演算法
    void PreOrder(BinTreeNode<T>* subTree, void (*visit)(BinTreeNode<T>* p)) const;
    void InOrder(BinTreeNode<T>* subTree, void (*visit)(BinTreeNode<T>* p)) const;
    void PostOrder(BinTreeNode<T>* subTree, void (*visit)(BinTreeNode<T>* p)) const;
    //前序,中序,後序非遞迴演算法
    void PreOrderNonRecursion(void(*visit)(BinTreeNode<T>* p));
    void InOrderNonRecursion(void(*visit)(BinTreeNode<T>* p));
    void PostOrderNonRecursion(void(*visit)(BinTreeNode<T>* p));

    //層次遍歷
    void LevelOrder(void (*visit)(BinTreeNode<T>* p));

    //求樹高
    int Height() const;
    int Height(BinTreeNode<T>* subTree) const;
    int HeightNoRecursion();

    //求節點個數
    int Size() const;                       //從根開始
    int Size(BinTreeNode<T>* subTree) const;      //前序遍歷順序
    int SizeNonRecursionByLevelOrder();     //非遞迴方法,層次遍歷順序
    int SizeNonRecursionByPreOrder();       //非遞迴方法,前序遍歷順序

    //求葉子結點總數
    int LeavesSize() const;   //從根開始
    int LeavesSize(BinTreeNode<T>* t) const;   //前序遍歷順序
    int LeavesSizeNonRecursionByLevelOrder();
    int LeavesSizeNonRecursionByPreOrder();

    //廣義表輸出二叉樹
    void PrintBinTree();
    void PrintBinTree(BinTreeNode<T>* BT);

private:
    BinTreeNode<T>* root;
};










//

//從根開始建立樹
template<class T>
void BinaryTree<T>::Create()
{
    cout << "請輸入結束的標誌" << endl;
    T endValue;
    cin >> endValue;
    cout << "請輸入二叉樹結點的值 (0結束)" << endl;
    Create(root, endValue);
}


//前序順序建立二叉樹
template<class T>
void BinaryTree<T>::Create(BinTreeNode<T>*& BT, T endValue)
{

    T x;
    cin >> x;
    if (x == endValue)
    {
        BT = 0;
    }
    else
    {
        BT = new BinTreeNode<T>(x);
        Create(BT->leftchild, endValue);
        Create(BT->rightchild, endValue);
    }
}


//從根開始刪除
template<class T>
void BinaryTree<T>::destroy()
{
    destroy(root);
}

//刪除以subtree為根的樹
template<class T>
void BinaryTree<T>::destroy(BinTreeNode<T>* subTree)
{
    if (subTree != 0)
    {
        destroy(subTree->leftchild);
        destroy(subTree->rightchild);
        delete subTree;
    }
    root = 0;  //不然刪完遍歷會報錯
}






//

//前序,中序,後序遞迴遍歷演算法
template<class T>
void BinaryTree<T>::PreOrder(void (*visit)(BinTreeNode<T>* p)) const
{
    if (root == 0)
    {
        cout << "該樹為空" << endl;
        return;
    }
    PreOrder(root, visit);
}



template<class T>
void BinaryTree<T>::InOrder(void (*visit)(BinTreeNode<T>* p)) const
{
    if (root == 0)
    {
        cout << "該樹為空" << endl;
        return;
    }
    InOrder(root, visit);
}



template<class T>
void BinaryTree<T>::PostOrder(void (*visit)(BinTreeNode<T>* p)) const
{
    if (root == 0)
    {
        cout << "該樹為空" << endl;
        return;
    }
    PostOrder(root, visit);
}




//前序,中序,後序遍歷過載

template<class T>
void BinaryTree<T>::PreOrder(BinTreeNode<T>* subTree, void (*visit)(BinTreeNode<T>* p)) const
{
    if (subTree != 0)
    {
        visit(subTree);
        PreOrder(subTree->leftchild, visit);
        PreOrder(subTree->rightchild, visit);
    }
}


template<class T>
void BinaryTree<T>::InOrder(BinTreeNode<T>* subTree, void (*visit)(BinTreeNode<T>* p)) const
{
    if (subTree != 0)
    {
        InOrder(subTree->leftchild, visit);
        visit(subTree);
        InOrder(subTree->rightchild, visit);
    }
}
template<class T>
void BinaryTree<T>::PostOrder(BinTreeNode<T>* subTree, void(*visit)(BinTreeNode<T>* p)) const
{
    if (subTree != 0)
    {
        PostOrder(subTree->leftchild, visit);
        PostOrder(subTree->rightchild, visit);
        visit(subTree);
    }
}






//非遞迴前序,中序,後序遍歷演算法
template<class T>
void BinaryTree<T>::PreOrderNonRecursion(void(*visit)(BinTreeNode<T>* p))
{
    if (root == 0)
    {
        cout << "該樹為空" << endl;
        return;
    }
    stack<BinTreeNode<T>*> S;
    BinTreeNode<T>* p = root;
    do
    {
        //一直往左,訪問並記錄結點以便返回
        while (p != 0)
        {
            S.push(p);
            visit(p);
            p = p->leftchild;
        }
        if (!S.empty())
        {
            p = S.top();
            S.pop();
            p = p->rightchild;
        }
    } while (p != 0 || !S.empty());
    cout << endl;
}


template<class T>
void BinaryTree<T>::InOrderNonRecursion(void(*visit)(BinTreeNode<T>* p))
{
    if (root == 0)
    {
        cout << "該樹為空" << endl;
        return;
    }
    stack<BinTreeNode<T>*> S;
    BinTreeNode<T>* p = root;
    do {
        //一直往左,訪問並記錄結點以便返回
        while (p != 0)
        {
            S.push(p);
            p = p->leftchild;
        }
        if (!S.empty())
        {
            p = S.top();
            S.pop();
            visit(p);
            p = p->rightchild;
        }
    } while (p != 0 || !S.empty());
    cout << endl;
}


template<class T>
void BinaryTree<T>::PostOrderNonRecursion(void(*visit)(BinTreeNode<T>* p))
{
    if (root == 0)
    {
        cout << "該樹為空" << endl;
        return;
    }
    stack<stkNode<T>> S;
    stkNode<T> w;
    BinTreeNode<T>* p = root;
    do
    {
        while (p != 0)
        {
            w.ptr = p;
            w.tag = 0;
            S.push(w);
            p = p->leftchild;
        }
        bool continuing = true;
        while (continuing && !S.empty())
        {
            w = S.top();
            S.pop();
            p = w.ptr;
            switch (w.tag)
            {
                case 0:
                    w.tag = 1;
                    S.push(w);
                    continuing = false; //停止這個while迴圈,讓它去找最左的左子樹0
                    p = p->rightchild;
                    break;
                case 1:
                    visit(p);
                    break;
            }
        }
    } while (!S.empty());
    cout << endl;
}



//層次遍歷
template<class T>
void BinaryTree<T>::LevelOrder(void(*visit)(BinTreeNode<T>* p))
{
    queue<BinTreeNode<T>*> Q;
    BinTreeNode<T>* p = root;
    Q.push(p);//指向根節點的指標入隊
    while (!Q.empty())
    {
        p = Q.front();
        Q.pop();
        visit(p);
        if (p->leftchild != 0)
        {
            Q.push(p->leftchild);
        }

        if (p->rightchild != 0)
        {
            Q.push(p->rightchild);
        }
    }
}






//求樹高
template<class T>
int BinaryTree<T>::Height() const
{
    return Height(root);
}


template<class T>
int BinaryTree<T>::Height(BinTreeNode<T>* subTree) const
{
    if (subTree == 0)
    {
        return 0;
    }
    int leftchildHeight = Height(subTree->leftchild);
    int rightchildHeight = Height(subTree->rightchild);
    return (leftchildHeight > rightchildHeight) ? leftchildHeight + 1 : rightchildHeight + 1;
}


//非遞迴求樹高,層次遍歷順序
template<class T>
int BinaryTree<T>::HeightNoRecursion()
{
    int depth = 0;
    BinTreeNode<T>* p = root;
    queue<BinTreeNode<T>*> q;
    q.push(p);  //根指標入隊
    while (!q.empty())
    {
        depth++;
        int width = q.size();
        for (int i = 0; i < width; i++)
        {
            p = q.front();
            q.pop();
            if (p->leftchild != 0)
                q.push(p->leftchild);
            if (p->rightchild != 0)
                q.push(p->rightchild);
        }
    }
    return depth;
}






//求結點個數
template<class T>
int BinaryTree<T>::Size() const
{
    return Size(root);
}


template<class T>
int BinaryTree<T>::Size(BinTreeNode<T>* subTree) const
{
    if (subTree == 0)
        return 0;
    return 1 + Size(subTree->leftchild) + Size(subTree->rightchild);
}




//非遞迴求節點個數,層次遍歷順序
template<class T>
int BinaryTree<T>::SizeNonRecursionByLevelOrder()
{
    //如果樹根為空,則節點數為0
    if (root == 0)
        return 0;
    //如果不空,則可以執行下面的操作
    int size = 1;  //至少有根節點
    BinTreeNode<T>* p = root;
    queue<BinTreeNode<T>*> Q;
    Q.push(p);  根指標入隊
    while (!Q.empty())
    {
        int width = Q.size();  //獲取當前層次寬度,也就是知道下一層次的所有節點個數
        for (int i = 0; i < width; i++)
        {
            p = Q.front();     //獲取隊頂元素
            Q.pop();          //彈出隊頂元素
            if (p->leftchild != 0)
            {
                size++;
                Q.push(p->leftchild);
            }
            if (p->rightchild != 0)
            {
                size++;
                Q.push(p->rightchild);
            }
        }
    }
    return size;
}



template<class T>
int BinaryTree<T>::SizeNonRecursionByPreOrder()
{
    if (root == 0)
        return 0;
    stack<BinTreeNode<T>*> S;
    BinTreeNode<T>* p = root;
    int size = 0;  //結點計數器
    do
    {
        while (p != 0)
        {
            S.push(p);
            size++;
            p = p->leftchild;
        }
        if (!S.empty())
        {
            p = S.top();
            S.pop();
            p = p->rightchild;
        }
    } while (p != 0 || !S.empty());
    return size;
}



//求葉子結點數目
template<class T>
int BinaryTree<T>::LeavesSize() const
{
    return LeavesSize(root);
}



template<class T>
int BinaryTree<T>::LeavesSize(BinTreeNode<T>* t) const
{
    if (t == 0)
        return 0;
    if (t->leftchild == 0 && t->rightchild == 0)
        return 1;
    return LeavesSize(t->leftchild) + LeavesSize(t->rightchild);
}





template<class T>
int BinaryTree<T>::LeavesSizeNonRecursionByLevelOrder()
{
    //如果樹根為空,則節點數為0
    if (root == 0)
        return 0;
    //初始時葉子結點計數器置0
    int size = 0;
    BinTreeNode<T>* p = root;
    queue<BinTreeNode<T>*> Q;
    Q.push(p);   //根指標入隊
    while (!Q.empty())
    {
        int width = Q.size();       //獲取當前層次寬度,也就是知道下一層次的所有節點個數
        for (int i = 0; i < width; i++)
        {
            p = Q.front();       //獲取隊頂元素
            Q.pop();			//彈出隊頂元素
            if (p->leftchild == 0 && p->rightchild == 0)
            {
                size++;
            }
            else
            {
                if (p->leftchild != 0)
                    Q.push(p->leftchild);
                if (p->rightchild != 0)
                    Q.push(p->rightchild);
            }
        }
    }
    return size;
}



template<class T>
int BinaryTree<T>::LeavesSizeNonRecursionByPreOrder()
{
    if (root == 0)
        return 0;
    stack<BinTreeNode<T>*>S;
    BinTreeNode<T>* p = root;
    int size = 0;
    do {
        while (p != 0)
        {
            S.push(p);
            //葉子結點呢
            if (p->leftchild == 0 && p->rightchild == 0)
            {
                size++;
                break;
            }
            p = p->leftchild;
        }
        if (!S.empty())
        {
            p = S.top();
            S.pop();
            p = p->rightchild;
        }
    } while (p != 0 || !S.empty());
    return size;
}




//廣義表輸出二叉樹
template<class T>
void BinaryTree<T>::PrintBinTree()
{
    PrintBinTree(root);
}



template<class T>
void BinaryTree<T>::PrintBinTree(BinTreeNode<T>* BT)
{
    if (BT != 0)
    {
        cout << BT->data;
        if (BT->leftchild != 0 || BT->rightchild != 0)
        {
            cout << "(";
            PrintBinTree(BT->leftchild);  // 遞迴輸出左子樹
            if (BT->rightchild != 0)
            {
                cout << ",";
                PrintBinTree(BT->rightchild); // 遞迴輸出右子樹
            }
            cout << ")";
        }
    }
}




















//輸出結點data值的函式
template<class T>
void PrintData(BinTreeNode<T>* p)
{
    cout << p->data << " ";
}





int main()
{
    BinaryTree<char> a;
    a.Create();

    cout << endl << endl;
    cout << "前序遞迴遍歷" << endl;
    a.PreOrder(PrintData);

    cout << endl << endl;
    cout << "中序遞迴遍歷" << endl;
    a.InOrder(PrintData);

    cout << endl << endl;
    cout << "後序遞迴遍歷" << endl;
    a.PostOrder(PrintData);

    cout << endl << endl << endl;
    cout << "前序非遞迴遍歷" << endl;
    a.PreOrderNonRecursion(PrintData);

    cout << endl;
    cout << "中序非遞迴遍歷" << endl;
    a.InOrderNonRecursion(PrintData);

    cout << endl;
    cout << "後序非遞迴遍歷" << endl;
    a.PostOrderNonRecursion(PrintData);

    cout << endl;
    cout << "層次遍歷" << endl;
    a.LevelOrder(PrintData);

    cout << endl;
    cout << "遞迴求樹的高度" << endl;
    cout << "height: " << a.Height();

    cout << endl << endl;
    cout << "非遞迴求樹的高度" << endl;
    cout << "height: " << a.HeightNoRecursion();

    cout << endl << endl << endl << endl;
    cout << "遞迴求結點個數" << endl;
    cout << "size: " << a.Size();

    cout << endl << endl;
    cout << "層次順序非遞迴求結點個數" << endl;
    cout << "size: " << a.SizeNonRecursionByLevelOrder();

    cout << endl << endl;
    cout << "前序順序非遞迴求結點個數" << endl;
    cout << "size: " << a.SizeNonRecursionByPreOrder();


    cout << endl << endl;
    cout << "***************************************************" << endl;
    cout << endl << endl;
    cout << "遞迴求葉子結點總數" << endl;
    cout << "leavesSize: " << a.LeavesSize() << endl;

    cout << endl << endl;
    cout << "層次順序非遞迴方法求葉子結點總數" << endl;
    cout << "leavesSize: " << a.LeavesSizeNonRecursionByLevelOrder() << endl;

    cout << endl << endl;
    cout << "前序順序非遞迴方法求葉子結點總數" << endl;
    cout << "leavesSize: " << a.LeavesSizeNonRecursionByPreOrder() << endl;


    cout << endl << endl;
    cout << "廣義表輸出" << endl;
    a.PrintBinTree();

    cout << endl;
}

相關文章