C++ 二叉樹的實現、基本操作以及指標使用注意事項(轉自部落格)
阿新 • • 發佈:2018-12-24
內容:
- 模板實現簡單的二叉樹
- 二叉樹的前序,中序,後序遍歷
- 統計二叉樹結點的個數和深度
- 二叉樹的銷燬操作
具體的實現過程及注意事項見程式碼部分;
#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"; } } }