希尔排序+堆排序简介与代码实现

本文介绍了希尔排序和堆排序两种高效排序算法。希尔排序通过比较相距一定间隔的元素来工作,堆排序则是利用优先队列进行排序的方法。文章详细讲解了这两种排序算法的工作原理及其实现代码。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

希尔排序

简介

希尔排序是第一批冲破二次时间屏障的第一批算法,其使用比较相距一定间隔的元素来工作,各趟比较的距离随着算法的进行而减少,知道比较相邻距离的最后一趟排序为止。因此也叫做最小增量排序

希尔排序的最重要部分在于增量序列,即使用的距离序列h1,h2,⋯ ,hnh_1,h_2,\cdots,h_nh1,h2,,hn,其中只要h1=1h_1=1h1=1则希尔排序有效,但是增量序列的选择却是决定希尔排序时间复杂度的决定性因素。
希尔排序生效的还有一个重要前提是“hkh_khk排序性”不变,此时后一次排序不会打乱前一次的排序结果。

序列选择

1.Shell序列

Shell序列指的是ht=[N/2]h_t=[N/2]ht=[N/2]hk=[hk+1/2]h_k=[h_{k+1}/2]hk=[hk+1/2]的序列,使用该代码的希尔排序代码如下:

void sort(long long num[],int N){
	int i=N/2;
	while(i>=1){
		for(int j=0;j<i;j++){
			for(int k=j;k<N;k+=i){
				for(int m=k;m>j;m-=i){
					if(num[m]<num[m-i]){
						long long temp=num[m];
						num[m]=num[m-i];
						num[m-i]=temp;
					}
					else
						break;
				}
			}
		}
		i/=2;
	}
}

其最坏情形运行时间复杂度为Θ(N2)\Theta(N^2)Θ(N2),只要令NNN为2的幂,并且使得当h=2h=2h=2时的两条序列都为单调序列但不相交,例如

1,9,2,10,3,11,4,12,...

此时,除了h=1h=1h=1以外的增量序列均不会对其排序,浪费大量时间,具体证明这里不再赘述。

2.Hibbard序列
void sort(long long num[],int N){
	int i=1;
	while(i<N){
	    i=2*i;
	}
	i=i/2-1;
	while(i>=1){
		for(int j=0;j<i;j++){
			for(int k=j;k<N;k+=i){
				for(int m=k;m>j;m-=i){
					if(num[m]<num[m-i]){
						long long temp=num[m];
						num[m]=num[m-i];
						num[m-i]=temp;
					}
					else
						break;
				}
			}
		}
		i=(i+1)/2-1;
	}
}

Hibbard序列使用的是形如1,3,7,...,2k−11,3,7,...,2^k-11,3,7,...,2k1的增量序列,其最坏复杂度为O(N32)O(N^{\frac{3}{2}})O(N23),证明不再赘述。

堆排序

堆排序是将优先队列用于排序的一种方法,简单来说,只要先对数组进行建堆操作建立最大堆,然后按顺序Delete Max即可。如果我们用一个新的数组去存取Delete得到的最大值,会导致其空间复杂度会达到O(N)O(N)O(N)。为了降低空间复杂度,我们会将堆的堆首元素与堆尾元素交换位置,然后使堆的大小减小一后调整堆为最大堆。
实现代码如下:

void percdown(long long a[],int i,int N){
    while(i<N){
        if(2*i+2<N){
            if(a[2*i+2]>a[2*i+1])
                if(a[2*i+2]>a[i]){
                    long long temp=a[i];
                    a[i]=a[2*i+2];
                    a[2*i+2]=temp;
                    i=2*i+2;
                }
                else
                    break;//break容易被忘记
            else
                if(a[2*i+1]>a[i]){
                    long long temp=a[i];
                    a[i]=a[2*i+1];
                    a[2*i+1]=temp;
                    i=2*i+1;
                }
                else
                    break;
        }
        else if(2*i+1<N){
            if(a[2*i+1]>a[i]){
                long long temp=a[i];
                a[i]=a[2*i+1];
                a[2*i+1]=temp;
                i=2*i+1;
            }
            else
                break;
        }
        else
        break;
    }
}
void sort(long long num[],int N){
    for(int i=N-1;i>=0;i--){
        percdown(num,i,N);
    }
    for(int i=0;i<N;i++){
        long long temp=num[0];
        num[0]=num[N-1-i];
        num[N-1-i]=temp;
        percdown(num,0,N-1-i);
    }
}

P1177【模板】快速排序

题目描述

利用快速排序算法将读入的 NNN 个数从小到大排序后输出。

快速排序是信息学竞赛的必备算法之一。对于快速排序不是很了解的同学可以自行上网查询相关资料,掌握后独立完成。(C++ 选手请不要试图使用 STL,虽然你可以使用 sort 一遍过,但是你并没有掌握快速排序算法的精髓。)

输入格式

111 行为一个正整数 NNN,第 222 行包含 NNN 个空格隔开的正整数 aia_iai,为你需要进行排序的数,数据保证了 aia_iai 不超过 10910^9109

输出格式

将给定的 NNN 个数从小到大输出,数之间空格隔开,行末换行且无空格。

样例 #1

样例输入 #1

5
4 2 4 5 1

样例输出 #1

1 2 4 4 5

提示

对于 20%20\%20% 的数据,有 N≤103N\leq 10^3N103

对于 100%100\%100% 的数据,有 N≤105N\leq 10^5N105

AC代码如下

希尔排序

#include <stdio.h>
long long p[1000001];
void sort(long long num[],int N){
	int i=N/2;
	while(i>=1){
		for(int j=0;j<i;j++){
			for(int k=j;k<N;k+=i){
				for(int m=k;m>j;m-=i){
					if(num[m]<num[m-i]){
						long long temp=num[m];
						num[m]=num[m-i];
						num[m-i]=temp;
					}
					else
						break;
				}
			}
		}
		i/=2;
	}
}

int main()
{
 int n;
 scanf("%d",&n);
 for (int i = 0;i < n;i++)
 scanf("%lld",&p[i]);
 sort(p,n);
 for (int i = 0;i < n;i++)
 printf("%lld ",p[i]);
 return 0;
}

堆排序

#include <stdio.h>
long long p[1000001];
void percdown(long long a[],int i,int N){
    while(i<N){
        if(2*i+2<N){
            if(a[2*i+2]>a[2*i+1])
                if(a[2*i+2]>a[i]){
                    long long temp=a[i];
                    a[i]=a[2*i+2];
                    a[2*i+2]=temp;
                    i=2*i+2;
                }
                else
                    break;
            else
                if(a[2*i+1]>a[i]){
                    long long temp=a[i];
                    a[i]=a[2*i+1];
                    a[2*i+1]=temp;
                    i=2*i+1;
                }
                else
                    break;
        }
        else if(2*i+1<N){
            if(a[2*i+1]>a[i]){
                long long temp=a[i];
                a[i]=a[2*i+1];
                a[2*i+1]=temp;
                i=2*i+1;
            }
            else
                break;
        }
        else
        break;
    }
}
void sort(long long num[],int N){
    for(int i=N-1;i>=0;i--){
        percdown(num,i,N);
    }
    for(int i=0;i<N;i++){
        long long temp=num[0];
        num[0]=num[N-1-i];
        num[N-1-i]=temp;
        percdown(num,0,N-1-i);
    }
}

int main()
{
 int n;
 scanf("%d",&n);
 for (int i = 0;i < n;i++)
 scanf("%lld",&p[i]);
 sort(p,n);
 for (int i = 0;i < n;i++)
 printf("%lld ",p[i]);
 return 0;
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值