常见排序算法导读(3)[简单选择排序]

这一节将介绍简单选择排序(Simple Selection Sort)。 在介绍简单排序算法之前,先给出排序的确切定义,并简单介绍一下排序算法的稳定性。

排序的确切定义

假设含有n个对象的序列为{R[0], R[1], ..., R[n-1]}, 其对应的关键字(key)序列为{K[0], K[1], ..., K[n-1]}。 所谓排序, 就是确定0, 1, ..., n-1的一种排列p[0], p[1], ..., p[n-1], 使各个关键字满足如下的非递减(升序)或非递增(降序)关系:

    K[p[0]] <= K[p[1]] <= ... <= K[p[n-1]]

    K[p[0]] >= K[p[1]] >= ... >= K[p[n-1]]

也就是说, 所谓排序,就是根据关键字递增或递减的顺序,把数据对象依次排列起来,使一组任意排列的对象变成一组按其关键字线性有序的对象。

排序算法的稳定性

如果在对象序列中有两个对象R[i]R[j],它们的关键字K[i] == K[j],且在排序之前,对象R[i]排在R[j]前面。如果在排序之后,对象R[i]仍排在R[j]的前面,则称这个排序算法是稳定的,否则称这个排序算法是不稳定的。 例如:在A中学B年级C班,有两个学霸分别叫陈小明和黎小军,陈小明的学号为007,黎小军的学号为008,在一次期末考试的时候,陈小明和黎小军的总成绩(750分为满分)都是699。按照稳定的排序算法,陈小明应该排在黎小军的前面;如果按照不稳定的排序算法,陈小明就排到了黎小军的后面。虽然使用稳定的排序算法和不稳定的排序算法,排序的结果会有所不同,但不能说不稳定的排序算法就不好,各有各的用途罢了。

注意:后面讨论的所有排序算法,如未特别说明,都是升序排序。

下面以简单选择排序为例讨论选择排序(selection sort)算法。

什么是选择排序?

一种最简单的排序算法是这样的:首先,找到数组中最小的那个元素;其次,将它和数组的第一个元素交换位置(如果第一个元素就是最小元素,那么它就和自己交换);再次,在剩下的元素中找到最小的元素,将它与数组的第二个元素交换位置。如此循环往复,直到将整个数组都排好序。这种方法叫做选择排序(selection sort),因为它在不断地选择剩余元素之中的最小的那一个。

o 简单选择排序(simple selection sort)的C代码实现 : 函数s2sort()

 1 /*
 2  * Simple Selection Sort (s2sort in short)
 3  */
 4 void                                      //
 5 s2sort(int a[], size_t n)                 // NOTE: a[0 .. i] is always sorted and
 6 {                                         //       a[i+1 .. n-1] is unsorted
 7     for (int i = 0; i < n; i++) {         //
 8         int min = i;                      // Index of minimal element
 9                                           // Find the minimal element in
10         for (int j = i + 1; j < n; j++) { //     the unsorted a[i+1 .. n-1]
11             if (a[j] < a[min]) {          // If this element is less, then
12                 min = j;                  //     it is the new minimum and
13             }                             //     remember its index
14         }                                 //
15                                           //
16         if (i != min) {                   // Exchange the new mininum a[i]
17             exchange(a, i, min);          //     found in a[i+1 .. n-1]
18         }                                 // with     the old minimum a[i]
19     }                                     //
20 }                                         //
21
22 static void exchange(int a[], int i, int j)
23 {
24     int t = a[i];
25     a[i]  = a[j];
26     a[j]  = t;
27 }

另外, 为了更好的理解,这里也给出s2sort()的递归实现。

 1 static unsigned int getIndexOfMin(int a[], size_t n);
 2 static void exchange(int a[], int i, int j);
 3
 4 void
 5 s2sort(int a[], size_t n)
 6 {
 7     if (n == 1)
 8         return;
 9
10     int min = getIndexOfMin(a, n);
11     if (min != 0)
12         exchange(a, 0, min);
13     s2sort(++a, --n);
14 }
15
16 static unsigned int getIndexOfMin(int a[], size_t n)
17 {
18     int min = 0;
19     for (int i = 0; i < n; i++)
20         if (a[i] < a[min])
21             min = i;
22     return min;
23 }
24
25 static void exchange(int a[], int i, int j)
26 {
27     int t = a[i];
28     a[i]  = a[j];
29     a[j]  = t;
30 }

接下来,给出一个完整的s2sort.c并编译后测试, 以便形象化地理解简单选择排序的全过程。 【注: 动画演示戳这里

o s2sort.c // 将s2sort()做稍稍增强以打印详细的排序过程

 1 #include <stdio.h>
 2 #include <stdlib.h>
 3
 4 typedef struct obs_s {
 5         unsigned int loop;
 6         unsigned int exch;
 7 } obs_t;
 8
 9 obs_t g_obs = { .loop = 0, .exch = 0 };
10
11 static void exchange(int a[], int i, int j);
12 static void show(int a[], size_t n);
13
14 static void exchange(int a[], int i, int j)
15 {
16     int t = a[i];
17     a[i]  = a[j];
18     a[j]  = t;
19 }
20
21 static void show(int a[], size_t n)
22 {
23         for (int i = 0; i < n; i++)
24                 printf("%c ", a[i]);
25 }
26
27 void
28 s2sort(int a[], size_t n)
29 {
30         for (int i = 0; i < n; i++) {
31                 int min = i;
32
33                 for (int j = i + 1; j < n; j++) {
34                         if (a[j] < a[min]) {
35                                 min = j;
36                         }
37                         g_obs.loop++;
38                 }
39
40                 if (i != min) {
41                         exchange(a, i, min);
42
43                         g_obs.exch++;
44                         printf("#%2d:\t\t", i); show(a, n);
45                         printf("\t// exchange(a[%d], a[%d])\n", i, min);
46                 } else {
47                         printf("#%2d:\t\t", min); show(a, n);
48                         printf("\n");
49                 }
50
51         }
52 }
53
54 int
55 main(int argc, char *argv[])
56 {
57         if (argc < 2) {
58                 fprintf(stderr, "Usage %s <C1> [C2] ...\n", argv[0]);
59                 return -1;
60         }
61
62         argc--;
63         argv++;
64
65         size_t n = argc;
66         int *a = (int *)malloc(sizeof(int) * argc);
67         if (a == NULL) {
68                 fprintf(stderr, "failed to malloc()\n");
69                 return -1;
70         }
71
72         for (int i = 0; i < n; i++)
73                *(a+i) = argv[i][0];
74
75         printf("               \t0 1 2 3 4 5 6 7 8 9 10\n");
76         printf("Before sorting:\t"); show(a, n); printf("\n");
77         s2sort(a, n);
78         printf("After  sorting:\t"); show(a, n); printf("\n");
79         printf("\n");
80         printf("Total num of loops:     %2d\n", g_obs.loop);
81         printf("Total num of exchanges: %2d\n", g_obs.exch);
82
83         free(a); a = NULL;
84
85         return 0;
86 }

o 编译并测试

$ gcc -g -Wall -m32 -std=c99 -o s2sort s2sort.c
$ ./s2sort      S O R T E X A M P L E
                0 1 2 3 4 5 6 7 8 9 10
Before sorting: S O R T E X A M P L E
# 0:            A O R T E X S M P L E   // exchange(a[0], a[6])
# 1:            A E R T O X S M P L E   // exchange(a[1], a[4])
# 2:            A E E T O X S M P L R   // exchange(a[2], a[10])
# 3:            A E E L O X S M P T R   // exchange(a[3], a[9])
# 4:            A E E L M X S O P T R   // exchange(a[4], a[7])
# 5:            A E E L M O S X P T R   // exchange(a[5], a[7])
# 6:            A E E L M O P X S T R   // exchange(a[6], a[8])
# 7:            A E E L M O P R S T X   // exchange(a[7], a[10])
# 8:            A E E L M O P R S T X
# 9:            A E E L M O P R S T X
#10:            A E E L M O P R S T X
After  sorting: A E E L M O P R S T X

Total num of loops:     55
Total num of exchanges:  8
$

以上排序过程截图如下(截图来源: Algorithms Fourth Edition P249)

小结: 对于长度为N的数组,简单选择排序需要大约(N*N/2)次比较和N次交换。 简单排序算法是不稳定的算法,其时间复杂度和空间复杂度是:

Worst-case performance 	    О(N**2)
Best-case  performance 	    О(N**2)
Average    performance 	    О(N**2)
Worst-case space complexity О(N) total, O(1) auxiliary

到此为止,我们已经完全弄明白了简单选择排序的原理。其核心就是:整个序列中最小的元素首先被挑选出来放在序列的最前端。也就是第一个被排好的元素是位于序列的首部,这一点与直接插入排序相同,但与冒泡排序正好相反。下一节,我们将介绍直接插入排序。

时间: 2024-08-02 02:48:29

常见排序算法导读(3)[简单选择排序]的相关文章

排序算法篇--之简单选择排序

简单选择排序,就是执行n-i次比较,然后从n-i+1个数据中选择最小的值,如果最小值不是第i(1=<i<=n)个,则和第i个交换. 1 <?php 2 $arr = array(9,5,4,8,7,6,0,3,2,1); 3 4 /** 5 * 返回经过简单选择排序算法排序后的数组 6 * @param $array array 要进行排序的数组 7 * return array 进过排序后的数组 8 */ 9 function SelectSort($array){ 10 11 for

Java排序算法(二):简单选择排序

[基本思想] 在要排序的一组数中.选出最小的一个数与第一个位置的数交换:然后在剩下的数中再找出最小的与第二个位置的数交换,如此循环至倒数第二个数和最后一个数比較为止. 算法关键:找到最小的那个数.并用变量记住它的下标. [java实现] public class SimpleSelectionSort { public static void main(String[] args) { int[] arr = { 9, 1, 5, 8, 3, 7, 4, 6, 2 }; System.out.p

算法一之简单选择排序

一.  选择排序的思想 选择排序的基本思想是:每一趟在n-i+1(i=1,2,-n-1)个记录中选取关键字最小的记录作为有序序列中第i个记录.基于此思想的算法主要有简单选择排序.树型选择排序和堆排序. 简单选择排序的基本思想:第1趟,在待排序记录r[1]~r[n]中选出最小的记录,将它与r[1]交换:第2趟,在待排序记录r[2]~r[n]中选出最小的记录,将它与r[2]交换:以此类推,第i趟在待排序记录r[i]~r[n]中选出最小的记录,将它与r[i]交换,使有序序列不断增长直到全部排序完毕.

七大内部排序算法总结(插入排序、希尔排序、冒泡排序、简单选择排序、快速排序、归并排序、堆排序)

 写在前面: 排序是计算机程序设计中的一种重要操作,它的功能是将一个数据元素的任意序列,重新排列成一个按关键字有序的序列.因此排序掌握各种排序算法非常重要.对下面介绍的各个排序,我们假定所有排序的关键字都是整数.对传入函数的参数默认是已经检查好了的.只是简单的描述各个算法并给出了具体实现代码,并未做其他深究探讨. 基础知识: 由于待排序的记录数量不同,使得排序过程中设计的存储器不同,可将排序方法分为两大类:一类是内部排序,指的是待排序记录存放在计算机随机存储器中进行的排序过程.另一类是外部排序,

直接插入排序、二分插入排序、希尔排序、冒泡排序与简单选择排序

一.直接插入排序 稳定,时间复杂度:最好O(n).最差O(n^2).平均O(n^2),空间复杂度O(1) void InsertSort(int L[], int n) { int i, j,key; for (i = 1; i<n; i++) if(L[i] < L[i-1])//需要将L[i]插入到有序表L[0...i-1] { key = L[i]; for(j = i-1; j >= 0 && key < L[j]; j--)//后移 L[j+1] = L[

【数据结构】——排序算法——3.1、选择排序

      [数据结构]--排序算法--3.1.选择排序 一.先上维基的图: 分类 排序算法 数据结构 数组 最差时间复杂度 О(n2) 最优时间复杂度 О(n2) 平均时间复杂度 О(n2) 最差空间复杂度 О(n) total, O(1)auxiliary 二.描述: 选择算法算是最直观的一个了.每次在队列里抽取一个极大(或极小)值进行排列.每次都需要遍历未被抽取的元素队列. 三.Java程序: static void selection_sort(int[] unsorted) { for

常见的排序算法(二) 选择排序

选择排序(Selection sort)是一种简单直观的排序算法.它的工作原理是每一次从待排序的数据元素中选出最小(或最大)的一个元素,存放在序列的起始位置,直到全部待排序的数据元素排完. 选择排序: 思想 n个记录的文件的直接选择排序可经过n-1趟直接选择排序得到有序结果: ①初始状态:无序区为R[1..n],有序区为空. ②第1趟排序 在无序区R[1..n]中选出关键字最小的记录R[k],将它与无序区的第1个记录R[1]交换,使R[1..1]和R[2..n]分别变为记录个数增加1个的新有序区

排序算法学习之简单排序(冒泡排序,简单选择排序,直接插入排序)

一.冒泡排序 冒泡排序算是最基础的一种算法了,复杂度为O(N^2),其基本思想是:从最低端数据开始,两两相邻比较,如果反序则交换.代码如下: /*最基本的冒泡排序*/ void BubbleSort1 (int n, int *array) /*little > big*/ { int i, j; for (i=0; i<n-1; i++) { for (j=n-1; j>i; j--) { if (array[j] < array[j-1]) { int temp = array

Hark的数据结构与算法练习之简单选择排序

/* * 简单选择排序 */ public class SimpleSort { public static void main(String[] args) { int[] arrayData = { 5, 9, 6, 7, 4, 1, 2, 3, 8 }; SimpleSortMethod(arrayData); for (int integer : arrayData) { System.out.print(integer); System.out.print(" "); } }