选择排序(selection sorts)算法大串讲

来源:互联网 发布:mac win7安装盘制作 编辑:程序博客网 时间:2024/05/16 10:29

文章出自:http://dsqiu.iteye.com/blog/1706817

选择排序(selection sorts)算法大串讲

本文内容框架:

§1 选择排序

§2 锦标赛排序

 §3 堆排序

§4 Smooth Sort

§5 小结

 

 

 

§1 选择排序

选择排序(Selection sort)

 

选择排序(Selection sort)是一种简单直观的排序算法。它的工作原理如下。首先在未排序序列中找到最小(大)元素,存放到排序序列的起始位置,然后,再从剩余未排序元素中继续寻找最小(大)元素,然后放到已排序序列的末尾。以此类推,直到所有元素均排序完毕。下图能够帮助很直观的理解出选择排序算法的思想:

 

 

选择排序动画演示

 

C代码  收藏代码
  1. void select_sort( int *a, int n)  
  2. {  
  3.     register int i, j, min, t;  
  4.     for( i = 0; i < n - 1; i ++)  
  5.     {  
  6.         min = i;  
  7.         //查找最小值  
  8.         for( j = i + 1; j < n; j ++)  
  9.             if( a[ min] > a[ j])  
  10.                 min = j;  
  11.         //交换  
  12.         if( min != i)  
  13.         {  
  14.             t = a[ min];  
  15.             a[ min] = a[ i];  
  16.             a[ i] = t;  
  17.         }  
  18.     }  
  19. }  

选择排序的交换操作介于和次之间。选择排序的比较操作为次之间。选择排序的赋值操作介于和次之间。比较次数O(n^2),比较次数与关键字的初始状态无关,总的比较次数N=(n-1)+(n-2)+...+1=n*(n-1)/2。 交换次数O(n),最好情况是,已经有序,交换0次;最坏情况是,逆序,交换n-1次。 交换次数比冒泡排序少多了,由于交换所需CPU时间比比较所需的CPU时间多,n值较小时,选择排序比冒泡排序快。

 

 

简单选择排序算法改进

传统的简单选择排序,每趟循环只能确定一个元素排序后的定位。我们可以考虑改进为每趟循环确定两个元素(当前趟最大和最小记录)的位置,从而减少排序所需的循环次数。改进后对n个数据进行排序,最多只需进行[n/2]趟循环即可。

 

 

 

 

§2 锦标赛排序

 

 

锦标赛排序(tournament iree sort)

 

直接选择排序要执行n-1趟(i=0,1,…,n-2),第i越要从n-i个对象中选出一个具有最小排序码的对象,需要进行n-i-1次排序码比较。当n比较大时,排序码比较次数相当多。这是因为在后一趟比较选择时,往往把前一趟已做过的比较又重复做了 一遍,没有把前一趟比较的结果保留下来。

  锦标赛排序(tournament iree sort)克服了这一缺点。它的思想与体育比赛类似。首先取得n个对象的排序码,进行两两比较,得到[n/2]个比较的优胜者(排序码小者),作 为第一步比较的结果保留下来。然后对这[n/2]个对象再进行排序码的两两比较,……, 如此重复,直到选出一个排序码最小的对象为止。

 

C代码  收藏代码
  1. #include <stdio.h>   
  2. #include <stdlib.h>   
  3. int _;   
  4. #define swap(x, y) { _=x;x=y;y=_; }   
  5. //#define max(x, y) ( ((x)>(y))?(x):(y) )   
  6. //#define min(x, y) ( ((x)<(y))?(x):(y) )   
  7. #define MAX (int)(((unsigned)(~((int)0)))>>1)   
  8. #define MIN (-MAX-1)   
  9.    
  10. void Adjust(int *b, int x, int n)   
  11. {   
  12.        int l = x * 2 + 1;   
  13.        int r = l + 1;   
  14.    
  15.        //printf("%d\n", MAX);   
  16.        if (l >= n) {   
  17.               b[x] = MAX;   
  18.               return;   
  19.        }   
  20.        else if (r >= n) {   
  21.               b[x] = b[l];   
  22.               return;   
  23.        }   
  24.    
  25.        if (b[l] == b[x]) {   
  26.               Adjust(b, l, n);   
  27.        }   
  28.        else {   
  29.               Adjust(b, r, n);   
  30.        }   
  31.        b[x] = min(b[l], b[r]);   
  32. }   
  33.    
  34. void GameSort(int *a, int n)   
  35. {   
  36.        int i, len, *b;   
  37.        void Out(int *, int);   
  38.    
  39.        len = 1;   
  40.        while (len < n) {   
  41.               len <<= 1;   
  42.        }   
  43.        len = 2 * len - 1;   
  44.        b = (int *)malloc(sizeof(int) * len);   
  45.    
  46.        for (i=len/2; i<len; i++) {   
  47.               b[i] = (i-len/2<n) ? (a[i-len/2]) : (MAX);   
  48.        }   
  49.    
  50.        for (i=len/2-1; i>=0; i--) {   
  51.               b[i] = min(b[2 * i + 1], b[2 * i + 2]);   
  52.        }   
  53.        for (i=0; i<n; i++) {   
  54.               a[i] = b[0];   
  55.               Out(b, len); //不断跟踪输出完全二叉树b[]状态   
  56.               Adjust(b, 0, len);   
  57.        }   
  58.    
  59.        free(b);   
  60. }   
  61.    
  62. int main()   
  63. {   
  64.        int a[] = { 21, 25, 49, 25, 16, 8, 63, 63, 100, 1002 };   
  65.        int i, n = 9;   
  66.    
  67.        for (i=0; i<n; i++) {   
  68.               printf("%5d", a[i]);   
  69.        }   
  70.        printf("\n");   
  71.    
  72.        GameSort(a, n);   
  73.        for (i=0; i<n; i++) {   
  74.               printf("%5d", a[i]);   
  75.        }   
  76.        printf("\n");   
  77.    
  78.        return 0;   
  79. }   
  80.    
  81. // ---- 输出部分, 与程序算法无关 ----   
  82. // ---- 为了打出那个树状, 好看 ----   
  83.    
  84. #include <math.h>   
  85.    
  86. void Out(int *a, int n)   
  87. {   
  88.        void _Out(int *, int);   
  89.    
  90.        //printf("%d===\n", n / 2 + 1);   
  91.        _Out(a + (n / 2), n / 2 + 1);   
  92. }   
  93.    
  94. void _Out(int *a, int n)   
  95. {   
  96.        static int i, j, set = 0;   
  97.        int len = log((double)n) / log((double)2) + 1;   
  98.        int l, r, have;   
  99.    
  100.        int **b = (int **)malloc(sizeof(int *) * len);   
  101.        for (i=0; i<len; i++) {   
  102.               b[i] = (int *)malloc(sizeof(int) * n);   
  103.               for (j=0; j<n; j++) {   
  104.                      b[i][j] = MIN;   
  105.               }   
  106.        }   
  107.    
  108.        //printf("%d\n", MIN);   
  109.        for (i=0; i<n; i++) {   
  110.               b[len - 1][i] = a[i];   
  111.        }   
  112.        for (i=len-1; i>=1; i--) {   
  113.               have = 0;   
  114.               for (j=0; j<n; j++) {   
  115.                      if (b[i][j] != MIN) {   
  116.                             (++have==1)?(l=j):(r=j);   
  117.                      }   
  118.                      if (have == 2) {   
  119.                             b[i-1][(l+r)/2] = min(b[i][l], b[i][r]);   
  120.                             have = 0;   
  121.                      }   
  122.               }   
  123.        }   
  124.    
  125.        printf("\n ---- Set %d ----\n", set++);   
  126.        for (i=0; i<len; i++) {   
  127.               for (j=0; j<n; j++) {   
  128.                      if (b[i][j] == MIN) {   
  129.                             printf("    ");   
  130.                      }   
  131.                      else if (b[i][j] == MAX) {   
  132.                             printf(" MAX");   
  133.                      }   
  134.                      else {   
  135.                             printf("  %02d", b[i][j]);   
  136.                      }   
  137.               }   
  138.               printf("\n");   
  139.        }   
  140. }  

 

 

 

§3 堆排序

 

堆排序(heap sort)

锦标赛算法有两个缺点:辅助存储空间较多、最大值进行多余的比较。堆排序就是在锦标赛排序的基础上改进——只需要O(1)的辅助存储空间,减少最大值的比较。

堆排序算法的演示。首先,将元素进行重排,以符合堆的条件。图中排序过程之前简单的绘出了堆树的结构。

 

二叉堆是完全二叉树或者是近似完全二叉树。

二叉堆满足二个特性:

1.父结点的键值总是大于或等于(小于或等于)任何一个子节点的键值。

2.每个结点的左子树和右子树都是一个二叉堆(都是最大堆或最小堆)。

当父结点的键值总是大于或等于任何一个子节点的键值时为最大堆。当父结点的键值总是小于或等于任何一个子节点的键值时为最小堆。下图展示一个最小堆:

 

堆的存储

一般都用数组来表示堆,i结点的父结点下标就为(i – 1) / 2。它的左右子结点下标分别为2 * i + 1和2 * i + 2。如第0个结点左右子结点下标分别为1和2。

 

在堆的数据结构中,堆中的最大值总是位于根节点。堆中定义以下几种操作:

最大堆调整(Max_Heapify):将堆的末端子结点作调整,使得子结点永远小于父结点

创建最大堆(Build_Max_Heap):将堆所有数据重新排序

堆排序(HeapSort):移除位在第一个数据的根结点,并做最大堆调整的递归运算

 

 

Cpp代码  收藏代码
  1. #include <cstdio>  
  2. #include <cstdlib>  
  3. #include <cmath>  
  4.    
  5. const int HEAP_SIZE = 13; //堆大小  
  6.    
  7. int parent(int);  
  8. int left(int);  
  9. int right(int);  
  10. void Max_Heapify(int [], intint);  
  11. void Build_Max_Heap(int []);  
  12. void print(int []);  
  13. void HeapSort(int [], int);  
  14.    
  15. /*父结点*/  
  16. int parent(int i)  
  17. {  
  18.     return (int)floor((i - 1) / 2);  
  19. }  
  20.    
  21. /*左子结点*/  
  22. int left(int i)  
  23. {  
  24.     return (2 * i + 1);  
  25. }  
  26.    
  27. /*右子结点*/  
  28. int right(int i)  
  29. {  
  30.     return (2 * i + 2);  
  31. }  
  32.    
  33. /*从单一子结点创建最大堆*/  
  34. void Max_Heapify(int A[], int i, int heap_size)  
  35. {  
  36.     int l = left(i);  
  37.     int r = right(i);  
  38.     int largest;  
  39.     int temp;  
  40.     if(l < heap_size && A[l] > A[i])  
  41.     {  
  42.         largest = l;  
  43.     }  
  44.     else  
  45.     {  
  46.         largest = i;  
  47.     }  
  48.     if(r < heap_size && A[r] > A[largest])  
  49.     {  
  50.         largest = r;  
  51.     }  
  52.     if(largest != i)  
  53.     {  
  54.         temp = A[i];  
  55.         A[i] = A[largest];  
  56.         A[largest] = temp;  
  57.         Max_Heapify(A, largest, heap_size);  
  58.     }  
  59. }  
  60.    
  61. /*建立最大堆*/  
  62. void Build_Max_Heap(int A[])  
  63. {  
  64.     for(int i = (HEAP_SIZE-1)/2; i >= 0; i--)  
  65.     {  
  66.         Max_Heapify(A, i, HEAP_SIZE);  
  67.     }  
  68. }  
  69.    
  70. /*输出最大堆*/  
  71. void print(int A[])  
  72. {  
  73.     for(int i = 0; i < HEAP_SIZE;i++)  
  74.     {  
  75.         printf("%d ", A[i]);  
  76.     }  
  77.     printf("\n");  
  78. }  
  79.    
  80. /*利用堆进行排序*/  
  81. void HeapSort(int A[], int heap_size)  
  82. {  
  83.     Build_Max_Heap(A);  
  84.     int temp;  
  85.     for(int i = heap_size - 1; i >= 0; i--)  
  86.     {  
  87.         temp = A[0];  
  88.         A[0] = A[i];  
  89.         A[i] = temp;  
  90.         Max_Heapify(A, 0, i);  
  91.     }  
  92.     print(A);  
  93. }  
  94.    
  95. /*测试*/  
  96. int main(int argc, char* argv[])  
  97. {  
  98.     int A[HEAP_SIZE] = {19, 1, 10, 14, 16, 4, 7, 9, 3, 2, 8, 5, 11};  
  99.     HeapSort(A, HEAP_SIZE);  
  100.     system("pause");  
  101.     return 0;  
  102. }  

 

堆的操作

堆的操作主要是插入和删除,插入总是将插入元素放在堆的末尾,然后进行恢复堆次序处理;删除操作是将要删除元素和最后一个元素替换,然后进行恢复堆次序处理。其实归根结底也是堆的调整操作,只是多了对堆大小(元素个数)的修改)。

 

 

§4 Smooth Sort 

Smooth Sort算法

 

Smooth Sort基本思想和Heap Sort相同,但Smooth Sort使用的是一种由多个堆组成的优先队列,这种优先队列在取出最大元素后剩余元素可以就地调整成优先队列,所以Smooth Sort不用像Heap Sort那样反向地构建堆,在数据基本有序时可以达到O(n)复杂度。Smooth Sort算法在维基百科上有详细介绍。

    Smooth Sort是所有算法中时间复杂度理论值最好的,但由于Smooth Sort所用的优先队列是基于一种不平衡的结构,复杂度因子很大,所以该算法的实际效率并不是很好。

 

 

Cpp代码  收藏代码
  1. #include <cstdio>  
  2.  #include <cstdlib>  
  3.  #include <ctime>  
  4.    
  5.  static unsigned int set_times = 0;  
  6.  static unsigned int cmp_times = 0;  
  7.    
  8.  template<typename item_type> void setval(item_type& item1, item_type& item2) {  
  9.      set_times += 1;  
  10.      item1 = item2;  
  11.      return;  
  12.  }  
  13.    
  14.  template<typename item_type> int compare(item_type& item1, item_type& item2) {  
  15.      cmp_times += 1;  
  16.      return item1 < item2;  
  17.  }  
  18.    
  19.  template<typename item_type> void swap(item_type& item1, item_type& item2) {  
  20.      item_type item3;  
  21.    
  22.      setval(item3, item1);  
  23.      setval(item1, item2);  
  24.      setval(item2, item3);  
  25.      return;  
  26.  }  
  27.    
  28.  static const unsigned int leonardo[] = {  
  29.      1, 1, 3, 5, 9, 15, 25, 41, 67, 109, 177, 287, 465, 753, 1219, 1973,  
  30.      3193, 5167, 8361, 13529, 21891, 35421, 57313, 92735, 150049, 242785,  
  31.      392835, 635621, 1028457, 1664079, 2692537, 4356617, 7049155, 11405773,  
  32.      18454929, 29860703, 48315633, 78176337, 126491971, 204668309, 331160281,  
  33.      535828591, 866988873, 1402817465, 2269806339u, 3672623805u,  
  34.  };  
  35.    
  36.  template<typename item_type> inline void smooth_sort_fix(  
  37.          item_type* array, int current_heap, int level_index, int* levels) {  
  38.      int prev_heap;  
  39.      int max_child;  
  40.      int child_heap1;  
  41.      int child_heap2;  
  42.      int current_level;  
  43.    
  44.      while(level_index > 0) {  
  45.          prev_heap = current_heap - leonardo[levels[level_index]];  
  46.          if(compare(array[current_heap], array[prev_heap])) {  
  47.              if(levels[level_index] > 1) {  
  48.                  child_heap1 = current_heap - 1 - leonardo[levels[level_index] - 2];  
  49.                  child_heap2 = current_heap - 1;  
  50.                  if(compare(array[prev_heap], array[child_heap1])) break;  
  51.                  if(compare(array[prev_heap], array[child_heap2])) break;  
  52.              }  
  53.              swap(array[current_heap], array[prev_heap]);  
  54.              current_heap = prev_heap;  
  55.              level_index -= 1;  
  56.          } else break;  
  57.      }  
  58.    
  59.      current_level = levels[level_index];  
  60.      while(current_level > 1) {  
  61.          max_child = current_heap;  
  62.          child_heap1 = current_heap - 1 - leonardo[current_level - 2];  
  63.          child_heap2 = current_heap - 1;  
  64.    
  65.          if(compare(array[max_child], array[child_heap1])) max_child = child_heap1;  
  66.          if(compare(array[max_child], array[child_heap2])) max_child = child_heap2;  
  67.          if(max_child == child_heap1) {  
  68.              swap(array[current_heap], array[child_heap1]);  
  69.              current_heap = child_heap1;  
  70.              current_level -= 1;  
  71.          }  
  72.          else if(max_child == child_heap2) {  
  73.              swap(array[current_heap], array[child_heap2]);  
  74.              current_heap = child_heap2;  
  75.              current_level -= 2;  
  76.          } else break;  
  77.      }  
  78.      return;  
  79.  }  
  80.    
  81.  template<typename item_type> void smooth_sort(item_type* array, int size) {  
  82.    
  83.      int levels[64] = {1};  
  84.      int toplevel = 0;  
  85.      int i;  
  86.    
  87.      for(i = 1; i < size; i++) {  
  88.          if(toplevel > 0 && levels[toplevel - 1] - levels[toplevel] == 1) {  
  89.              toplevel -= 1;  
  90.              levels[toplevel] += 1;  
  91.          } else if(levels[toplevel] != 1) {  
  92.              toplevel += 1;  
  93.              levels[toplevel] = 1;  
  94.          } else {  
  95.              toplevel += 1;  
  96.              levels[toplevel] = 0;  
  97.          }  
  98.          smooth_sort_fix(array, i, toplevel, levels);  
  99.      }  
  100.    
  101.      for(i = size - 2; i > 0; i--) {  
  102.          if(levels[toplevel] <= 1) {  
  103.              toplevel -= 1;  
  104.          } else {  
  105.              levels[toplevel] -= 1;  
  106.              levels[toplevel + 1] = levels[toplevel] - 1;  
  107.              toplevel += 1;  
  108.    
  109.              smooth_sort_fix(array, i - leonardo[levels[toplevel]], toplevel - 1, levels);  
  110.              smooth_sort_fix(array, i, toplevel, levels);  
  111.          }  
  112.      }  
  113.      return;  
  114.  }  
  115.    
  116.  int main(int argc, char** argv) {  
  117.      int capacity = 0;  
  118.      int size = 0;  
  119.      int i;  
  120.      clock_t clock1;  
  121.      clock_t clock2;  
  122.      double data;  
  123.      double* array = NULL;  
  124.    
  125.      // generate randomized test case  
  126.      while(scanf("%lf", &data) == 1) {  
  127.          if(size == capacity) {  
  128.              capacity = (size + 1) * 2;  
  129.              array = (double*)realloc(array, capacity * sizeof(double));  
  130.          }  
  131.          array[size++] = data;  
  132.      }  
  133.    
  134.      // sort  
  135.      clock1 = clock();  
  136.      smooth_sort(array, size);  
  137.      clock2 = clock();  
  138.    
  139.      // output test result  
  140.      fprintf(stderr, "smooth_sort:\t");  
  141.      fprintf(stderr, "time %.2lf\t", (double)(clock2 - clock1) / CLOCKS_PER_SEC);  
  142.      fprintf(stderr, "cmp_per_elem %.2lf\t", (double)cmp_times / size);  
  143.      fprintf(stderr, "set_per_elem %.2lf\n", (double)set_times / size);  
  144.      for(i = 0; i < size; i++) {  
  145.          fprintf(stdout, "%lf\n", array[i]);  
  146.      }  
  147.      free(array);  
  148.      return 0;  
  149.  }  

 

 

 

§5 小结

这篇博文列举了选择排序的几个算法,管中窥豹,不求甚解。如果你有任何建议或者批评和补充,请留言指出,不胜感激,更多参考请移步互联网。

 

 

 

 

 

参考:

①MoreWindows:http://blog.csdn.net/morewindows/article/details/6709644

②RichSelian:http://www.cnblogs.com/richselian/archive/2011/09/16/2179148.html

③kapinter:http://zdker.blog.163.com/blog/static/584834200659636560/

④更多参考来着维基百科

 

0 0
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 微信钱包充值话费不到帐怎么办 京东买的显示器过保坏了怎么办 支付宝充话费充错号码是空号怎么办 京东充话费充错了号码该怎么办 微信红包充话费不到账怎么办 支付宝充话费等待第三方发货怎么办 微信充话费显示成功但没收到怎么办 微信退款一直在退款中怎么办 文件大于100发不了微信怎么办 微信的传送文件大于100怎么办 微信钱包话费充值错误怎么办 微信转账到不了账也退不回是怎么办 求人办事微信发红包对方不收怎么办 微信上交了订金对方不退怎么办 交通事故对方伤员堵大门搂腿怎么办 电脑开机桌面文件都没了怎么办 qq飞车手游队长换了微信群怎么办 qq飞车手游登录授权失败怎么办 安装时提示安装包发现错误怎么办 苹果6p升级系统验证失败怎么办 w10开不了机无限重启怎么办 微信朋友圈里的表情图打不开怎么办 金立手机微信启动录音被拒绝怎么办 微信帐号解封后漂流瓶不能用怎么办 微信怎么在电脑上登不上去怎么办 玩旧版60级魔兽经常花屏怎么办? 我的世界手机版物品栏不见了怎么办 苹果手机掉进水里出现花屏该怎么办 球球大作战还没进去停止运行怎么办 ps3 e3硬破芯片坏了怎么办 电话打开后页面上没有东西怎么办 WPS在电脑安装后卸载不了怎么办 ps总要以管理员的身份打开怎么办 3d关的慢保存慢怎么办 无法与服务器建立可靠的连接怎么办 被抵押的房子开发商不解押怎么办 手机系统语言是英文没有中文怎么办 w7主机网插口灯不亮了没网怎么办 电脑用了5年变得很卡了怎么办 苹果6s系统占12g怎么办 百度网盘下载的压缩包打不开怎么办