插入排序的改良----希尔排序(ShellSort)
基本介绍:
希尔排序是直接插入排序的改良算法,所以,时间复杂度肯定优于直接插入排序。其主要思路还是直接插入排序的思想,与之不同的就是,希尔排序将一个待排序的序列进行了分组操作,对每一组分别进行直接插入排序。
算法思想:(假设数组arr的长度为n)
先取一个小于n的整数d1(n/2)作为第一个增量,把数组的全部元素进行分组。所有距离为d1的倍数的元素放在同一个组中。先在各组内进行直接插入排序;然后,取第二个增量d2(d1/2)<d1重复上述的分组和排序,直至所取的增量dt=1( dt <d(t-1)<…<d2<d1),此时,所有的元素放在同一组中进行直接插入排序为止。这就完成了希尔排序的整个过程。
如图所示:
手工过程:
假设某组数据有37个元素,count = 37;
第一轮步长为:18(count/2),需要从下标为0开始到下标17,每一组都进行一次直接插入排序;
若中间某步的步长为s,则下标为0,到下标s-1,且每组进行直接插入排序;
重复此过程,每次步长为前一次步长的1/2(第一次步长为count/2),直到步长为0的时候结束循环。
伪代码: C语言:
#include<stdio.h>
#include<malloc.h>
#include<time.h>
#include<stdlib.h>
typedef unsigned char boolean;
#define TRUE 1
#define FALSE 0
void initData(int *array, int count, int minValue, int maxValue);
void showArray(int *array, int count);
void insertSort(int *array, int count, int startIndex, int step);
void shellSort(int *array, int count);
void shellSort(int *array, int count) {
int step;
int startIndex;
for(step = count/2; step > 0; step/=2) {
for(startIndex = 0; startIndex < step; startIndex++) {
insertSort(array, count, startIndex, step);
}
}
}
void insertSort(int *array, int count, int startIndex, int step) {
int i;
int j;
int tmp = 0;
for(i = startIndex+step; i < count; i+=step) {
int index;
tmp = array[i];
for(index = startIndex; index < i && tmp > array[index]; index+=step);
for(j = i; j > index; j-=step) {
array[j] = array[j-step];
}
array[index] = tmp;
}
}
void showArray(int *array, int count) {
int i;
for(i = 0; i < count; i++) {
printf(i == 0 ? "%d" : ", %d", array[i]);
}
printf("\n");
}
void initData(int *array, int count, int minValue, int maxValue) {
int i = 0;
int value = maxValue - minValue + 1;
srand(time(0));
for(i = 0; i < count; i++) {
array[i] = minValue + rand()%value;
}
}
void main(void) {
int *array;
array = (int *)calloc(sizeof(int), 20);
initData(array, 20, 1, 100);
showArray(array, 20);
shellSort(array, 20);
showArray(array, 20);
}
Java语言:
public class ShellSort {
public static void main(String[] args) {
int[] array = new int[20];
initData(array, 200);
showData(array);
shellSort(array);
showData(array);
}
private static void shellSort(int[] array) {
if(array == null) {
throw new RuntimeException("array is null!");
}
int len = array.length;
if(len == 0) {
throw new RuntimeException("array length is zero!");
}
for(int step = len/2; step > 0; step/=2) {
for(int startIndex = 0; startIndex < step; startIndex++) {
insertSort(array, len, startIndex, step);
}
}
}
private static void insertSort(int[] array, int len, int startIndex, int step) {
int tmp = 0;
for(int i = startIndex+step; i < len; i+=step) {
tmp = array[i];
int index = 0;
for(index = startIndex; index < i && array[index] < tmp; index+=step);
for(int j = i; j > index; j-=step) {
array[j] = array[j-step];
}
array[index] = tmp;
}
}
/**
* 显示数组
* @param array
*/
private static void showData(int[] array) {
for(int i = 0; i < array.length; i++) {
System.out.printf(i == 0 ? "%d" : ", %d", array[i]);
}
System.out.println();
}
/**
* 初始化一个数组,元素随机产生
* @param array 要初始化的数组
* @param maxValue 数组元素的最大值
*/
private static void initData(int[] array, int maxValue) {
for(int i = 0; i < array.length; i++) {
array[i] = (int)(Math.random()*maxValue);
}
}
}
讨论:
1)、时间和空间复杂度的分析:
时间复杂度:平均:O(NlogN),极端情况:O(n^2)
空间复杂度:O(1)
2)、非稳定排序