C语言二叉树和堆

二叉树基础知识:

1.栈、队列和顺序表都是线性结构

但是二叉树不是,二叉树是多分支结构

2.任何一棵树都可以拆分为子树和根节点,许多二叉树的相关问题都是用分治的思想进行函数的递归进行解决。

例:前序,中序,后序遍历二叉树

前序遍历:

void print_Front(pNode a)
{
	if (a == NULL)
	{
		printf("N ");
		return;
	}

	printf("%d ", a->val);
	print_Front(a->LeftChild);
	print_Front(a->RightChild);
}

3.二叉树链表实现可以用左孩子、右兄弟的方法来找到各个节点

struct TreeNode
{
	int data;
	struct TreeNode* leftchild;
	struct TreeNode* rightbrother;
};

图:

如上图,就可以找到二叉树中的所有节点。但缺点是:空间存在不小的浪费

4.也可以用双亲表示法来用数组造二叉树(但是:该方法只适合满二叉树和完全二叉树):

即:每个元素都存储好自己的父亲的下标位置,没有父亲的存-1

下标位置规律:

左孩子下标 = 父下标 * 2 + 1

右孩子下标 = 父下标 * 2 + 2

父下标 = (孩子下标 - 1 ) / 2 

例:

注:物理结构是数组(实际上的)

逻辑结构是二叉树(想象中的)

4.5.搜索二叉树特点:

左节点数据 < 根数据 < 右节点数据

5.堆:

堆分为大堆和小堆,但他们都是完全二叉树

大堆:父节点都大于子节点

小堆:父节点都小于子节点

6.完全二叉树要用数组去存储,但非完全二叉树要用链式结构去存储

可以用二叉链和三叉链存储

二叉链:

三叉链:

做题时要具备的良好素养:

1.一个节点含有的子树的个数就是该节点的度

2.一棵具有n个节点n-1条边

3.子树不能相交,即树不能有环

4.度为二的节点的个数始终等于度为零的节点个数 - 1

即:n0 = n2 + 1

5.二叉树可以是空树

6.完全二叉树的节点N和高度h的关系:

完全二叉树为满二叉树的情况:

N = 2 ^ h - 1

h = log(N + 1)

完全二叉树最后一层只有一个节点的情况:

N = 2 ^ (h - 1)

h = logN + 1

建议先记N = f(h),指数形式的这个好记

7.堆插入数据:用的是向上调整算法,时间复杂度:O(logN)

插入数据:
直接在数组尾部插入数据,然后向上调整

堆删除数据:用的是向下调整算法,时间复杂度:O(logN)

删除操作:
将顶部数据和数组最后一个元素换位,然后数组元素总数--,再让顶部数据向下调整

8.想要用向上调整建堆或向下调整建堆,就必须先确保根节点的左子树和右子树都统一是大堆或小堆,然后才能用此方法

9.用堆排序来排列一个升序数组:

用到了向下调整算法,向下调整建堆

typedef int tree_data_type;

void Swap(int* p1, int* p2)
{
	int tem = *p1;
	*p1 = *p2;
	*p2 = tem;
}

void Downsort_alg(int *a, int father, int n)
{
	int flag = 1;
	while (flag == 1)
	{
		flag = 0;
		if (father * 2 + 1 >= n)
		{
			break;
		}
		tree_data_type tem = father * 2 + 1;
		if (father * 2 + 2 < n && a[father * 2 + 1] < a[father * 2 + 2])
		{
			tem = father * 2 + 2;
		}
		if (a[tem] > a[father])
		{
			Swap(&a[tem], &a[father]);
			flag = 1;
			father = tem;
		}
	}
}

void Heapsort(int* a, int n)
{
	assert(a);
	assert(n > 0);

	int i = (n - 1 - 1) / 2;
	for (; i >= 0; i--)
	{
		Downsort_alg(a, i, n);
	}
}

void Heap_sort_order(int* a, int n)
{
	assert(a);
	assert(n > 0);
	Heapsort(a, n);

	int i = 0;
	while(n > 0)
	{	
		Swap(&a[0], &a[n - 1]);
		--n;
		Downsort_alg(a, 0, n);
	}
}

10.想要在n个数据中选出前k大的数据:

一个可以容纳k个元素的小堆

遍历n个数据,只要某个数据比顶点数据大,就将二者置换,接着向下调整算法

完事后,堆里边的就是前k大的数据

时间复杂度:k + (N - k) * logk

这是N远大于k的情况下

例:

在n个数据里边找前k小的数据

void create()
{
	srand((unsigned int)time(NULL));
	FILE* pf = fopen("test.txt", "w");

	int i = 0;
	for (i = 0; i < 10000; i++)
	{
		int tem = rand() * 100 + rand() * 10 + rand();
		fprintf(pf, "%d\n", tem);
	}
	fclose(pf);
	pf = NULL;
}

#define k 5
void Top(int n)
{
	FILE* pf = fopen("test.txt", "r");
	int a[k];
	int i = 0;
	for (; i < k; i++)
	{
		fscanf(pf, "%d", &a[i]);
	}
	Heapsort(a, k);//建的是大堆
	//找前k小的值
	for (; i < n; i++)
	{
		int tem;
		fscanf(pf, "%d", &tem);
		if (tem < a[0])
		{
			int tem1 = tem;
			tem = a[0];
			a[0] = tem1;
			Heapsort(a, k);
		}
	}
	print(a, k);
	fclose(pf);
	pf = NULL;
}

11.二叉树的层序遍历:

新造数组来完成,出一个进一个,没孩子不进或进NULL

例:

造数组出来的过程就是

12.OJ题目当中的二叉树数组表示时,都是用的层序

13.若根节点层数为1,则非空二叉树的第i层上最多2^(i - 1)个节点

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值