排序算法六:选择排序之直接选择排序




引言

在我的博文《​​“主宰世界”的10种算法短评​​》中给出的首个算法就是高效的排序算法。本文将对排序算法做一个全面的梳理,从最简单的“冒泡”到高效的堆排序等。

系列博文的前五篇分别讲述了插入排序和交换排序,本文介绍选择排序中直接选择排序这一似乎是最慢的排序算法。



排序相关的的基本概念

  • 排序:将一组杂乱无章的数据按一定的规律顺次排列起来。
  • 数据表( data list): 它是待排序数据对象的有限集合。
  • 排序码(key):通常数据对象有多个属性域,即多个数据成员组成,其中有一个属性域可用来区分对象,作为排序依据。该域即为排序码。每个数据表用哪个属性域作为排序码,要视具体的应用需要而定。
  • 分类
  • 内排序:指在排序期间数据对象全部存放在内存的排序;
  • 外排序:指在排序期间全部对象个数太多,不能同时存放在内存,必须根据排序过程的要求,不断在内、外存之间移动的排序。


排序算法的分析

排序算法的稳定性

如果在对象序列中有两个对象r[i]和r[j] ,它们的排序码k[i]==k[j] 。如果排序前后,对象r[i]和r[j] 的相对位置不变,则称排序算法是稳定的;否则排序算法是不稳定的。

排序算法的评价

时间开销

  • 排序的时间开销可用算法执行中的数据比较次数与数据移动次数来衡量。
  • 算法运行时间代价的大略估算一般都按平均情况进行估算。对于那些受对象排序码序列初始排列及对象个数影响较大的,需要按最好情况和最坏情况进行估算

空间开销

算法执行时所需的附加存储。



直接选择排序

基本思想

N个元素,每次挑出最大或者最小,执行(n-1)次循环。实际上选择排序是最简单的一种排序算法,因为它的思想非常朴素,每趟都选出剩余中最大或者最小的排在已经排好的数据后面。

直接排序处理流程:

  1. 从待排序序列中,找到关键字最小的元素;
  2. 如果最小元素不是待排序序列的第一个元素,将其和第一个元素互换;
  3. 从余下的 N - 1 个元素中,找出关键字最小的元素,重复1,2步,直到排序结束。

算法排序过程图示

排序算法六:选择排序之直接选择排序_排序算法

排序算法六:选择排序之直接选择排序_数据_02

算法分析

时间复杂度

直接选择排序的排序码比较次数KCN 与整个待排序对象序列象的初始排列无关。KCN=∑n−2i=0(n−i−1)=n(n−1)2。

移动次数:最好的时候为0;最坏的时候为3(n−1);

说明一下:基本上所有的排序算法最后的时候都是对应着已经完全排好序了,而最坏的时候通常都是反序排列。

所以,综合以上,简单排序的时间复杂度为 O(N2)。

空间复杂度

简单选择排序需要占用一个临时空间,在交换数值时使用。

特点

  • 对于大数据表效率不高;
  • 简单;
  • 重复执行相同的工作,并没有从上一次的迭代中学到任何有助于的排序的知识。
  • 移动次数可能是排序算法中比较好的了。如果采用in-place的数据交换方法,选择排序数据项的移动次数就一直为0。
  • 不是一个稳定排序(从给的图示就可以看出)

单纯从每趟的效果上看,选择排序挑选最大或最小与冒泡算法有点类似,都是将剩下中的最大最小排起来,唯一的区别是冒泡算法是临近的两个数据项如果逆序就会交换,而选择排序不进行交换,只是在选定最值后进行交换。因此选择排序实际上并没有学到什么东西,每次迭代就是为了排好一个。而冒泡排序通过逆序的两个两两交换能够使得最值冒出来,而且还能实现未排序部分的初排序,最后能够通过判定是否发生交换提前终止迭代。

算法c plus plus描述

#include <iostream>

using namespace std;

void swap(int *n, int *m) {
int tmp;
tmp = *m;
*m = *n;
*n = tmp;
}

void print(int a[], int sz) {
for (int i = 0; i < sz; i++ ) cout << a[i] << " ";
cout << endl;
}

void SelectionSort(int a[], int sz) {
int i,j,mn;
/* traverse the entire array */
for (i = 0; i < sz; i++) {
/* find the min */
mn = i;
/* compare against all other elements */
for (j = i + 1; j < sz; j++) {
if (a[j] < a[mn]) mn = j;
}
swap(a[mn], a[i]);
print(a,sz);
}
}

int main()
{
int a[] = {4,6,9,1,2,0,8,7,5,3};
const size_t sz = sizeof(a)/sizeof(a[0]);
print(a,sz);
cout << "---------------------\n" ;
SelectionSort(a, sz);
}


输出为:

4 6 9 1 2 0 8 7 5 3
---------------------
0 6 9 1 2 4 8 7 5 3
0 1 9 6 2 4 8 7 5 3
0 1 2 6 9 4 8 7 5 3
0 1 2 3 9 4 8 7 5 6
0 1 2 3 4 9 8 7 5 6
0 1 2 3 4 5 8 7 9 6
0 1 2 3 4 5 6 7 9 8
0 1 2 3 4 5 6 7 9 8
0 1 2 3 4 5 6 7 8 9
0 1 2 3 4 5 6 7 8 9


2015-9-26 艺少