二叉樹的實現

來源:互聯網
上載者:User

由於本人能力有限,本文參考另一位大牛的代碼,在此對他表示感謝!

vs2008運行正確,如有誤,請各位大牛指正!

// BiTree.cpp : 定義控制台應用程式的進入點。//三叉鏈表實現二叉樹,有雙親域#include "stdafx.h"#include <iostream>using namespace std;const int MaxBTreeSize = 20;template<class T>//二叉樹節點類class BTNode{public:T data;BTNode* lchild;BTNode* rchild;BTNode* parent;BTNode():lchild(NULL),rchild(NULL),parent(NULL){ }};//二叉樹類template<class T>class BTree{public: //提供介面BTree();BTree(const BTree<T>& bTree);//拷貝建構函式~BTree();const BTree<T>& operator=(const BTree<T>& bTree);//重載賦值運算子void  createBTree();//按先序建立二叉樹void  InitBiTree(); //初始化二叉樹void  destoryBTree();//銷毀二叉樹bool  isEmptyBTree();//檢查二叉樹是否為空白void  inOrderTraverse(); //中序遍曆void  preOrderTraverse();//先序遍曆void  postOrderTraverse(); //後序遍曆void  levelOrderTraverse();//層序遍曆int   heightBTree();//二叉樹高度int   widthBTree(); //二叉樹寬度int   nodeCountBTree();  //二叉樹結點個數int   LeavesCountBTree();//二叉樹葉子個數int   nodeLevelBTree(T item);//結點item在的層次bool  allParentBTree(T item);//找item的所有祖先void  findCommonAncestor(const BTNode<T>* p1,const BTNode<T>* p2,BTNode<T>*& ancestor);//二叉樹中2個節點p1, p2的最小公用祖先節點void  longPathBTree();//輸出從每個葉子結點到根結點的最長路徑bool  isFullBTree();  //判斷二叉樹是否是完全二叉樹void  exchangeChildBTree();//交換二叉樹的孩子bool  findBTree(const T item,BTNode<T>*& ret)const;             //尋找結點bool  getParent(const BTNode<T>* p,BTNode<T>*& ret) const;      //返回父親bool  getLeftChild(const BTNode<T>* p,BTNode<T>*& ret) const;   //返回左孩子bool  getRightChild(const BTNode<T>* p,BTNode<T>*& ret) const;  //返回右孩子bool  getLeftSibling(const BTNode<T>* p,BTNode<T>*& ret) const; //返回左兄弟bool  getRightSibling(const BTNode<T>* p,BTNode<T>*& ret) const;//返回右兄弟protected://為了繼承BTNode<T>* root;private://為了實現公有函數void  create(BTNode<T>*& p);//以p為根結點建樹void  createParent(BTNode<T>* p);//為以p為根節點的樹設定其指向雙親的結點 void  copyTree(BTNode<T>*& copyTreeRoot,BTNode<T>* otherTreeRoot);//把以otherTreeRoot為根節點的部分拷貝到copyTreeRoot為根節點的部分void  destory(BTNode<T>*& p);//銷毀以p為根節點的子樹void  inOrder(BTNode<T>* p);//中序遍曆以p為根節點的子樹void  preOrder(BTNode<T>* p);//先序遍曆以p為根節點的子樹void  postOrder(BTNode<T>* p);//後序遍曆以p為根節點的子樹void  levelOrder(BTNode<T>* p);//層次遍曆以p為根節點的子樹int   height(BTNode<T>* p);//計算以p為根節點的高度int   width(BTNode<T>* p);int   max(int x,int y);int   min(int x,int y);//計算以p為根,倆孩子的最值int   nodeCount(BTNode<T>* p);//計算以p為根節點的結點個數int   leavesCount(BTNode<T>* p);//計算以p為根節點的葉子個數void  nodeLevel(T item,BTNode<T>* p,int level,int& nlevel);//計算以p為根節點的樹中item所在層次,如有多個元素,則返回一個最小值(離根最近),如果沒有出現,則返回0bool  find(BTNode<T>*p,const T item,bool& isFind,BTNode<T>*& cur)const;//在p指向的二叉樹中,傳回值為item的指標bool  allParent(T item,BTNode<T>* p,BTNode<T>* path[MaxBTreeSize],int& len,int& number,bool& isFind);//找item的所有祖先void  longPath(BTNode<T>* p,int len,int& maxLen,BTNode<T>*& longNode);//輸出從每個葉子結點到根結點的最長路徑bool  isFull(BTNode<T>* p);//判斷以p為根的二叉樹是不是完全二叉樹void  exchangeChild(BTNode<T>*& p);//交換以p為根節點的二叉樹};template<class T>BTree<T>::BTree(){root = NULL;}template<class T>BTree<T>::BTree(const BTree<T>& bTree)//拷貝建構函式{if (bTree.root == NULL){root = NULL;}else{copyTree(root,bTree.root);}}template<class T>void  BTree<T>::copyTree(BTNode<T>*& copyTreeRoot,BTNode<T>* otherTreeRoot)//把以otherTreeRoot為根節點的部分拷貝到copyTreeRoot為根節點的部分{//利用先序遍曆實現 遞迴if (otherTreeRoot != NULL){copyTreeRoot = new BTNode<T>;copyTreeRoot->data = otherTreeRoot->data;copyTree(copyTreeRoot->lchild,otherTreeRoot->lchild);copyTree(copyTreeRoot->rchild,otherTreeRoot->rchild);if (copyTreeRoot->lchild != NULL)//別忘了雙親域{copyTreeRoot->lchild->parent = copyTreeRoot;}if (copyTreeRoot->rchild != NULL){copyTreeRoot->rchild->parent = copyTreeRoot;}}}template<class T>BTree<T>::~BTree(){destory(root);}template<class T>void BTree<T>::destory(BTNode<T>*& p)//以後根遍曆的方式銷毀以p為根節點的子樹 {if (p!=NULL){destory(p->lchild);destory(p->rchild);delete p;p = NULL;}} template<class T>const BTree<T>& BTree<T>::operator=(const BTree<T>& bTree){if (this != &bTree)//避免自賦值{if (root!=NULL)//如果被賦值對象不空,則釋放資源{destory(root);}if (bTree.root == NULL){root = NULL;}else{copyTree(root,bTree.root);}}return *this;}template<class T>void  BTree<T>::createBTree()//按先序建立二叉樹{cout<<"請按先序次序輸入節點的值,#表示空結點:";create(root);}template<class T>void BTree<T>::create(BTNode<T>*& p)//以p為根結點建樹(藉助先序遍曆){T newData;cin>>newData;if (newData == '#')//輸入#表示結點為空白{p = NULL;}else{p = new BTNode<T>;//輸入非#則建立一個結點p->data = newData;create(p->lchild);//遞迴建立左子樹create(p->rchild);//遞迴建立右子樹if (p->lchild != NULL){p->lchild->parent = p;//別忘了雙親域}if (p->rchild != NULL){p->rchild->parent = p;}}}template<class T>void BTree<T>::createParent(BTNode<T>* p)//為以p為根節點的樹設定其指向雙親的結點 {//利用先序遍曆,邊遍曆邊初始化,在父親找到兒子時,為兒子賦值if (p == root){p->parent = NULL;}if (p->lchild != NULL){p->lchild->parent = p;}if (p->rchild != NULL){p->rchild->parent = p;}createParent(p->lchild);createParent(p->rchild);}template<class T>void  BTree<T>::InitBiTree() //初始化二叉樹{root = NULL;}template<class T>void  BTree<T>::destoryBTree()//銷毀二叉樹      {destory(root);}template<class T>bool  BTree<T>::isEmptyBTree()//檢查二叉樹是否為空白{return (root == NULL);}template<class T>void  BTree<T>::preOrderTraverse()//先序遍曆{preOrder(root);}template<class T>void  BTree<T>::preOrder(BTNode<T>* p)//先序遍曆以p為根節點的部分{if (p != NULL){cout<<p->data<<" ";preOrder(p->lchild);preOrder(p->rchild);}/*if (p==NULL){return;}cout<<p->data<<" ";preOrder(p->lchild);preOrder(p->rchild);*/}template<class T>void  BTree<T>::inOrderTraverse() //中序遍曆{inOrder(root);}template<class T>void  BTree<T>::inOrder(BTNode<T>* p)//中序遍曆以p為根節點的部分{if (p != NULL){inOrder(p->lchild);cout<<p->data<<" ";inOrder(p->rchild);}}template<class T>void  BTree<T>::postOrderTraverse() //後序遍曆{postOrder(root);}template<class T>void  BTree<T>::postOrder(BTNode<T>* p)//後序遍曆以p為根節點的部分{if (p != NULL){postOrder(p->lchild);postOrder(p->rchild);cout<<p->data<<" ";}}template<class T>void  BTree<T>::levelOrderTraverse()//層序遍曆{levelOrder(root);}template<class T>void  BTree<T>::levelOrder(BTNode<T>* p)//層次遍曆以p為根節點的子樹{//定義迴圈隊列BTNode<T> *queue[MaxBTreeSize];int front = 0;int rear = 0;BTNode<T> *current;if (p != NULL){       queue[(rear++)%MaxBTreeSize] = p;//根結點如隊列while(rear!=front)//隊列空時迴圈結束{current = queue[(front++)%MaxBTreeSize]; //出隊列cout<<current->data<<" ";//訪問結點//當前被訪問結點的左右孩子依次入隊列if ((rear+1)%MaxBTreeSize != front)//隊列不滿{if (current->lchild != NULL)//左孩子不空,入隊列{queue[(rear++)%MaxBTreeSize] = current->lchild;}}if ((rear+1)%MaxBTreeSize != front)//隊列不滿{if (current->rchild != NULL)//右孩子不空,入隊列{queue[(rear++)%MaxBTreeSize] = current->rchild;}}}}}template<class T>int BTree<T>::heightBTree()//二叉樹高度{return height(root);}template<class T>int BTree<T>::height(BTNode<T>* p)//計算以p為根節點的高度  利用後序遍曆,先計算左右子樹的高度{   if (p == NULL)   {   return 0;   }   else   {   return max(height(p->lchild),height(p->rchild))+1;   }  }template<class T>int   BTree<T>::widthBTree() //二叉樹寬度{return width(root);}template<class T>int BTree<T>::width(BTNode<T>* p)//利用一般隊列{//定義隊列BTNode<T> *queue[MaxBTreeSize];int front = 0;//指向隊列中第一個元素int rear = 0;//指向隊列中最後一個元素,注意此處與迴圈隊列不同//根結點入隊列queue[rear] = p;//注意此處與迴圈隊列不同BTNode<T> *current;int last = 0;//last記錄本層最後一個元素的下標int maxWidth = 0;//最終的寬度int temWidth = 0;//記錄每層的寬度    while(front <= last)//本層結點沒有完全出隊列{       current = queue[front++]; //出隊列   temWidth++;//記錄本層的寬度   if (current->lchild != NULL)//左孩子不空,入隊列   {           queue[++rear] = current->lchild;   }   if (current->rchild != NULL)//右孩子不空,入隊列   {   queue[++rear] = current->rchild;   }   if (last < front)//當本層出隊列完畢,更新下一層的last   {   last = rear;   if (temWidth > maxWidth)   {   maxWidth = temWidth;//更新最大寬度   }   temWidth = 0;//每層寬度求完,歸零   }}return maxWidth;}template<class T>int BTree<T>::nodeCountBTree()  //二叉樹結點個數{return nodeCount(root);}//利用後根遍曆得到template<class T>int BTree<T>::nodeCount(BTNode<T>* p)//計算以p為根節點的結點個數{if (p == NULL){        return 0;}else{return nodeCount(p->lchild)+nodeCount(p->rchild)+1;}}template<class T>int BTree<T>::LeavesCountBTree()//二叉樹葉子個數{return leavesCount(root);}//利用先根遍曆template<class T>int  BTree<T>::leavesCount(BTNode<T>* p)//計算以p為根節點的葉子個數{if (p == NULL)//遞迴出口一{return 0;}if (p->lchild==NULL && p->rchild==NULL)//出口二{return 1;}else{return leavesCount(p->lchild)+leavesCount(p->rchild);}   }template<class T>int BTree<T>::nodeLevelBTree(T item)//結點item在的層次,如有多個結點,返回最近的層次{int nlevel = 0;nodeLevel(item,root,1,nlevel);return nlevel;}//利用先序次序,遇到第一次結點即停止  用一個變數記錄層次template<class T>void BTree<T>::nodeLevel(T item,BTNode<T>* p,int level,int& nlevel)//計算以p為根節點的中item所在層次,如有多個元素,則返回一個最小值(離根最近),如果沒有出現,則返回0{    if (p == NULL)    {nlevel = 0;//return;    }else{if (p->data == item){nlevel = level; //level記錄的是本層層數,level初始值為1//return;}else//沒有找到,在左右子樹中遞迴的尋找{if (nlevel == 0)//nlevel=0表示沒有找到{nodeLevel(item,p->lchild,level+1,nlevel);}if (nlevel == 0)//如果在左子樹上找到就停止,不會再到右子樹上尋找{nodeLevel(item,p->rchild,level+1,nlevel);}}}}template<class T>bool BTree<T>::allParentBTree(T item)//找item的所有祖先{BTNode<T> *path[MaxBTreeSize];int len = 0;int number = 0;bool isFind = false;allParent(item,root,path,len,number,isFind);cout<<item<<"的所有祖先:";for (int i=0; i<number;i++){cout<<path[i]->data<<" ";}cout<<endl;return true;}//利用先序遍曆,將item所有的祖先存放到數組path中,然後從根開始輸出//找到第一個值為item的祖先template<class T>bool BTree<T>::allParent(T item,BTNode<T>* p,BTNode<T>* path[MaxBTreeSize],int& len,int& number,bool& isFind)//找item的所有祖先{//參數的設定很重要,要找item,因此要有標誌isFind,祖先很多用數組儲存,祖先個數用numberif (p!=NULL){if (!isFind)//沒有找到{if (p->data!=item){path[len++] = p;//沒有找到,將當前節點放入數組path中allParent(item,p->lchild,path,len,number,isFind);//在左右子樹中繼續尋找allParent(item,p->rchild,path,len,number,isFind);len--;//將不是祖先的結點從數組中剔除}            else{isFind = true;number = len;}}}return isFind;}template<class T>void BTree<T>::findCommonAncestor(const BTNode<T>* p1,const BTNode<T>* p2,BTNode<T>*& ancestor)//二叉樹中2個節點p1, p2的最小公用祖先節點{BTNode<T> *path1[MaxBTreeSize];int p1_len = 0;int p1_number = 0;bool isFind_p1 = false;BTNode<T> *path2[MaxBTreeSize];int p2_len = 0;int p2_number = 0;bool isFind_p2 = false;allParent(p1->data,root,path1,p1_len,p1_number,isFind_p1);allParent(p2->data,root,path2,p2_len,p2_number,isFind_p2);/*for (int i=0; i<p1_number&&i<p2_number; i++)*/for (int i=0; i<min(p1_number,p2_number); i++){if (path1[i] != path2[i]){ancestor = path1[i-1];break;}if (i==min(p1_number,p2_number)-1){ancestor = path1[i];}}}template<class T>void BTree<T>::longPathBTree()//輸出從每個葉子結點到根結點的最長路徑{   int len = 0;   int maxLen = 0;//最大路徑長度   BTNode<T> *longNode;//記錄最長路徑上的葉子結點   longPath(root,len,maxLen,longNode);   if (root == NULL)   {   cout<<"二叉樹為空白!"<<endl;   }   else   {   cout<<"從葉子結點到根結點的最長路徑:";   while(longNode!=NULL)   {   cout<<longNode->data<<" ";   longNode = longNode->parent;   }   cout<<endl;   }} /* 求出最長路徑的那個葉子節點,只有路徑可以藉助parent和longNode求出 方法:藉助先序遍曆完成 p:要求二叉樹的最長路徑 len: 正在處理節點的層次數  longNode表示找到後,指向最長路徑 maxLen:表示最長的長度 */template<class T>void BTree<T>::longPath(BTNode<T>* p,int len,int& maxLen,BTNode<T>*& longNode)//輸出從每個葉子結點到根結點的最長路徑{    if (p == NULL)    {len = 0;    }else{len++;//記錄正在處理結點的層數if (p->lchild==NULL && p->rchild==NULL)//找到葉子結點 先考慮特殊情況{if (len>maxLen){maxLen = len;//更新最大路徑長度longNode = p;}}else//當前處理的結點不是葉子結點{longPath(p->lchild,len,maxLen,longNode);//在左右子樹上繼續尋找葉子結點longPath(p->rchild,len,maxLen,longNode);len--;//注意此步 找路徑和找祖先一樣都需要減}}}template<class T>bool BTree<T>::isFullBTree()  //判斷二叉樹是否是完全二叉樹{if (isFull(root)){return true;}else{return false;}}/*思路:按層次遍曆方式,先把所有結點(不管當前結點是否有左右孩子)都入隊列. 若為完全二叉樹,則層次遍曆時得到的肯定是一個連續的不包含null 指標的序列. 如果序列中出現了null 指標,則說明不是完全二叉樹。*/ template<class T>bool BTree<T>::isFull(BTNode<T>* p)//判斷以p為根的二叉樹是不是完全二叉樹{bool isExist = false;//表示現在這個狀態下,隊列中是不是存在null 指標   /*  當隊中出現null 指標時,看看null 指標之後是不是有非空的指標, 如果null 指標後有非null 指標出現,則肯定不是完全二叉樹,     如果null 指標之後沒有非null 指標,則是完全二叉樹 */  BTNode<T> *queue[MaxBTreeSize];int front = 0;int rear = 0;BTNode<T> *current;if (p!=NULL){         queue[(rear++)%MaxBTreeSize] = p;  while(front != rear) { current = queue[(front++)%MaxBTreeSize]; if (current == NULL)//存在null 指標 { isExist = true; } else {//在current之前就已經出現null 指標                if (isExist && (current->lchild!=NULL || current->rchild!=NULL))                {return false;                }if ((rear+1)%MaxBTreeSize != front){queue[(rear++)%MaxBTreeSize] = current->lchild;}if ((rear+1)%MaxBTreeSize != front){    queue[(rear++)%MaxBTreeSize] = current->rchild;}    }        }}return true;}template<class T>void BTree<T>::exchangeChildBTree()//交換二叉樹的孩子{exchangeChild(root);}template<class T>void BTree<T>::exchangeChild(BTNode<T>*& p)//交換以p為根節點的二叉樹 以先序的方式遞迴實現{if (p!=NULL){if (p->lchild!=NULL || p->rchild!=NULL){BTNode<T> *temp;temp = p->lchild;p->lchild = p->rchild;p->rchild =temp;}exchangeChild(p->lchild);exchangeChild(p->rchild);}}template<class T>bool BTree<T>::findBTree(const T item,BTNode<T>*& ret)const             //尋找結點{bool isFind = false;return find(root,item,isFind,ret);}template<class T>bool BTree<T>::find(BTNode<T>*p,const T item,bool& isFind,BTNode<T>*& cur)const//在p指向的二叉樹中,傳回值為item的指標{if (p!=NULL){if (!isFind){if (p->data != item)//沒有找到,在左子樹中繼續尋找{find(p->lchild,item,isFind,cur);}else{isFind = true;cur = p;}if (p->data != item)//沒有找到,在右子樹中繼續尋找{find(p->rchild,item,isFind,cur);}else{isFind = true;cur = p;}}}return isFind;}template<class T>bool BTree<T>::getParent(const BTNode<T>* p,BTNode<T>*& ret) const      //返回父親{if (p->parent!=NULL){ret = p->parent;return true;}return false;}template<class T>bool BTree<T>::getLeftChild(const BTNode<T>* p,BTNode<T>*& ret) const   //返回左孩子{if (p->lchild!=NULL){ret = p->lchild;return true;}return false;}template<class T>bool BTree<T>::getRightChild(const BTNode<T>* p,BTNode<T>*& ret) const  //返回右孩子{if (p->rchild!=NULL){   ret = p->rchild;   return true;}return false;}template<class T>bool BTree<T>::getLeftSibling(const BTNode<T>* p,BTNode<T>*& ret) const //返回左兄弟{if (p->parent!=NULL){if (p->parent->lchild != p){            ret = p->parent->lchild;return true;}}return false;}template<class T>bool BTree<T>::getRightSibling(const BTNode<T>* p,BTNode<T>*& ret) const//返回右兄弟{if (p->parent!=NULL){if (p->parent->rchild != p){ret = p->parent->rchild;return true;}}return false;}template<class T>int BTree<T>::max(int x,int y){return (x>y?x:y);}template<class T>int BTree<T>::min(int x,int y)//計算以p為根,倆孩子的最值{return (x<y?x:y);}int _tmain(int argc, _TCHAR* argv[]){BTree<char> *tree = new BTree<char>;tree->createBTree();cout<<"先序遍曆:";tree->preOrderTraverse();cout<<endl;cout<<"中序遍曆:";tree->inOrderTraverse();cout<<endl;cout<<"後序遍曆:";tree->postOrderTraverse();cout<<endl;cout<<"層序遍曆:";tree->levelOrderTraverse();cout<<endl;cout<<"樹的高度:"<<tree->heightBTree()<<endl;cout<<"樹的寬度:"<<tree->widthBTree()<<endl;    cout<<"樹的結點個數:"<<tree->nodeCountBTree()<<endl;cout<<"樹的葉子結點個數:"<<tree->LeavesCountBTree()<<endl;cout<<"E所在的層次:"<<tree->nodeLevelBTree('E')<<endl;    char a = 'F';cout<<tree->allParentBTree(a);cout<<"樹是否為完全二叉樹?1表示是,0表示否。結果是:"<<tree->isFullBTree()<<endl;    tree->longPathBTree();BTNode<char> *ret;if (tree->findBTree('E',ret)){if (ret->lchild){           cout<<"左孩子:"<<ret->lchild->data<<endl;}        else{cout<<ret->data<<"沒有左孩子!"<<endl;}if (ret->rchild){cout<<"右孩子:"<<ret->rchild->data<<endl;}else{cout<<ret->data<<"沒有右孩子!"<<endl;}}    BTNode<char> *node1;BTNode<char> *node2;tree->findBTree('F',node1);tree->findBTree('E',node2);BTNode<char> *ancesor;tree->findCommonAncestor(node1,node2,ancesor);cout<<node1->data<<"和"<<node2->data<<"的最小公用祖先:"<<ancesor->data<<endl;system("pause");return 0;}

 

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.