目录
一、二叉树的链式结构
二、手动创建一棵链式二叉树
三、 二叉树的遍历
(1)前序遍历(先序遍历)
(2)中序遍历
(3)后序遍历
四、二叉树的有关函数
(1)头文件
(2)二叉树结点总数
(3) 二叉树叶子结点个数
(4) 二叉树第k层结点个数
(5)二叉树的高度/深度
(6) 二叉树查找值为x的结点
(7)二叉树的销毁
五、层序遍历
六、判断是否为完全二叉树
七、写在最后
一、二叉树的链式结构
链表来表示二叉树,其实就是用链来指示元素的逻辑关系。
链表中的每个结点由3个域组成:数据域和左右指针域,其中左右指针分别用来给出该结点左孩子和右孩子所在链的结点的存储地址。
typedef int BTDatatype;
//二叉链
typedef struct BinaryTreeNode
{
BTDatatype val;//当前结点的值域
struct BinaryTreeNode* left;//指向当前结点的左孩子
struct BinaryTreeNode* right;//指向当前结点的右孩子
}
二、手动创建一棵链式二叉树
二叉树分为空树和非空二叉树,其中非空二叉树由根结点、根结点的左孩子和根结点的右孩子组成。而根结点的左右子树又是由子树结点、子树结点的左孩子和子树结点的右孩子组成的,因此二叉树的定义是递归的。
//创建新结点
BTNode* BuyNode(int val)
{
BTNode* newnode = (BTNode*)malloc(sizeof(BTNode));
if(newnode == NULL)
{
perror("malloc fail!");
reutrn NULL;
}
newnode->val = val;
newnode->left = newnode->right = NULL;
return newnode;
}
//创建二叉树
BTNode* CreatTree()
{
BTNode* n1 = BuyNode(1);
BTNode* n2 = BuyNode(2);
BTNode* n3 = BuyNode(3);
BTNode* n4 = BuyNode(4);
BTNode* n5 = BuyNode(5);
BTNode* n6 = BuyNode(6);
BTNode* n7 = BuyNode(7);
n1->left = n2;
n1->right = n4;
n2->left = n3;
n4->left = n5;
n4->right = n6;
n5->left = n7;
return n1;
}
三、 二叉树的遍历
(1)前序遍历(先序遍历)
访问根结点的操作发生在遍历其左右子树之前;
访问顺序为:根结点、左子树、右子树,即:根左右。
void PerOrder(BTNode* root)
{
//若根结点为空,直接返回
if(root == NULL)
{
printf("NULL");
return;
}
//先打印根结点的数据
printf("%d ",root->val);
//遍历左孩子
PerOrder(root->left);
//遍历右孩子
PerOrder(root->right);
}
(2)中序遍历
访问根结点的操作发生在遍历其左右子树之中(间);
访问顺序为:左子树、根结点、右子树,即:左根右。
void InOrder(BTNode* root)
{
if(root == NULL)
{
printf("NULL");
return;
}
InOrder(root->left);
printf("%d ",root->val);
InOrder(root->right);
}
(3)后序遍历
访问根结点的操作发生在遍历其左右子树之后;
访问顺序为:左子树、右子树、根结点,即:左右根。
void PostOrder(BTNode* root)
{
if(root == NULL)
{
printf("NULL");
return;
}
PostOrder(root->left);
PostOrder(root->right);
printf("%d ",root->val);
}
四、二叉树的有关函数
(1)头文件
// ⼆叉树结点总数
int BinaryTreeSize(BTNode* root);
// ⼆叉树叶⼦结点个数
int BinaryTreeLeafSize(BTNode* root);
// ⼆叉树第k层结点个数
int BinaryTreeLevelKSize(BTNode* root, int k);
//⼆叉树的深度/⾼度
int BinaryTreeDepth(BTNode* root);
// ⼆叉树查找值为x的结点
BTNode* BinaryTreeFind(BTNode* root, BTDataType x);
// ⼆叉树的销毁
void BinaryTreeDestory(BTNode** root);
(2)二叉树结点总数
int BinaryTreeSize(BTNode* root)
{
if(root == NULL)
{
return 0;
}
//根结点+左子树中结点的个数+右子树中结点的个数
return 1 + BinaryTreeSize(root->left) + BinaryTreeSize(root->right);
}
(3) 二叉树叶子结点个数
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);
}
(4) 二叉树第k层结点个数
int BinaryTreeLevelKSize(BTNode* root, int k)
{
if(root == NULL)
{
return 0;
}
//第k层
if(k == 1)
{
return 1;
}
//左子树的第k层结点数+右子树的第k层结点数
return BinaryTreeLevelKSize(root->left, k-1) + BinaryTreeLevelKSize(root->right, k-1);
}
(5)二叉树的高度/深度
int BinaryTreeDepth(BTNode* root)
{
if(root == NULL)
{
return 0;
}
//分别求得左右子树的深度
int leftDeep = BinaryTreeDepth(root->left);
int rightDeep = BinaryTreeDepth(root->right);
//根结点 + 左右子树的深度的最大值
return leftDeep > rightDeep ? leftDeep + 1 : rightDeep + 1;
}
(6) 二叉树查找值为x的结点
BTNode* BinaryTreeFind(BTNode* root, BTDataType x)
{
if(root == NULL)
{
return NULL;
}
找到值为x的数据
if(root->val == x)
{
return root;
}
//在左子树中找值为x的数据
//如果在左子树找到,直接返回,无需在右子树寻找
BTNode* leftFind = BinaryTreeFind(root->left, x);
if(leftFind)
{
return leftFind;
}
BTNode* rightFind = BinaryTreeFind(root->right, x);
if(rightFind)
{
return rightFind;
}
如若在左右子树都没有找到,则说明找不到
return NULL;
}
(7)二叉树的销毁
//注意传入的是指针的地址,形参为二级指针
void BinaryTreeDestory(BTNode** root)
{
if(*root == NULL)
{
return;
}
//销毁左右子树
BinaryTreeDestory(&((*root)->left));
BinaryTreeDestory(&((*root)->right));
//销毁根结点
free(*root);
*root = NULL;
}
五、层序遍历
设⼆叉树的根结点所在层数为1,层序遍历就是从所在⼆叉树的根结点出发,首先访问第⼀层的树根结点,然后从左到右访问第2层上的结点,接着是第三层的结点,以此类推,自上而下,从左至右逐层访问树的结点的过程。
实现层序遍历需要额外借助数据结构:队列。
void LevelOrder(BTNode* root)
{
Queue q;
QueueInit(&q);
QueuePush(&q, root);
while(!QueueEmpty(&q))
{
//取队头,并打印
BTNode* front = QueueFront(&q);
printf("%d ",front->val);
//队头结点的左右孩子入队列
if(front->left)
{
QueuePush(&q, front->left);
}
if(front->right)
{
QueuePush(&q, front->rught);
}
}
//此时队列为空,销毁队列
QueueDestroy(&q);
}
六、判断是否为完全二叉树
bool BinaryTreeComplete(BTNode* root)
{
Queue q;
QueueInit(&q);
QueuePush(&q, root);
while (!QueueEmpty(&q))
{
BTNode* top = QueueFront(&q);
QueuePop(&q);
if (top == NULL)
{
break;
}
QueuePush(&q, top->_left);
QueuePush(&q, top->_right);
}
//队列不一定为空
while (!QueueEmpty(&q))
{
BTNode* top = QueueFront(&q);
QueuePop(&q);
if (top != NULL)
{
QueueDesTroy(&q);
return false;
}
}
QueueDesTroy(&q);
return true;
}
如果是完全二叉树,跳出一个循环之后队列中剩下的全都是NULL结点;
如果不是完全二叉树,跳出一个循环之后队列中还有非空结点。
七、写在最后
我们已经学习了实现二叉树的两种方法:顺序结构(堆)和链式结构。
敬请期待“二叉树OJ题”~