树的介绍 and 递归处理一些习题~
程序员文章站
2022-04-25 16:49:22
...
下面树的遍历前中后序采用了递归处理,但递归容易导致栈溢出,这里给出了非递归的方法
https://blog.csdn.net/Z_JUAN1/article/details/80952209
一、 树
· 有一个特殊的结点,称为根节点,根节点没有前区关系
· 除了根节点外,其余结点被分为M(M>0)个互不相交的集合T1、T2....Tm,其中每一个集合Ti(1<= i <m)又是一颗结构与树类似的子树,每颗子树的根节点有且只有一个前驱,可以是0个或多个后继
so~树是递归定义的
结点: 12个节点
结点的度:结点A的度为3,结点B的度为2,结点J的度为0
叶节点:J F K L H I
祖先结点:K的祖先结点A C G
子孙结点:B的祖先结点E F J
孩子结点:结点A的孩子结点为B C D
双亲结点:结点A是结点B C D的双亲结点
兄弟结点:B C D 互为兄弟结点,E F G H I 互为堂兄弟结点
树的度:3(所有节点的度的最大值)
树的深度:4
二、二叉树
· 每个结点最多有两颗子树,即二叉树不存在度大于2的结点
· 二叉树的子树有左右之分,其子树的次序不可更改
满二叉树 && 完全二叉树
满二叉树:所有的分支都存在左子树和右子树,并且所有的叶子节点都在同一层
完全二叉树:一棵具有N个结点的二叉树的结构与满二叉树的前N个结点的结构相同
基本操作:
遍历结点:前序、中序、后序
前序:A B D C E F
中序:D B A E C F
后序:D B E F C A
接下来我们看一些面试题吧~
1. 创建二叉树
树是一个递归的过程,所以这类题中我们大量的用到了递归
因为每一个子树又可以是一棵独立的树
//创建根
TreeNode *GreatRoot(DataType data)
{
TreeNode *pRoot = (TreeNode *)malloc(sizeof(TreeNode));
assert(pRoot);
pRoot->pleft = NULL;
pRoot->pright = NULL;
pRoot->data = data;
return pRoot;
}
//创建二叉树
TreeNode *GreatTree(DataType preorder[], int size,int *pIndex)
{
if (*pIndex >= size)
{
return NULL;
}
if (preorder[*pIndex] == '#')
{
*pIndex += 1;
return NULL;
}
TreeNode *pRoot = GreatRoot(preorder[*pIndex]);
*pIndex += 1;
pRoot->pleft = GreatTree(preorder, size, pIndex);
pRoot->pright = GreatTree(preorder, size, pIndex);
return pRoot;
}
2.前中后遍历二叉树
//前序
void PreOrder(TreeNode *pRoot)
{
if (pRoot == NULL);
return ;
printf("%c ",pRoot->data);
PreOrder(pRoot->pleft);
PreOrder(pRoot->pright);
}
//中序
void InOrder(TreeNode *pRoot)
{
if (pRoot == NULL);
return ;
PreOrder(pRoot->pleft);
printf("%c ", pRoot->data);
PreOrder(pRoot->pright);
}
//后序
void PostOrder(TreeNode *pRoot)
{
if (pRoot == NULL);
return ;
PreOrder(pRoot->pleft);
PreOrder(pRoot->pright);
printf("%c ", pRoot->data);
}
3.结点个数
//结点个数
int GetSize(TreeNode *pRoot)
{
if (pRoot = NULL){
return NULL;
}
return GetSize(pRoot->pleft) + GetSize(pRoot->pright) + 1;
}
4.叶子结点个数
//叶子结点个数
int GetLeafSize(TreeNode *pRoot)
{
if (pRoot == NULL){
return 0;
}
if (pRoot->pleft == NULL && pRoot->pright == NULL){
return 1;
}
return GetLeafSize(pRoot->pleft) + GetLeafSize(pRoot->pright);
}
5.第k层的结点个数
找到第K层进行左树+右树
//第k层的结点个数
int GetKLevelSize(TreeNode *pRoot, int k)
{
assert(k>=1);
if (pRoot == NULL)
{
return 0;
}
if (k = 1)
{
return 1;
}
return GetKLevelSize(pRoot->pleft, k - 1)
+ GetKLevelSize(pRoot->pright, k - 1);
}
6.判断一个节点是否在二叉树中// 找到,返回结点地址,否则返回 NULL
TreeNode * Find(TreeNode *pRoot, DataType data)
{
if (pRoot == NULL)
{
return NULL;
}
if (pRoot->data == data)
{
return pRoot;
}
TreeNode *pFound = Find(pRoot->pleft,data);
if (pFound != NULL)
{
return pFound;
}
return Find(pRoot->pright, data);
}
7.树的高度
#define MAX(x,y) ((x)>(y)?(x):(y))
int GetHeight(TreeNode *pRoot)
{
if (pRoot == NULL)
{
return 0;
}
int left = GetHeight(pRoot->pleft);
int right = GetHeight(pRoot->pright);
return MAX(left, right) + 1;
}
8.层序遍历
a.初始化一个队列
b.将根节点的指针入队列
c.当队列为非空时,循环以下步骤:
> 取队头元素并访问
> 若该结点的左子树非空,将该结点的左子树入队列
> 若该结点的右子树非空,将该结点的右子树入队列
//层序遍历
void LevelOrder(TreeNode *pRoot)
{
if (pRoot == NULL)
{
printf("\n");
return;
}
Queue queue;
TreeNode *pFront;
QueueInit(&queue);
QueuePush(&queue, pRoot);
while (!QueueIsEmpty(&queue))
{
pFront = QueueFront(&queue);
QueuePop(&queue);
printf("%c ", pFront->data);
if (pFront->pleft != NULL){
QueuePush(&queue, pFront->pleft);
}
if (pFront->pright != NULL){
QueuePush(&queue, pFront->pright);
}
}
printf("\n");
}
9.判断是否为完全二叉树//是否为完全二叉树
// 是返回 1,不是返回 0
int IsComplete(TreeNode *pRoot)
{
if (pRoot == NULL){
return 1;
}
Queue queue;
TreeNode *pFront;
QueueInit(&queue);
QueuePush(&queue, pRoot);
while (!QueueIsEmpty(&queue))
{
pFront = QueueFront(&queue);
QueuePop(&queue);
if (pFront == NULL)
{
break;
}
QueuePush(&queue, pFront->pleft);
QueuePush(&queue, pFront->pright);
}
while (!QueueIsEmpty(&queue))
{
pFront = QueueFront(&queue);
QueuePop(&queue);
if (pFront != NULL)
{
return 0;
}
}
return 1;
}
看一下测试函数吧~
void Tree()
{
DataType *preorder = "ABD###CE##F";
//DataType *preorder = "AB##C";
int index = 0;
TreeNode *pRoot = GreatTree(preorder, strlen(preorder), &index);
PreOrder(pRoot); printf("\n"); //前序
InOrder(pRoot); printf("\n"); //中序
PostOrder(pRoot); printf("\n"); //后序
printf("结点数: %d\n", GetSize(pRoot));
printf("叶子结点数: %d\n", GetLeafSize(pRoot));
int k = 2;
printf("第 %d 层结点数: %d\n", k, GetKLevelSize(pRoot, k));
char C;
Find(pRoot, C);
printf("树的高度为: %d\n", GetHeight(pRoot));
LevelOrder(pRoot);
printf("%d\n", IsComplete(pRoot));
}