二叉樹的實現

/*********************************************************
* Description:參數傳遞:C++ 二叉樹的實現以及指針使用注意事項
* Author:charley
* DateTime:2010-12-8 11:00
* Compile Environment:win7+vs2008
***********************************************************/


#include <iostream>
using namespace std;


//*************************************************************************************
//二叉樹結點類的定義
template<class T>                  //模版結構體
struct TreeNode
{
    T data;                       //節點的內容
    TreeNode <T> *Lchild,*Rchild; //節點的左子樹和右子樹


//可選擇參數的默認構造函數
    /*TreeNode(T nodeValue = T(),TreeNode<T> *leftNode = NULL,TreeNode<T> *rightNode = NULL )
        :data(nodeValue),Lchild(leftNode),Rchild(rightNode){} */      
};


//**************************************************************************************
//二叉樹的建立
template <class T> //模版方法
void createBinaryTree(TreeNode<T> *&root )  //傳遞指針的引用
{
    TreeNode<T>* p = root;
    T nodeValue ;
    cin>>nodeValue;
    if(nodeValue==-1)
    {
        root=NULL;
    }
    else
    {
        root=new TreeNode<T>();            //構造一個節點
        root->data = nodeValue;
        createBinaryTree(root->Lchild);    //遞歸構造左子樹
        createBinaryTree(root->Rchild);    //遞歸構造右子樹
    }
}


//************************************************************************************
//二叉樹的先序遍歷
template <class T>
void preOrder( TreeNode<T> * & p) //傳遞指針的引用
{
    if(p)
    {
        cout<<p->data<<" ";
        preOrder(p->Lchild);
        preOrder(p->Rchild);
    }
}


//**************************************************************************************
//二叉樹的中序遍歷
template <class T>
void inOrder(TreeNode<T> * & p) //傳遞指針的引用
{
    
    if(p)
    {
        inOrder(p->Lchild);
        cout<<p->data<<" ";
        inOrder(p->Rchild);
    }
}


//**************************************************************************************
//二叉樹的後序遍歷
template <class T>
void postOrder(TreeNode<T> *& p) //傳遞指針的引用
{
    if(p)
    {
        postOrder(p->Lchild);
        postOrder(p->Rchild);
        cout<<p->data<<" ";
    }
}


//*************************************************************************************
//統計二叉樹中結點的個數
template<class T>
int countNode(TreeNode<T> * & p) //傳遞指針的引用
{
    if(p == NULL) return 0;
    return 1+countNode(p->Lchild)+countNode(p->Rchild);
}


//***********************************************************************************
//求二叉樹的深度
template<class T>
int depth(TreeNode<T> *& p) //傳遞指針的引用
{
    if(p == NULL)
        return -1;
    int h1 = depth(p->Lchild);
    int h2 = depth(p->Rchild);
    if(h1>h2)return (h1+1);
    return h2+1;
}


//***********************************************************************************
//二叉樹的消毀操作
//容易混淆的錯誤聲明:void destroy(TreeNode<T>* p) 這種聲明會創建一個局部的臨時對象來保存傳遞的指針
//雖然2個指針都執行同一塊堆空間,delete局部指針 也會刪除二叉樹結構所佔用的堆內存
//但是全局傳遞的那個指針將會是垃圾指針,會產生不可預料的錯誤
//void destroy(TreeNode<T> *& p) 此函數的參數爲全局指針的一個別名,代表全局指針rootNode本身
// 這樣p = NULL;能達到置空指針的左右
//可選的方案是在調用完destroy方法之後,在主函數中執行rootNode = NULL操作
template<class T>
void destroy(TreeNode<T> *& p)  //傳遞指針的引用,消毀函數,用來消毀二叉樹中的各個結點
{
    if(p)
    {
//錯誤 return之後 沒有執行delete p
        //return destroy(p->Lchild);
        //return destroy(p->Rchild);


destroy(p->Lchild);
destroy(p->Rchild);


//delete只能釋放由用戶通過new方式在堆中申請的內存,
//是通過變量聲明的方式由系統所聲明的棧內存不能使用delete刪除


//delete和free函數一樣,不修改它參數對應指針指向的內容,也不修改指針本身,
//只是在堆內存管理結構中將指針指向的內容標記爲可被重新分配
        delete p;


//堆上內存釋放 棧上指針並不銷燬
//此時p指向的地址未知,此時執行*p = ? 操作會導致不可預料的錯誤
//但是可以重新賦值p = &x;
//最好delete之後把P置空
p = NULL;


    }
}


//********************************************************************************
//主函數的設計 
int main ()
{
    TreeNode<int> * rootNode = NULL;
    int choiced = 0;
    while(true)
    {
        system("cls"); //清屏
        cout<<"\n\n\n                              ---主界面---\n\n\n";
        cout<<"                     1、創建二叉樹                2、先序遍歷二叉樹\n";
        cout<<"                     3、中序遍歷二叉樹            4、後序遍歷二叉樹\n";
        cout<<"                     5、統計結點總數              6、查看樹深度    \n";
        cout<<"                     7、消毀二叉樹                0、退出\n\n";
        cout<<"             請選擇操作:";
        cin>>choiced;
        if(choiced == 0)
            return 0;
        else if(choiced == 1)
        {
            system("cls");
            cout<<"請輸入每個結點,回車確認,並以-1結束:\n";
            createBinaryTree(rootNode );
        }
        else if(choiced == 2)
        {
            system("cls");
            cout<<"先序遍歷二叉樹結果:\n";
            preOrder(rootNode);
            cout<<endl;
            system("pause"); //暫停屏幕
        }
        else if(choiced == 3)
        {
            system("cls");
            cout<<"中序遍歷二叉樹結果:\n";
            inOrder(rootNode);
            cout<<endl;
            system("pause");
        }
        else if(choiced == 4)
        {
            system("cls");
            cout<<"後序遍歷二叉樹結果:\n";
            postOrder(rootNode);
            cout<<endl;
            system("pause");
        }
        else if(choiced == 5)
        {
            system("cls");
            int count = countNode(rootNode);
            cout<<"二叉樹中結點總數爲"<<count<<endl;
            system("pause");
        }
        else if(choiced == 6)
        {
            system("cls");
            int dep = depth(rootNode);
            cout<<"此二叉樹的深度爲"<<dep<<endl;
            system("pause");
        }
        else if(choiced == 7)
        {
            system("cls");
            cout<<"二叉樹已被消毀!\n";
            destroy(rootNode);
            cout<<endl;
            system("pause");
        }
        else 
        {
            system("cls");
            cout<<"\n\n\n\n\n\t錯誤選擇!\n";
        }
        
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章