希尔排序是插入式排序的一种,也称缩小增量排序,是对 直接插入排序 的一种更高效的改进算法,
基本思想:
希尔排序是把记录按下标的一定增量(也就是按一定的步长)分组,对每组使用直接插入排序算法排序;随着增量逐渐减少(每循环一次减半),每组包含的关键词越来越多,当增量减至1时(相当于一次直接插入排序),整个文件恰被分成一组,算法便终止。
我是这么理解的,希尔排序可以说是一种跳跃式的排序(直接插入排序是每次与前面挨个比较步长为1),过程大致分为2个阶段,步长不为1的时候为——模糊排序阶段;步长等于1的时候为——精确排序阶段(也就是一次直接插入排序)。前面的模糊排序阶段是为后面精确排序做铺垫,上一篇中也说了,排序也就是确定元素的位置,所以在模糊排序过程的时候同样使用了二分法大致确定了元素的位置,后面精确排序的时候就不需要有很大的移动,因此达到高效。
比如:对A[] ={ 63,4, 24, 1, 3, 15}排序,首先我们使用起始步长 step =Length/2=3 对数组中每个元素等步长比较,交换,也就是说A[0] 与A[0+step=3]比较,A[0]>A[3]交换位置,A[0]=1,A[3]=63(就这么一下,1就跳到了首位了),然后进行下一组比较A[1]>A[4](下标都相差3,前面比后面的大才交换) ,交换,然后A[2]与A[5]比较A[2]>A[5],交换,第一次比较完毕.(此时数组已大致有序) 步长减半,step = step/2=1,此时进行直接插入排序 (具体参考直接插入排序)并不需要大量的移位就排序完成了。
下面我们随机生成10000个数字并进行希尔排序与直接插入排序,输出前十个元素,再比较两种排序使用的时间。
C++实例:
#include<iostream>
#include<cstdlib>
#include<vector> //加入数组容器
#include<ctime> //加入时间头文件
#include<cstdio>
using namespace std;
void ShellSort(vector<int> array,int Length)
{
clock_t start,end; //定义开始,结束时间
int step=Length/2,temp,i,j; //定义起始步长,
start=clock();//开始计时
while(step>=1)
{
for(i=step;i<Length;i++)
{
temp=array[i];
//这里当step=1的时候有没有很像直接插入排序了
for(j=i-step;j>=0&&temp<array[j];j=j-step)
{
array[j+step]=array[j];
}
array[j+step]=temp;
}
step=step/2;//步长逐渐缩短
}
end=clock();//记录结束时间
//输出前十个
for(i=0;i<10;i++)
{
cout<<array[i]<<" ";
}
cout<<endl;
cout<<"希尔排序用时:"<<end-start<<"毫秒"<<endl;
}
void InsertSort(vector<int> array,int Length)
{
int i,j,key;
clock_t start,end;
start=clock();//记录开始时间
for(i=1;i<Length;i++) //确定待插入元素
{
key = array[i]; //key为待插入元素
for(j=i;j>0&&array[j-1]>key;j--) //查找要插入的位置,循环结束,则找到插入位置
{
array[j]=array[j-1]; //向后移位,腾出插入的空间
}
array[j]=key; //插入元素
}
end=clock();//记录结束时间
for(i=0;i<10;i++)
{
cout<<array[i]<<" ";
}
cout<<endl;
cout<<"直接插入排序用时:"<<end-start<<"毫秒"<<endl;
}
void main()
{
vector<int> array;
vector<int> array2;
for(int i=1;i<=10000;i++) //对10000个随机数排序
{
array.push_back(rand()); //将随机数装进数组也就是入队
}
int Length=array.size(); //获取长度
array2=array;
ShellSort(array,Length); //希尔排序
InsertSort(array2,Length); //直接插入排序
}
结果:
看见了吧,两者相差了好多倍呢。
C#实例:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading; //Sleep
using System.Diagnostics; //要添加这个引用否则没有Stopwatch
namespace ShellSort2
{
class Sort
{//希尔排序方法
public void ShellSort(List<int> array)
{
int Length = array.Count/2;
int step=Length/2,i,j,temp;
Stopwatch watch = new Stopwatch();//计时语句
watch.Start();
while (step >= 1)
{
for (i = step; i < Length; i++)
{
temp = array[i];
for (j = i - step; j >= 0 && temp < array[j]; j = j - step)
{
array[j + step] = array[j];
}
array[j + step] = temp;
}
step = step / 2;
}
watch.Stop();
Console.WriteLine("前十个元素:" + String.Join(" ", array.Take(10).ToList()));//输出前十个
Console.WriteLine("希尔排序用时:" + watch.ElapsedMilliseconds);
}
static void Main(string[] args)
{
List<int> array =new List<int>() ;
for(int i=0;i<10000;i++)
{
Thread.Sleep(1);//这里需要暂停线程,否则随机数有很大部分都相等
array.Add(new Random((int)DateTime.Now.Ticks).Next(1,100000));
}
Sort sorter = new Sort();
sorter.ShellSort(array);
}
}
}
结果:
java实例:
哎呀!我电脑上的java启动不了啦,不好意思了,我下一篇再补充出来吧!!
有什么建议或意见欢迎留言^_^