Gnome排序(地精排序),起初由Hamid Sarbazi-Azad 于2000年提出,并被称为stupid排序,后来被Dick Grune描述并命名为“地精排序”,作为一个排序算法,和插入排序类似,除了移动一个元素到最终的位置,是通过交换一系列的元素实现,就像冒泡排序一样。概念上十分简单,不需要嵌套循环。时间复杂度为O,但是如果初始数列基本有序,时间复杂度将降为O(n)。实际上Gnome算法可以和插入排序算法一样快。平均运行时间为O.
Gnome排序算法总是查找最开始逆序的一对相邻数,并交换位置,基于交换两元素后将引入一个新的相邻逆序对,并没有假定当前位置之后的元素已经有序
下面gnome排序算法的伪代码,使用0起始索引数组:
procedure gnomeSort(a[]) pos := 1 while pos < length(a) if (a[pos] >= a[pos-1]) pos := pos + 1 else swap a[pos] and a[pos-1] if (pos > 1) pos := pos - 1 end if end if end while end procedure
实例
给定一个无序数组, a = [5, 3, 2, 4], gnome排序将在while循环中执行如下的步骤. "current position"采用加粗黑体:
Current array | Action to take |
---|---|
[5, 3, 2, 4] | a[pos] < a[pos-1], swap: |
[3, 5, 2, 4] | a[pos] >= a[pos-1], increment pos: |
[3, 5, 2, 4] | a[pos] < a[pos-1], swap and pos > 1, decrement pos: |
[3, 2, 5, 4] | a[pos] < a[pos-1], swap and pos <= 1, increment pos: |
[2, 3, 5, 4] | a[pos] >= a[pos-1], increment pos: |
[2, 3, 5, 4] | a[pos] < a[pos-1], swap and pos > 1, decrement pos: |
[2, 3, 4, 5] | a[pos] >= a[pos-1], increment pos: |
[2, 3, 4, 5] | a[pos] >= a[pos-1], increment pos: |
[2, 3, 4, 5] | pos == length(a), finished. |
C代码如下:
1 #include<stdio.h> 2 #include<string.h> 3 #include<math.h> 4 #include<ctype.h> 5 #include<stdbool.h> 6 #include<stdlib.h> 7 #include<time.h> 8 9 void swap(int *a, int *b) //交换两元素的值 10 { 11 int t; 12 t=*a; 13 *a=*b; 14 *b=t; 15 } 16 17 void printArray(int a[], int count) //打印数组元素 18 { 19 int i; 20 for(i=0; i<count; i++) 21 printf("%d ",a[i]); 22 printf("\n"); 23 } 24 25 void gnome_sort(int *a, int len) //gnome排序算法 26 { 27 int pos=1; 28 while(pos<len) 29 { 30 if(a[pos]>=a[pos-1]) 31 { 32 pos++; 33 } 34 else 35 { 36 swap(&a[pos],&a[pos-1]); 37 if(pos>1) pos--; 38 } 39 } 40 } 41 42 int main(void) 43 { 44 int a[]={3, 5, 4, 6, 9, 7, 8, 0, 1}; 45 int n=sizeof(a)/sizeof(*a); 46 printArray(a,n); 47 gnome_sort(a,n); 48 printArray(a,n); 49 return 0; 50 }
优化算法
gnome算法还可以通过引入一个变量,用于存储每次返回到数组前面的位置来进行优化。采用这样的优化,gnome排序将成为一个变种插入排序,下面优化后gnome排序算法的伪代码,使用0起始索引数组:
procedure optimizedGnomeSort(a[]) pos := 1 last := 0 while pos < length(a) if (a[pos] >= a[pos-1]) if (last != 0) pos := last last := 0 end if pos := pos + 1 else swap a[pos] and a[pos-1] if (pos > 1) if (last == 0) last := pos end if pos := pos - 1 else pos := pos + 1 end if end if end while end procedure
C代码如下:
#include<stdio.h> #include<string.h> #include<math.h> #include<ctype.h> #include<stdbool.h> #include<stdlib.h> #include<time.h> void swap(int *a, int *b) //交换两元素的值 { int t; t=*a; *a=*b; *b=t; } void printArray(int a[], int count) //打印数组元素 { int i; for(i=0; i<count; i++) printf("%d ",a[i]); printf("\n"); } void optimizedGnome_Sort(int *a, int len) //优化后的gnome排序 { int last,pos; last=0; pos=1; while(pos<len) { if(a[pos]>=a[pos-1]) { if(last!=0) { pos=last; last=0; } pos++; } else { swap(&a[pos],&a[pos-1]); if(pos>1) { if(last==0) last=pos; pos--; } else { pos++; } } } } int main(void) { int a[]={3, 5, 4, 6, 9, 7, 8, 0, 1}; int n=sizeof(a)/sizeof(*a); printArray(a,n); optimizedGnome_Sort(a,n); printArray(a,n); return 0; }