前言:
前期学习二叉树,包括堆,都是利用数组实现。
接下来就用链表的形式实现二叉树,并实现二叉树的相关功能。
二叉树前序遍历:
什么是前序遍历,任何一棵二叉树都可以分为根和左子树、右子树。
例如:
前序遍历的顺序:根 左子树 右子树。
例如如下二叉树前序遍历顺序:
如果想要前序遍历一个二叉树代码如下:
void pre_order(BTNode*Node)
{
if (Node == NULL)
{
return;
}
printf("%d ",Node->_data);
pre_order(Node->_left);
pre_order(Node->_right);
}
利用前序遍历插入数据:
将ABD##E#H##CF##G##(#表示NULL)通过前序遍历插入
代码如下:
BTNode* BinaryTreeCreate(BTDataType* a, int* pi)
{
assert(a);
if (a[*pi] == '#')
{
(*pi)++;
return NULL;
}
BTNode* root = (BTNode*)malloc(sizeof(BTNode));
if (root == NULL)
{
perror("malloc::error");
exit(-1);
}
root->_data = a[(*pi)++];
root->_left = BinaryTreeCreate(a,pi);
root->_right = BinaryTreeCreate(a,pi);
return root;
}
二叉树的中序遍历、后序遍历:
有了前序遍历的经验,中序后序遍历就不难写出。
中序遍历访问顺序:左子树 根 右子树
后序遍历访问顺序:左子树 右子树 根
代码如下:
//中序遍历
void middle_order(BTNode*root)
{
if (root == NULL)
{
return;
}
middle_order(root->_left);
printf("%c ", root->_data);
middle_order(root->_right);
}
//后序遍历
void post_order(BTNode*root)
{
if (root == NULL)
{
return;
}
post_order(root->_left);
post_order(root->_right);
printf("%c ", root->_data);
}
二叉树的销毁:
思路:
1、必须先释放左右孩子,最后释放根,不然会导致根丢失,找不到孩子了。
2、如果根的左右孩子都为空,则释放空间并返回。
代码如下:
void BinaryTreeDestory(BTNode* root)
{
if (root == NULL)
return;
if (root->_left == NULL && root->_right == NULL)
{
free(root);
root = NULL;
return;
}
BinaryTreeDestory(root->_left);
BinaryTreeDestory(root->_right);
}
二叉树节点个数:
思路:
1、 需要遍历,将一个二叉树看作一个根一个左孩子和一个右孩子。
2、 左孩子的节点个数+有孩子的节点个数+本身(1)。
代码如下:
int BinaryTreeSize(BTNode* root)
{
if (root == NULL)
{
return 0;
}
return BinaryTreeSize(root->_left) + BinaryTreeSize(root->_right) + 1;
}
二叉树叶子节点个数:
思路:
1、当根的左孩子和右孩子都等于NULL时,返回1;
2、当根为NULL时,返回0;
代码如下:
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层的节点数:
思路:
1、如果是第一层直接返回1
2、如果不是第一层,则为左孩子的第k层的节点数+有右孩子的第k层的节点数。
代码如下:
int BinaryTreeLevelKSize(BTNode* root, int k)
{
if (k == 0||root == NULL)
{
return 0;
}
if (k == 1)
{
return 1;
}
return BinaryTreeLevelKSize(root->_left, k-1) + BinaryTreeLevelKSize(root->_right, k-1);
}
二叉树查找值为x的节点:
代码如下:
BTNode* BinaryTreeFind(BTNode* root, BTDataType x)
{
if (root == NULL)
return NULL;
if (root->_data == x)
return root;
if (!(BinaryTreeFind(root->_left, x) ||
BinaryTreeFind(root->_right, x)))
return NULL;
}
*二叉树层序遍历:
思路:
这里由于是初阶,层序遍历我们借助队列层序遍历。
主要思路:
一个节点不为空就要进队列,然后记录之后pop如果一个节点的左右节点不为空,就让左右孩子进去。
代码如下:
void BinaryTreeLevelOrder(BTNode* root)
{
Queue q;
QueueInit(&q);
if (root)
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");
}
QueueDestroy(&q);
}
判断一个二叉树是否为完全二叉树:
思路:
借助层序遍历的思想,如果一个二叉树只有右孩子没有左孩子,那么当前二叉树不是完全二叉树。
代码如下:
// 判断二叉树是否是完全二叉树
int BinaryTreeComplete(BTNode* root)
{
Queue q;
QueueInit(&q);
if (root)
QueuePush(&q, root);
while (!QueueEmpty(&q))
{
BTNode* front = QueueFront(&q);
QueuePop(&q);
if (front->_left)
QueuePush(&q, front->_left);
if (front->_right)
QueuePush(&q, front->_right);
if (front->_left == NULL && front->_right != NULL)
return 0;
}
return 1;
QueueDestroy(&q);
}