之前说的选择,插入,冒泡三种基本排序,时间复杂度都为O平方,直到希尔排序的出现,打破了O平方的魔咒.希尔排序的基本思想我理解是属于分而治之,把一个无序序列划分为若干个子序列,再分别对这写子序列使用三种基本排序方法进行排序.
下边直接看示意图:
要排的序列为 int array[] = {12,32,2,4,6,54,34,76,89,32,14};排序为升序排序
第一次划分:假设间隔d = 3,那么可以划分为{12,32,2,4,6,54,34,76,89,32,14}得到三个子序列(一个颜色集合为一个子序列)
接着对三个子序列按基本排序法排序,得到{4,6,2,12,14,54,32,32,89,34,76},从这里我们可以看到,这个序列已经基本有序.
第二次划分:缩减间隔d=2,那么可划分为{4,6,2,12,14,54,32,32,89,34,76} 得到两个子序列,然后对这两个子序列按基本排序法排序,
得到 {2,6,4,12,14,32,32,34,76,54,89}
第三次划分:缩减间隔d=1,划分为 {2,6,4,12,14,32,32,34,76,54,89},到了这里,整个序列基本已经排好了,只需要在使用一次基本排序,做少量的元素交换,便可完成序列的排序.
以上便是希尔排序的基本思想,先分而治之,划分为各个子序列,各自排序,之后只需要统一做少量的交换工作,便可完成整个序列的排序.下边来看看代码,这里我分别使用选择排序,插入排序来实现
#include <iostream>
#include <string.h>
#include <errno.h>
#include <stdio.h>
using namespace std;
//需要注意的是,这里的类模板需要放在头文件中去实现,这里为了直观,直接放这里了
template <typename T>
class Sort : public Object
{
private:
static void swap(T& nLeft, T& nRight)
{
T tmp = nLeft;
nLeft = nRight;
nRight = tmp;
}
public:
//基于选择排序的希尔排序
static void SelectShell(T* nArray, int nLen, bool Min2Max = true)
{
int d = nLen;
while(d > 1)
{
d = d/3 +1;
int count = 0;
while(count<d)
{
for(int i=count; i<nLen; i+=d)
{
int index = i;
for(int j=i+d; j<nLen; j+=d)
{
if( Min2Max ? (nArray[index] > nArray[j]):(nArray[index] < nArray[j]))
{
index = j;
}
}
if(index != i)
{
swap(nArray[index], nArray[i]);
}
}
count++;
}
}
}
//基于插入排序的希尔排序
static void InsertShell(T* nArray, int nLen, bool Min2Max = true)
{
int d = nLen;
while(d > 1)
{
d = d/3 + 1;
int count = 0;
while(count < d)
{
for(int i=count; i<nLen; i+=d)
{
int index = i;
T e = nArray[index];
for(int j=i; j>=0; j-=d)
{
if( Min2Max ? (e < nArray[j]):(e> nArray[j]))
{
nArray[j+d] = nArray[j];
index = j;
}
}
if(index != i)
{
nArray[index] = e;
}
}
count++;
}
}
}
};
int main(int argc, char* argv[])
{
int array[] = {12,32,2,4,6,54,13,34,25,87,76,89,32,14,23};
int len = sizeof(array)/sizeof(int);
Sort<int>::InsertShell(array, len);
for(int i=0; i<len; i++)
{
cout << array[i] << " ";
}
cout << endl;
Sort<int>::SelectShellShell(array, len, false);
for(int i=0; i<len; i++)
{
cout << array[i] << " ";
}
cout << endl;
return 0;
}
main测试函数中分别用了基于插入排序与基于选择排序的希尔排序来测试,一个测升序,一个测降序,其结果是符合我们的预期的