树的介绍 and 递归处理一些习题~

下面树的遍历前中后序采用了递归处理,但递归容易导致栈溢出,这里给出了非递归的方法

               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));
	
}

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值