二叉树之二叉链表

来源:互联网 发布:sai软件多大 编辑:程序博客网 时间:2024/06/05 08:10

    二叉树一般多采用二叉链表存储,其基本思想是:令二叉树的每个结点对应一个链表结点,链表结点除了存放与二叉树结点有关的数据信息外,还要设置指示左右孩子结点的指针。二叉链表的结点结构如下图所示,其中data是数据域,lchild是左指针域,rchild是右指针域;当左右孩子都不存在时,左右指针都为空。


   用C++的结构体类型描述二叉树链表的结点:

template<class Type>struct BiNode{Type data;//数据域BiNode<Type> *lchild, *rchild;//指向左孩子和右孩子结点的指针};

一、二叉树的遍历

    遍历是二叉树最基本的操作。二叉树的遍历是指从根节点出发,按照某种次序访问二叉树中的所有结点,使得每个结点被访问且仅被访问一次。由于二叉树中每个结点都有可能有两棵子树,因而需要寻找一条合适的搜索路径。

    由二叉树的定义可以知道,一棵二叉树由根结点、根结点的左子树和根结点的右子树三部分组成。因此只要一次遍历这三部分就可以遍历整个二叉树了。

    前序、中序、后序遍历用递归实现,层次遍历通过队列来辅助实现。

    1.前序遍历

    思路:

    若二叉树为空,则空操作返回,否则:

    (1)访问根结点

    (2)前序遍历根结点的左子树

    (3)前序遍历根结点的右子树

template<class Type>void BiTree<Type>::PreOrder(BiNode<Type>* bt){if (bt == NULL)return;else{cout << bt->data << " ";PreOrder(bt->lchild);PreOrder(bt->rchild);}}

    2.中序遍历

    思路:

    若二叉树为空,则空操作返回,否则:

    (1)中序遍历根结点的左子树

    (2)访问根结点

    (3)中序遍历根结点的右子树

template<class Type>void BiTree<Type>::InOrder(BiNode<Type>* bt){if (bt == NULL)return;else{InOrder(bt->lchild);cout << bt->data << " ";InOrder(bt->rchild);}}

    3.后序遍历

    思路:

    若二叉树为空,则空操作返回,否则:

    (1)后序遍历根结点的左子树

    (2)后序遍历根结点的右子树

    (3)访问根结点

template <class Type>void BiTree<Type>::PostOrder(BiNode<Type>* bt){if (bt == NULL)return;else{PostOrder(bt->lchild);PostOrder(bt->rchild);cout << bt->data << " ";}}

    4.层次遍历

    在进行层次遍历时,对某一层的结点访问完后,再按照它们的访问次序对各个结点的左孩子和右孩子顺序访问,这样一层一层进行,先访问的结点其左孩子也要先访问,这符合队列的操作特性。

    思路:

    (1)队列Q初始化

    (2)如果二叉树非空,则根指针入队列

    (3)循环直到队列Q为空

            3.1 q是取的队头元素

            3.2 访问q的数据域

            3.3 若q存在左孩子,则将左孩子指针入队列

            3.4 若q存在右孩子,则将右孩子指针入队列

template<class Type>void BiTree<Type>::LevelOrder(){SeqQueue<Type> sq;if (root == NULL)return;else{sq.EnQueue(root);while (!sq.isEmpty()){BiNode<Type>* p = new BiNode<Type>;p = sq.DeQueue();cout << p->data << " ";if (p->lchild != NULL)sq.EnQueue(p->lchild);if (p->rchild != NULL)sq.EnQueue(p->rchild);}}}

二、创建二叉树

    构造函数的功能是建立一个二叉树,建立二叉树可以有多种方式,一个较为简单的方法就是根据一个结点序列来建立二叉树。由于前序、中序、后序序列中任何一个都不能唯一确定一个二叉树,因此不能直接使用。三种序列不能唯一确定二叉树的原因是:不能确定其左右子树的情况。针对以上问题,可以对二叉树做如下处理:将二叉树的每个结点的空指针引出一个虚结点,其值为以特定值,如#,以表示其为空。把这样处理后的二叉树称为原二叉树的扩展二叉树。

            

    为简化问题,这里设二叉树中的结点均是一个字符。假设扩展二叉树的前序遍历序列由键盘输入,建立过程:

    (1)输入根结点,如果输入的是#,则表明该二叉树是空树,即bt=NULL,否则:

    (2)输入的字符赋给bt->data

    (3)依次递归建立它的左右子树

template<class Type>BiNode<Type>* BiTree<Type>::CreatePre(BiNode<Type>* bt){Type ch;cin >> ch;if (ch == '#')bt = NULL;else{bt = new BiNode<Type>;bt->data = ch;bt->lchild = CreatePre(bt->lchild);bt->rchild = CreatePre(bt->rchild);}return bt;}

三、释放二叉树所占存储空间

    二叉链表属于动态存储分配,需要在析构函数中释放二叉链表中的所有结点。在释放某结点时,该结点的左右子树都已经释放。所以,应该采取后序遍历,访问某结点时将该结点的存储空间释放。

template<class Type>void BiTree<Type>::Release(BiNode<Type>* bt){if (bt != NULL){Release(bt->lchild);Release(bt->rchild);delete bt;}}

    根据遍历算法的框架,适当修改访问操作的内容,可以派生出许多关于二叉树的应用算法。

四、求二叉树的结点的个数

    将访问操作改为计数操作,分别计算根结点左右子树的结点的个数,相加后再记上根结点。

template<class Type>int BiTree<Type>::Count(BiNode<Type>* bt){if (bt == NULL)return 0;else{int left = Count(bt->lchild);int right = Count(bt->rchild);return left + right + 1;}}

五、求二叉树的深度

    当二叉树为空时,深度是0,;若二叉树不为空,深度应该是左右子树深度的最大值加1,而其左右子树深度的求解又可以通过递归调用本算法来完成。

template<class Type>int BiTree<Type>::Depth(BiNode<Type>* bt){if (bt == NULL)return 0;else{int left = Depth(bt->lchild);int right = Depth(bt->rchild);return (left > right ? left : right) + 1;}}

六、输出二叉树后序遍历的逆序

    要得到后序的逆序,只要按照后序遍历相反的顺序即可,即先访问根结点再遍历根结点的右子树,最后遍历根结点的左子树。要注意和前序遍历的区别。

template<class Type>void BiTree<Type>::PostOrderReverse(BiNode<Type>* bt){if (bt == NULL)return;else{cout << bt->data << " ";PostOrderReverse(bt->rchild);PostOrderReverse(bt->lchild);}}

七、查找结点x的双亲

    如果当前指向的结点的左孩子或者右孩子存在且值等于x,则该结点就是x的双亲。

template<class Type>BiNode<Type>* BiTree<Type>::getParent(BiNode<Type>* bt, Type x){if (bt == NULL)return NULL;if (bt->lchild != NULL&&bt->lchild->data == x || bt->rchild != NULL&&bt->rchild->data == x)return bt;BiNode<Type>* p = getParent(bt->lchild,x);if (p)return p;return getParent(bt->rchild,x);}

八、查找结点x的存在

    如果当前结点的数据域的值为x,则将该结点返回。

template<class Type>BiNode<Type>* BiTree<Type>::Search(BiNode<Type>* bt, Type x){if (bt == NULL)return NULL;if (bt->data == x)return bt;BiNode<Type>* p = Search(bt->lchild, x);if (p)return p;return Search(bt->rchild,x);}

九、删除以x为结点的子树

    遍历查找到指向x的结点指针,然后依次释放该结点的左右子树。

template<class Type>void BiTree<Type>::DeleteChild(BiNode<Type>* bt, Type x){if (bt == NULL)return;if (bt->data == x){Release(bt->lchild);bt->lchild = NULL;Release(bt->rchild);bt->rchild = NULL;return;}else{DeleteChild(bt->lchild,x);DeleteChild(bt->rchild,x);}cout << "不存在该结点!" << endl;}

十、前序打印叶子结点

    叶子结点的特点是:其左右孩子结点指针都为空!

template<class Type>void BiTree<Type>::PrePrintLeave(BiNode<Type>* bt){if (bt == NULL)return;if (bt->lchild == NULL&&bt->rchild == NULL){cout << bt->data << " ";}PrePrintLeave(bt->lchild);PrePrintLeave(bt->rchild);}

十一、交换二叉树中所有的左右子树

    对二叉树进行前序遍历,在遍历过程中访问某结点时交换该结点的左右子树。

template<class Type>void BiTree<Type>::Exchange(BiNode<Type>* bt){if (bt == NULL)return;else{BiNode<Type>* tmp = bt->lchild;bt->lchild = bt->rchild;bt->rchild = tmp;}Exchange(bt->lchild);Exchange(bt->rchild);}



下面附上所有源码,如有不足之处,请多指教!

BiNode.h

#ifndef BINODE_H#define BINODE_H#include <iostream>#include <cstdlib>using namespace std;template<class Type>struct BiNode{Type data;//数据域BiNode<Type> *lchild, *rchild;//指向左孩子和右孩子结点的指针};#endif


BiTree.h

#ifndef BITREE_H#define BITREE_H#include "BiNode.h"template<class Type>class BiTree{public:BiNode<Type>* root;//根结点private:BiNode<Type>* CreatePre(BiNode<Type>* bt);//前序建立二叉树void Release(BiNode<Type>* bt);//释放结点空间void PreOrder(BiNode<Type>* bt);//前序遍历二叉树void InOrder(BiNode<Type>* bt);//中序遍历二叉树void PostOrder(BiNode<Type>* bt);//后序遍历二叉树int Count(BiNode<Type>* bt);//计算二叉树中结点的个数int Depth(BiNode<Type>* bt);//计算二叉树的深度void PrePrintLeave(BiNode<Type>* bt);//前序打印二叉树的叶子结点void PostOrderReverse(BiNode<Type>* bt);//逆序打印后序遍历BiNode<Type>* getParent(BiNode<Type>* bt, Type x);  //查找双亲BiNode<Type>* Search(BiNode<Type>* bt, Type x);//查找结点的存在void DeleteChild(BiNode<Type>* bt, Type x);//删除以X为根结点的子树void Exchange(BiNode<Type>* bt);                    //交换二叉树中的所有左右子树public:BiTree();~BiTree();void CreatePre();void Release();void PreOrder();void InOrder();void PostOrder();void LevelOrder();int Count();int Depth();void PrePrintLeave();void PostOrderReverse();BiNode<Type>* getParent(Type x);BiNode<Type>* Search(Type x);void DeleteChild(Type x);void Exchange();};#endif

BiTree.cpp

#include "BiTree.h"#include "SeqQueue.h"template<class Type>BiTree<Type>::BiTree(){root = new BiNode<Type>;root->lchild = NULL;root->rchild = NULL;}template<class Type>BiTree<Type>::~BiTree(){Release(root);}template<class Type>void BiTree<Type>::CreatePre(){root = CreatePre(root);}template<class Type>void BiTree<Type>::PreOrder(){PreOrder(root);}template<class Type>void BiTree<Type>::InOrder(){InOrder(root);}template<class Type>void BiTree<Type>::PostOrder(){PostOrder(root);}template<class Type>void BiTree<Type>::LevelOrder(){SeqQueue<Type> sq;if (root == NULL)return;else{sq.EnQueue(root);while (!sq.isEmpty()){BiNode<Type>* p = new BiNode<Type>;p = sq.DeQueue();cout << p->data << " ";if (p->lchild != NULL)sq.EnQueue(p->lchild);if (p->rchild != NULL)sq.EnQueue(p->rchild);}}}template<class Type>int BiTree<Type>::Count(){return Count(root);}template<class Type>int BiTree<Type>::Depth(){return Depth(root);}template<class Type>void BiTree<Type>::PostOrderReverse(){PostOrderReverse(root);}template<class Type>void BiTree<Type>::PrePrintLeave(){PrePrintLeave(root);}template<class Type>BiNode<Type>* BiTree<Type>::getParent(Type x){return getParent(root, x);}template<class Type>BiNode<Type>* BiTree<Type>::Search(Type x){return Search(root, x);}template<class Type>void BiTree<Type>::DeleteChild(Type x){DeleteChild(root, x);}template<class Type>void BiTree<Type>::Exchange(){Exchange(root);}template<class Type>BiNode<Type>* BiTree<Type>::CreatePre(BiNode<Type>* bt){Type ch;cin >> ch;if (ch == '#')bt = NULL;else{bt = new BiNode<Type>;bt->data = ch;bt->lchild = CreatePre(bt->lchild);bt->rchild = CreatePre(bt->rchild);}return bt;}template<class Type>void BiTree<Type>::PreOrder(BiNode<Type>* bt){if (bt == NULL)return;else{cout << bt->data << " ";PreOrder(bt->lchild);PreOrder(bt->rchild);}}template<class Type>void BiTree<Type>::InOrder(BiNode<Type>* bt){if (bt == NULL)return;else{InOrder(bt->lchild);cout << bt->data << " ";InOrder(bt->rchild);}}template <class Type>void BiTree<Type>::PostOrder(BiNode<Type>* bt){if (bt == NULL)return;else{PostOrder(bt->lchild);PostOrder(bt->rchild);cout << bt->data << " ";}}template<class Type>void BiTree<Type>::Release(BiNode<Type>* bt){if (bt != NULL){Release(bt->lchild);Release(bt->rchild);delete bt;}}template<class Type>int BiTree<Type>::Count(BiNode<Type>* bt){if (bt == NULL)return 0;else{int left = Count(bt->lchild);int right = Count(bt->rchild);return left + right + 1;}}template<class Type>int BiTree<Type>::Depth(BiNode<Type>* bt){if (bt == NULL)return 0;else{int left = Depth(bt->lchild);int right = Depth(bt->rchild);return (left > right ? left : right) + 1;}}template<class Type>void BiTree<Type>::PostOrderReverse(BiNode<Type>* bt){if (bt == NULL)return;else{cout << bt->data << " ";PostOrderReverse(bt->rchild);PostOrderReverse(bt->lchild);}}template<class Type>void BiTree<Type>::PrePrintLeave(BiNode<Type>* bt){if (bt == NULL)return;if (bt->lchild == NULL&&bt->rchild == NULL){cout << bt->data << " ";}PrePrintLeave(bt->lchild);PrePrintLeave(bt->rchild);}template<class Type>BiNode<Type>* BiTree<Type>::getParent(BiNode<Type>* bt, Type x){if (bt == NULL)return NULL;if (bt->lchild != NULL&&bt->lchild->data == x || bt->rchild != NULL&&bt->rchild->data == x)return bt;BiNode<Type>* p = getParent(bt->lchild,x);if (p)return p;return getParent(bt->rchild,x);}template<class Type>BiNode<Type>* BiTree<Type>::Search(BiNode<Type>* bt, Type x){if (bt == NULL)return NULL;if (bt->data == x)return bt;BiNode<Type>* p = Search(bt->lchild, x);if (p)return p;return Search(bt->rchild,x);}template<class Type>void BiTree<Type>::DeleteChild(BiNode<Type>* bt, Type x){if (bt == NULL)return;if (bt->data == x){Release(bt->lchild);bt->lchild = NULL;Release(bt->rchild);bt->rchild = NULL;return;}else{DeleteChild(bt->lchild,x);DeleteChild(bt->rchild,x);}cout << "不存在该结点!" << endl;}template<class Type>void BiTree<Type>::Exchange(BiNode<Type>* bt){if (bt == NULL)return;else{BiNode<Type>* tmp = bt->lchild;bt->lchild = bt->rchild;bt->rchild = tmp;}Exchange(bt->lchild);Exchange(bt->rchild);}

SeqQueue.h

#ifndef SEQQUEUE_H#define SEQQUEUE_H#include "BiNode.h"const int QueueSize = 10;template<class Type>class SeqQueue{public:BiNode<Type>* data[QueueSize];//存放指向BiNode的结点的指针int front, rear;public:SeqQueue();//构造函数~SeqQueue();//析构函数void EnQueue(BiNode<Type>* x);//入队列BiNode<Type>* DeQueue();//出队列BiNode<Type>* getQueue();//取队头元素bool isEmpty();//判空bool isFull();//判满};#endif

SeqQueue.cpp

#include "SeqQueue.h"//初始化空队列,队头和队尾指针均指向数组的高端template<class Type>SeqQueue<Type>::SeqQueue(){front = rear = QueueSize - 1;}template<class Type>SeqQueue<Type>::~SeqQueue(){}//入队列template<class Type>void SeqQueue<Type>::EnQueue(BiNode<Type>* x){if ((rear + 1) % QueueSize == front){cerr << "入队列失败!" << endl;exit(1);}else{rear = (rear + 1) % QueueSize;data[rear] = x;}}//出队列template<class Type>BiNode<Type>* SeqQueue<Type>::DeQueue(){if (front == rear){cerr << "出队列失败!" << endl;exit(1);}else{front = (front + 1) % QueueSize;return data[front];}}//取队头元素template<class Type>BiNode<Type>* SeqQueue<Type>::getQueue(){if (front == rear){cerr << "出队列失败!" << endl;exit(1);}else{return data[(front + 1) % QueueSize];}}//判空template<class Type>bool SeqQueue<Type>::isEmpty(){return (front == rear) ? true : false;}//判满template<class Type>bool SeqQueue<Type>::isFull(){return ((rear + 1) % QueueSize == front) ? true : false;}

main.cpp
#include "SeqQueue.h"#include "BiTree.h"#include "SeqQueue.cpp"#include "BiTree.cpp"void menu(){cout << "————————————————菜单————————————————" << endl;cout << "                        1.输入可扩展的前序序列创建二叉树" << endl;cout << "                        2.用前序、中序、后序、后序逆序、层次遍历法遍历二叉树" << endl;cout << "                        3.求二叉树中结点的个数" << endl;cout << "                        4.求二叉树的深度" << endl;cout << "                        5.前序打印叶子结点" << endl;cout << "                        6.查找结点x的双亲" << endl;cout << "                        7.判断结点x的存在" << endl;cout << "                        8.删除以x为根结点的子树" << endl;cout << "                        9.交换二叉树的所有左右子树" << endl;cout << "                        10.退出" << endl;cout << "——————————————————————————————————" << endl;}int main(){int choice;BiTree<char>* btree = NULL;do{system("cls");menu();cout << "请选择:";cin >> choice;switch (choice){case 1:if (btree != NULL){delete btree;}btree = new BiTree<char>;btree->CreatePre();system("pause");break;case 2:cout << "前序遍历:";btree->PreOrder();cout << endl;cout << "中序遍历:";btree->InOrder();cout << endl;cout << "后序遍历:";btree->PostOrder();cout << endl;cout << "后序逆序遍历:";btree->PostOrderReverse();cout << endl;cout << "层次遍历:";btree->LevelOrder();cout << endl;system("pause");break;case 3:cout << "该二叉树的结点个数:" << btree->Count() << endl;system("pause");break;case 4:cout<<"该二叉树的深度:"<<btree->Depth()<<endl;system("pause");break;case 5:cout << "前序次序打印叶子结点:";btree->PrePrintLeave();system("pause");break;case 6:char x;cout << "请输入要查找的结点x:";cin >> x;if (btree->getParent(x)){cout << "双亲:" << btree->getParent(x)->data << endl;}else{cout << "没有双亲!" << endl;}system("pause");break;case 7:char y;cout << "请输入要查找的结点x:";cin >> y;if (btree->Search(y)){cout << "存在该结点!" << endl;}else{cout << "不存在该结点!" << endl;}system("pause");break;case 8:char z;cout << "请输入要删除子树的根结点:";cin >> z;btree->DeleteChild(z);system("pause");break;case 9:btree->Exchange();system("pause");break;case 10:exit(1);}} while (1);return 0;}

测试结果:

    输入序列  ABC###DEF##G##HI##J##

    遍历输出:



    结点个数:


    深度:


    前序打印叶子结点:


    查找双亲:


   删除结点:




    交换左右子树:


0 0
原创粉丝点击