三叉链表实现二叉树的基本操作
三叉链表存储表示
改进于二叉链表,增加指向父节点的指针,能更好地实现结点间的访问。
存储结构
/* 二叉树的三叉链表存储表示 */ typedef struct BiTPNode { TElemType data; struct BiTPNode *parent,*lchild,*rchild; /* 双亲、左右孩子指针 */ }BiTPNode,*BiPTree;
下面给出二叉树采用三叉链表,实现了二叉树的构造、遍历、深度、宽度、结点个数、叶子个数 以及 结点的交换、层次、祖先、双亲、左孩子、右孩子、左兄弟、右兄弟各种功能:
#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所在层次,如有多个元素,则返回一个最小值(离根最近),如果没有出现,则返回0 bool 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& seat,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(this->root,bTree.root); } } template<class T> BTree<T>::~BTree() { destory(root); } 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(this->root,bTree.root); } } return *this; } template<class T> void BTree<T>::createBTree() { cout<<"按先序次序输入各结点值,输入#表示空结点:"<<endl; create(root); } /*借助先序遍历创建二叉树*/ template<class T> void BTree<T>::create(BTNode<T>*& p) { T newData; cin>>newData; if ('#'==newData) { p=NULL; } else { p = new BTNode<T>; p->data = newData; //注意,把左孩子链到父亲的左链域的操作是在调用这个函数体的函数体中进行,具体就是p->lchild = new BTNode<T>; 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) { 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>::copyTree(BTNode<T>*& dstTreeRoot,BTNode<T>* srcTreeRoot) { if (srcTreeRoot) { dstTreeRoot = new BTNode<T>; dstTreeRoot->data = srcTreeRoot->data; copyTree(dstTreeRoot->lchild,srcTreeRoot->lchild); copyTree(dstTreeRoot->rchild,srcTreeRoot->rchild); if (dstTreeRoot->lchild)//如果自己的孩子存在,则为孩子找到孩子的父亲 { dstTreeRoot->lchild->parent = dstTreeRoot; } if (dstTreeRoot->rchild) { dstTreeRoot->rchild->parent = dstTreeRoot; } } } template<class T> bool BTree<T>::isEmptyBTree() { return (root==NULL); } template<class T> void BTree<T>::preOrderTraverse() { preOrder(root); cout<<endl; } template<class T> void BTree<T>::preOrder(BTNode<T>* p) { if (p) { cout<<p->data; preOrder(p->lchild); preOrder(p->rchild); } } template<class T> void BTree<T>::inOrderTraverse() { inOrder(root); cout<<endl; } template<class T> void BTree<T>::inOrder(BTNode<T>* p) { if (p) { inOrder(p->lchild); cout<<p->data; inOrder(p->rchild); } } template<class T> void BTree<T>::postOrderTraverse() { postOrder(root); cout<<endl; } template<class T> void BTree<T>::postOrder(BTNode<T>* p) { if (p) { postOrder(p->lchild);//先访问左结点 postOrder(p->rchild);//再访问右结点 cout<<p->data; //再访问根 } } template<class T> void BTree<T>::levelOrderTraverse() { levelOrder(root); cout<<endl; } template<class T> void BTree<T>::levelOrder(BTNode<T>* p) { BTNode<T>* cur; //定义队列 int front=0; int rear=0; BTNode<T>* queue[MaxBTreeSize]; if (p) { queue[(rear++)%MaxBTreeSize]=p; while(front != rear)//队空停止执行 { cur = queue[(front++)%MaxBTreeSize];//总是先出队,在访问,在把孩子入队 cout<<cur->data; if ((rear+1)%MaxBTreeSize != front)//队不满,入左孩子 { if (cur->lchild) { queue[(rear++)%MaxBTreeSize]=cur->lchild; } } if ((rear+1)%MaxBTreeSize != front)//队不满,入右孩子 { if (cur->rchild) { queue[(rear++)%MaxBTreeSize]=cur->rchild; } } } } } template<class T> int BTree<T>::heightBTree() { return height(root); } /*利用后根遍历得到--先算左右子树高度,再计算自己的高度*/ template<class T> int BTree<T>::height(BTNode<T>* p) { if (!p) { return 0; } else { /* int lchildHeight = 1+height(p->lchild); int rchildHeight = 1+height(p->rchild); if (lchildHeight > rchildHeight) { return lchildHeight; } else { return rchildHeight; } */ return 1+max(height(p->lchild),height(p->rchild)); } } /*借助层次遍历*/ template<class T> int BTree<T>::width(BTNode<T>* p) { //使用队列,但是不能使用循环的队列,只能使用一般的队列,因为循环队列正常情况下也会出现front>last BTNode<T>* cur; int front = 0;//这里front总是指向第一个元素,和循环队列没有区别 int rear=0; //这里rear总是指向最后一个元素,和循环队列有区别,循环队列总是指向最后一个元素的下一位front>last int last=0;//last是本层中最右一个节点的下标 int tmpWidth = 0;//tmpWidth表示局部宽度 int maxWidth = 0;//maxWidth保存最大宽度 BTNode<T>* queueBTNode[MaxBTreeSize]; if (!p) { maxWidth=0; } else { //根结点入队 queueBTNode[rear] = p; while(front<=last)//当本层结点还没全部出队 { cur = queueBTNode[front++];//front总是指向第一个元素 tmpWidth++; if (cur->lchild) { queueBTNode[++rear]=cur->lchild;//rear总是指向刚刚入队的结点,即总是指向最后一个元素 } if (cur->rchild) { queueBTNode[++rear]=cur->rchild; } if (front>last)//本层已经处理完毕--队头已经超过上一层的最后一个元素 { last =rear; if (tmpWidth>maxWidth) { maxWidth=tmpWidth; } tmpWidth=0;//重新记录下一层的结点数 } } } return maxWidth; } template<class T> int BTree<T>::widthBTree() { return width(root); } template<class T> int BTree<T>::nodeCountBTree() { return nodeCount(root); } /*利用后根遍历得到*/ template<class T> int BTree<T>::nodeCount(BTNode<T>* p) { if (!p) { return 0; } else { return 1 + nodeCount(p->lchild) + nodeCount(p->rchild); } } template<class T> int BTree<T>::LeavesCountBTree() { return leavesCount(root); } /*利用前根遍历得到*/ template<class T> int BTree<T>::leavesCount(BTNode<T>* p) { if (!p) { return 0; } if (p->lchild==NULL && p->rchild==NULL)//先检查下自身是不是叶子,是返回1 { return 1; } else { return leavesCount(p->lchild) + leavesCount(p->rchild);//再求自己的左子树中的叶子个数 和 右子树的叶子个数 之后求和 } } /*如有多个节点,取离根最近的*/ /*利用先序的方式求层次,遇到第一个节点停止*/ template<class T> void BTree<T>::nodeLevel(T item,BTNode<T>* p,int level,int& nlevel) { if(p==NULL)//出口一:结点不存在 { nlevel = 0; } else { if (p->data == item)//出口二:找到该结点 { nlevel=level+1; } else //没找到,则往下递归 { if (nlevel==0) { nodeLevel(item,p->lchild,level+1,nlevel); } if (nlevel==0) { nodeLevel(item,p->rchild,level+1,nlevel); } } } } template<class T> int BTree<T>::nodeLevelBTree(T item) { int level =0; nodeLevel(item,root,0,level); return level; } /*利用先序遍历,把item的祖先都放到数组path中,之后直接输出,从根开始.. 要求找到第一个与item相同的结点的 所有双亲*/ template<class T> bool BTree<T>::allParent(T item,BTNode<T>* p,BTNode<T>* path[MaxBTreeSize],int& len,int& seat,bool& isFind) { if (p!=NULL) { if (!isFind)//没找到的时候才继续找,找到直接跳出 { if (p->data !=item) { path[len++]=p; allParent(item,p->lchild,path,len,seat,isFind); allParent(item,p->rchild,path,len,seat,isFind); len--; } else { isFind = true; seat = len;//记录双亲个数 } } } return isFind; } template<class T> bool BTree<T>::allParentBTree(T item) { int seat = 0; bool isFind = false; BTNode<T>* path[MaxBTreeSize]; int len = 0;//数组最后一个元素的位置 allParent(item,root,path,len,seat,isFind); for (int i=0;i<seat;i++) { cout<<path[i]->data; } cout<<endl; return isFind; } /*思路:按层次遍历方式,先把所有结点(不管当前结点是否有左右孩子)都入队列. 若为完全二叉树,则层次遍历时得到的肯定是一个连续的不包含空指针的序列. 如果序列中出现了空指针,则说明不是完全二叉树。*/ template<class T> bool BTree<T>::isFull(BTNode<T>* p) { bool isExist = false;//表示现在这个状态下,队列中是不是存在空指针 /* 当队中出现空指针时,看看空指针之后是不是有非空的指针, 如果空指针后有非空指针出现,则肯定不是完全二叉树, 如果空指针之后没有非空指针,则是完全二叉树 */ BTNode<T>* cur; //定义队列 int front=0; int rear=0; BTNode<T>* queue[MaxBTreeSize]; if (p) { queue[(rear++)%MaxBTreeSize]=p; while(front != rear)//队空停止执行 { cur = queue[(front++)%MaxBTreeSize];//总是先出队,在访问,在把孩子入队 if (cur==NULL)//入队的有空指针,使用标志位isExist记录,表示已经出现过空,之后再遇到非空时,就表示为不是完全二叉树。 { isExist = true; } else { if (isExist && (cur->lchild!=NULL || cur->rchild!=NULL)) { return false;//在cur指向之前已经有空指针出现,现在又有非空指针出现,则不是完全二叉树 } //不管孩子是否为空,都入队列 if ((rear+1)%MaxBTreeSize != front)//队不满,入左孩子 { queue[(rear++)%MaxBTreeSize]=cur->lchild; } if ((rear+1)%MaxBTreeSize != front)//队不满,入右孩子 { queue[(rear++)%MaxBTreeSize]=cur->rchild; } } } } return true;//执行至此必为队空且中间无空指针,是完全二叉树 } template<class T> bool BTree<T>::isFullBTree() { if (isFull(root)) { return true; } return false; } template<class T> void BTree<T>::longPathBTree() { BTNode<T>* longPathNode=NULL; int maxlen = 0; longPath(root,0,maxlen,longPathNode);//调用longPath函数能找到路径最长的那个叶子 if (root==NULL) { cout<<"二叉树为空!"<<endl; } else { BTNode<T>* cur = longPathNode; while(cur!=root) { cout<<cur->data; cur = cur->parent; } cout<<root->data<<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> void BTree<T>::exchangeChild(BTNode<T>*& p) { if(p) { 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> void BTree<T>::exchangeChildBTree() { exchangeChild(root); } template<class T> void BTree<T>::findCommonAncestor(const BTNode<T>* p1,const BTNode<T>* p2,BTNode<T>*& ancestor) { int seat1=0;//记录找到时双亲的个数 int seat2=0; int len_p1=0;//记录正在处理结点的层次数 int len_p2=0; bool isFind_p1 = false;//二叉树中是否存在p1指向的结点 bool isFind_p2 = false; BTNode<T>* path_p1[MaxBTreeSize]; BTNode<T>* path_p2[MaxBTreeSize]; allParent(p1->data,root,path_p1,len_p1,seat1,isFind_p1); allParent(p2->data,root,path_p2,len_p2,seat2,isFind_p2); //当seat1 = seat2 = 0时,表示二叉树中没有此结点 for (int i=0;i<=seat1 && i<=seat2 ;i++) { if (path_p1[i] != path_p2[i]) { ancestor = path_p1[i-1]; return; } } } template<class T> void BTree<T>::destoryBTree() { destory(root); } /*使用后根的方式销毁二叉树*/ template<class T> void BTree<T>::destory(BTNode<T>*& p) { if(p) { destory(p->lchild);//销毁左子树 destory(p->rchild);//销毁右子树 delete p; //销毁根 p=NULL; } } template<class T> int BTree<T>::max(int x,int y) { if (x>y) { return x; } else { return y; } } template<class T> int BTree<T>::min(int x,int y) { if (x>y) { return y; } else { return x; } } 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 { if (p) { 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) { 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) { 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) { 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) { 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) { if (p->parent->rchild != p)//判断是否等于自身 { ret = p->parent->rchild; return true; } } return false; } //代码测试 int main() { BTree<char> tree; tree.createBTree(); //---遍历 cout<<"中序遍历:"; tree.inOrderTraverse(); cout<<"先序遍历:"; tree.preOrderTraverse(); cout<<"后序遍历:"; tree.postOrderTraverse(); cout<<"层次遍历:"; tree.levelOrderTraverse(); //调用拷贝构造函数 BTree<char> tree1 = tree; //---结点个数,叶子个数 cout<<"叶子个数:"<<tree1.LeavesCountBTree()<<endl; cout<<"二叉书中结点个数"<<tree1.nodeCountBTree()<<endl; //---高度、宽度 cout<<"二叉树的高度:"<<tree1.heightBTree()<<endl; cout<<"二叉树的宽度:"<<tree1.widthBTree()<<endl; //---完全二叉树 if (tree1.isFullBTree()) { cout<<"二叉树是完全二叉树!"<<endl; } else { cout<<"二叉树不是完全二叉树!"<<endl; } //---最长路径 cout<<"二叉树最长路径:"; tree1.longPathBTree(); //---共同的最近祖先 BTNode<char>* ancestor = NULL; BTNode<char>* ret1=NULL; BTNode<char>* ret2=NULL; if (tree1.findBTree('C',ret1) && tree1.findBTree('G',ret2)) { tree1.findCommonAncestor(ret1,ret2,ancestor); cout<<ret1->data<<"和"<<ret2->data<<"的最近祖先为:"<<ancestor->data<<endl; } //调用赋值构造函数 BTree<char> tree2; tree2 = tree; //---结点D的层次、祖先、双亲、左孩子、右孩子、左兄弟、右兄弟 BTNode<char>* cur = NULL; if (tree2.findBTree('D',cur))//判断二叉树中是不是有结点D { cout<<"D所在的层次为:"<<tree2.nodeLevelBTree('D')<<endl; cout<<"D的所有祖先为:"; tree2.allParentBTree('D'); BTNode<char>* ret=NULL; if (tree2.getParent(cur,ret)) { cout<<cur->data<<"的双亲为:"<<ret->data<<endl; } else { cout<<cur->data<<"没有双亲!"<<endl; } if (tree2.getLeftChild(cur,ret)) { cout<<cur->data<<"的左孩子为:"<<ret->data<<endl; } else { cout<<cur->data<<"没有左孩子!"<<endl; } if (tree2.getRightChild(cur,ret)) { cout<<cur->data<<"的右孩子为:"<<ret->data<<endl; } else { cout<<cur->data<<"没有右孩子!"<<endl; } if (tree2.getLeftSibling(cur,ret)) { cout<<cur->data<<"的左兄弟为:"<<ret->data<<endl; } else { cout<<cur->data<<"没有左兄弟!"<<endl; } if (tree2.getRightSibling(cur,ret)) { cout<<cur->data<<"的右兄弟为:"<<ret->data<<endl; } else { cout<<cur->data<<"没有右兄弟!"<<endl; } } else { cout<<"D不存在!"<<endl; } //---树交换左右孩子 tree2.exchangeChildBTree(); cout<<"孩子交换后,层次遍历:"; tree2.levelOrderTraverse(); system("pause"); return 0; } /* 注意: 1、因为BTree类含有指针成员变量,则需要重载赋值构造函数、拷贝构造函数和析构函数 2、BTree类定义的几个私有成员函数,用来处理以某一结点为根的部分。它可以用来实现类的公共成员函数 3、把树根定义为受保护的变量,可以派生特定的二叉树类 */
要求输入二叉树的状态:
输入方法:
因为是按先序创建二叉树,因此应该先把 要构建的二叉树的先序遍历写出来,没有子树的用#补充,就可以了
测试结果:
“过一个平凡无趣的人生实在太容易了,你可以不读书,不冒险,不运动,不写作,不外出,不折腾……但是,人生最后悔的事情就是:我本可以。”——陈素封。