數組表示法用於完全二叉樹的存儲表示非常有效,但表示一般二叉樹,尤其是形態劇烈變化的二叉樹,存儲空間的利用很不理想
使用二叉鏈表表示二叉樹:
#include <iostream> using namespace std; template <class T> struct BinTreeNode{ T data; BinTreeNode<T> *leftChild,*rightChild; BinTreeNode():leftChild(NULL),rightChild(NULL){} BinTreeNode(T x,BinTreeNode<T> *l=NULL,BinTreeNode<T> *r=NULL):data(x),leftChild(l),rightChild(r){}; }; template <class T> class BinaryTree{ public: BinaryTree():root(NULL){} BinaryTree(T value):RefValue(value),root(NULL){} BinaryTree(const BinaryTree<T>& s){root=Copy(s.root);} //復制構造函數 ~BinaryTree(){destroy(root);} bool IsEmpty(){return(root==NULL);} BinTreeNode<T> *Parent(BinTreeNode<T> *current){ //返回父結點 return(root==NULL||root==current)?NULL:Parent(root,current); } BinTreeNode<T> *LeftChild(BinTreeNode<T> *current){ //返回左子女 return(current!=NULL)?current->leftChild:NULL; } BinTreeNode<T> *RightChild(BinTreeNode<T> *current){ //返回右子女 return(current!=NULL)?current->rightChild:NULL; } int Height(){return Height(root);} //返回樹高度 int Size(){return Size(root);} //返回結點數 BinTreeNode<T> *getRoot()const{return root;} //取根 void preOrder(void (*visit)(BinTreeNode<T> *p)){preOrder(root,visit);} //對根結點前序遍歷 void InOrder(void (*visit)(BinTreeNode<T> *p)){InOrder(root,visit);} //對根結點中序遍歷 void postOrder(void (*visit)(BinTreeNode<T> *p)){postOrder(root,visit);} //對根結點后序遍歷 void levelOrder(void (*visit)(BinTreeNode<T> *p)); //層次序遍歷 int Insert(const T& item); //插入新元素 BinTreeNode<T> *Find(T& item)const; //搜索 protected: BinTreeNode<T> *root; //二叉樹根指針 T RefValue; //數據輸入停止標志,用廣義表表示二叉樹的時候用 void CreateBinTree(istream& in,BinTreeNode<T> *subTree); //從文件讀入建樹 bool Insert(BinTreeNode<T> *subTree,const T&x); //插入 void destroy(BinTreeNode<T> *subTree); //刪除 BinTreeNode<T> *Copy(BinTreeNode<T> *orignode); //復制 int Height(BinTreeNode<T> *subTree)const; //返回樹高度 int Size(BinTreeNode<T> *subTree)const; //返回結點數 BinTreeNode<T> *Parent(BinTreeNode<T> *subTree,BinTreeNode<T> *current); //從結點subTree開始搜索結點current的父結點 BinTreeNode<T> *Find(BinTreeNode<T> *subTree,const T& x)const; //搜尋值為x的結點 void Traverse(BinTreeNode<T> *subTree,ostream& out); //前序遍歷輸出 void preOrder(BinTreeNode<T>* subTree, void (*visit)(BinTreeNode<T> *p)); //對p結點前序遍歷 void InOrder(BinTreeNode<T>* subTree, void (*visit)(BinTreeNode<T> *p)); //中序遍歷 void postOrder(BinTreeNode<T>* subTree, void (*visit)(BinTreeNode<T> *p)); //后序遍歷 friend istream& operator>>(istream& in,BinaryTree<T>& Tree); friend ostream& operator<<(ostream& out,BinaryTree<T>& Tree); friend bool operator==(const BinaryTree<T>& s,const BinaryTree<T>& t); bool equal(BinTreeNode<T> *a,BinTreeNode<T> *b)const; }; template <class T> void BinaryTree<T>::destroy(BinTreeNode<T> *subTree){ //私有函數,若指針subTree不為空,則刪除根為subTree的子樹 if(subTree!=NULL){ destroy(subTree->leftChild); destroy(subTree->rightChild); delete subTree; } } template <class T> BinTreeNode<T> *BinaryTree<T>::Parent(BinTreeNode<T> *subTree,BinTreeNode<T> *current){ //私有函數,從結點subTree開始搜索結點current的父結點,返回父結點地址或者NULL if(subTree==NULL) return NULL; if(subTree->leftChild==current || subTree->rightChild==current) return subTree; BinTreeNode<T> *p; if((p=Parent(subTree->leftChild,current))!=NULL) return p; //使用p=Parent(subTree->leftChild,current)遞歸在左子樹中搜索,p==NULL則說明搜索失敗 else return Parent(subTree->rightChild,current); } template <class T> void BinaryTree<T>::Traverse(BinTreeNode<T> *subTree,ostream& out){ //私有函數,搜索並前序輸出根為subTree的二叉樹 if(subTree!=NULL){ out<<subTree->data<<''; Traverse(subTree->leftChild,out); //遞歸搜索並輸出subTree的左子樹 Traverse(subTree->rightChild,out); //遞歸搜索並輸出subTree的右子樹 } } template <class T> istream& operator>>(istream& in,BinaryTree<T>& Tree){ //重載操作,輸入並建立一顆二叉樹Tree,in是輸入流對象 Tree.CreateBinTree(in,Tree.root); //此處友元函數不能直接訪問類的成員函數 return in; } template <class T> ostream& operator<<(ostream& out,BinaryTree<T>& Tree){ //重載操作,輸出一顆二叉樹Tree,out是輸出流對象 out<<"二叉樹的前序遍歷\n"; Tree.Traverse(Tree.root,out); //從根開始輸出 out<<endl; return out; } template <class T> bool operator==(const BinaryTree<T>& s,const BinaryTree<T>& t){ //判斷兩棵二叉樹的等價性,它需要是BinaryTree類的友元函數 return s.equal(s.root,t.root); //此處s是const對象,equal應該是const方法 } template <class T> void BinaryTree<T>::preOrder(BinTreeNode<T> *subTree, void (*visit)(BinTreeNode<T> *)) { if(subTree!=NULL){ visit(subTree); preOrder(subTree->leftChild,visit); preOrder(subTree->rightChild,visit); } } template <class T> void BinaryTree<T>::InOrder(BinTreeNode<T> *subTree, void (*visit)(BinTreeNode<T> *)) { //遞歸函數,此算法按照中序次序遍歷以subTree為根的子樹 if(subTree!=NULL){ InOrder(subTree->leftChild,visit); visit(subTree); InOrder(subTree->rightChild,visit); } } template <class T> void BinaryTree<T>::postOrder(BinTreeNode<T> *subTree, void (*visit)(BinTreeNode<T> *)) { if(subTree!=NULL){ postOrder(subTree->leftChild,visit); postOrder(subTree->rightChild,visit); visit(subTree); } } template <class T> int BinaryTree<T>::Size(BinTreeNode<T> *subTree)const{ //私有函數,介紹以subTree為根的二叉樹的結點個數 if(subTree==NULL) return 0; else return 1+Size(subTree->leftChild)+Size(subTree->rightChild); } template <class T> int BinaryTree<T>::Height(BinTreeNode<T> *subTree)const{ //私有函數,計算以subTree為根的二叉樹的深度 if(subTree==NULL) return 0; else{ int i=Height(subTree->leftChild); int j=Height(subTree->rightChild); return(i<j)?j+1:i+1; } } template <class T> BinTreeNode<T> *BinaryTree<T>::Copy(BinTreeNode<T> *orignode){ //私有函數,這個函數返回一個指針,給出一個以orignode為根的二叉樹的副本 if(orignode==NULL) return NULL; BinTreeNode<T> *temp=new BinTreeNode<T>; temp->data=orignode->data; temp->leftChild=Copy(orignode->leftChild); //此處注意不能直接=,因為需要建立新結點再賦值 temp->rightChild=Copy(orignode->rightChild); return temp; } template <class T> bool BinaryTree<T>::equal(BinTreeNode<T> *a,BinTreeNode<T> *b)const{ //如果a和b的子樹不同,則函數返回false,否則函數返回true,它需要是BinTreeNode類的友元函數 if(a==NULL && b==NULL) return true; if(a!=NULL && b!=NULL && a->data==b->data && equal(a->leftChild,b->leftChild) && equal(a->rightChild,b->rightChild)) return true; else return false; } template <class T> void BinaryTree<T>::CreateBinTree(istream& in,BinTreeNode<T> *subTree){ //私有函數,以前序遍歷方式遞歸建立二叉樹 T item; if(!in.eof()){ //讀不到輸入流時in.eof()為真 in>>item; subTree=new BinTreeNode<T>(item); if(subTree==NULL){ cerr<<"分配存儲錯誤!"<<endl; exit(1); } CreateBinTree(in,subTree->leftChild); CreateBinTree(in,subTree->rightChild); } else subTree=NULL; }
二叉鏈表找到父結點很困難,可以使用三叉鏈表
輸入輸出二叉樹時,可以輸入一個廣義表形式的二叉樹,此時需要用棧保存字符。棧的最大深度==二叉樹的高度==廣義表表示中圓括號嵌套的最大層數加1(根結點)
template <class T> void CreateBinTree(istream& in,BinTreeNode<char>* &BT){ //從輸入流in輸入二叉樹的廣義表表示建立對應的二叉鏈表,依次從保存廣義表的字符串ls中輸入字符 Stack<BinTreeNode<char> *> s; BT=NULL; //置空二叉樹表 BinTreeNode<char> *p,*t; int k; //用k作為處理左右子樹標志 char ch; in>>ch; while(ch!=RefValue){ //逐個字符處理 switch(ch){ case '(':s.Push(p);k=1;break; //輸入若是左擴號,則表明子表的開始,將根結點入棧,K置為1 case ')':s.Pop(t);break; //輸入若是右括號,則表明子表結束,將根結點出棧 case ',':k=2;break; //遇到的是逗號,則表示以左子女為根的子樹處理完畢 default:p=new BinTreeNode(ch); //輸入若是字母,為它建立新結點,根據k的值將其鏈接到父節點上 if(BT==NULL) BT=p; else if(k==1){ s.getTop(t); t->leftChild=p; //鏈入*t的左子女 } else{ s.getTop(t); t->rightChild=p; //鏈入*t的右子女 } } in>>ch; } } template <class T> void PrintBTree(BinTreeNode<T> *BT){ //以廣義表的形式輸出二叉樹 if(BT!=NULL){ cout<<BT->data; if(BT->leftChild!=NULL||BT->rightChild!=NULL){ cout<<'('; PrintBTree(BT->leftChild); cout<<','; if(BT->rightChild!=NULL) PrintBTree(BT->rightChild); cout<<')'; } } }