基于 c 的排序算法

学了基本的 C 语法后,我们来试着解决一下排序问题:给定一个数组,要求使得数组内的数(整数)从小到大排序。

选择排序

最简单的排序方法就是先找最小值,把它排到第一个,再找第二小值,把它排到第二个……以此类推。

void selectionSort(int* arr, int len)
{
    int i, j, minIndex, temp;
    for(i=0;i<len-1;++i)
    {
        minIndex=i;
        for(j=i+1;j<len;++j)
        {
            if(arr[j]<arr[minIndex])
            {
                minIndex=j;
            }
        }
        temp=arr[minIndex];
        arr[minIndex]=arr[i];
        arr[i]=temp;
    }
}

测试:

#include <stdio.h>

int main(void)
{
    int arr[]={2,3,7,6,5,1,4,9,8,0};
    int len = (int) sizeof(arr) / sizeof(*arr);
    selectionSort(arr, len);
    for(int i=0;i<len;++i)
        printf("%d ", arr[i]);
    return 0;
}

输出:

0 1 2 3 4 5 6 7 8 9

选择排序是表现最稳定的排序算法之一,因为无论什么数据进去都是 $O(n^2)$ 的时间复杂度,所以用到它的时候,数据规模越小越好。唯一的好处可能就是不占用额外的内存空间了吧。理论上讲,选择排序可能也是平时排序一般人想到的最多的排序方法了吧。

冒泡排序

我们每次只比较相邻的两个数,如果前一个数大于后一个数,就将它们交换。用这种方法遍历整个数组,没有数需要交换时,就说明整个数组已经排好序了。这个算法的名字由来是因为越小的元素会经由交换慢慢“浮”到数列的顶端。

void bubbleSort(int* arr, int len)
{
    int i, j, temp, flag;
    for(i=len;i>0;--i)
    {
        flag=1;
        for(j=0;j<i-1;++j)
        {
            if(arr[j]>arr[j+1])
            {
                temp=arr[j];
                arr[j]=arr[j+1];
                arr[j+1]=temp;
                flag=0;
            }
        }
        if(flag==1) break;
    }
}

我们上面加了一点优化。每次遍历完后,最大的数肯定会排到后面,那么下一次遍历的话,就只需要遍历到倒数第二个就可以了。

冒泡排序的复杂度依然是 $O(n^2)$

插入排序

插入排序有点像扑克牌,当新摸到一张牌时,我们会将它与已经拍好序的牌比较,然后插到合适的位置。不过这里要注意的是,由于数组的空间是固定的,所以每次插入时,我们需要将插入点后的数据依次往后移一个单元。

void insertionSort(int* arr, int len)
{
    int i, j, key;
    for (j = 1; j < len; j++)
    {
        key = arr[j];
        i = j - 1;
        while (i >= 0 && arr[i] > key)
        {
            arr[i+1] = arr[i];
            i--;
        }
        arr[i+1] = key;
    }
}

插入排序的复杂度依然是 $O(n^2)$

参考