二叉树纯代码详解 ,看了直接会实现二叉树!!!
目录
1.基本结构
2.基本函数代码实现
3.函数的具体实现,解释在代码里面
1.基本结构
结点构成(一个数据区域,两个左右指针),每一个结点都只有唯一父母,两个孩子
2.基本函数代码实现…
//二叉树的创建
bool CreatBiTree(BiTree& T);
//二叉树的销毁
bool DestroyBiTree(BiTree &T);
//二叉树的节点总数
int BiNodeCount(BiTree T);
//二叉树的叶子节点个数
int BiNodeLeafCount(BiTree T);
//二叉树的深度
int BiNodeDepth(BiTree T);
//前序遍历
bool BiTreePreOrder(BiTree& T);
//中序遍历
bool BiTreeInOrder(BiTree T);
//后序遍历
bool BiTreePostOrder(BiTree T);
//层次遍历需要队列
bool LevelOrder(BiTree T);
//是否是完全二叉数
bool BiTreeComplete(BiTree T);
3.函数的具体实现,解释在代码里面
3.1二叉树的创建
//二叉树的创建
bool CreatBiTree(BiTree& T) {
TEdatatype data;
scanf("%c",&data);
if (char == "#") //"#"表示为空
T = NULL;
else {
if (!T = (BiTree)malloc(sizeof(BiNode))){
cout << "分配内存失败" << endl;
exit(-1);
}
//利用前序存储,中序后序都一样
T->_data = data;
CreatBiTree(T->_Lchild);
CreatBiTree(T->_Rchild);
}
return true;
}
3.2二叉树的销毁
//二叉树的销毁
bool DestroyBiTree(BiTree* T) {
//T是指向BiTree T 的指针,也就是二级指针
if (T) {
if ((*T)->_Lchild)
//别忘了引用噢(形参的改变不影响实参)
DestroyBiTree(&(*T)->_Lchild);
if ((*T)->_Rchild)
DestroyBiTree(&(*T)->_Rchild);
free(T);
T = NULL;
}
return true;
}
#####3 .3二叉树的结点数
//还是用递归思路,简单来说就是从最后面一个二叉树开始计数,每次返回所二叉树的结点数在一起累加,最后+1是第一个结点
//二叉树的节点总数
int BiNodeCount(BiTree T) {
if (T == NULL)
return 0;
return BiNodeCount(T->_Lchild) + BiNodeCount(T->_Rchild) + 1;
}
3.4二叉树的叶子结点数
//思路和二叉树的结点数大同小异,添加一项限制为叶子结点的特点左右孩子为空就行,
//二叉树的叶子节点个数
int BiNodeLeafCount(BiTree T) {
if (T == NULL)
return 0;
if (T->_Lchild == NULL && T->_Rchild == NULL)
return 1;
return BiNodeLeafCount(T->_Lchild) + BiNodeLeafCount(T->_Rchild);
}
3.5二叉树的深度
//我们知道结点数为N的满二叉树(默认根结点的深度为1)深度为:log(N+1),下面就是任意二叉树的深度计算
//二叉树的深度
int BiNodeDepth(BiTree T) {
if (T == NULL)
return 0;
int m = BiNodeDepth(T->_Lchild);
int n = BiNodeDepth(T->_Rchild);
//左右结点那个大,就在其上+1,就是当前的深度,在返回到上面依次累加
if (m > n) {
return m + 1;
}
else {
return n + 1;
}
}
3.6三种遍历:前序,中序,后序
//前序遍历
bool BiTreePreOrder(BiTree T) {
if (T == NULL)
return 0;
cout << T->_data;
BiTreePostOrder(T->_Lchild);
BiTreePostOrder(T->_Rchild);
return true;
}
//中序遍历
bool BiTreeInOrder(BiTree T) {
if (T == NULL)
return 0;
BiTreePostOrder(T->_Lchild);
cout << T->_data;
BiTreePostOrder(T->_Rchild);
return true;
}
//后序遍历
bool BiTreePostOrder(BiTree T) {
if (T == NULL)
return 0;
BiTreePostOrder(T->_Lchild);
BiTreePostOrder(T->_Rchild);
cout << T->_data;
return true;
}
3.7层次遍历和判断是否是完全二叉树
前面的还是比较基础,这两个需要利用到队列辅助实现所以说数据结构一定要学好,至少每个的代码呀,性质啥的都要做到心里有数
下面看到代码同学·
1.前期准备阶段:构造一个二叉链和链队
typedef char TEdatatype;
//二叉链
typedef struct BiNode {
//数据
TEdatatype _data;
//左右孩子指针
struct BiNode* _Lchild, * _Rchild;
}BiNode, * BiTree;
//typedef结点的指针,这就是我们队列的元素
typedef BiNode* QDataElem;
//我们使用的链队,顺序队有些麻烦
//链队的结点
typedef struct QNode {
QDataElem _data;
struct QNode* next;
}QNode, *pQueue;
//头尾指针
typedef struct LinkQueue {
//头指针
pQueue fornt;
//尾指针
pQueue rear;
}LinkQueue;
//初始化队列
bool InitQueue(LinkQueue& Q);
//销毁队列
bool DestroyQueue(LinkQueue& Q);
//判断队列为空
bool QueueEmpty(LinkQueue Q);
//入队
bool EnQueue(LinkQueue& Q, QDataElem e);
//出队
bool DeQueue(LinkQueue& Q, QDataElem& e);
2.开始利用链队,主要就是出队和入队判空这些性质
2.1队列的代码实现
//初始化队列
bool InitQueue(LinkQueue& Q) {
//先创建一个队列节点,首尾指针都指向
Q.fornt = Q.rear = (pQueue)malloc(sizeof(QNode));
if (!Q.fornt) {
exit(-1);
}
Q.fornt->next = NULL;
return true;
}
//销毁队列
bool DestroyQueue(LinkQueue& Q) {
pQueue p ;
//类似链表的循环删除,从第一个开始
while (Q.fornt) {
p = Q.fornt->next;
free(p);
Q.fornt = p;
//可以用尾指针代替p,
}
return true;
}
//判断队列为空
bool QueueEmpty(LinkQueue Q) {
return Q.fornt = Q.rear = NULL;
}
//入队
bool EnQueue(LinkQueue& Q, QDataElem e) {
//分配一个队列内存
pQueue p = (pQueue)malloc(sizeof(QNode));
if (!p) {
exit(-1); //分配失败
}
//赋值给p结点,同时接上队列
p->_data = e; p->next = NULL;
Q.rear->next = p;
//移动尾指针
Q.rear = p; //别忘了尾指针的移动
return true;
}
//出队 e来存储出队的元素,当然你也可以按照你的喜好来作为返回值
bool DeQueue(LinkQueue& Q, QDataElem& e) {
pQueue p=NULL;
//为空
if (!Q.rear) {
cout << "队列为空";
return false;
}
//一个数据
if (Q.fornt = Q.rear) {
e = Q.fornt->_data;
free(Q.fornt);
Q.fornt = Q.rear = NULL; //释放内容之后,记得制空指针噢
return true;
}
//普遍的多数据,链表学的好直接拿捏链队嘿嘿
p = Q.fornt->next;
e = Q.fornt->_data;
free(Q.fornt);
Q.fornt = p; //别忘记了首指针的移动
return true;
}
2.2层次遍历代码实现
//层次遍历需要队列
bool LevelOrder(BiTree T) {
//管他先判空,在很多比赛中即使不会,也可以骗分嘿嘿
if (T == NULL)
return false;
LinkQueue Q; BiTree TT; //定义一个队列,定义一个二叉树(用来存出去的二叉树结点也就是队列元素)
InitQueue(Q); //初始化队列
EnQueue(Q, T); //根结点指针并入队列,,注意不是一个数据,是一个树进去了,为一串数据(数组)
while (!QueueEmpty(Q)) { //队列不为空,循环
DeQueue(Q, TT); //进去了根结点T,出结点T,存在TT,
cout << TT->_data; //打印TT,TT是头部元素
//就是一层一层出了
if(TT->_Lchild) EnQueue(Q, TT->_Lchild); //有左孩子就出左孩子
if (TT->_Rchild) EnQueue(Q, TT->_Rchild); //有右孩子就出右孩子
}
return true;
}
2.3判断是否是完全二叉树
//是否是完全二叉数,利用一个巧妙的思维
bool BiTreeComplete(BiTree T) {
if (T == NULL)
return true;
LinkQueue Q; BiTree TT; //定义一个队列,定义一个二叉树
InitQueue(Q); //初始化队列
EnQueue(Q, T); //根结点指针并入队列,注意不是一个数据是一个树进去了,为一串数组
while (!QueueEmpty(Q)) { //队列不为空,循环
DeQueue(Q, TT); //进去了根结点T,出结点T,存在TT,
if (TT == NULL) {
break;
//为什么二叉树中遇到了空就退出循环
//完全二叉树一定是:前面有数据后面为空(ABCDEF#####)
//非完全二叉树就是:(ABCDEF###G##H##)
//所以我们只要判断后面为空部分中是不是有数据就行
}
if (TT->_Lchild) EnQueue(Q, TT->_Lchild); //有左孩子就出左孩子
if (TT->_Rchild) EnQueue(Q, TT->_Rchild); //有右孩子就出右孩子
}
//完全二叉树一定是:前面有数据后面为空(ABCDEF#####)
//非完全二叉树就是:(ABCDEF###G##H##)
//后面为空的部分在来上面步骤,入队出队就行
while (!QueueEmpty(Q)) {
DeQueue(Q, TT); //和上面一样
if (TT) {
DestroyQueue(Q); //记得销毁噢
return false;
}
}
DestroyQueue(Q);
return true;
}