OpenDSA 全教程

Chapter 13 Sorting

| 关于   «  4. 冒泡排序   ::   目录   ::   6. 交换排序的代价  »

5. 选择排序

5.1. 选择排序

再考虑给过去一年的电话账单排序这个问题。 另一种直观的做法是:翻遍整叠账单直到找到一月份的那张,把它 抽出来。 然后翻遍剩下的一叠,找到二月份的账单,放在一月份的后面。 对着不断缩小的一叠账单继续这样做,按顺序选出下一张,直到 全部完成。 这就是我们最后一个 \(\Theta(n^2)\) 排序算法—— 选择排序 的灵感来源。 选择排序的第 \(i\) 趟"选出"数组中第 \(i\) 大的 键,把该记录放到数组末端。 换句话说,选择排序先找到无序线性表中最大的键,然后找 次大的,依此类推。 它的独特之处在于记录交换的次数很少。 为了找到下一个更大的键,需要扫过数组整个无序部分,但 只需一次交换就能把记录放到位。 因此,所需的交换总次数是 \(n-1\) (最后一条记录"免费" 就位)。

下面是选择排序的一种实现。

void selsort(int[] A) {
  for (int i=0; i<A.length-1; i++) {       // Select i'th biggest record
    int bigindex = 0;                      // Current biggest index
    for (int j=1; j < A.length-i; j++)     // Find the max value
      if (A[j] > A[bigindex])              // Found something bigger  
        bigindex = j;                      // Remember bigger index
    swap(A, bigindex, A.length-i-1);       // Put it into place
  }
}
void selsort(T[] A) {
  for (int i=0; i<A.length-1; i++) {       // Select i'th biggest record
    int bigindex = 0;                      // Current biggest index
    for (int j=1; j<A.length-i; j++)       // Find the max value
      if (A[j].compareTo(A[bigindex]) > 0) // Found something bigger
        bigindex = j;                      // Remember bigger index
    swap(A, bigindex, A.length-i-1);       // Put it into place
  }
}
void selectionsort(Comparable* A[], int n) {
  for (int i = 0; i < n-1; i++) { // Select i'th biggest record
    int bigindex = 0;             // Current biggest index
    for (int j = 1; j < n-i; j++) // Find the max value
      if (*A[j] > *A[bigindex])   // Found something bigger
        bigindex = j;             // Remember bigger index    
    swap(A, bigindex, n-i-1);     // Put it into place
  }
}

考虑下面这个数组的例子。

Settings

Proficient Saving... Error Saving
Server Error
Resubmit

现在继续第二趟。 不过,由于最大的记录已经在右端,我们不必再看它。

Settings

Proficient Saving... Error Saving
Server Error
Resubmit

选择排序就这样一直进行下去,直到整个数组有序。

下面的可视化把整个过程串在一起。

现在请自己试一试,看看你是否理解了选择排序的工作原理。

5.2. 选择排序分析

任何算法都可以写出略微不同的版本。 例如,我们可以把选择排序写成找最小的记录、再找次小的, 依此类推。 我们把这个版本的选择排序写得尽可能接近冒泡排序实现的行为。 这表明选择排序本质上就是冒泡排序,区别在于:不是反复交换 相邻的值来让下一个更大的记录就位,而是记住待选记录的位置, 最后只做一次交换。

下面的可视化分析选择排序所需的比较次数和交换次数。

Settings

Proficient Saving... Error Saving
Server Error
Resubmit

5.3. 指针交换

Settings

Proficient Saving... Error Saving
Server Error
Resubmit

下面是一些帮助你检查选择排序理解程度的复习题。

   «  4. 冒泡排序   ::   目录   ::   6. 交换排序的代价  »

关闭窗口