数据结构之二叉树 二

目录

一、堆排序

(1)方式一

(2)方式二

二、建堆的时间复杂度

三、二叉树的遍历

 (1)前序

 (2)中序

(3)后序

(4)计算二叉树的节点个数(图为上面的二叉树)

方法一:遍历

方法二:传计数变量的地址

方法三:计算左右子树,分治下去​

(5)求二叉树的叶子结点个数

(6)第k层结点个数

(7)计算二叉树深度

(8) 二叉树查找值为x的结点

(9)检查是否是完全二叉树

 (10) 二叉树的销毁

 四、层序遍历

五、二叉树遍历


一、堆排序

(1)方式一

思路:建立堆,然后获取堆顶元素,再插入数组,在进行堆顶与最后一个元素交换,删除最后一个元素,从堆顶向下调整找到次大或次小的元素,依次重复

//堆排序方式一:
void HeapSort(int* arr,int n)
{
	HP hp;
	HeapInit(&hp);
	int i = 0;
	//排成升序,建立一个n个元素的小堆,每次取堆顶的元素,堆顶的元素每次都是最小的,然后删除堆顶元素,之后就是次小的在堆顶
	for (i = 0;i < n;i++)
	{
		HeapPush(&hp,arr[i]);
	}
	//获取堆顶元素放到arr数组中
	for (i = 0;i < n;i++)
	{
		arr[i] = HeapTop(&hp);
		//将堆顶元素删除
		HeapPop(&hp);
	}
	HeapDestroy(&hp);
}

(2)方式二

分析:升序,建大堆,选出最大的数,最大的数跟最后一个数交换,把最后一个数不看做堆里面,进行向下调整,就可以选出次小的数(logn),以此类推,重复上面的过程。
          降序则建小堆,选出最小的数,最小的数与最后一个数交换,把最后一个数不看做对立面,进行向下调整,以此重复即可。     

//堆排序方式二:直接操控a数组,直接把a建成堆,要求空间复杂度为o(1)
void HeapSort(int* arr, int n)
{
	//方式1:
	//将下标为0的数当作一个堆,将a构成一个小堆,依次加入后面的数
	//int i = 0;
	//for (i = 1;i < n;i++)
	//{
	//	AdujustUp(arr, i);//i是控制加入的下标
	//}

	//方式2:向下调整算法的前提是左右子树都是小堆,
	//叶子结点所在的子树不需要调,所以倒着走第一个非叶子节点(最后一个结点的父亲)的子树
	int i = n - 1; //o(n)
	for (i = (i - 1) / 2;i >= 0;i--)
	{
		AdjustDown(arr,n,i);
	}
	//升序,建大堆 o(n*logn)
	for (int j = n - 1;j > 0;j--)
	{
		Swap(&arr[0],&arr[j]);
		AdjustDown(arr,j,0);
	}
}

二、建堆的时间复杂度

三、二叉树的遍历

 (1)前序

 代码:
 

// 二叉树前序遍历
void PreOrder(BTNode* root)
{
	if (root == NULL)
	{
		printf("NULL ");
		return;
	}
	printf("%c ",root->data);
	PreOrder(root->left);
	PreOrder(root->right);
}

 (2)中序


// 二叉树中序遍历
void InOrder(BTNode* root)
{
	if (root == NULL)
	{
		printf("NULL ");
		return;
	}
	InOrder(root->left);
	printf("%c ", root->data);
	InOrder(root->right);
}

(3)后序

图如前序和中序基本一样
代码:

//二叉树后序遍历
void PostOrder(BTNode* root)
{
	if (root == NULL)
	{
		printf("NULL ");
		return;
	}
	PostOrder(root->left);
	PostOrder(root->right);
	printf("%c ",root->data);
}

(4)计算二叉树的节点个数(图为上面的二叉树)

方法一:遍历

// 二叉树节点个数
int BinaryTreeSize(BTNode* root)
{
	//思路一,遍历
	if (root == NULL)
	{
		return;
	}
	int count = 0;
	++count;
	BinaryTreeSize(root->left);
	BinaryTreeSize(root->right);
	return count;
}

此时的结果为1,为什么呢?
因为递归是在栈中创建的,每次调用都会创建一个新的栈,函数结束,那么里面的数据就会被销毁,而count是一个局部变量,所以每次都被销毁了,所以count为1。

那么我们加一个static(在静态区创建count,每次的count不会被销毁)有用吗?

 答案没有错,但是是有些问题的,比如再计算一次它的个数,count每次都没有销毁,就变为了12

 所以方法1还是有些问题的,但是也是一种好的思路。

方法二:传计数变量的地址

 //二叉树节点个数
void BinaryTreeSize(BTNode* root,int* pn)
{
	//思路二:传计数变量的地址,并不会随着栈的销毁而销毁
	if (root == NULL)
	{
		return;
	}
	++(*pn);
	BinaryTreeSize(root->left,pn);
	BinaryTreeSize(root->right,pn);
}

方法三:计算左右子树,分治下去

//思路三:
int BinaryTreeSize(BTNode* root)
{
	return root == NULL ? 0 : (BinaryTreeSize(root->left) + BinaryTreeSize(root->right) )+1;
}

(5)求二叉树的叶子结点个数

// 二叉树叶子节点个数
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);
}

(6)第k层结点个数


// 二叉树第k层节点个数
int BinaryTreeLevelKSize(BTNode* root, int k)
{
	assert(k >= 1);
	if (root == NULL)
	{
		return 0;
	}
	if (k == 1)
	{
		return 1;
	}
	//root不为空,并且k>1
	//假如k= 4,那么就相当于root->left的第三层
	return BinaryTreeLevelKSize(root->left,k-1) + BinaryTreeLevelKSize(root->right,k-1);
}

(7)计算二叉树深度

//计算二叉树的高度
int BinaryTreeDepth(BTNode* root)
{
	if (root == NULL)
	{
		return 0;
	}
	//栈开辟的太多,比较之后又重新计算了左右子树的高度,所以不提倡
	//return BinaryTreeDepth(root->left) > BinaryTreeDepth(root->right) ? (BinaryTreeDepth(root->left) + 1) : (BinaryTreeDepth(root->right) + 1);

	//所以最好计算左子树高度和右子树高度之后保存一下,不需要在重新计算
	int LeftTreeDepth = BinaryTreeDepth(root->left);
	int RightTreeDepth = BinaryTreeDepth(root->right);
	return LeftTreeDepth > RightTreeDepth ? LeftTreeDepth + 1 : RightTreeDepth + 1;
}

(8) 二叉树查找值为x的结点

思路:

从根节点找,没找到,到左子树找,左子树没找到,再往左子树的左子树找,直到左子树为NULL,再到右子树去找,依次重复,找到了返回给上一层依次重复

// 二叉树查找值为x的节点
BTNode* BinaryTreeFind(BTNode* root, DataType x)
{
	if (root == NULL)
	{
		return NULL;
	}
	//根是不是x
	 if (root->data == x)
	{
		return root;
	}
	 //没找到递归到左子树和右子树去找
	 BTNode* left = BinaryTreeFind(root->left, x);//下一层递归左子树找到了,返回的是这里,是向上一层一层往回返的
	 if (left != NULL)//不为空就表示找到了,因为没找到返回的是空
	 {
		 return left;
	 }
	 BTNode* right =  BinaryTreeFind(root->right, x);
	 if (right != NULL)
	 {
		 return right;
	 }
	return NULL; 
}

(9)检查是否是完全二叉树

思路: 如果当前节点为空,则后面全为空才为完全二叉树,如果当前节点不为空,则将它的孩子插入队列。

代码:

bool BinaryTreeComplete(BTNode* root)
{
	Queue queue;
	QueueInit(&queue);
	QueuePush(&queue,root);
	while (!QueueEmpty(&queue))
	{
		BTNode* front = QueueFront(&queue);
		QueuePop(&queue);
		if (front == NULL )
		{
			break;
		}
		else
		{
			QueuePush(&queue,front->left);
			QueuePush(&queue, front->right);
		}
	}
	//遇到空以后,检查队列中剩下的节点
	//1.剩下的全是空,则是完全二叉树
	//2.剩下的存在非空,则不是完全二叉树
	while (!QueueEmpty(&queue))
	{
		BTNode* front = QueueFront(&queue);
		QueuePop(&queue);
		if (front != NULL)
		{
			QueueDestroy(&queue);
			return false;
		}
	}
	QueueDestroy(&queue);
	return true;
}

 (10) 二叉树的销毁

void BinaryTreeDestroy(BTNode* root)
{
	//运用后序的方式,因为如果先把根销毁就找不到左右根了
	if (root == NULL)
	{
		return;
	}
	BinaryTreeDestroy(root->left);
	BinaryTreeDestroy(root->right);
	free(root);
}

 

 

 四、层序遍历

 队列中存放的是二叉树的节点

代码:

//层序遍历
void BinaryTreeLevelOrder(BTNode* root)
{
	//队列里面放的是结点的指针,因为这样才能拿到它的孩子的地址
	if (root == NULL)
	{
		return;
	}
	Queue s1;
	QueueInit(&s1);
	QueuePush(&s1,root);
	while (!QueueEmpty(&s1))
	{
		BTNode* front = QueueFront(&s1);
		 QueuePop(&s1);
		 //打印出来的这个节点
		 printf("%c ",front->data);

		 //将孩子带入
		 if (front->left != NULL )
		 {
			 QueuePush(&s1,front->left);
		 }
		 if (front->right != NULL)
		 {
			 QueuePush(&s1,front->right);
		 }
	}
	printf("\n");
	QueueDestroy(&s1);
}

运行结果:

五、二叉树遍历

二叉树遍历_牛客题霸_牛客网 (nowcoder.com)

 思路:按照前序建立二叉树,然后进行中序遍历

 

#include<stdio.h>
#include<stdlib.h>

struct TreeNode
{
    struct TreeNode* left;
    struct TreeNode* right;
    char val;
};

struct TreeNode* CreateTree(char* arr, int* i)
{
    if (arr[(*i)] == '#')
    {
        (*i)++;
        return NULL;
    }
    //建立节点
    struct TreeNode* root = (struct TreeNode*)malloc(sizeof(struct TreeNode));
    root->val = arr[(*i)++];
    root->left = CreateTree(arr, i);
    root->right = CreateTree(arr, i);
    return root;
}
void InOrder(struct TreeNode* root)
{
    if (root == NULL)
        return;
    InOrder(root->left);
    printf("%c ", root->val);
    InOrder(root->right);
}
int main()
{
    char arr[100];
    scanf("%s",arr);
    {
        int i = 0;
        struct TreeNode* root = CreateTree(arr, &i);
        InOrder(root);
    }
    return 0;
}

 运行结果:

 

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值