题目链接
前言:
看了很多题解,也知道这题有更简单的做法,但是还是根据陈老师的方法来实现一遍
关键点:
1、首先是明确用数组来存这颗完全二叉树,那是最省最适合的
2、关键思路:
是对这一堆数进行排序
然后求出左子树的结点的个数
进而可以求出根节点,进行赋值
之后有一个难点是如何根据根结点(该数组是以0下标开始)求出左子树和右子树的根结点:
int Left = Troot*2+1;
int Right = Left+1;
再不断递归
void solve(int ALeft, int ARight, int Troot)
{
//ALeft为正在进行操作的数组的第一个数的下标, 同理ARight正在进行操作的数组的第一个数的下标
//Troot为当前根结点所在的数组的位置
//n为当前所求数组的个数
int n = ARight-ALeft+1;
if (n==0)
return;
//L为左子树的结点个数
int L = GetLefttree(n);
//求出根节点,进行赋值
T[Troot] = tree[L+ALeft];
//推出左子树和右子树的根节点的个数
int Left = Troot*2+1;
int Right = Left+1;
//递归左右子树
solve(ALeft, ALeft+L-1, Left);
solve(ALeft+L+1, ARight, Right);
}
3、如何求左子树的结点数:
首先明确(假如树的根节点为第一层, 即h = 1),则第n层有
pow(2, h-1);
总共n层树,有
pow(2, h)-1;
看如下图
X的值是不能超过pow(2, h-1);
4、还有个细节是如何进行排序,c语言的排序函数是qsort,之前用的是c++都是sort,这是第一次,记录下用法
int compare(const void*a, const void*b)
{
return *(int *)a - *(int*)b;
}qsort(tree, n, sizeof(int), compare);
tree为要排序数组的指针,可以用数组名
n为数组大小,即为要排序的大小
sizeof(int)为数组里的每一个元素的字节
compare为自定义的排序函数
代码:
# include <stdio.h>
# include <stdlib.h>
# include <math.h>
int n;
int tree[1010];
int T[1010];
int GetLefttree(int num)
{
int a = num+1;
a/=2;
int sumh = 0;
while (a)
{
sumh++;
a/=2;
}
int x = num-pow(2, sumh)+1;
if (x>pow(2, sumh-1))
x = pow(2, sumh-1);
return pow(2, sumh-1)+x-1;
}
void solve(int ALeft, int ARight, int Troot)
{
int n = ARight-ALeft+1;
if (n==0)
return;
int L = GetLefttree(n);
T[Troot] = tree[L+ALeft];
int Left = Troot*2+1;
int Right = Left+1;
solve(ALeft, ALeft+L-1, Left);
solve(ALeft+L+1, ARight, Right);
}
int compare(const void*a, const void*b)
{
return *(int *)a - *(int*)b;
}
int main()
{
scanf("%d", &n);
for (int i=0; i<n; i++)
scanf("%d", &tree[i]);
qsort(tree, n, sizeof(int), compare);
// for (int i=0; i<n; i++)
// printf("%d ", tree[i]);
solve(0, n-1, 0);
printf("%d", T[0]);
for (int i=1; i<n; i++)
printf(" %d", T[i]);
return 0;
}