二叉樹

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

template <class T>
struct TreeNode
{
    TreeNode(const T& value = T())
        :_value(value)
        ,_lchild(0)
        ,_rchild(0)
    {}
    T _value;//節點的值
    TreeNode<T>* _lchild;//左孩子
    TreeNode<T>* _rchild;//右孩子
};

template <class T>
class BinaryTree
{
public:
    typedef TreeNode<T> Node;
    BinaryTree()//無參構造函數
        :_root(NULL)
    {}
    BinaryTree(const T* a,size_t size,const T& invalid)//構造函數
    {
        assert(a);
        size_t index = 0;
        _root = CreatTree(a,size,invalid,index);
    }
    BinaryTree(const BinaryTree<T>& b)//拷貝構造
    {
        _root = Copy(b._root);
    }
    //現代寫法的賦值運算符重載1
    BinaryTree& operator=(const BinaryTree<T>& b)
    {
        if (this != &b)
        {
            Node* tmp = Copy(b._root);
            Destroy(_root) ;
            _root = tmp;
            //swap(_root,tmp);
        }
        return *this;
    }
    ////現代寫法的賦值運算符重載2
    //BinaryTree& operator=(BinaryTree<T> b)
    //{
    //  swap(b._root,_root);
    //  return *this;
    //}
    ~BinaryTree()//析構
    {
        if (NULL != _root)
        {
            Destroy(_root);
            _root = NULL;
        }
    }
    protected:
    //按照先序遍歷遞歸建樹
    Node* CreatTree(const T* a,size_t size,const T& invalid,size_t& index)//注意index的傳值方式
    {
        assert(a);
        Node* root = NULL;
        if (a[index] != invalid && index < size)//按先序遍歷建樹
        {
            root = new Node(a[index]);
            root->_lchild = CreatTree(a,size,invalid,++index);
            root->_rchild = CreatTree(a,size,invalid,++index);
        }
        return root;
    }
    //拷貝對象
    Node* Copy(Node* root)
    {
        Node* tmp = NULL;

        if(root)
        {
            tmp = new Node(root->_value);
            tmp->_lchild = Copy(root->_lchild);
            tmp->_rchild = Copy(root->_rchild);
        }
        return tmp;
    }
    //釋放空間
    void Destroy(Node*& root)
    {
        if(root)//用後序遍歷方式釋放空間
        {
            Destroy(root->_rchild);
            Destroy(root->_lchild);
            delete root;
            root = NULL;
        }
    }
private:
    Node* _root;//根節點
};




2、遍歷二叉樹 
二叉樹的遍歷方式一共分爲四種:先序遍歷、中序遍歷、後序遍歷和層序遍歷,而前三種遍歷又分爲遞歸遍歷和非遞歸遍歷,層序遍歷則是藉助隊列先進先出的特性來輔助完成。 
【遞歸遍歷二叉樹】
void preorder(Node* root)//先序遍歷打印樹的各個節點   if (root) { cout<<root->_value<<" "; //訪問當前節點的值   preorder(root->_lchild); //遞歸遍歷左子樹  preorder(root->_rchild); //遞歸遍歷右子樹   } }   void inorder(Node* root)//中序遍歷打印樹的各個節點  { if (root) { preorder(root->_lchild); //遞歸遍歷左子樹 cout<<root->_value<<" "; //訪問當前節點的值 preorder(root->_rchild); //遞歸遍歷右子樹  } } void postorder(Node* root)//後序遍歷打印樹的各個節點   { if (root) { preorder(root->_lchild); //遞歸遍歷左子樹  preorder(root->_rchild); //遞歸遍歷右子樹   cout<<root->_value<<" "; //訪問當前節點的值  } } void levelorder(Node* root)//層序遍歷打印樹的各個節點  { queue<Node*> q; if (root)   {   q.push(root);//將根節點插進隊列 } while(!q.empty()) { Node* front = q.front(); q.pop(); cout<<front->_value<<" "; if (front->_lchild) { q.push(front->_lchild); if (front->_rchild) q.push(front->_rchild); } } } 二叉樹的非遞歸遍歷:
public:
    void PreOrder()//先序遍歷打印樹的各個節點
    {
        cout<<"先序遍歷:";
        preorderR(_root);
        cout<<endl;
    }
    void InOrder()//中序遍歷打印樹的各個節點
    {
        cout<<"中序遍歷:";
        inorderR(_root);
        cout<<endl;
    }
    void PostOrder()//後序遍歷打印樹的各個節點
    {
        cout<<"後序遍歷:";
        postorderR(_root);
        cout<<endl;
    }
    void LevelOrder()//層序遍歷打印樹的各個節點
    {
        cout<<"層序遍歷:";
        levelorder(_root);
        cout<<endl;
    }

算法:
void preorderR(Node* root)//先序遍歷打印樹的各個節點
    {
        Node* cur = root;
        stack<Node*> s;
        while (!s.empty() || cur)//只要當前節點和棧不同時爲空,就說明樹沒遍歷完
        {
            while(cur)//先序遍歷,遇到樹根節點直接訪問數據並將其壓棧
            {
                cout<<cur->_value<<" ";
                s.push(cur);
                cur = cur->_lchild;
            }

            Node* top = s.top();//取出棧頂元素,到此說明此節點以及其左子樹已經訪問過了
            s.pop();

            cur = top->_rchild;//以子問題的方式去訪問右子樹
        }
        cout<<endl;
    }
    void inorderR(Node* root)//中序遍歷打印樹的各個節點
    {
        Node* cur = root;
        stack<Node*> s;
        while(!s.empty() || cur)//只要當前節點和棧不同時爲空,就說明樹沒遍歷完
        {
            while(cur)//中序遍歷,遇到樹根節點直接將其壓棧
            {
                s.push(cur);
                cur = cur->_lchild;
            }

            Node* top = s.top();//取出棧頂元素,到此說明此節點的左子樹已經訪問過了
            cout<<top->_value<<" ";//訪問棧頂元素(即根節點)
            s.pop();

            cur = top->_rchild;//以子問題的方式去訪問右子樹
        }
        cout<<endl;
    }
    void postorderR(Node* root)//後序遍歷打印樹的各個節點
    {
        Node* cur = root;
        Node* prev = NULL;//上一個訪問過的數據
        stack<Node*> s;
        while(!s.empty() || cur)//只要當前節點和棧不同時爲空,就說明樹沒遍歷完
        {
            //後序遍歷,遇到樹根節點直接將其壓棧
            while(cur)
            {
                s.push(cur);
                cur = cur->_lchild;
            }

            Node* top = s.top();//取棧頂元素,但不一定能訪問

            //當節點右子樹爲空或已經訪問過時對其直接進行訪問
            if (top->_rchild==NULL || top->_rchild==prev)
            {
                cout<<top->_value<<" ";
                prev = top;//將prev更新爲已經訪問的節點
                s.pop();
            }
            else//以子問題的方式去訪問右子樹
            {
                cur = top->_rchild;
            }
       }
        cout<<endl;
    }

    void levelorder(Node* root)//層序遍歷打印樹的各個節點
    {
        queue<Node*> q;
        if (root)
        {
            q.push(root);//將根節點插進隊列
        }
        while(!q.empty())
        {
            Node* front = q.front();
            q.pop();
            cout<<front->_value<<" ";
            if (front->_lchild)
            {
                q.push(front->_lchild);
            }
            if (front->_rchild)
            {
                q.push(front->_rchild);
            }
        }
    }




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