最优时间复杂度为o(n),又称缩小增量排序。
逻辑分析:
1、希尔排序首先是确定增量,默认的希尔增量(不一定是最优)为length/2。
2、根据增量分组,将分组的元素利用直接插入法排序。
3、增量=增量/2,再次分组,一直到增量为1为止。
通过上述步骤我们可以知道,代码会有3个循环,第一个gap的更新,即for(int gap=len/2;gap>0;gap/=2)。第二个和第三个循环是对分组数组进行直接插入排序。
代码分析:
数组a[] = { 2,1,4,5,3,8,7,9,0,6 },length=10。
第一次大循环
gap=length/2=5,i=5,j=i-gap=0,a[j]=2<a[j+gap]=8,此时数组不做任何操作。
gap=length/2=5,i=6,j=i-gap=1,a[j]=1<a[j+gap]=7,此时数组不做任何操作。
gap=length/2=5,i=7,j=i-gap=2,a[j]=4<a[j+gap]=9,此时数组不做任何操作。
gap=length/2=5,i=8,j=i-gap=3,a[j]=5<a[j+gap]=0,故交换a[j]和a[j+gap],数组a[]= { 2,1,4,0,3,8,7,9,5,6 }。
gap=length/2=5,i=9,j=i-gap=4,a[j]=3<a[j+gap]=6,此时数组不做任何操作。
第二次大循环
gap=gap/2=2,i=2,j=i-gap=0,a[j]=3<a[j+gap]=4,此时数组不做任何操作。
gap=gap/2=2,i=3,j=i-gap=1,a[j]=1>a[j+gap]=0,故交换a[j]和a[j+gap],数组a[]= { 2,0,4,1,3,8,7,9,5,6 }。
gap=gap/2=2,i=4,j=i-gap=2,a[j]=4>a[j+gap]=3,故交换a[j]和a[j+gap],数组a[]= { 2,0,3,1,4,8,7,9,5,6 }。
gap=gap/2=2,i=4,j=i-gap=0,a[j]=2<a[j+gap]=3,此时数组不做任何操作。
gap=gap/2=2,i=5,j=i-gap=3,a[j]=1<a[j+gap]=8,此时数组不做任何操作。
gap=gap/2=2,i=6,j=i-gap=4,a[j]=4<a[j+gap]=7,此时数组不做任何操作。
gap=gap/2=2,i=7,j=i-gap=5,a[j]=8<a[j+gap]=9,此时数组不做任何操作。
gap=gap/2=2,i=8,j=i-gap=6,a[j]=7>a[j+gap]=5,故交换a[j]和a[j+gap],数组a[]= { 2,0,3,1,4,8,5,9,7,6 }。
gap=gap/2=2,i=9,j=i-gap=7,a[j]=9>a[j+gap]=6,故交换a[j]和a[j+gap],数组a[]= { 2,0,3,1,4,8,5,6,7,9 }。
第三次大循环
gap=gap/2=1,i=1,j=i-gap=0,a[j]=2>a[j+gap]=0,故交换a[j]和a[j+gap],数组a[]= { 0,2,3,1,4,8,5,6,7,9 }。
gap=gap/2=1,i=2,j=i-gap=1,a[j]=2<a[j+gap]=3,此时数组不做任何操作。
gap=gap/2=1,i=3,j=i-gap=2,a[j]=3>a[j+gap]=1,故交换a[j]和a[j+gap],数组a[]= { 0,2,1,3,4,8,5,6,7,9 }。
gap=gap/2=1,i=3,j=j-gap=1,a[j]=2>a[j+gap]=1,故交换a[j]和a[j+gap],数组a[]= { 0,1,2,3,4,8,5,6,7,9 }。
gap=gap/2=1,i=3,j=j-gap=0,a[j]=0<a[j+gap]=1,此时数组不做任何操作。
gap=gap/2=1,i=4,j=i-gap=3,a[j]=3<a[j+gap]=4,此时数组不做任何操作。
gap=gap/2=1,i=5,j=i-gap=4,a[j]=4<a[j+gap]=8,此时数组不做任何操作。
gap=gap/2=1,i=6,j=i-gap=5,a[j]=8>a[j+gap]=5,故交换a[j]和a[j+gap],数组a[]= { 0,1,2,3,4,5,8,6,7,9 }。
gap=gap/2=1,i=6,j=j-gap=4,a[j]=4<a[j+gap]=5,此时数组不做任何操作。
gap=gap/2=1,i=7,j=i-gap=6,a[j]=8>a[j+gap]=6,故交换a[j]和a[j+gap],数组a[]= { 0,1,2,3,4,5,6,8,7,9 }。
gap=gap/2=1,i=7,j=j-gap=5,a[j]=5<a[j+gap]=6,此时数组不做任何操作。
gap=gap/2=1,i=8,j=i-gap=7,a[j]=8>a[j+gap]=7,故交换a[j]和a[j+gap],数组a[]= { 0,1,2,3,4,5,6,7,8,9 }。
gap=gap/2=1,i=8,j=j-gap=6,a[j]=6<a[j+gap]=7,此时数组不做任何操作。
gap=gap/2=1,i=9,j=i-gap=8,a[j]=8<a[j+gap]=9,此时数组不做任何操作。
排序完成,输出数组a[]= { 0,1,2,3,4,5,6,7,8,9 }。
#include<iostream>
#include<cstdlib>
using namespace std;
//交换
void swap(int &a, int &b)
{
int temp = a;
a = b;
b = temp;
}
//希尔排序,首先根据增量分组,然后对分组元素进行直接插入排序
void shellSort(int a[], int length)
{
for (int gap = length/2; gap>0; gap/=2)
{
for (int i = gap; i<length;++i)
{
for (int j = i - gap; j >=0 && a[j] > a[j + gap]; j -= gap)
{
swap(a[j], a[j + gap]);
}
}
}
}
int main()
{
int a[] = { 2,1,4,5,3,8,7,9,0,6 };
shellSort(a, 10);
for (int i = 0; i < 10; i++)
{
cout << a[i] << "";
}
cout << endl;
system("pause");
return 0;
}
发现上述代码真的有好多重复的地方,加了一个标志,来改进一下
#include<iostream>
#include<cstdlib>
using namespace std;
void swap(int &a, int &b)
{
int temp = a;
a = b;
b = temp;
}
void shellSort(int a[], int length)
{
for (int gap = length/2; gap>0; gap/=2)
{
for (int i = gap; i<length;++i)
{
bool action = true;
for (int j = i - gap; j >=0 && action; j -= gap)
{
if (a[j] > a[j + gap])
{
swap(a[j], a[j + gap]);
}
else action = false;
}
}
}
}
int main()
{
int a[] = { 65,44,77,5,24,89,72,58,40,69 };
shellSort(a, 10);
for (int i = 0; i < 10; i++)
{
cout << a[i] << " ";
}
cout << endl;
system("pause");
return 0;
}