想要对二叉树进行操作,我们得先构建一个二叉树
因此,这里的问题就是给定数据,如何将数据在逻辑结构上变成二叉树?
结构定义:
typedef int BTDataType;
typedef struct BinaryTreeNode
{
BTDataType val;
struct BinaryTreeNode* left;
struct BinaryTreeNode* right;
}BTNode;
我们想构建上图的二叉树(#代表空),有两种方式
方法1:手动构建
BTNode* CreateTreeNode(BTDataType x)
{
BTNode* newNode = (BTNode*)malloc(sizeof(BTNode));
if (newNode == NULL)
{
perror("CreateTreeNode:malloc fail");
exit(-1);
}
newNode->val = x;
newNode->left = NULL;
newNode->right = NULL;
return newNode;
}
//方法1:手动构建
BTNode* CreateBinaryTree(BTDataType* a)
{
BTNode* n1 = CreateTreeNode('a');
BTNode* n2 = CreateTreeNode('b');
BTNode* n3 = CreateTreeNode('c');
BTNode* n4 = CreateTreeNode('d');
BTNode* n5 = CreateTreeNode('e');
BTNode* n6 = CreateTreeNode('f');
BTNode* n7 = CreateTreeNode('g');
n1->left = n2;
n2->left = n3;
n2->right = n4;
n4->left = n5;
n4->right = n6;
n5->right = n7;
return n1;
}
很显然,这种方法不够高效,如果有上百个结点,每个结点都要我们手动去连接,效率实在太低;
我们的第二种方法是给你一个二叉树的前序/中序/后序遍历,用递归去构建二叉树;
当然了,在讲这种方法前,我们得先知道一棵树的前序/中序/后序遍历是什么
对于任意一颗二叉树,都有三种遍历,对应着不同的结点访问顺序
- 前序遍历:根->左子树->右子树
- 中序遍历:左子树->根->右子树
- 后序遍历:左子树->右子树->根
可以看到,三种遍历的本质是根结点的访问顺序
//前序遍历
void PrevOrder(BTNode* root)
{
if (root == NULL)
{
printf("NULL ");
return;
}
printf("%c ", root->val);
PrevOrder(root->left);
PrevOrder(root->right);
}
//中序遍历
void InOrder(BTNode* root)
{
if (root == NULL)
{
printf("NULL ");
return;
}
InOrder(root->left);
printf("%c ", root->val);
InOrder(root->right);
}
//后序遍历
void PostOrder(BTNode* root)
{
if (root == NULL)
{
printf("NULL ");
return;
}
PostOrder(root->left);
PostOrder(root->right);
printf("%c ", root->val);
}
讲完了二叉树的遍历,就可以试着用递归去构建二叉树了
方法2:递归构建
//方法2:代码自动构建
BTNode* CreateBinaryTree(BTDataType* a, int* pi)
{
if (a[(*pi)] == '#')
{
(*pi)++;
return NULL;
}
BTNode* newNode = (BTNode*)malloc(sizeof(BTNode));
if (newNode == NULL)
{
perror("CreateBinaryTree:malloc fail");
exit(-1);
}
newNode->val = a[(*pi)++];
newNode->left = CreateBinaryTree(a, pi);
newNode->right = CreateBinaryTree(a, pi);
return newNode;
}
//结点个数
int BinaryTreeSize(BTNode* root)
{
if (root == NULL)
return 0;
return 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 BinaryTreeKSize(BTNode* root, int k)
{
if (root == NULL)
return 0;
if (k == 1)
return 1;
return BinaryTreeKSize(root->left, k - 1) + BinaryTreeKSize(root->right, k - 1);
}
//查找值为x的结点
BTNode* BinaryTreeFind(BTNode* root, BTDataType x)
{
if (root == NULL)
return NULL;
if (root->val == x)
return root;
BTNode* ret1 = BinaryTreeFind(root->left, x);
if (ret1)
return ret1;
BTNode* ret2 = BinaryTreeFind(root->right, x);
if (ret2)
return ret2;
return NULL;
}
上面介绍的前序/中序/后序遍历属于深度优先遍历(DFS),准确点说前序遍历属于深度优先遍历;
而层序遍历属于广度优先遍历(BFS)
//层序遍历
void LevelOrder(BTNode* root)
{
Queue q;
QueueInit(&q);
if (root != NULL)
QueuePush(&q, root);
while (!QueueEmpty(&q))
{
QDataType front = QueueFront(&q);
QueuePop(&q);
if (front)
{
printf("%c ", front->val);
QueuePush(&q, front->left);
QueuePush(&q, front->right);
}
}
QueueDestroy(&q);
}
如果想打印完一层后换行,再打印下一层,该怎么实现?
//层序遍历
void LevelOrder(BTNode* root)
{
Queue q;
QueueInit(&q);
if (root != NULL)
QueuePush(&q, root);
int levelSize = 1;
while (!QueueEmpty(&q))
{
while (levelSize--)
{
QDataType front = QueueFront(&q);
QueuePop(&q);
if (front)
{
printf("%c ", front->val);
QueuePush(&q, front->left);
QueuePush(&q, front->right);
}
}
printf("\n");
levelSize = QueueSize(&q);
}
QueueDestroy(&q);
}
//判断一颗二叉树是否为完全二叉树
bool IsCompleteBinaryTree(BTNode* root)
{
Queue q;
QueueInit(&q);
if (root != NULL)
QueuePush(&q, root);
while (!QueueEmpty(&q))
{
QDataType front = QueueFront(&q);
QueuePop(&q);
if (front)
{
QueuePush(&q, front->left);
QueuePush(&q, front->right);
}
else
{
break;
}
}
while (!QueueEmpty(&q))
{
QDataType front = QueueFront(&q);
QueuePop(&q);
if (front != NULL)
{
QueueDestroy(&q);
return false;
}
}
QueueDestroy(&q);
return true;
}
//二叉树的销毁
void BinaryTreeDestroy(BTNode* root)
{
if (root == NULL)
return;
BinaryTreeDestroy(root->left);
BinaryTreeDestroy(root->right);
free(root);
}
需要源码的小伙伴可以去我的Gitee主页查看
BInaryTree/BInaryTree · baiyahua/LeetCode - 码云 - 开源中国 (gitee.com)