2019年3月24日
堆排序,大,小顶堆的建立,堆插入
首先去复习了数据结构中学的堆排序。伪代码如下:
typedef SqList HeapType;
void HeapAdjust( HeapType &H, int s, int m)
{
rc = H.r[s];
for( j=2*s; j<=m; j*=2){ //沿key较大的孩子结点向下筛选
if( j<m && H.r[j].key < H.r[j+1].key) ++j;
if( rc.key >= H.r[j].key) break;
H.r[s] = H.r[j]; s = j;
}
H.r[s] = rc;
}
void HeapSort( HeapType &H )
{ (1)
for( i=H.length/2; i>0; --i) //建立初始堆,从i= ?n/2?到1,反复“筛选”
HeapAdjust( H, i, H.length);
(2)
for( i=H.length; i>1; --i){
H.r[1] ←→ H.r[i]; //堆顶记录和当前未排子序列中
//最后一个记录相交换
HeapAdjust( H, 1, i-1 ); //将H. r[l .. i - 1] 重新调整为大顶堆
}
} (参考小甲鱼视频)
代码如下:
void swap(int a[],int x,int y){
int temp;
temp=a[x];
a[x]=a[y];
a[y]=temp;
}
void HeapAdjust(int a[],int s,int n){
//s下面的序号都已经是一个小顶堆了 ,此时考虑的是由于a[s]一个的变化的变化引起下面小顶堆的变化
int i,temp;
temp=a[s];//存放需要调整的双亲节点
for(i=2*s;i<=n;i*=2){
if(i<n&&a[i]>a[i+1])//保证i<n否则不需要i+1
i++;
if(temp<=a[i]) break;
a[s]=a[i];
s=i;
}
a[s]=temp;
}
void CreateHeap(int a[],int n){
int i;
for(i=n/2;i>0;i--){//从最大的非叶子节点开始筛选
HeapAdjust(a,i,n);//从a[i]到a[n]调整为小顶堆
}
for(i=n;i>1;i--){//进行n-1次,
swap(a,1,i);
HeapAdjust(a,1,i-1);
//因为一个根节点发生变化,可能不再是小顶堆,(根节点之下都还是小顶堆)重新构建堆
}
}
本来以为是简单的建堆,结果发现怎么建堆都得不出输出样例的结果。原因如下:我用的建堆方法是直接生成完全二叉树然后从i/2结点开始调整,这种建堆方式时间复杂度为线性。本题中的要求是一个一个插入到堆中,时间复杂度为O(N Log N)。
#include<stdio.h>
int h[1000];
int insert(int x,int i){
int temp;
if(h[i/2]<=x){
h[i]=x;
}
while(h[i/2]>x&&i/2>0){
temp=h[i/2];
h[i/2]=x;
h[i]=temp;
i=i/2;
}
}
int main()
{
int n,i,m,x,t,k;
scanf("%d",&n);
scanf("%d",&m);
scanf("%d",&h[1]);
for(i=2;i<=n;i++){
scanf("%d",&x);
insert(x,i);
}
for(t=0;t<m;t++){
scanf("%d",&k);
for(i=k;i>1;i=i/2){
printf("%d ",h[i]);
}
printf("%d",h[1]);
printf("\n");
}
}
或者一点小改动
#include<stdio.h>
int h[1001];
int size=0;
#define min -10001;
void insert(int x){
int i;
for(i=++size;h[i/2]>x;i=i/2){
h[i]=h[i/2];
}
h[i]=x;
}
int main(){
int n,m,i,temp;
scanf("%d%d",&n,&m);
h[0]=min;
for(i=0;i<n;i++){
scanf("%d",&temp);
insert(temp);
}
for(i=0;i<m;i++){
scanf("%d",&temp);
printf("%d",h[temp]);
while(temp>1){
temp=temp/2;
printf(" %d",h[temp]);
}
printf("\n");
}
}