数据结构:二叉树部分接口(链式)
目录
二叉树的遍历
1.通过前序遍历的数据构造二叉树
2.二叉树销毁
3. 二叉树节点个数
4. 二叉树叶子节点的个数
5.二叉树第k层节点个数
6.二叉树查找值为x的节点
7.二叉树的前/中/后序遍历
8.层序遍历
9.判断二叉树是否是完全二叉树
二叉树的遍历
前序、中序以及后序遍历
学习二叉树结构,最简单的方式就是遍历。所谓二叉树遍历(Traversal)是按照某种特定的规则,依次对二叉树中的结点进行相应的操作,并且每个结点只操作一次。访问结点所做的操作依赖于具体的应用问题。 遍历是二叉树上最重要的运算之一,也是二叉树上进行其它运算的基础。
按照规则,二叉树的遍历有:前序/中序/后序的递归结构遍历:
1. 前序遍历(Preorder Traversal 亦称先序遍历)——访问根结点的操作发生在遍历其左右子树之前。
2. 中序遍历(Inorder Traversal)——访问根结点的操作发生在遍历其左右子树之中(间)。
3. 后序遍历(Postorder Traversal)——访问根结点的操作发生在遍历其左右子树之后。
这里的二叉树接口是二叉树部分功能的实现,并不是链式二叉树的增删改查
// 通过前序遍历的数组"ABD##E#H##CF##G##"构建二叉树
BTNode* BinaryTreeCreate(BTDataType* a, int* pi);
// 二叉树销毁
void BinaryTreeDestory(BTNode** root);
// 二叉树节点个数
int BinaryTreeSize(BTNode* root);
// 二叉树叶子节点个数
int BinaryTreeLeafSize(BTNode* root);
// 二叉树第k层节点个数
int BinaryTreeLevelKSize(BTNode* root, int k);
// 二叉树查找值为x的节点
BTNode* BinaryTreeFind(BTNode* root, BTDataType x);
// 二叉树前序遍历
void BinaryTreePrevOrder(BTNode* root);
// 二叉树中序遍历
void BinaryTreeInOrder(BTNode* root);
// 二叉树后序遍历
void BinaryTreePostOrder(BTNode* root);
// 层序遍历
void BinaryTreeLevelOrder(BTNode* root);
// 判断二叉树是否是完全二叉树
bool BinaryTreeComplete(BTNode* root);
1.通过前序遍历的数据构造二叉树
// 通过前序遍历的数组"ABD##E#H##CF##G##"构建二叉树
// a指的是数组 *pi 指的是数组里元素个数
BTNode* BinaryTreeCreate(BTDataType* a, int* pi)
{
//若为'#'则*pi++,并且返回空
if (a[(*pi)] == '#')
{
(*pi)++;
return NULL;
}
BTNode* root = (BTNode*)malloc(sizeof(BTNode));
root->_data = a[(*pi)++];
root->_left = BinaryTreeCreate(a,pi);
root->_right = BinaryTreeCreate(a, pi);
return root;
2.二叉树销毁
// 二叉树销毁
void BinaryTreeDestory(BTNode** root)
{
if (*root)
{
// 注意这里是二级指针
BinaryTreeDestory(&(*root)->_left);
BinaryTreeDestory(&(*root)->_right);
free(*root);
*root = NULL;
}
}
3. 二叉树节点个数
通过递归求节点个数
/ 二叉树节点个数
int BinaryTreeSize(BTNode* root)
{
if (root == NULL)
{
return 0;
}
return BinaryTreeSize(root->_left)+ BinaryTreeSize(root->_right)+1;
}
4. 二叉树叶子节点的个数
一个节点没有孩子则为叶子节点
// 二叉树叶子节点个数
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);
}
5.二叉树第k层节点个数
(根节点为第一层,第二层为其孩子节点....依次往下递增)
二叉树第k层节点 == 左孩子的第k-1层 + 右孩子的第k-1层节点
// 二叉树第k层节点个数
int BinaryTreeLevelKSize(BTNode* root, int k)
{
if (root == NULL)
{
return 0;
}
//当k == 1 时, 即为第k层的节点
if (k == 1)
{
return 1;
}
return BinaryTreeLevelKSize(root->_left, k - 1)+ BinaryTreeLevelKSize(root->_right,k-1);
}
6.二叉树查找值为x的节点
// 二叉树查找值为x的节点
BTNode* BinaryTreeFind(BTNode* root, BTDataType x)
{
BTNode* ret;
if (root == NULL)
{
return NULL;
}
//根节点查找
if (root->_data == x)
{
return root;
}
//根节点找不到,则左孩子查找
ret = BinaryTreeFind(root->_left, x);
// 若找到此节点,则ret不为空,直接返回该地址
if (ret)
return ret;
//左海子找不到,则右孩子查找
ret = BinaryTreeFind(root->_right, x);
if (ret)
// 若找到此节点,则ret不为空,直接返回该地址
return ret;
//都找不到返回空
return NULL;
}
7.二叉树的前/中/后序遍历
// 二叉树前序遍历
void BinaryTreePrevOrder(BTNode* root)
{
if (root == NULL)
{
return;
}
printf("%d ", root->_data);
BinaryTreePrevOrder(root->_left);
BinaryTreePrevOrder(root->_right);
}
// 二叉树中序遍历
void BinaryTreeInOrder(BTNode* root)
{
if (root == NULL)
{
return;
}
BinaryTreeInOrder(root->_left);
printf("%d ", root->_data);
BinaryTreeInOrder(root->_right);
}
// 二叉树后序遍历
void BinaryTreePostOrder(BTNode* root)
{
if (root == NULL)
{
return;
}
BinaryTreePostOrder(root->_left);
BinaryTreePostOrder(root->_right);
printf("%d ", root->_data);
}
8.层序遍历
层序遍历需要创建一个队列(尾进头出),插入根节点到队列中,然后打印头结点,接着插入其左孩子节点,最后删除头节点,以此循坏,直到队列为空。
// 层序遍历
void BinaryTreeLevelOrder(BTNode* root)
{
if (root == NULL)
{
printf("此二叉树为空\n");
return;
}
// 创造队列
Queue qu;
QueueInit(&qu);
//创造一个变量记住队列中头节点
BTNode* cur;
// 插入根节点
QueuePush(&qu, root);
//若队列不为空,则循坏
while (!QueueEmpty(&qu))
{
//找到队列的头节点
cur = QueueFront(&qu);
printf("%c ", cur->_data);
//插入头节点的左孩子(左孩子不为空)
if (cur->_left)
{
QueuePush(&qu, cur->_left);
}
//插入头节点的右孩子(右孩子不为空)
if (cur->_right)
{
QueuePush(&qu, cur->_right);
}
//删除头节点
QueuePop(&qu);
}
printf("\n");
QueueDestroy(&qu);
}
9.判断二叉树是否是完全二叉树
思想:创建一个队列,插入头结点之后,再出头节点,接着再插入其左右孩子节点,一直循坏该操作,知道队列中删除的元素为空时退出循坏,此时的队列并不为空,接着继续判断队列后面的元素是否都为空,若都为空则为完全二叉树,反之则不是
// 判断二叉树是否是完全二叉树
bool BinaryTreeComplete(BTNode* root)
{
//创造一个队列
Queue qu;
QueueInit(&qu);
// 若树的根节点不为空,则插入到队列中
if (root)
{
QueuePush(&qu, root);
}
//创造一个变量来记住队列中的头元素
BTNode* front;
//队列插入一层,出一个结点进两个孩子,若有空则退出循坏
while (!QueueEmpty(&qu))
{
// front = 队列中头元素
front = QueueFront(&qu);
//删除队列的头结点
QueuePop(&qu);
//若头元素为空则退出循坏
if (front == NULL)
{
break;
}
//插入左右孩子
QueuePush(&qu, front->_left);
QueuePush(&qu, front->_right);
}
//判断空后是否继续为空
while (!QueueEmpty(&qu))
{
front = QueueFront(&qu);
QueuePop(&qu);
//若front不为空,则不是完全二叉树
if (front != NULL)
{
QueueDestroy(&qu);
return false;
}
}
//都为空,则返回true
QueueDestroy(&qu);
return true;
}