Time Limit: 1000 ms Memory Limit: 65536 KiB
Problem Description
我们已经学习了各种排序方法,知道在不同的情况下要选择不同的排序算法,以期达到最好的排序效率;对于待排序数据来说,若数据基本有序且记录较少时, 直接插入排序的效率是非常好的,希尔排序就是针对一组基本有序的少量数据记录进行排序的高效算法。你的任务是对于给定的数据进行希尔排序,其中增量dk=n/(2^k)(k=1,2,3……)
Input
连续输入多组数据,每组输入数据的第一行给出一个正整数N(N <= 10000),随后连续给出N个整数表示待排序关键字,数字间以空格分隔。
Output
输出dk=n/2和dk=1时的结果。
Sample Input
10 10 9 8 7 6 5 4 3 2 1 10 -5 9 7 -11 37 -22 99 288 33 66
Sample Output
5 4 3 2 1 10 9 8 7 6 1 2 3 4 5 6 7 8 9 10 -22 9 7 -11 37 -5 99 288 33 66 -22 -11 -5 7 9 33 37 66 99 288
Hint
Source
xam
先写的插入排序的模板,在Insert_sort_initial函数内,插入排序函数的主要思路就是将数组的第一位空出用于存放待加入有序序列的元素a[ i ](由for循环控制,下标从2开始到n),再通过place变量,利用第二个for循环,寻找到合适的插入位置,并且用place变量存储。通过第三个for循环将a[place]至a[ i ]的元素均向前挪一位,将a[ 0 ]放至a[ place ]。
插入排序模板如下:
void Into_sort_initial(int a[],int n)
{
a[0]=a[1];
int place=0;
for(int i=2; i<=n; i++)
{
a[0]=a[i];
if(a[i]>=a[i-1])
{
place=i;
}
else if(a[i]<a[i-1])
{
//先找出正确的位置,再对数字进行填入
for(int k=1; k<i; k++)
{
if(a[k-1]<=a[i]&&a[i]<a[k])
{
place=k;
}
}
for(int j=i; j>place; j--)
{
a[j]=a[j-1];
}
}
a[place]=a[0];
}
}//相当于一开始的插入排序模板,为了希尔排序更改后,添加了start与step,即开始的下标与步长
注意希尔排序的意义,希尔排序即通过控制步长达到分序列进行插入排序的过程,需要建立变量控制其开始start,结束end,步长step,添加这三个变量后普通的插入排序应设置为start=1,end=n,step=1。
注意此时start-step必须大于等于1,不然会出现越界的情形。
void Into_sort(int a[],int start,int end,int step)
{
a[0]=a[start];//其实是用于存放待交换的数字的?
int place=0;//存放应当放置的位置
for(int i=start+step; i<=end; i+=step)
{
a[0]=a[i];
if(a[i]<a[i-step])
{
for(int k=start; k<i; k+=step)
{
if(k-step>=1)
{
if(a[i]>=a[k-step]&&a[i]<a[k])
{
place=k;
}
}//当可以向后减去一个步长的时候
else if(k-step<1)
{
if(a[i]<a[k])
{
place=k;
}
}//当不能减去步长的时候,比如处理只有一个元素的边界值时
}
}
else if(a[i]>=a[i-step])
{
place=i;//直接设置放置的位置为i
}
for(int j=i; j>place; j-=step)
{
a[j]=a[j-step];//将place到i之前的数字均向前移动一位
}
a[place]=a[0];//将放置位置数字赋值为key
}
}
完整的代码如下:
#include <iostream>
using namespace std;
int a[10000];
void Into_sort_initial(int a[],int n)
{
a[0]=a[1];
int place=0;
for(int i=2; i<=n; i++)
{
a[0]=a[i];
if(a[i]>=a[i-1])
{
place=i;
}
else if(a[i]<a[i-1])
{
//先找出正确的位置,再对数字进行填入
for(int k=1; k<i; k++)
{
if(a[k-1]<=a[i]&&a[i]<a[k])
{
place=k;
}
}
for(int j=i; j>place; j--)
{
a[j]=a[j-1];
}
}
a[place]=a[0];
}
}//相当于一开始的插入排序模板,为了希尔排序更改后,添加了start与step,即开始的下标与步长
void Into_sort(int a[],int start,int end,int step)
{
a[0]=a[start];//其实是用于存放待交换的数字的?
int place=0;//存放应当放置的位置
for(int i=start+step; i<=end; i+=step)
{
a[0]=a[i];
if(a[i]<a[i-step])
{
for(int k=start; k<i; k+=step)
{
if(k-step>=1)
{
if(a[i]>=a[k-step]&&a[i]<a[k])
{
place=k;
}
}//当可以向后减去一个步长的时候
else if(k-step<1)
{
if(a[i]<a[k])
{
place=k;
}
}//当不能减去步长的时候,比如处理只有一个元素的边界值时
}
}
else if(a[i]>=a[i-step])
{
place=i;//直接设置放置的位置为i
}
for(int j=i; j>place; j-=step)
{
a[j]=a[j-step];//将place到i之前的数字均向前移动一位
}
a[place]=a[0];//将放置位置数字赋值为key
}
}
void Hill_sort(int a[],int n,int start,int step)
{
while(step!=0)
{
step=step/2;
for(int i=start; i<start+step; i++)
{
Into_sort(a,i,n,step);
}
if(step==(n/2)||step==1)
{
for(int l=1; l<=n; l++)
{
if(l<n)
{
cout<<a[l]<<" ";
}
else if(l==n)
{
cout<<a[l]<<endl;
}
}
}
}
}
int main()
{
int n;
while(cin>>n)
{
for(int i=1; i<=n; i++)
{
cin>>a[i];
}
Hill_sort(a,n,1,n);
}
return 0;
}