希尔排序(Shell)
- 思想:将数组元素分成若干组,每组分别进行插入排序,使整个数组逐渐变成部分有序数组,再慢慢减少所分的组数,最终合并成一个组 。
- 较于插入排序的优化原理:普通插入排序对少量数据效率高;普通插入排序对越有序的数据效率越高;
- 希尔排序中先分组即是将大数组分成若干小数组,此时进行普通插入排序效率高;
- 在慢慢减少分组时,大量无序数据已逐渐变成部分有序数据,此时就算是大量的数据,进行普通插入排序效率依旧高。
- 优缺点:能够用于大量无序的数据,但是不稳定 。
- 复杂度:平均时间复杂度:O(nlogn)、最好:O(nlogn),最坏:O(n)
不需要额外的辅助空间。 - 稳定性:不稳定
源代码
- 以下是合并在一起的写法
/****************************************
题目:希尔排序 (优化后的插入排序)
- 将数组分成group组元素(在逻辑上进行分组);
- 其中i与i+group为同一组,其他组以此类推;
- 然后每一组都分别进行插入排序;
- 再不断缩小组数,直到组数为0
****************************************/
//参数:
// numbers[]:数组
// length:数组长度
void Shell(int numbers[], int length)
{
//1. 判断传入的参数是否有效
if (numbers == nullptr || length <= 0)
return;
int j = 0;
int temp = 0; //临时变量
int group = length / 2; //第一次分的组数,每组最多两个元素
//2. 组数不为0时循环
while (group >= 1)
{
//3. 以下即为普通插入排序,group用于获取每组的元素
// 外层循环代表每组插入的轮次,每轮的结果都是:将后面的数据插入前面的有序序列中
for (int i = group; i < length; ++i)
{
//4. 暂存有序序列后面的一个元素作为需要插入的元素
// 第一轮时,将下标为0的元素看作有序序列,将下标为0+group的同组元素暂存准备进行插入
temp = numbers[i];
//5. 内层循环完成元素的移动(当数列有序时,内层循环只运行一次就break了,总的时间复杂度就会变成O(n))
for (j = i - group; j >= 0; j -= group)
{
//6. 如果要插入的元素大于或等于有序序列中的某一个元素,说明要插入的元素的位置就在这个元素后面
if (numbers[j] <= temp)
break;
//7. 未找到插入位置则将元素依次往后移动
numbers[j + group] = numbers[j];
}
//8. 将要插入的元素放在找到的位置
numbers[j + group] = temp;
}
//9. 将组数减半继续插入排序
group = group / 2;
}
}
//简单测试
int main()
{
const int length = 7;
int numbers[length] = { 3, 2, 7, 11, 9, 4, 2 };
Shell(numbers, length);
for (int i = 0; i < length; i++)
cout << numbers[i] << " ";
cout << endl;
return 0;
}
- 以下是分成两个函数的写法,详细注释我就不写了,一样理解就行
void InsertSort_s(int[], int, int); //插入排序函数的声明
//希尔排序
void Shell(int numbers[], int length)
{
//1. 判断传入的参数是否有效
if (numbers == nullptr || length <= 0)
return;
int group = length / 2; //第一次分的组数,每组最多两个元素
//2. 组数不为0时循环
while (group >= 1)
{
//3. 以下即为普通插入排序,group用于获取每组的元素
InsertSort_s(numbers, length, group);
//4. 将组数减半继续插入排序
group = group / 2;
}
}
//配套的插入排序
//注:当group = 1时,即为普通的插入排序,可以直接调用
void InsertSort_s(int numbers[], int length, int group)
{
int j;
int temp; //临时变量
for (int i = group; i < length; ++i)
{
temp = numbers[i];
for (j = i - group; j >= 0; j -= group)
{
if (numbers[j] <= temp)
break;
numbers[j + group] = numbers[j];
}
numbers[j + group] = temp;
}
}
//简单测试
int main()
{
const int length = 12;
int numbers[length] = { 3, 2, 7, 11, 9, 4, 2, 10, 14, 19, 15, 21 };
Shell(numbers, length);
for (int i = 0; i < length; i++)
cout << numbers[i] << " ";
cout << endl;
return 0;
}
仍有不足,欢迎交流。