数据结构-二叉树(2)链表法和广义表法表示二叉树
数组表示法用于完全二叉树的存储表示非常有效,但表示一般二叉树,尤其是形态剧烈变化的二叉树,存储空间的利用很不理想
使用二叉链表表示二叉树:
#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<<')'; } } }