受post的启发,我搜索了最糟糕的heapsort案例并在cs.stackexchange.com上找到this question,但唯一的答案并没有真正回答这个问题,所以我决定挖掘我自己。经过几个小时的推理和编码,我已经解决了。我认为这个问题在SO中更好,所以我在这里发布。
问题是找到一个包含从1到n的不同数字的堆化数组,这样当将它转换为有序数组时,所有筛选操作中的交换总数是最大的。
答案 0 :(得分:3)
当然有一种强力算法可以计算所有可能的堆化数组并计算每个数组的交换次数,我已经这样做以验证下面解决方案的结果。
让我们从N = 1开始:1
N = 2:显然,它是[2,1]
N = 3:[3,x,1] 由于每个筛选呼叫最多会产生一些 交换等于“高度(等于⌊log(n)⌋”(来自 进行筛选调用的节点的堆的底部,所以 我们将1放在数组的末尾。显然,x = 2。
N = 4:[4,x,y,1]
在第一次提取-max之后,我们需要heapify [1,x,y]。如果我们将它筛选到N = 3,[3,2,1]的情况下,因为这个筛选操作产生的交换次数等于“高度”,加上N = 3时的最大交换次数,所以当N = 4时,最大交换次数的情况。 因此,我们将"siftDown" version of heapify向后转换为[3,2,1]:与其父项交换1,直到1为根。所以x = 2,y = 3
N = n:[n,a,b,c,...,x,1]
因此,通过归纳,我们在N = n时做同样的事情:首先
extract-max,当N =时,我们将[1,a,b,c,...,x]向下移动到堆化数组
n-1个。所以我们向后做,得到我们的东西。
输出N:
时输出满足要求的堆化数组的代码#include<stdio.h>
const int MAXN = 50001;
int heap[MAXN];
int main()
{
int n;
int len,i,j;
while(scanf("%d",&n)!=EOF)
{
heap[1]=1;
len=1;
for(i=2;i<=n;i++)
{
j=len;
while(j>1)
{
heap[j]=heap[j/2];
j/=2;
}
heap[1]=i;
heap[++len]=1;
}
for(i=1;i<=n;i++)
{
if(i!=1) printf(" ");
printf("%d",heap[i]);
}
printf("\n");
}
return 0;
}