由於本人能力有限,本文參考另一位大牛的代碼,在此對他表示感謝!
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;}