排序算法和查找算法一样是最常用最重要的算法之一,排序算法有 交换排序、 插入排序、 选择排序和 归并排序等,本专栏给大家介绍一些以上排序算法中的经典算法,今天先给大家介绍第一种—— 简单选择排序。本文完整代码见:https://github.com/kfcyh/sort/tree/master/select。
简介
简单选择排序是选择排序的一种,选择排序原理是:第一次从待排序的数据元素中选出最小(或最大)的一个元素,存放在序列的起始位置,然后再从剩余的未排序元素中寻找到最小(大)元素,然后放到已排序的序列的末尾。以此类推,直到全部待排序的数据元素的个数为零(引自百度百科)。只看概念恐怕大家都不太明白,鉴于简单选择排序的原理较简单,下面我们直接通过代码进行讲解。
代码实现
首先我们提供一个排序用的顺序表结构,此结构也用于之后讲解的其他排序算法。然后提供一个内联交换函数,此函数也用于其他排序算法。
#pragma once
#include <stdlib.h>
#include <iostream>
using namespace std;
#define MAXSIZE 10
typedef struct list {
int r[MAXSIZE + 1];
int length;
list():length(0){}
}*SqList;
inline void swap(SqList L, int i, int j)
{
int temp = L->r[i];
L->r[i] = L->r[j];
L->r[j] = temp;
}
排序函数
void SelectSort(SqList L)
{
int i, j, min;
for (i = 1; i < L->length; i++)
{
min = i;
for (j = i + 1; j <= L->length; j++)
{
if (L->r[min] > L->r[j])
min = j;
}
if (i != min)
swap(L, i, min);
}
}
下面通过排序集合{9,1,5,8,3,7,4,6,2}讲解代码:
-
外循环 i i i从1循环到8,由第一个数字遍历至倒数第二个数。内循环 j j j从 i + 1 i+1 i+1循环到9。当 i = 1 i=1 i=1时, L − > r [ i ] = 9 L->r[i]=9 L−>r[i]=9, m i n = 1 min=1 min=1,然后 L − > r [ m i n ] L->r[min] L−>r[min]与 L − > r [ j ] ( j = 2...9 ) L->r[j](j=2...9) L−>r[j](j=2...9)比较,当 L − > r [ m i n ] > L − > r [ j ] L->r[min]>L->r[j] L−>r[min]>L−>r[j]时交换两数,因为第一次内循环 L − > r [ 2 ] L->r[2] L−>r[2]最小,最终 L − > r [ m i n ] = L − > r [ 2 ] = 1 L->r[min]=L->r[2]=1 L−>r[min]=L−>r[2]=1,第一次内循环结束。
-
第二次内循环, i = 2 i=2 i=2, L − > r [ i ] = 9 L->r[i]=9 L−>r[i]=9, m i n = 2 min=2 min=2,过程同上,循环结束时 L − > r [ m i n ] = L − > r [ 9 ] = 2 L->r[min]=L->r[9]=2 L−>r[min]=L−>r[9]=2。
-
第三次内循环, i = 3 i=3 i=3, L − > r [ i ] = 5 L->r[i]=5 L−>r[i]=5, m i n = 3 min=3 min=3,过程同上,循环结束时 L − > r [ m i n ] = L − > r [ 5 ] = 3 L->r[min]=L->r[5]=3 L−>r[min]=L−>r[5]=3。
-
重复上述过程直至 i = 8 i=8 i=8结束。
性能分析
综上分析,简单选择排序与冒泡排序相比,最大优势是移动交换次数少,每次循环需要比较 n − i n-i n−i次,总共需要 ∑ i = 1 n − 1 ( n − i ) = n ( n − 1 ) 2 \sum_{i=1}^{n-1}(n-i)=\frac{n(n-1)}{2} ∑i=1n−1(n−i)=2n(n−1)。对于交换次数,最好情况为0,最坏为 n − 1 n-1 n−1,平均的时间复杂度为 O ( n 2 ) O(n^2) O(n2),所以简单选择排序虽然与冒泡排序时间复杂度相同,但性能优于冒泡排序。