排序算法-2-选择排序

选择排序

前面讲了插入排序,下面说另一种很容易想到的排序方法:选择排序。

原理

选择排序的原理非常简单,就像按学号点名,先点学号最小的,放在第一个位置,然后点学号第二小的,放在第二个位置,依此类推,直到剩最后一个为止。

实现

按照这个原理我们来用代码实现。这时问题又来了:是否可以像插入排序一样,也不需要另外开辟空间,直接在原址上排序呢?答案同样是可以。怎么做呢?因为已经排过序的和没有排过序的学生总数是一定的,我们将一个数组分成两部分,左边一部分表示已排序的学生,右边一部分表示还未排序的学生,这样一个数组就存储下了。
还有一个问题是点名选出来学生放在哪,只有一个数组意味着他必须要在未排序的学生这边占一个位置,当然他自己被选走了也会空出来一个位置,所以一个简单的解决办法就是做一个交换,另外一个办法是依次往右挪一个空位置出来。交换的方式运算量会小一些,但不稳定,而往右挪的方式可以保持稳定,但运算量大一些。(这里顺便解释一下稳定性:指的是当有任意两个或多个相同值的元素存在时,排序前后它们的相对位置是否能确定保持不变。比如数组中有两个2,为以示区别不妨分别叫2A和2B,排序前2A在2B的左边,若排序后不能保证2A还是在2B的左边,就是不稳定的排序。只要有任意一组相同元素排完序不稳定,排序算法就是不稳定的。必须保证所有位置所有元素排完序都稳定才能称之为稳定排序。比如插入排序就是一个稳定的排序。)

下面就是用C语言实现的代码,采用交换的方式。
- 要排序的数组a有n个元素,a[0...j-1]为已排好序的元素,a[j...n-1]是还未排序的。
- 外层循环进行n-1次,每次先从还未排序的元素a[j...n-1]中找到最小的一个a[index],然后交换a[index]与a[j]。

void selection_sort(int a[], int n)
{
    if(n<=0)
        return;

    for(int j=0;j<n-1;j++) {
        // 在还未排序的元素a[j...n-1]中找到最小的一个
        int min=a[j];
        int index=j;
        for(int i=j;i<n;i++) {
            if(a[i]<min) {
                min=a[i];
                index=i;
            }
        }
        // 交换
        a[index]=a[j];
        a[j]=min;
    }
}

为了验证此函数的效果,加上了如下辅助代码,对3个数组进行排序,运行结果在最后,可见排序成功。

#include <stdio.h>
#include <stdlib.h>

#define SIZE_ARRAY_1 5
#define SIZE_ARRAY_2 6
#define SIZE_ARRAY_3 20

void selection_sort(int a[], int n);
void show_array(int a[], int n);

void main()
{
    int array1[SIZE_ARRAY_1]={1,4,2,-9,0};
    int array2[SIZE_ARRAY_2]={10,5,2,1,9,2};
    int array3[SIZE_ARRAY_3];

    for(int i=0; i<SIZE_ARRAY_3; i++) {
        array3[i] = (int)((40.0*rand())/(RAND_MAX+1.0)-20);
    }

    printf("Before sort, ");
    show_array(array1, SIZE_ARRAY_1);
    selection_sort(array1, SIZE_ARRAY_1);
    printf("After sort, ");
    show_array(array1, SIZE_ARRAY_1);

    printf("Before sort, ");
    show_array(array2, SIZE_ARRAY_2);
    selection_sort(array2, SIZE_ARRAY_2);
    printf("After sort, ");
    show_array(array2, SIZE_ARRAY_2);

    printf("Before sort, ");
    show_array(array3, SIZE_ARRAY_3);
    selection_sort(array3, SIZE_ARRAY_3);
    printf("After sort, ");
    show_array(array3, SIZE_ARRAY_3);
}

void show_array(int a[], int n)
{
    if(n>0)
        printf("This array has %d items: ", n);
    else
        printf("Error: array size should bigger than zero.\n");

    for(int i=0; i<n; i++) {
        printf("%d ", a[i]);
    }
    printf("\n");
}

运行结果:

Before sort, This array has 5 items: 1 4 2 -9 0
After sort, This array has 5 items: -9 0 1 2 4
Before sort, This array has 6 items: 10 5 2 1 9 2
After sort, This array has 6 items: 1 2 2 5 9 10
Before sort, This array has 20 items: 13 -4 11 11 16 -12 -6 10 -8 2 0 5 -5 0 18 16 5 8 -14 4
After sort, This array has 20 items: -14 -12 -8 -6 -5 -4 0 0 2 4 5 5 8 10 11 11 13 16 16 18

分析

时间复杂度

从代码可见,用了两层for循环,且每个循环都是 n 的量级,所以插入排序的时间复杂度为 O(n^2)。

空间复杂度

因为选择排序直接在原址进行,不需要另外的空间,所以空间复杂度是 O(1)。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值