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

希尔排序

简介

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

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

序列选择

1.Shell序列

Shell序列指的是 h t = [ N / 2 ] h_t=[N/2] ht=[N/2] h k = [ h k + 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;
	}
}

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

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

此时,除了 h = 1 h=1 h=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 , . . . , 2 k − 1 1,3,7,...,2^k-1 1,3,7,...,2k1的增量序列,其最坏复杂度为 O ( N 3 2 ) 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【模板】快速排序

题目描述

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

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

输入格式

1 1 1 行为一个正整数 N N N,第 2 2 2 行包含 N N N 个空格隔开的正整数 a i a_i ai,为你需要进行排序的数,数据保证了 a i a_i ai 不超过 1 0 9 10^9 109

输出格式

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

样例 #1

样例输入 #1

5
4 2 4 5 1

样例输出 #1

1 2 4 4 5

提示

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

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

AC代码如下

希尔排序

#include 
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 
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;
}

你可能感兴趣的:(数据结构,算法,排序算法,数据结构)