代碼
#include <stdio.h>
#include <stdlib.h>
int initialStep(int size);
void sort(int array[], int from, int end);
void insertSort(int array[], int groupIndex, int step, int end);
void move(int array[], int startIndex, int endIndex, int step);
void PrintArray(const char* strMsg,int array[],int nLength);
int main(int argc, char *argv[])
{
int data[13]={8,5,4,6,13,7,1,9,12,11,3,10,2};
sort(data,0,12);
PrintArray("Shell Sort:",data,13);
system("PAUSE");
return 0;
}
/**
* 根據數組長度求初始步長
*
* 我們選擇步長的公式為:2^k-1,2^(k-1)-1,...,15,7,3,1 ,其中2^k 減一即為該步長序列,k
* 為排序輪次
*
* 初始步長:step = 2^k-1
* 初始步長約束條件:step < len - 1 初始步長的值要小於數組長度還要減一的值(因
* 為第一輪分組時盡量不要分為一組,除非數組本身的長度就小於等於4)
*
* 由上面兩個關係試可以得知:2^k - 1 < len - 1 關係式,其中k為輪次,如果把 2^k 表 達式
* 轉換成 step 運算式,則 2^k-1 可使用 (step + 1)*2-1 替換(因為 step+1 相當於第k-1
* 輪的步長,所以在 step+1 基礎上乘以 2 就相當於 2^k 了),即步長與數組長度的關係不等式為
* (step + 1)*2 - 1 < len -1
*
* @param len 數組長度
* @return
*/
int initialStep(int size) {
/*
* 初始值設定為步長公式中的最小步長,從最小步長推匯出最長初始步長值,即按照以下公式來推:
* 1,3,7,15,...,2^(k-1)-1,2^k-1
* 如果數組長度小於等於4時,步長為1,即長度小於等於4的數組不且分組,此時直接退化為直接插
* 入排序
*/
int step = 1;
//試探下一個步長是否滿足條件,如果滿足條件,則步長置為下一步長
while ((step + 1) * 2 - 1 < size - 1)
{
step = (step + 1) * 2 - 1;
}
printf("初始步長 - %d\n",step);
return step;
}
/**
* 排序演算法的實現,對數組中指定的元素進行排序
* @param array 待排序的數組
* @param from 從哪裡開始排序
* @param end 排到哪裡
* @param c 比較子
*/
void sort(int array[], int from, int end) {
int groupIndex;
//初始步長,實質為每輪的分組數
int step = initialStep(end - from + 1);
//第一層迴圈是對排序輪次進行迴圈。(step + 1) / 2 - 1 為下一輪步長值
for (; step >= 1; step = (step + 1) / 2 - 1) {
//對每輪裡的每個分組進行迴圈
for (groupIndex = 0; groupIndex < step; groupIndex++) {
//對每組進行直接插入排序
insertSort(array, groupIndex, step, end);
}
}
}
/**
* 直接插入排序實現
* @param array 待排序數組
* @param groupIndex 對每輪的哪一組進行排序
* @param step 步長
* @param end 整個數組要排哪個元素止
* @param c 比較子
*/
void insertSort(int array[], int groupIndex, int step, int end) {
int i,j;
int startIndex = groupIndex;//從哪裡開始排序
int endIndex = startIndex; //排到哪裡
/*
* 排到哪裡需要計算得到,從開始排序元素開始,以step步長,可求得下一元素是否在數組範圍內,
* 如果在數組範圍內,則繼續迴圈,直到索引超現數組範圍
*/
while ((endIndex + step) <= end) {
endIndex += step;
}
// i為每小組裡的第二個元素開始
for (i = groupIndex + step; i <= end; i += step) {
for (j = groupIndex; j < i; j += step) {
int insertedElem = array[i];
//從有序數組中最一個元素開始尋找第一個大於待插入的元素
if (array[j]>= insertedElem) {
//找到插入點後,從插入點開始向後所有元素後移一位
move(array, j, i - step, step);
array[j] = insertedElem;
break;
}
}
}
}
/**
* 以指定的步長將數組元素後移,步長指定每個元素間的間隔
* @param array 待排序數組
* @param startIndex 從哪裡開始移
* @param endIndex 到哪個元素止
* @param step 步長
*/
void move(int array[], int startIndex, int endIndex, int step) {
int i;
for (i = endIndex; i >= startIndex; i -= step) {
array[i + step] = array[i];
}
}
void PrintArray(const char* strMsg,int array[],int nLength)
{
int i;
printf("%s",strMsg);
for(i=0;i<nLength;i++)
{
printf("%d ",array[i]);
}
printf("\n");
}
以上代碼主要修改自:http://www.javaeye.com/topic/547734
http://www.javaeye.com/topic/547735
其它參考資料:
http://www.cnblogs.com/ziyifly/archive/2008/09/10/1288499.html
http://www.java2000.net/p11750
http://mintelong.javaeye.com/blog/467833
http://student.zjzk.cn/course_ware/data_structure/web/paixu/paixu8.2.2.1.htm
http://www.cnblogs.com/hualei/archive/2010/08/17/1801850.html