【二叉树】大学有棵树叫高数,数据结构也有棵二叉树-代码详解
文章目录
- 二叉树
- 二叉树结构
- 快速构建一颗二叉树
- 前序遍历
- 中序遍历
- 后序遍历
- 层序遍历
- 注意点
- 计算二叉树结点个数
- 求叶子结点个数
- 求第K层结点个数
- 求二叉树的深度
- 查找值为x的结点
- 关于二叉树递归应该注意的问题:
- 判断二叉树是否是完全二叉树
- 层序遍历:
- 二叉树销毁
- BinaryTree.h
- BinaryTree.c
- test.c
- 层序遍历+判断完全二叉树(test2.C)
- Queue.c
- Queue.h
二叉树
普通二叉树增删查改没有什么价值,因为用来存数据,太复杂了
价值体现
1.搜索二叉树(最多查找高度次) ,平衡搜索二叉树,ALV树 红黑树 B 树 ->最坏情况O(N)
2.哈夫曼树
二叉树结构
以存放字符为例子
typedef char BTDataType;
typedef struct BinaryTreeNode
{struct BinaryTreeNode* right;//指向左孩子struct BinaryTreeNode* left;//指向右孩子BTDataType data;//存放数据
}BTNode;
快速构建一颗二叉树
树的结构
BTNode* BuyNode(BTDataType x)
{BTNode* newnode = (BTNode*)malloc(sizeof(BTNode));if (newnode == NULL){printf("malloc fail\n");exit(-1);}else{newnode->data = x;newnode->left = NULL;newnode->right = NULL;}return newnode;
}BTNode* BuyTree()
{//构建一颗二叉树//1.创建结点BTNode* nodeA = BuyNode('A');BTNode* nodeB = BuyNode('B');BTNode* nodeC = BuyNode('C');BTNode* nodeD = BuyNode('D');BTNode* nodeE = BuyNode('E');BTNode* nodeF = BuyNode('F');//2.链接nodeA->left = nodeB;nodeA->right = nodeC;nodeB->left = nodeD;nodeC->left = nodeE;nodeC->right = nodeF;return nodeA;
}
// A
// B C
// D NULL E F
前序遍历
前序遍历(Preorder Traversal 亦称先序遍历)——访问根结点的操作发生在遍历其左右子树之前。
前序遍历: 根 - 左子树 - 右子树
//前序遍历
void PreOrder(BTNode* root)
{if (root == NULL){printf("NULL ");return ;}printf("%c ", root->data);//根PreOrder(root->left);//左子树PreOrder(root->right);//右子树
}
图解
中序遍历
中序遍历(Inorder Traversal)——访问根结点的操作发生在遍历其左右子树之中(间)。
小技巧:把整棵二叉树投影到一条直线的顺序就是中序遍历的结果
中序遍历: 左子树 - 根- 右子树
//中序遍历
void InOrder(BTNode* root)
{if (root == NULL){printf("NULL ");return;}InOrder(root->left);//左子树printf("%c ", root->data);//根InOrder(root->right);//右子树
}
后序遍历
后序遍历(Postorder Traversal)——访问根结点的操作发生在遍历其左右子树之后
后序遍历: 左子树 - 右子树 -根
//后序遍历
void PostOrder(BTNode* root)
{if (root == NULL){printf("NULL ");return;}PostOrder(root->left);//遍历左子树PostOrder(root->right);//遍历右子树printf("%c ", root->data);//根
}
层序遍历
借助队列的特点:先进先出
核心思想:上一层带下一层
实现
1.根节点进队列
2.当前结点出来时,把它的左孩子和右孩子都带进去队列,这样上一层结点出的时候,带入下一层的结点
3.当队列为空,说明最后一层没有结点了,遍历结束
//队列存放的是二叉树结点的地址
//层序遍历
void LevelOrder(BTNode* root)
{//空树就直接返回if (root == NULL){return;}Queue q;QueueInit(&q);//根节点先入队列QueuePush(&q, root);while (!QueueEmpty(&q)){BTNode* front = QueueFront(&q);//得到队头的节点QueuePop(&q);//出队头数据printf("%c ", front->data);//把左孩子和右孩子都带进队列//因为左孩子和右孩子不一定存在,所以要判断if (front->left){QueuePush(&q, front->left);//入的是结点的地址}if (front->right){QueuePush(&q, front->right);//入的是结点的地址}}printf("\n");//使用完队列之后要记得销毁QueueDestory(&q);
}
注意点
1.队列声明的问题
如果写成这样:err
原因:**编译器不认识BTNode **
解决方法:在前面先声明。编译器的查找语法是往上找
解决:加一个前置声明
声明只是告诉告诉编译器这个是结构体
队列中存放的是二叉树结点指针
2.Pop只是把指向结点的指针出队, 二叉树结点并没有被删除
计算二叉树结点个数
二叉树可以为空树 所以不用断言
空树结点个数:0
方法1:遍历计数思想
使用局部变量 —不可行
int BinaryTreeSize(BTNode* root)
{//如果是空树返回0if(root == NULL){return 0;}int count = 0;count++;BinaryTreeSize(root->left);//递归左子树计数BinaryTreeSize(root->right);//递归右子树计数return count;
}
每次递归开辟新的栈帧,所以count变量不是同一个,并不是对同一个count进行++
方法2:使用static 或者全局变量 —可行
//方式2:全局变量
int count = 0;
int BinaryTreeSize(BTNode* root)
{//如果是空树返回0if(root == NULL){return 0;}//方式1:使用static修饰 静态变量//static int count = 0;//本质是前序遍历count++;BinaryTreeSize(root->left);//递归左子树计数BinaryTreeSize(root->right);//递归右子树计数return count;
}
这种方式可行,但是如果再次调用此函数就会发生错误。因为count的值会叠加
方法3:在外部传址,然后遍历
int BinaryTreeSize(BTNode* root,int* pn)
{if(root == NULL){return 0;}(*pn)++;BinaryTreeSize(root->left,pn);//递归左子树计数BinaryTreeSize(root->right,pn);//递归右子树计数
}
方法4:通过返回值带回
二叉树结点个数 = 左子树结点个数 + 右子树的结点个数 + 根本身(1)
//二叉树结点个数
int BinaryTreeSize(BTNode* root)
{//结点个数 = 根 + 左子树结点个数 + 右子树结点个数//如果根为空(空树)->返回0return root == NULL ? 0 : BinaryTreeSize(root->left)+ BinaryTreeSize(root->right) + 1;
}
求叶子结点个数
叶子结点的特点:左子树和右子树都为空
如何求叶子结点个数
思路:二叉树的叶子结点个数 = 左子树的叶子结点个数 + 右子树的叶子结点个数
//二叉树叶子结点个数
int BinaryTreeLeafSize(BTNode* root)
{//如果空树->没有叶子结点,返回0if (root == NULL){return 0;}//如果左子树和右子树都为空->就是叶子if ((root->left == NULL) && (root->right == NULL)){return 1;}//遍历左子树和右子树求叶子结点return BinaryTreeLeafSize(root->left) + BinaryTreeLeafSize(root->right);
}
求第K层结点个数
核心思路:
求第k层结点 ->转化求左子树的第K-1层结点个数 + 右子树的第K-1层结点个数
//求第K层结点个数
int BinaryTreeLevelSize(BTNode* root,int k)
{//求第K层结点个数 == >转化为求第K-1层的左子树和右子树的结点个数if (root == NULL){return 0;}//当递归到k = 1层时,就是要求的那一层的结点个数,如果是结点就会返回1,否则就是NULL,在上面返回0if (1 == k) //防止写成k = 1{return 1;}//递归左子树和右子树的k-1层return BinaryTreeLevelSize(root->left, k - 1)+ BinaryTreeLevelSize(root->right, k - 1);}
求二叉树的深度
思路:当前数的高度/深度 = 左子树的深度 和右子树的深度的较大者 + 1
不断递归下去,然后把左子树和右子树的高度较大者返回给上一层 ,就是左子树/右子树的高度
然后根结点再+1就是树的高度
效率低的写法:
//二叉树的高度/深度
int BinaryTreeDepth(BTNode* root)
{ //二叉树的深度 = 左子树的深度和右子树的深度的较大者 +1(根节点)//空树返回0if (root == NULL){return 0;}return BinaryTreeDepth(root->left) > BinaryTreeDepth(root->right)? BinaryTreeDepth(root->left) + 1 : BinaryTreeDepth(root->right) + 1;//返回左子树和右子树的较大者+1
}
由于递归算出左树和右树的深度没有保存结果,还得再算一次,效率太低
效率高的写法
保存左树的高度和右树的高度
//二叉树的高度/深度
int BinaryTreeDepth(BTNode* root)
{ //二叉树的深度 = 左子树的深度和右子树的深度的较大者 +1(根节点)//空树返回0if (root == NULL){return 0;}int LeftDepth = BinaryTreeDepth(root->left);//计算左子树的高度int RightDepth = BinaryTreeDepth(root->right) ;//计算右子树的高度return LeftDepth > RightDepth ? LeftDepth + 1 : RightDepth + 1;//返回左子树和右子树的较大者+1//或者写成://return fmax(BinaryTreeDepth(root->left),BinaryTreeDepth(root->right));
}
fmax和fmin
作用:返回两个浮点参数种较大/较小的一个 要引用#include<math.h>头文件
查找值为x的结点
思路
1.如果是空树(根为空) 返回NULL
2.如果root结点不是我们要找的,先到左树去找,左树找不到,再去右树找
3.如果左树和右树都找不到,说明树中没有值为x的结点 ->返回NULL
错误想法
BTNode* BinaryTreeFind(BTNode* root,BTDataType x)
{//空树返回NULLif(root == NULL){return NULL;}if(root ->data == x){return root;}BinaryTreeFind(root->left,x);BinaryTreeFind(root->right,x);
}
报错
不是所有路径都有返回值
递归图解
原因:递归返回的是上一层调用的地方,这样不一定能返回到最外层
递归带返回值的不可以写成这样,带返回值的递归:后面都要有返回值
注意:如果在左子树或者右子树找到了就会返回地址,找不到就返回NULL
所以如果左子树不为空,或者右子树不为空,说明找到了
效率低的写法
if(BinaryTreeFind(root->left,x))
{return BinaryTreeFind(root->left,x);
}
if(BinaryTreeFind(root->right,x))
{return BinaryTreeFind(root->right,x);
}
写成这样效率太低 没保存结果导致要多算一遍
保存左树和右树的返回值
按照前序遍历的顺序查找
下一层递归的结果返给上一层,然后上一层依据这个结果判断要不要去右子树找…不断迭代,直到把整棵树都找完/在左树/右树/根找到了
递归图解
在左子树找不到->去右子树找
整颗树都找不到->返回NULL
//查找值为x的结点
BTNode* BinaryTreeFind(BTNode* root,BTDataType x)
{//空树返回NULLif (root == NULL){return NULL;}//思路: 先判断根的值是不是x 不是的话 去左子树找 左子树找不到再去右子树找 (类似前序遍历)if (root->data == x){return root;}//去左子树寻找BTNode* left = BinaryTreeFind(root->left,x);//如果左子树不为空 说明找到了if (left){return left;}//左子树找不到就去右子树寻找BTNode* right = BinaryTreeFind(root->right, x);//如果右子树不为空 说明找到了if (right){return right;}//注意!!!如果在整棵树都找不到 ->返回NULLreturn NULL;
}
效率低的写法
//去左子树寻找BTNode* left = BinaryTreeFind(root->left,x);//左子树找不到就去右子树寻找BTNode* right = BinaryTreeFind(root->right, x);//如果左子树不为空 说明找到了if (left){return left;}//如果右子树不为空 说明找到了if (right){return right;}
这样写效率也低 。因为如果在左子树找到了,就不用在右子树找了。
关于二叉树递归应该注意的问题:
1.带返回值的递归结果不能舍弃:
如查找值x的结点时的递归
2.防止重复递归
如:计算叶子结点个数
解决方法:把值保存起来
3.防止多查找
如:查找值x的结点时的递归,左子树找到了,就不需要在右子树查找
判断二叉树是否是完全二叉树
完全二叉树和非完全二叉树的区别:
层序遍历时:
完全二叉树的非空结点是连续的
非完全二叉树的非空结点是不连续的
思路
层序遍历:
- 当遇到空指针跳出循环,检查后面的元素,如果后面有一个结点不是空,说明不是完全二叉树
- 如果后面的元素全部都是空指针->就是完全二叉树
后面的数据全部为空才是完全二叉树,后面空结点连续不一定是完全二叉树
注意:
完全二叉树也可以是空的(没有结点) 二叉排序树自然也可以是空的 满二叉树同样可以是空的
//判断是否是完全二叉树
bool BinaryTreeComplete(BTNode* root)
{//空树是完全二叉树if (root == NULL){return true;}//层序遍历 遇到空结点则跳出Queue q;//创建队列,队列存放的是二叉树结点的指针 QueueInit(&q);//队列初始化QueuePush(&q, root);//先入根节点while (!QueueEmpty(&q)){BTNode* front =QueueFront(&q);QueuePop(&q);//如果遇到空了,就可以跳出,比较后面的结点if (front == NULL){break;}//否则把左孩子和右孩子带进来,空结点也要带进队列else{QueuePush(&q, front->left);QueuePush(&q, front->right);}}//遇到空指针了,break/队列为空跳出,判断后面的元素//1.剩下的全是空,则是完全二叉树//2.剩下的存在非空,说明不是完全二叉树while (!QueueEmpty(&q)){BTNode* front = QueueFront(&q);QueuePop(&q);//如果有一个不为空->不是完全二叉树,返回falseif (front !=NULL ){//返回都要先销毁:QueueDestory(&q);return false;}}//注意:最后要销毁队列QueueDestory(&q);//如果全部都为空,while跳出循环return true;
}
二叉树销毁
如果传一级指针,root结点置空了也没有用,要在外部再置空
free(root)有用,释放的是root指向的空间的内容
但是 root = NULL 没用,因为传的是一级指针,相当于传值,并不会真实改变root的指向
前序:如果先释放根 就找不到左右了 要先保存左右
中序:释放左之后释放根,就找不到右了
所以使用后序的方式释放更好,先释放左再释放右,最后释放根
//二叉树的销毁
void BinaryTreeDestory(BTNode* root)
{//可以为空树,所以不用断言空树直接返回if(root == NULL){return;}//使用后序销毁,防止找不到根free(root->left);free(root->right);free(root);root = NULL;//没作用,在外部再置空
}//外部
BTNode* root = BuyTree();
BinaryTreeDestory(root);
root = NULL;
方式2:传二级指针
void BinaryTreeDestory(BTNode** root)//外部BTNode* root = BuyTree();BinaryTreeDestory(&root);
BinaryTree.h
#pragma once
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>typedef char BTDataType;
typedef struct BinaryTreeNode
{struct BinaryTreeNode* right;//指向左孩子struct BinaryTreeNode* left;//指向右孩子BTDataType data;//存放数据
}BTNode;//前序遍历
void PreOrder(BTNode* root);//中序遍历
void InOrder(BTNode* root);//后序遍历
void PostOrder(BTNode* root);//二叉树的销毁
void BinaryTreeDestory(BTNode* root);//二叉树叶子结点个数
int BinaryTreeLeafSize(BTNode* root);//二叉树结点个数
int BinaryTreeSize(BTNode* root);//求第K层结点个数
int BinaryTreeLevelSize(BTNode* root, int k);//二叉树的高度/深度
int BinaryTreeDepth(BTNode* root);//查找值为x的结点
BTNode* BinaryTreeFind(BTNode* root, BTDataType x);
BinaryTree.c
#define _CRT_SECURE_NO_WARNINGS 1
#pragma once
#include"BTree.h"//前序遍历
void PreOrder(BTNode* root)
{if (root == NULL){printf("NULL ");return ;}printf("%c ", root->data);PreOrder(root->left);PreOrder(root->right);
}//中序遍历
void InOrder(BTNode* root)
{if (root == NULL){printf("NULL ");return;}InOrder(root->left);printf("%c ", root->data);InOrder(root->right);
}//后序遍历
void PostOrder(BTNode* root)
{if (root == NULL){printf("NULL ");return;}PostOrder(root->left);PostOrder(root->right);printf("%c ", root->data);
}//二叉树的销毁
void BinaryTreeDestory(BTNode* root)
{assert(root);//保存根BTNode* cur = root;//使用后序销毁free(root->left);free(root->right);free(root);
}//二叉树结点个数
int BinaryTreeSize(BTNode* root)
{//结点个数 = 根 + 左子树结点个数 + 右子树结点个数return root == NULL ? 0 : BinaryTreeSize(root->left)+ BinaryTreeSize(root->right) + 1;
}//二叉树叶子结点个数
int BinaryTreeLeafSize(BTNode* root)
{//叶子结点:做左子树和右子树都为空if (root == NULL){return 0;}//如果左子树和右子树都为空->就是叶子if ((root->left == NULL) && (root->right == NULL)){return 1;}return BinaryTreeLeafSize(root->left) + BinaryTreeLeafSize(root->right);
}//求第K层结点个数
int BinaryTreeLevelSize(BTNode* root,int k)
{//求第K层结点个数 == >转化为求第K-1层的左子树和右子树的结点个数if (root == NULL){return 0;}if (1 == k) //防止写成k = 1{return 1;}return BinaryTreeLevelSize(root->left, k - 1)+ BinaryTreeLevelSize(root->right, k - 1);}//二叉树的高度/深度
int BinaryTreeDepth(BTNode* root)
{ //二叉树的深度 = 左子树的深度和右子树的深度的较大者 +1(根节点)if (root == NULL){return 0;}int LeftDepth = BinaryTreeDepth(root->left) ;int RightDepth = BinaryTreeDepth(root->right) ;return LeftDepth > RightDepth ? LeftDepth + 1 : RightDepth + 1;
}//查找值为x的结点
BTNode* BinaryTreeFind(BTNode* root,BTDataType x)
{//空树返回NULLif (root == NULL){return NULL;}//思路: 先判断根的值是不是x 不是的话 去左子树找 左子树找不到再去右子树找 (类似前序遍历)if (root->data == x){return root;}//去左子树寻找BTNode* left = BinaryTreeFind(root->left,x);//如果左子树不为空 说明找到了if (left){return left;}//左子树找不到就去右子树寻找BTNode* right = BinaryTreeFind(root->right, x);//如果右子树不为空 说明找到了if (right){return right;}//注意!!!如果在整棵树都找不到 ->返回NULLreturn NULL;
}
test.c
#define _CRT_SECURE_NO_WARNINGS 1
#pragma once
#include"BTree.h"BTNode* BuyNode(BTDataType x)
{BTNode* newnode = (BTNode*)malloc(sizeof(BTNode));if (newnode == NULL){printf("malloc fail\n");exit(-1);}else{newnode->data = x;newnode->left = NULL;newnode->right = NULL;}return newnode;
}BTNode* BuyTree()
{//构建一颗二叉树//1.创建结点BTNode* nodeA = BuyNode('A');BTNode* nodeB = BuyNode('B');BTNode* nodeC = BuyNode('C');BTNode* nodeD = BuyNode('D');BTNode* nodeE = BuyNode('E');BTNode* nodeF = BuyNode('F');//2.链接nodeA->left = nodeB;nodeA->right = nodeC;nodeB->left = nodeD;nodeC->left = nodeE;nodeC->right = nodeF;return nodeA;// A
// B C
// D NULL E F
}
int main()
{BTNode* root = BuyTree();PreOrder(root); //测试前序printf("\n");InOrder(root);//测试中序printf("\n");PostOrder(root);//测试后序printf("\n");printf("TreeSize = %d\n", BinaryTreeSize(root));printf("TreeLeafSize = %d\n", BinaryTreeLeafSize(root));printf("以A为根结点,第%d层结点个数为:%d\n", 2, BinaryTreeLevelSize(root, 2));printf("以A为根结点,第%d层结点个数为:%d\n", 3, BinaryTreeLevelSize(root, 3));printf("二叉树的高度为:%d\n",BinaryTreeDepth(root));BinaryTreeDestory(root);return 0;
}
层序遍历+判断完全二叉树(test2.C)
构建出的树的结构
#define _CRT_SECURE_NO_WARNINGS 1
#pragma once
#include<stdio.h>
#include"Queue.h"BTNode* BuyNode(BTDataType x)
{BTNode* newnode = (BTNode*)malloc(sizeof(BTNode));if (newnode == NULL){printf("malloc fail\n");exit(-1);}else{newnode->data = x;newnode->left = NULL;newnode->right = NULL;}return newnode;
}BTNode* BuyTree()
{//构建一颗二叉树//1.创建结点BTNode* nodeA = BuyNode('A');BTNode* nodeB = BuyNode('B');BTNode* nodeC = BuyNode('C');BTNode* nodeD = BuyNode('D');BTNode* nodeE = BuyNode('E');BTNode* nodeF = BuyNode('F');//2.链接nodeA->left = nodeB;nodeA->right = nodeC;nodeB->left = nodeD;nodeC->left = nodeE;nodeC->right = nodeF;return nodeA;
}
// A
// B C
// D NULL E F//队列存放的是二叉树结点的地址
//层序遍历
void LevelOrder(BTNode* root)
{//空树就直接返回if (root == NULL){return;}Queue q;QueueInit(&q);//根节点先入队列QueuePush(&q, root);while (!QueueEmpty(&q)){BTNode* front = QueueFront(&q);//得到队头的节点QueuePop(&q);//出队头数据printf("%c ", front->data);//把左孩子和右孩子都带进队列//因为左孩子和右孩子不一定存在,所以要判断if (front->left){QueuePush(&q, front->left);//入的是结点的地址}if (front->right){QueuePush(&q, front->right);//入的是结点的地址}}printf("\n");//使用完队列之后要记得销毁QueueDestory(&q);
}//判断是否是完全二叉树
bool BinaryTreeComplete(BTNode* root)
{//空树是完全二叉树if (root == NULL){return true;}//层序遍历 遇到空结点则跳出Queue q;//创建队列,队列存放的是二叉树结点的指针 QueueInit(&q);//队列初始化QueuePush(&q, root);//先入根节点while (!QueueEmpty(&q)){BTNode* front =QueueFront(&q);QueuePop(&q);//如果遇到空了,就可以跳出,比较后面的结点if (front == NULL){break;}//否则把左孩子和右孩子带进来,空结点也要带进队列else{QueuePush(&q, front->left);QueuePush(&q, front->right);}}//遇到空指针了,break/队列为空跳出,判断后面的元素//1.剩下的全是空,则是完全二叉树//2.剩下的存在非空,说明不是完全二叉树while (!QueueEmpty(&q)){BTNode* front = QueueFront(&q);QueuePop(&q);//如果有一个不为空->不是完全二叉树,返回falseif (front !=NULL ){//返回都要先销毁:QueueDestory(&q);return false;}}//注意:最后要销毁队列QueueDestory(&q);//如果全部都为空,while跳出循环return true;
}
int main()
{BTNode* root = BuyTree();LevelOrder(root);bool tmp = BinaryTreeComplete(root);if (tmp){printf("yes\n");}else{printf("No\n");}return 0;
}
Queue.c
#define _CRT_SECURE_NO_WARNINGS 1
#pragma once
#include"Queue.h"//初始化
void QueueInit(Queue* pq)
{assert(pq);pq->head = NULL;pq->tail = NULL;}//销毁
void QueueDestory(Queue* pq)
{assert(pq);//链表要遍历销毁结点,不能直接销毁QueueNode* cur = pq->head;while (cur){//保存下一个结点QueueNode* next = cur->next;free(cur);cur = next;}pq->head = NULL;pq->tail = NULL;
}//队尾入数据
void QueuePush(Queue* pq, QDataType x)
{assert(pq);//相当于尾插//构建新结点QueueNode* newnode = (QueueNode*)malloc(sizeof(QueueNode));newnode->next = NULL;newnode->data = x;//情况1:链表为空if (pq->tail == NULL){pq->head = pq->tail = newnode;}//情况2://tail newnode else{pq->tail->next = newnode; //尾插//注意如果一开始没有数据,pq->tail = NULL,此时会出错,相当于对空指针解引用//所以没有数据时需要单独判断pq->tail = newnode;//指向新的尾}}//队头出数据
void QueuePop(Queue* pq)
{assert(pq);//情况1:链表为空/*if (pq->head == NULL){return -1;}*/assert(!QueueEmpty(pq));//情况2QueueNode* next = pq->head->next;//保存下一个结点free(pq->head);//释放队头pq->head = next;//next成为新的队头//注意!!!!如果一直删,删最后一个时候 此时next为NULL的,如果不把tail也置空,就会造成野指针if (pq->head == NULL){pq->tail = NULL;}
}//取队头数据
QDataType QueueFront(Queue* pq)
{assert(pq);//链表为空/*if (pq->head == NULL){return -1;}*/assert(!QueueEmpty(pq));return pq->head->data;
}//取队尾数据
QDataType QueueBack(Queue* pq)
{assert(pq);assert(!QueueEmpty(pq));return pq->tail->data;
}//队列的长度
int QueueSize(Queue* pq)
{assert(pq);//方法1:遍历统计//方法2:定义结构体时添加一个size变量,入数据:size++ 出数据size -- 用size标志队列长度//遍历统计QueueNode* cur = pq->head;int count = 0;while (cur){count++;cur = cur->next;}return count;
}//判断队列是否为空
bool QueueEmpty(Queue* pq)
{assert(pq);/*if (pq -> head == NULL){return true;}else{return false;}*/return pq->head == NULL;
}
Queue.h
#pragma once
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
#include<stdbool.h>//队列 - 先进先出 typedef char BTDataType;
typedef struct BinaryTreeNode
{struct BinaryTreeNode* right;//指向左孩子struct BinaryTreeNode* left;//指向右孩子BTDataType data;//存放数据
}BTNode;typedef BTNode* QDataType; //队列存放的是二叉树结点的地址//队列中的结构体
typedef struct QueueNode
{struct QueueNode* next;QDataType data;
}QueueNode;//存放指向结构体的两个指针
typedef struct Queue
{QueueNode* head;//指向的头QueueNode* tail;//指向的尾
}Queue;//初始化
void QueueInit(Queue* pq);//销毁
void QueueDestory(Queue* pq);//队尾入数据
void QueuePush(Queue* pq, QDataType x);//队头出数据
void QueuePop(Queue* pq);//取队头数据
QDataType QueueFront(Queue* pq);//取队尾数据
QDataType QueueBack(Queue* pq);//队列的长度
int QueueSize(Queue* pq);//判断队列是否为空
bool QueueEmpty(Queue* pq);
【二叉树】大学有棵树叫高数,数据结构也有棵二叉树-代码详解相关推荐
- 高可用集群技术之corosync应用详解(一)
Corosync概述: Corosync是集群管理套件的一部分,它在传递信息的时候可以通过一个简单的配置文件来定义信息传递的方式和协议等.它是一个新兴的软件,2008年推出,但其实它并不是一个真正意义 ...
- java二叉树合并_Java(树的前中后序遍历构造二叉树题型整合)前序和中序、中序和后序、前序和后序遍历序列构造二叉树算法整合归纳...
前言 二叉树各种花里胡哨的算法题真的把我搞晕了,今天特地整理出一类有关二叉树的算法题,希望能帮助阅读到此文章的人,今后不再受此类题型的困扰. 一.题目类型 已知二叉树的两种遍历序列,请根据该序列构建二 ...
- python画一棵树源代码_Python+Turtle动态绘制一棵树实例分享
本文实例主要是对turtle的使用,实现Python+turtle动态绘制一棵树的实例,具体代码: # drawtree.py from turtle import Turtle, mainloop ...
- 统计二叉树中叶子结点数数据结构C语言,统计二叉树中叶子结点个数的问题,
#include #include typedef struct Node { int data; struct Node *LChild; struct Node *RChild; }BiTNode ...
- 二叉树的先序、中序、后序、层序遍历方式详解,由遍历序列构造二叉树过程详解以及C++代码详细实现
二叉树的遍历 树与二叉树的定义.性质,二叉树的顺序存储结构.链式存储结构 二叉树的遍历是指按某条搜索路径访问树中每个结点,使得每个结点均被访问一次,而且仅被访问一次.由于二叉树是一种非线性结构,每个结 ...
- glide源码中包含了那种设计模式_腾讯阿里华为小米等大厂Android高端面试题145题(含部分详解)-Go语言中文社区...
前言 本篇是结合我之前面试别人的经验,以及跟一些在大厂待过的朋友,讨论总结出的一份很全面的大公司需要用到的一些高端Android技术.这里也专门整理了一个文档,重点和难点都有详细解析. 这些题目有点技 ...
- 高可用集群技术之heartbeat应用详解(一)
一.高可用集群基本概念 什么是高可用技术呢?在生产环境中我既要保证服务不间断的服务又要保证服务器稳定不down机,但是异常还是会发生,比如说:服务器硬件损坏...导致服务器down机,我该如何保证 ...
- mysql in从数据库取数_MySQL数据库中 where in 用法详解
本文主要向大家介绍了MySQL数据库中 where in 用法详解,通过具体的内容向大家展现,希望对大家学习MySQL数据库有所帮助. 这里分两种情况来介绍 WHERE column IN (valu ...
- 习题:有100个学生种100棵树,其中高中生每人种3棵树,初中生每人种1棵树,小学生每3人种1棵树,问高中生、初中生、小学生各有多少人?
个人答案: #include <iostream>using namespace std;int main(){int x, y, z;for(x = 0; x <= 100; x+ ...
最新文章
- iOS开发网络篇—NSURLConnection基本使用
- 浅析ASP.NET页面缓存的几点体会
- Android设计模式(十五)--备忘录模式
- 摆摊真的一个月能上万嘛
- c++ 无法读取内存_为什么内存频率只有2133比实际低?开XMP提高内存频率方法
- 内存溢出 permgen_通过增加堆内存/ Permgen空间来修复Eclipse OutOfMemory错误
- 流放之路进传送门显示服务器断线,资讯:特别改动 优化组队经验获取 降低断图风险...
- 使用fseek()函数随机访问文件
- 数值分析(4)-多项式插值: 埃尔米塔插值法
- spring cloud分布式微服务-配置中心git示例
- 软考-计算机系统知识整理
- Java与网络调试助手TCP通信
- DHCP八种报文详解
- 使用JQuery.slideBox实现图片滚动效果
- 整理的一些java基础知识点,欢迎补充指正
- [Other]规范的邮件签名格式及HTML代码
- 视觉slam十四讲课后习题ch3-7
- 论文阅读-Detecting and Recovering Sequential DeepFake Manipulation(SeqFakeFormer)
- 分布式文件系统(DFS)浅析
- 模仿微信九宫格图片展示控件
热门文章
- 简历零经验的小白怎么写好简历?
- mongodb aggregate 聚合操作
- 字节跳动VP 谢欣:打造10倍速高效组织的秘密!
- 自动平面铣床的全球与中国市场2022-2028年:技术、参与者、趋势、市场规模及占有率研究报告
- PT_中心极限定理CLT:棣莫佛-拉普拉斯定理de Moivre - Laplace CLT+林德伯格-列维(Lindeberg-Levy)定理
- 五一出行哪种蓝牙耳机最好用?蓝牙耳机良心推荐
- 转载:技术大停滞——范式春梦中的地球工业文明6 台阶的本质:复杂度魔鬼
- 如何在手机上打开xmind文件_如何将 XMind 文件从电脑上传输至 XMind 安卓版? – XMind帮助中心...
- 淘宝新手开店常见误区有哪些?
- 《透明色,蒙版》如何用PPT扣除图,最快去除背景色