二叉樹C++實現資料結構實驗
阿新 • • 發佈:2019-02-14
#include <iostream> #include <string.h> #include <stack> #include <queue> using namespace std; template<class T> struct BiNode //二叉數節點 { T data; BiNode<T>* lchild, *rchild; }; template<class T> //模板類 class BiTree { public: BiTree(); //預設建構函式 ~BiTree(); //解構函式 BiNode<T>* GetRoot(); //返回根節點 void PreOrder(BiNode<T>* node); //先序遍歷 void InOrder(BiNode<T>* node); //中序遍歷 void PostOrder(BiNode<T>* node); //後序遍歷 void LevelOrder(BiNode<T>* node); //層次遍歷 //選做非遞迴實現 void PreOrderNonRec(BiNode<T>* node); //先 void InOrderNonRec(BiNode<T>* node); //中 void PostOrderNonRec(BiNode<T>* node); //後 //選做深度,節點數,葉子節點數, int NodesNum(BiNode<T>* node); //節點數 int TreeDepth(BiNode<T>* node); //深度 int LeafNum(BiNode<T>* node); //葉子節點數 //選做交換子樹 void SwapChild(BiNode<T>* node); //交換子樹 private: BiNode<T>* m_root; //獲取根節點 BiNode<T>* Create(); //建立二叉樹 }; template<class T> BiTree<T>::BiTree() { m_root = new BiNode<T>; m_root = Create(); } template<class T> BiTree<T>::~BiTree(){} template<class T> BiNode<T>* BiTree<T>::Create() //1. 按先序序列構造一棵二叉連結串列表示的二叉樹T; { char ch=getchar(); BiNode<T>* pnode; if (ch == ' ') pnode = NULL; else { pnode = new BiNode<T>; pnode->data = ch; pnode->lchild = Create(); pnode->rchild = Create(); } return pnode; } template<class T> BiNode<T>* BiTree<T>::GetRoot() { return m_root; } template<class T> void BiTree<T>::PreOrder(BiNode<T>* node) { if (!node) return; else { cout << node->data; PreOrder(node->lchild); PreOrder(node->rchild); } } template<class T> void BiTree<T>::InOrder(BiNode<T>* node) { //前後定根,中序定左右 if (!node) return; else { InOrder(node->lchild); cout << node->data; InOrder(node->rchild); } } template<class T> void BiTree<T>::PostOrder(BiNode<T>* node) { if (!node) return; else { PostOrder(node->lchild); PostOrder(node->rchild); cout << node->data; } } template<class T> void BiTree<T>::LevelOrder(BiNode<T>* node) { //層次遍歷需要queue來實現,思路: //@1初始化queue // if root為空 返回 //@2 push(root) //@3 while(queue不為空) // s <-- queue.front() // queue.pop() // 輸入s.data // if(s的左子樹不空) // s的左子樹入隊 // if(s的右子樹不空) // s的右子樹入隊 queue<BiNode<T>*> q; BiNode<T>* s = node; if (!s) return; q.push(s); while (!q.empty()) { s = q.front(); q.pop(); cout << s->data; if (s->lchild) q.push(s->lchild); if (s->rchild) q.push(s->rchild); } } //先序遍歷非遞迴需要藉助stack s來實現,模擬遞迴呼叫 //總的迴圈邊界是當前節點不為空或者stack不空, template<class T> void BiTree<T>::PreOrderNonRec(BiNode<T>* node) { stack<BiNode<T>*> s; BiNode<T>* p = node; while (p|| !s.empty()) { /* @1.每次找當前的節點的左子節點直到左為空,經過的節點入棧, @2.然後彈出當前節點,搜尋一次右節點,如果p為空並且s空則退出否則繼續@1 */ while (p)//這裡執行VL { cout << p->data;//V s.push(p);//訪問過的加入棧 p = p->lchild;//L } if (!s.empty())//這裡執行R { p = s.top(); s.pop(); p = p->rchild;//R } } } template<class T> void BiTree<T>::InOrderNonRec(BiNode<T>* node) { //@1 在當前節點p非空時候,將p入棧s,p的左子樹賦給p,保證左子樹都能入棧 // p為空時候,也就是左子樹最左邊訪問到了,這時候在棧非空的時候 //@2 取棧頂給p,輸入p,出棧,這時候最底層的最左邊節點訪問了,將p的右子樹賦給p,重複@1 stack<BiNode<T>*> s; BiNode<T>* p = node; while (p|| !s.empty()) { while (p)//這裡執行L { s.push(p); p = p->lchild; } if (!s.empty())//這裡執行VR { p = s.top(); cout << p->data; s.pop(); p = p->rchild; } } } template<class T> void BiTree<T>::PostOrderNonRec(BiNode<T>* node) { //訪問子節點的條件有兩種 //1.當前節點的左右節點都為空,可以直接訪問 //2.前一個被訪問的節點是當前節點的子節點 //這樣就需要兩個指標,一個指向當前一個指向前一個被訪問的節點 //然後保證入棧順序是先右再左,(這裡先壓右再壓左,這樣左在上面,就先訪問左) if (!node) return; stack<BiNode<T>*> s; s.push(node); BiNode<T>* pre = NULL; BiNode<T>* cur; while (!s.empty()) { cur = s.top(); if (!cur->lchild&& !cur->rchild ||(pre != NULL) && (pre == cur->lchild || pre == cur->rchild))//上一次訪問的是當前節點的左子樹 { cout << cur->data; s.pop(); pre = cur;//pre是前一個被訪問的節點 } else { if (cur->rchild) s.push(cur->rchild); if (cur->lchild) s.push(cur->lchild); } } } template<class T> int BiTree<T>::LeafNum(BiNode<T>* node) { //遞迴思路:找到葉子節點返回值加一,返回值計數 //2種情況 //1.節點為空,返回 0,傳遞回去 //2.每當到達葉子節點,返回 1,傳遞給上一層函式 if (!node) return 0; if (!node->lchild&&!node->rchild) return 1; return LeafNum(node->lchild) + LeafNum(node->rchild); } template<class T> int BiTree<T>::TreeDepth(BiNode<T>* node) { /* 遞迴思路: 每個節點都有自己的左右子樹, 每次返回當前節點左右子樹長度大的那個 1.如果根節點為空,則深度為0,返回0,遞迴的出口 2.否則深度至少為1,然後累加他們左右子樹的深度, */ int LChildDep = 1, RChildDep = 1; if (!node) return 0; LChildDep += TreeDepth(node->lchild);//每次返回之前子樹的長度 RChildDep += TreeDepth(node->rchild); return (LChildDep>RChildDep) ? (LChildDep) : (RChildDep); } template<class T> int BiTree<T>::NodesNum(BiNode<T>* node) { //思路,遞迴遍歷所有節點,如果不是空節點的話,遞迴返回值加1 if (!node) return 0; return NodesNum(node->lchild) + NodesNum(node->rchild) + 1; } template<class T> void BiTree<T>::SwapChild(BiNode<T>* node) { //思路,交換所有節點的節點,每個節點走一遍 if (node) { swap(node->lchild, node->rchild); SwapChild(node->lchild); SwapChild(node->rchild); } } /* 樣例輸入: ABC DE G F ↙ 樣例輸出: 先序建立一棵二叉樹,請輸入節點的值:ABC DE G F 建立完畢. 先序:ABCDEGF 中序:CBEGDFA 後序:CGEFDBA 層序:ABCDEFG 選做題1:採用非遞迴演算法實現二叉樹遍歷 先序:ABCDEGF 中序:CBEGDFA 後序:CGEFDBA 選做題2:求二叉樹的深度/結點數目/葉結點數目 TreeDepth is 5 NodesNum is 7 LeafNum is 3 選做題3:將二叉樹每個結點的左右子樹交換位置。 交換完畢. 先序:ABDFEGC 中序:AFDGEBC 後序:FGEDCBA 層序:ABDCFEG */ int main() { cout << "先序建立一棵二叉樹,請輸入節點的值:"; BiTree<char> bitree; cout << "建立完畢." << endl; cout << "先序:"; bitree.PreOrder(bitree.GetRoot()); cout << endl; cout << "中序:"; bitree.InOrder(bitree.GetRoot()); cout << endl; cout << "後序:"; bitree.PostOrder(bitree.GetRoot()); cout << endl; cout << "層序:"; bitree.LevelOrder(bitree.GetRoot()); cout << endl; cout << "選做題1:採用非遞迴演算法實現二叉樹遍歷" << endl; cout << "先序:"; bitree.PreOrderNonRec(bitree.GetRoot()); cout << endl; cout << "中序:"; bitree.InOrderNonRec(bitree.GetRoot()); cout << endl; cout << "後序:"; bitree.PostOrderNonRec(bitree.GetRoot()); cout << endl; cout << "選做題2:求二叉樹的深度/結點數目/葉結點數目" << endl; cout << "深度為 : " << bitree.TreeDepth(bitree.GetRoot()) << endl; cout << "結點數目 : " << bitree.NodesNum(bitree.GetRoot()) << endl; cout << "葉結點數目: " << bitree.LeafNum(bitree.GetRoot()) << endl; cout << "選做題3:將二叉樹每個結點的左右子樹交換位置。" << endl; bitree.SwapChild(bitree.GetRoot()); cout << "交換完畢." << endl; cout << "先序:"; bitree.PreOrder(bitree.GetRoot()); cout << endl; cout << "中序:"; bitree.InOrder(bitree.GetRoot()); cout << endl; cout << "後序:"; bitree.PostOrder(bitree.GetRoot()); cout << endl; cout << "層序:"; bitree.LevelOrder(bitree.GetRoot()); cout << endl; system("pause"); }