1. 程式人生 > >二叉樹基礎-二叉樹類模板的實現(資料結構基礎 第5周)

二叉樹基礎-二叉樹類模板的實現(資料結構基礎 第5周)

這裡參考了課本配套的程式簡單實現了二叉樹類模板,主要包含了二叉樹的建立和各種遍歷方法。
對於二叉樹的建立,這裡使用的是前序遍歷的方法建立的二叉樹,具體如下:
這裡寫圖片描述
這裡我使用的下圖中的二叉樹作為測試案例:
這裡寫圖片描述
具體不說了,詳見程式碼吧。
原始碼
//test.cpp

#include <iostream>
#include "BinaryTree.h"
#include "BinaryTreeNode.h"
#include <vector>
using namespace std;

//前序方法遞迴建立二叉樹
BinaryTreeNode<char>* createTree() {
    BinaryTreeNode<char
> *p;//這是使用區域性變數是有風險的,函式結束後會被釋放 char ch; cin >> ch; if (ch=='#'){ return NULL; } p = new BinaryTreeNode<char>(ch); p->setLeftchild(createTree()); p->setRightchild(createTree()); return p; } void printTrsverse(const vector<char>& v) { for
(int i=0; i<v.size(); i++) { cout << v.at(i); } cout << endl; } //示例,輸入"ABD##EG###C#FH##I##" int main() { BinaryTree<char> tr; tr.Initialize(createTree()); vector<char> v; v=tr.traversePreOrder(); cout << "前序遞迴遍歷:" << endl; printTrsverse(v); v=tr.traverseInOrder(); cout
<< "中序遞迴遍歷:" << endl; printTrsverse(v); v=tr.traversePostOrder(); cout << "後序遞迴遍歷:" << endl; printTrsverse(v); v=tr.traversePreOrderWithoutRecusion(); cout << "前序非遞迴遍歷:" << endl; printTrsverse(v); v=tr.traverseInOrderWithoutRecusion(); cout << "中序非遞迴遍歷:" << endl; printTrsverse(v); v=tr.traversePostOrderWithoutRecusion(); cout << "後序非遞迴遍歷:" << endl; printTrsverse(v); v=tr.traversePostOrderWithoutRecusion2(); cout << "後序非遞迴遍歷2:" << endl; printTrsverse(v); v=tr.traverseLevelOrder(); cout << "層次遍歷:" << endl; printTrsverse(v); return 0; }

//BinaryTree.h

#pragma once

#include "BinaryTreeNode.h"
#include <stack>
#include <queue>
#include <vector>
using namespace std;


enum Tags{Left,Right};

template <class T>
class StackElement
{
public:
    BinaryTreeNode<T>* pointer;
    Tags tag;
};

template <class T>
class BinaryTree  
{
private:
    BinaryTreeNode<T>*  root;                               //二叉樹根結點指標
    vector<T> elements;  //用於儲存遍歷的元素
private:
    void Visit(T elem) {elements.push_back(elem);};  //遍歷訪問元素的值
    void PreOrder(BinaryTreeNode<T>* root); //從root前序遍歷二叉樹或其子樹(遞迴部分)
    void InOrder(BinaryTreeNode<T>* root);  //從root中序遍歷二叉樹或其子樹(遞迴部分)    
    void PostOrder(BinaryTreeNode<T>* root); //從root後序遍歷二叉樹或其子樹(遞迴部分)   
    void PreOrderWithoutRecusion(BinaryTreeNode<T>* root); //從root非遞迴前序遍歷二叉樹或其子樹(遞迴部分)  
    void InOrderWithoutRecusion(BinaryTreeNode<T>* root);  //從root非遞迴中序遍歷二叉樹或其子樹(遞迴部分)  
    void PostOrderWithoutRecusion(BinaryTreeNode<T>* root);  //從root非遞迴後序遍歷二叉樹或其子樹  (遞迴部分)
    void PostOrderWithoutRecusion2(BinaryTreeNode<T>* root);  //從root非遞迴後序遍歷二叉樹或其子樹, 另一個版本(遞迴部分)
    void LevelOrder(BinaryTreeNode<T>* root);  //按層次遍歷二叉樹或其子樹
    BinaryTreeNode<T>* GetParent(BinaryTreeNode<T>* root,BinaryTreeNode<T>* current);//遞迴由root結點查詢current結點的父結點

public:
    BinaryTree(){root=NULL;};                               //建構函式
    virtual ~BinaryTree(){DeleteBinaryTree(root);};            //解構函式
    bool isEmpty() const                            
    {return ((root)?TRUE:FALSE);};                          //判定二叉樹是否為空樹

    void Initialize(BinaryTreeNode<T>* pointer) {root=pointer;};    

    BinaryTreeNode<T>* Root() {return root;};  //返回二叉樹根節點
    BinaryTreeNode<T>* Parent(BinaryTreeNode<T>* current); //返回current結點的父結點指標  
    BinaryTreeNode<T>* LeftSibling(BinaryTreeNode<T>* current); //返回current結點的左兄弟   
    BinaryTreeNode<T>* RightSibling(BinaryTreeNode<T>* current);//返回current結點的右兄弟

    //以elem作為根結點,leftTree作為樹的左子樹,rightTree作為樹的右子樹,構造一棵新的二叉樹
    void CreateTree(const T& elem, BinaryTree<T>& leftTree, BinaryTree<T>& rightTree);  
    void DeleteBinaryTree(BinaryTreeNode<T>* root);     //遞迴刪除二叉樹或其子樹   

    vector<T> traversePreOrder();  //從根節點前序遍歷,以下依次對應
    vector<T> traverseInOrder();
    vector<T> traversePostOrder();
    vector<T> traversePreOrderWithoutRecusion();
    vector<T> traverseInOrderWithoutRecusion();
    vector<T> traversePostOrderWithoutRecusion();
    vector<T> traversePostOrderWithoutRecusion2();
    vector<T> traverseLevelOrder();     
};

template<class T>
BinaryTreeNode<T>* BinaryTree<T>::GetParent(BinaryTreeNode<T>* root,BinaryTreeNode<T>* current)
{
    //從二叉樹的root結點開始,查詢current結點的父結點
    BinaryTreeNode<T>* temp;
    if(root==NULL)
        return NULL;
    //找到父結點
    if((root->leftchild()==current)||(root->rightchild()==current))
        return root;
    //遞迴尋找父結點
    if((temp=GetParent(root->leftchild(),current))!=NULL)
        return temp;
    else return GetParent(root->rightchild(),current);  
}

template<class T>
BinaryTreeNode<T>* BinaryTree<T>::Parent(BinaryTreeNode<T>* current)  //返回current結點的父結點指標
{
    if((current==NULL)||(current==root))
        return NULL;                    //空結點或者current為根結點時,返回NULL
    return GetParent(root,current);     //呼叫遞迴函式尋找父結點
}

template<class T>
BinaryTreeNode<T>* BinaryTree<T>::LeftSibling(BinaryTreeNode<T>* current)  //返回current結點的左兄弟
{
    if(current)                                         //current不為空
    {
        BinaryTreeNode<T>* temp=Parent(current);    //返回current結點的父結點
        if((temp==NULL)||current==temp->leftchild())
            return  NULL;           //如果父結點為空,或者current沒有左兄弟
        else return temp->leftchild();
    }
    return NULL;
}

template<class T>
BinaryTreeNode<T>* BinaryTree<T>::RightSibling(BinaryTreeNode<T>* current) //返回current結點的右兄弟
{
    if(current)                                 //current不為空
    {
        BinaryTreeNode<T>* temp=Parent(current);//返回current結點的父結點
        if((temp==NULL)||current==temp->rightchild())
            return  NULL;                   //如果父結點為空,或者current沒有右兄弟
        else return temp->rightchild();
    }
    return NULL;
}

template<class T>
void BinaryTree<T>::CreateTree(const T& elem, BinaryTree<T>& leftTree, BinaryTree<T>& rightTree) //以elem作為根結點,leftTree作為樹的左子樹,rightTree作為樹的右子樹,構造一棵新的二叉樹
{
    root=new BinaryTreeNode<T>(elem,leftTree.root,rightTree.root);  //建立新樹
    leftTree.root=rightTree.root=NULL;                              //原來兩棵子樹的根結點指空,避免訪問
}

template<class T>
void BinaryTree<T>::DeleteBinaryTree(BinaryTreeNode<T>* root)       //遞迴刪除二叉樹或其子樹
{
    if(root)
    {
        DeleteBinaryTree(root->left);
        DeleteBinaryTree(root->right);
        delete root;
    };
};

template<class T>
void BinaryTree<T>::PreOrder(BinaryTreeNode<T>* root)               //前序遍歷二叉樹或其子樹
{
    if(root!=NULL)
    {
        Visit(root->value());   
        PreOrder(root->leftchild());            //訪問左子樹
        PreOrder(root->rightchild());           //訪問右子樹
    }
};
template<class T>
vector<T> BinaryTree<T>::traversePreOrder() 
{
    elements.clear();
    PreOrder(root);
    return elements;
}

template<class T>
void BinaryTree<T>::InOrder(BinaryTreeNode<T>* root)                //中序遍歷二叉樹或其子樹
{
    if(root!=NULL)
    {
        InOrder (root->leftchild());            //訪問左子樹
        Visit(root->value());           //訪問當前結點
        InOrder (root->rightchild());           //訪問右子樹
    }
}
template<class T>
vector<T> BinaryTree<T>::traverseInOrder() 
{
    elements.clear();
    InOrder(root);
    return elements;
}

template<class T>
void BinaryTree<T>::PostOrder(BinaryTreeNode<T>* root)              //後序遍歷二叉樹或其子樹
{
    if(root!=NULL)
    {
        PostOrder(root->leftchild());           //訪問左子樹
        PostOrder (root->rightchild());         //訪問右子樹
        Visit(root->value());           //訪問當前結點
    }
}
template<class T>
vector<T> BinaryTree<T>::traversePostOrder() 
{
    elements.clear();
    PostOrder(root);
    return elements;
}

template<class T>
void BinaryTree<T>::PreOrderWithoutRecusion(BinaryTreeNode<T>* root)//非遞迴前序遍歷二叉樹或其子樹
{
//  using std::stack;

    stack<BinaryTreeNode<T>* > aStack;
    BinaryTreeNode<T>* pointer=root;                //儲存輸入引數    

    while(!aStack.empty()||pointer)             
    {
        if(pointer){
            Visit(pointer->value());        //訪問當前結點
            aStack.push(pointer);                   //當前結點地址入棧
            pointer=pointer->leftchild();           //當前連結結構指向左孩子
        }
        else {                                          //左子樹訪問完畢,轉向訪問右子樹
            pointer=aStack.top();                   //棧頂元素退棧                 
            aStack.pop();
            pointer=pointer->rightchild();      //當前連結結構指向右孩子
        } //else
    } //while
}
template<class T>
vector<T> BinaryTree<T>::traversePreOrderWithoutRecusion() 
{
    elements.clear();
    PreOrderWithoutRecusion(root);
    return elements;
}

template<class T>
void BinaryTree<T>::InOrderWithoutRecusion(BinaryTreeNode<T>* root) //非遞迴中序遍歷二叉樹或其子樹
{
//  using std::stack;
    stack<BinaryTreeNode<T>* > aStack;
    BinaryTreeNode<T>* pointer=root;                //儲存輸入引數    

    while(!aStack.empty()||pointer)             
    {
        if(pointer){
            aStack.push(pointer);                   //當前結點地址入棧
            pointer=pointer->leftchild();           //當前連結結構指向左孩子
        }
        else {                                          //左子樹訪問完畢,轉向訪問右子樹
            pointer=aStack.top();               
            Visit(pointer->value());        //訪問當前結點
            pointer=pointer->rightchild();      //當前連結結構指向右孩子
            aStack.pop();                           //棧頂元素退棧                 
        } //else
    } //while
}
template<class T>
vector<T> BinaryTree<T>::traverseInOrderWithoutRecusion() 
{
    elements.clear();
    InOrderWithoutRecusion(root);
    return elements;
}

template<class T>
void BinaryTree<T>::PostOrderWithoutRecusion(BinaryTreeNode<T>* root)//非遞迴後序遍歷二叉樹或其子樹
{
//  using std::stack;
    StackElement<T> element;
    stack<StackElement<T > > aStack;
    BinaryTreeNode<T>* pointer;
    if(NULL==root)
        return;                                     //空樹即返回
    else pointer=root;
    while(true)
    {
        //進入左子樹
        while(pointer!=NULL)
        {
            element.pointer=pointer;
            element.tag=Left;
            aStack.push(element);
            pointer=pointer->leftchild();
        }
        //托出棧頂元素
        element=aStack.top();
        aStack.pop();
        pointer=element.pointer;
        //從右子樹回來
        while(element.tag==Right)
        {
            Visit(pointer->value());        //訪問當前結點
            if(aStack.empty())
                return;
            else
            {
                element=aStack.top();
                aStack.pop();
                pointer=element.pointer;
            }
        }
        //從左子樹回來
        element.tag=Right;
        aStack.push(element);
        pointer=pointer->rightchild();
    }
}
template<class T>
vector<T> BinaryTree<T>::traversePostOrderWithoutRecusion() 
{
    elements.clear();
    PostOrderWithoutRecusion(root);
    return elements;
}

template<class T>
void BinaryTree<T>::PostOrderWithoutRecusion2(BinaryTreeNode<T>* root)
{//非遞迴後序遍歷二叉樹或其子樹, 另一個版本
//  using std::stack;
    stack<BinaryTreeNode<T>* > aStack;
    BinaryTreeNode<T> *p, *q;
    if(root==NULL)
        return;
    p=root;
    do{
        while(p!=NULL)                          //沿左路分支下降           
        {
            aStack.push(p);
            p=p->leftchild();
        }
        q=NULL;
        while(!aStack.empty())
        {
            p=aStack.top();
            aStack.pop();
            if(p->rightchild()==q)              //右子樹為空或剛剛被訪問過
            {
                Visit(p->value());      //訪問當前結點
                q=p;
            }
            else
            {
                aStack.push(p);
                p=p->rightchild();
                break;
            }
        }
    }while(!aStack.empty());
}
template<class T>
vector<T> BinaryTree<T>::traversePostOrderWithoutRecusion2() 
{
    elements.clear();
    PostOrderWithoutRecusion2(root);
    return elements;
}

template<class T>
void BinaryTree<T>::LevelOrder(BinaryTreeNode<T>* root) //按層次遍歷二叉樹或其子樹,這裡使用佇列來模擬
{
//  using std::queue;
    queue<BinaryTreeNode<T>*> aQueue;
    BinaryTreeNode<T>* pointer=root;

    if(pointer)
        aQueue.push(pointer);
    while(!aQueue.empty())
    {
        pointer=aQueue.front();
        Visit(pointer->value());        //訪問當前結點
        aQueue.pop();
        if(pointer->leftchild())
            aQueue.push(pointer->leftchild());
        if(pointer->rightchild())
            aQueue.push(pointer->rightchild());
    }
}
template<class T>
vector<T> BinaryTree<T>::traverseLevelOrder() 
{
    elements.clear();
    LevelOrder(root);
    return elements;
}

//BinaryTreeNode.h

#pragma once

template <class T> class BinaryTree;

template <class T>
class BinaryTreeNode  
{
friend class BinaryTree<T>;
private:
    T  element;                                         //二叉樹結點資料域
    BinaryTreeNode<T>*  left;                           //二叉樹結點指向左子樹的指標
    BinaryTreeNode<T>*  right;                          //二叉樹結點指向左子樹的指標
public:
    BinaryTreeNode();
    BinaryTreeNode(const T& ele);                       //給定資料的建構函式
    BinaryTreeNode(const T& ele,BinaryTreeNode* l, BinaryTreeNode* r);//給定資料的左右指標的建構函式
    T  value() const;                                   //返回當前結點的資料
    BinaryTreeNode<T>& operator= (const BinaryTreeNode<T>& Node)
    {this=Node;};                                       //過載賦值操作符
    BinaryTreeNode<T>*  leftchild() const;              //返回當前結點指向左子樹的指標
    BinaryTreeNode<T>*  rightchild() const;             //返回當前結點指向右子樹的指標
    void  setLeftchild(BinaryTreeNode<T>*);             //設定當前結點的左子樹
    void  setRightchild(BinaryTreeNode<T>*);            //設定當前結點的右子樹
    void  setValue(const T& val);                       //設定當前結點的資料域
    bool  isLeaf() const;                               //判定當前結點是否為葉結點,若是返回true
};

template<class T>
BinaryTreeNode<T>::BinaryTreeNode()
{
    left=right=NULL;
}

template<class T>
BinaryTreeNode<T>::BinaryTreeNode(const T& ele) //給定資料的建構函式
{
    element=ele;
    left=right=NULL;
}

template<class T>
BinaryTreeNode<T>::BinaryTreeNode(const T& ele,BinaryTreeNode* l, BinaryTreeNode* r)
    //給定資料的左右指標的建構函式
{
    element=ele;
    left=l;
    right=r;
}

template<class T>
T  BinaryTreeNode<T>::value() const
{
    return element; 
}

template<class T>
BinaryTreeNode<T>*  BinaryTreeNode<T>::leftchild() const
{
    return left;                                //返回當前結點指向左子樹的指標
}

template<class T>
BinaryTreeNode<T>*  BinaryTreeNode<T>::rightchild() const
{
    return right;                               //返回當前結點指向右子樹的指標
}   

template<class T>
void  BinaryTreeNode<T>::setLeftchild(BinaryTreeNode<T>* subroot)//設定當前結點的左子樹
{
    left=subroot;
}

template<class T>
void  BinaryTreeNode<T>::setRightchild(BinaryTreeNode<T>* subroot)//設定當前結點的右子樹
{
    right=subroot;
}

template<class T>
void  BinaryTreeNode<T>::setValue(const T& val) //設定當前結點的資料域
{
    element = val; 
} 

template<class T>
bool  BinaryTreeNode<T>::isLeaf() const         //判定當前結點是否為葉結點,若是返回true
{
    return (left == NULL) && (right == NULL); 
}

———————————2016.7.8記———————————————————————————–
上述test.cpp的createTree函式是有風險的,因為每次在函式內定義一個新結點,這樣在函式結束時就被釋放了。關於此問題很容易被忽視,詳見:二叉樹基礎-由中根序列和後根序列重建二叉樹(資料結構基礎 第5周)