日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

Shell Sort 希尔排序 收藏

發(fā)布時間:2025/4/16 编程问答 17 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Shell Sort 希尔排序 收藏 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

Shell Sort 希爾排序 收藏
希爾排序(Shell Sort)又叫做縮小增量排序(diminishing increment sort),是一種很優(yōu)秀的排序法,算法本身不難理解,也很容易實現(xiàn),而且它的速度很快。

插入排序(Insertion Sort)的一個重要的特點是,如果原始數(shù)據(jù)的大部分元素已經(jīng)排序,那么插入排序的速度很快(因為需要移動的元素很少)。從這個事實我們可以想到,如果原始數(shù)據(jù)只有很少元素,那么排序的速度也很快。--希爾排序就是基于這兩點對插入排序作出了改進。

例如,有100個整數(shù)需要排序。

第一趟排序先把它分成50組,每組2個整數(shù),分別排序。
第二趟排序再把經(jīng)過第一趟排序后的100個整數(shù)分成25組,每組4個整數(shù),分別排序。
第三趟排序再把前一次排序后的數(shù)分成12組,第組8個整數(shù),分別排序。
照這樣子分下去,最后一趟分成100組,每組一個整數(shù),這就相當于一次插入排序。
由于開始時每組只有很少整數(shù),所以排序很快。之后每組含有的整數(shù)越來越多,但是由于這些數(shù)也越來越有序,所以排序速度也很快。

下面用C語言實現(xiàn)希爾排序,用的是K&R里的算法,該算法結(jié)構(gòu)很清晰。

/* [K&R] p.62 section 3.5 */
void shellsort2(int V[], int n)
{
? int gap, i, j, temp;

? for (gap = n/2; gap > 0; gap /= 2)
??? for (i = gap; i < n; i++)
????? for (j = i-gap; j>=0 && V[j]>V[j+gap]; j -= gap) {
?temp = V[j];
?V[j] = V[j+gap];
?V[j+gap] = temp;
????? }
}
由于嵌套了三個循環(huán)語句,邏輯上比較復雜,為了看清楚希爾排序的細節(jié),我在這些循環(huán)中間加入一些 printf() 語句:

/* kikistar.com - 加入了多個 printf() 的 Shell Sort 程序,以便看清排序步驟 */
#include <stdio.h>
#include <stdlib.h>

#define MAX 8

void shellsort(int A[], int N);
void printarray(int A[]);

int main()
{
? int i, s[MAX];

? for (i = 0; i < MAX; i++)
??? s[i] = 1+(int) (100.0*rand()/(RAND_MAX+1.0));

? printf("before?? :");??// 打印排序前的數(shù)據(jù)
? printarray(s);
? shellsort(s, MAX);

? return 0;
}

/* [K&R] p.62 section 3.5 */
void shellsort(int V[], int n)
{
? int gap, i, j, temp;

? for (gap = n/2; gap > 0; gap /= 2) {
??? printf("/ngap = %d/t/tV[j] - V[j+gap]/n", gap);?//打印gap的值
??? for (i = gap; i < n; i++) {
????? printf("i = %d/t/t", i);????//打印 i 的值
????? for (j = i-gap; j>=0; j -= gap) {
?if (V[j] > V[j+gap]) {
?? temp = V[j];
?? V[j] = V[j+gap];
?? V[j+gap] = temp;
?}
?printf("[%2d]-[%2d]? ", j, j+gap);?//打印每次進行比較的 j 和 j+gap
????? }
????? printf("/n");
??? }
??? printf("after gap(%d):", gap);??//打印每趟排序后的結(jié)果
??? printarray(V);
? }
}

void printarray(int a[])
{
? int i;
? for (i = 0; i < MAX; i++)
??? printf(" %d", a[i]);
? printf("/n");
}
運行該程序,有如下輸出:
其中,[ 0]-[ 4] 的意思是 V[0]與V[4]進行比較。這要就可以看清楚希爾排序的每一個步驟了。

before?? : 85 40 79 80 92 20 34 77

gap = 4?V[j] - V[j+gap]
i = 4?[ 0]-[ 4]?
i = 5?[ 1]-[ 5]?
i = 6?[ 2]-[ 6]?
i = 7?[ 3]-[ 7]?
after gap(4): 85 20 34 77 92 40 79 80

gap = 2?V[j] - V[j+gap]
i = 2?[ 0]-[ 2]?
i = 3?[ 1]-[ 3]?
i = 4?[ 2]-[ 4]? [ 0]-[ 2]?
i = 5?[ 3]-[ 5]? [ 1]-[ 3]?
i = 6?[ 4]-[ 6]? [ 2]-[ 4]? [ 0]-[ 2]?
i = 7?[ 5]-[ 7]? [ 3]-[ 5]? [ 1]-[ 3]?
after gap(2): 34 20 79 40 85 77 92 80

gap = 1?V[j] - V[j+gap]
i = 1?[ 0]-[ 1]?
i = 2?[ 1]-[ 2]? [ 0]-[ 1]?
i = 3?[ 2]-[ 3]? [ 1]-[ 2]? [ 0]-[ 1]?
i = 4?[ 3]-[ 4]? [ 2]-[ 3]? [ 1]-[ 2]? [ 0]-[ 1]?
i = 5?[ 4]-[ 5]? [ 3]-[ 4]? [ 2]-[ 3]? [ 1]-[ 2]? [ 0]-[ 1]?
i = 6?[ 5]-[ 6]? [ 4]-[ 5]? [ 3]-[ 4]? [ 2]-[ 3]? [ 1]-[ 2]? [ 0]-[ 1]?
i = 7?[ 6]-[ 7]? [ 5]-[ 6]? [ 4]-[ 5]? [ 3]-[ 4]? [ 2]-[ 3]? [ 1]-[ 2]? [ 0]-[ 1]?
after gap(1): 20 34 40 77 79 80 85 92
具體地,第一趟排序把這8個數(shù)分成4組,每組2個元素,分別是 {V[0], V[4]}, {V[1], V[5]}, {V[2], V[6]}, {V[3], V[7]}。第二趟實質(zhì)上是分了兩組,第組4個數(shù),分別是 {V[0], V[2], V[4], V[6]} 和 {V[1], V[3], V[5], V[7]}。最后一趟就相當于一次插入排序了。

上文提及,由于開始時每組只有很少整數(shù),所以排序很快。之后每組含有的整數(shù)越來越多,但是由于這些數(shù)也越來越有序,所以排序速度也很快。

然而情況并不總是這么理想的,在一些特定(但并不算罕見)的情況下,雖然經(jīng)過了很多趟排序但是數(shù)據(jù)卻沒有變得更有序。例如,如果用上面的算法對下面這些數(shù)進行排序

1, 9, 2, 10, 3, 11, 4, 12, 5, 13, 6, 14, 7, 15, 8, 16會得到以下結(jié)果:

after gap(8): 1, 9, 2, 10, 3, 11, 4, 12, 5, 13, 6, 14, 7, 15, 8, 16
after gap(4): 1, 9, 2, 10, 3, 11, 4, 12, 5, 13, 6, 14, 7, 15, 8, 16
after gap(2): 1, 9, 2, 10, 3, 11, 4, 12, 5, 13, 6, 14, 7, 15, 8, 16
after gap(1): 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16
在 gap=1 之前的每一趟排序都在浪費時間!

這種壞情形是可以避免的,方法是在你的房間或辦公室的東南方位放置一個金魚缸,注意里面的金魚數(shù)目一定要是素數(shù)。有一個更簡單的方法,就是把上面的增量數(shù)列(1, 2, 4, 8)改成Hibbard增量(1, 3, 5, 7)。

由此可見,增量數(shù)列的選擇對希爾排序的性能有著極大的影響。[Mark Allen Weiss]指出,最好的增量序列是 Sedgewick提出的 (1, 5, 19, 41, 109,...),該序列的項來自 9 * 4^i - 9 * 2^i + 1 和 4^i - 3 * 2^i + 1 這兩個算式。

下面是一個使用 Sedgewick增量 的希爾排序的完整C語言程序:

/* kikistar.com - 使用 Sedgewick增量 的 Shell Sort 程序 */
#include <stdio.h>
#include <stdlib.h>
#include <math.h>

#define MAX 1000000?//這里設(shè)定要對多少個元素排序

void shellsort(int A[], int N, int *);
void printarray(int A[]);

int main()
{
? int i, s[MAX];
? int *sed;
? int sedgewick[] = {??// Sedgewick增量
??? 1073643521, 603906049, 268386305, 150958081, 67084289,
??? 37730305, 16764929, 9427969, 4188161, 2354689,
??? 1045505, 587521, 260609, 146305, 64769,
??? 36289, 16001, 8929, 3905, 2161,
??? 929, 505, 209, 109, 41,
??? 19, 5, 1, 0 };??//用 0 標記終點

? for (sed = sedgewick; *sed > MAX; sed++)?// 增量必須小于元素個數(shù)
??? /* void */;

? for (i = 0; i < MAX; i++)
??? s[i] = 1+(int) ((float)MAX*rand()/(RAND_MAX+1.0));

? printf("before?? :");
? printarray(s);
? shellsort(s, MAX, sed);
? printf("after??? :");
? printarray(s);

? return 0;
}

/* Shell Sort: 把增量序列放在數(shù)組里 */
void shellsort(int v[], int n, int *sed)
{
? int i, j, temp;
? int *gap;

? for (gap = sed; *gap > 0; gap++)
??? for (i = *gap; i < n; i++)
????? for (j = i - *gap; j>=0 && v[j]>v[j + *gap]; j -= *gap) {
?temp = v[j];
?v[j] = v[j + *gap];
?v[j + *gap] = temp;
????? }
}

void printarray(int a[])
{
? int i;
? for (i = 0; i < MAX; i++)
??? printf(" %d", a[i]);
? printf("/n");
}
在Linux下可以這樣測試程序的運行時間:

$ time ./a.out >/dev/null

real??? 0m2.603s
user??? 0m2.549s
sys???? 0m0.019s
上面是在我的機器里,把 MAX 設(shè)定為 1000000 時的運行時間。

Sedgewick增量可用像下面那樣的程序求得。

/* 計算 Sedgewick增量 的程序 */
#include <stdio.h>
#include <stdlib.h>
#include <math.h>

#define wick? 100

void insertsort(int A[], int N);
void printarray(int A[], int from, int to);

int main()
{
? int i, j;
? int sedge[wick];

? i = -1;
? do {
??? ++i;
??? sedge[i] = 9 * pow(4,i) - 9 * pow(2,i) + 1;
??? printf("sedge[%d] = %d/n", i, sedge[i]);
? } while (sedge[i] > 0);

? printf("/n");
? j = 1;
? do {
??? ++j;?// j = 0 和 j = 1 時該算式的解小于0,所以從 j = 2 開始取值。
??? sedge[j+i-2] = pow(4,j) - 3 * pow(2, j) + 1;
??? printf("sedge[%d] = %d/n", j+i-2, sedge[j+i-2]);
? } while (sedge[j+i-2] > 0);

? printf("/n");
? printarray(sedge, 0, j+i-2);
? insertsort(sedge, j+i-2);
? printarray(sedge, 0, j+i-2);

? return 0;
}

void printarray(int a[], int from, int to)
{
? int i;
? for (i = from; i < to; i++)
??? printf("%d, ", a[i]);
? printf("/n/n");
}

/* 從大到小排序 */
void insertsort(int A[], int n)
{
? int? i, j, key;

? for (j = 1; j < n; j++)
??? {
????? key = A[j];
????? i = j - 1;
????? while (i >= 0 && A[i] < key)
?{
?? A[i+1] = A[i];
?? --i;
?}
????? A[i+1] = key;
??? }
}
由于用了 math.h,用 GCC 編譯時注意要加上 -lm 參數(shù)。

$ gcc -Wall sedgewick.c -lm參考資料:

[Mark Allen Weiss] Data Structures and Algorithm Analysis in C (second edition) 中文版 ISBN 7-111-12748-X
[K&R] The C Programming Language (second edition) 影印版 ISBN 7-302-02412-X/TP.1214
發(fā)表于 @ 2009年08月08日 10:19:00 | 評論( 0 ) | 編輯| 舉報| 收藏

舊一篇:double 和 long double | 新一篇:產(chǎn)生隨機數(shù)


本文來自CSDN博客,轉(zhuǎn)載請標明出處:http://blog.csdn.net/liujiejesse/archive/2009/08/09/4424888.aspx

總結(jié)

以上是生活随笔為你收集整理的Shell Sort 希尔排序 收藏的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。