排序算法总结(算法导论)

排序算法是众多算法的基础,是实际工程中真正需要用到的算法之一。

在数据的组织中,排序因为能将数据变得有序,往往能带来访问效率的提高。另一方面,在有些时候,排序算法中前k大值等的求取本身就是直接需求。

数据hash算法是与排序相匹敌的另一类高效访问算法,效率高到O(1),但hash算法只能用于普通的插入查找,不能用于需要比较数值的情况,另一方面,对于小规模数据,hash算法的实际代码长度抵消了复杂度优势。


纸牌游戏中的插入排序通常是身边最能接触到的最简单排序算法,而堆排序则是一种稳定高效的排序算法。本文将由简入繁介绍相关的排序算法。


1、插入排序
int sort_insertion(int* data, int n){
    for (int i = 1; i<n; i++){
        //insert data[i] into sorted array data[0:i-1];
        int j = 0;
        int iv = data[i];
        for (j = i-1; j >= 0 && data[j]>iv; j--){
            data[j + 1] = data[j];
        }
        data[j + 1] = iv;
    }
    return 0;
}


这个算法原理是,依次将第 i 个数插入在 之前排好序的 i 大小的队列中,复杂度为 O(n^2)。

2、冒泡排序


int sort_up(int *data, int n){
    for (int i = 0; i<n; i++){
        for (int j = i + 1; j<n; j++){
            if (data[i] > data[j]){
                int temp = data[i];
                data[i] = data[j];
                data[j] = temp;
            }
        }
    }
    return 0;
}




这个算法原理是将余下的数依次上翻两两比较,从而将最小的数浮到顶部。1和2的算法简单,适合于小规模数据,由于其代码简短的优点,即使复杂度为O(n^2),效率依然不错。

3、快速排序


int sort_quick(int *data, int p, int q){
    if (p >= q){
        return 0;
    }
    int sep = data[q];
    int d = p - 1;
    for (int i = p; i<q; i++){
        if (data[i] < sep){
            d++;
            int temp = data[i];
            data[i] = data[d];
            data[d] = temp;
        }
    }
    d++;
    data[q] = data[d];
    data[d] = sep;

    sort_quick(data, p, d - 1);
    sort_quick(data, d + 1, q);
    return 0;
}


这个算法原理是用尾部数将数据分成大小两段,再分别递归。复杂度为 O(n logn),但是在极端情况下,比如数据已经排好序的情况下,复杂度退化为 O(n^2)。

4、计数排序

//k = max(data(n))
int sort_count(int* data, int k, int n){
    int *a = new int[k];
    int *b = new int[n];
    memset(a, 0, k*sizeof(int));
    memset(b, 0, n*sizeof(int));
    for (int i = 0; i < n; i++){
        a[data[i]] ++;
    }
    for (int i = 1; i < k; i++){
        a[i] = a[i - 1] + a[i];
    }
    for (int i = n-1; i >= 0; i--){
        b[a[data[i]]-1] = data[i];
        a[data[i]]--;
    }
    memcpy(data, b, n*sizeof(int));
    delete[]a;
    delete[]b;
    return 0;
}





计数排序时间复杂度为O(k+n),因为他并不是比较排序算法,所以下界优于 O( nlogn )。一个优点,它是稳定的。一个缺点,它不是原地的。

5、基数排序

技术排序利用了计数排序稳定性的特点。

SORT_RADIX(A, d)
for i<-1, d
    do use a stable sort to sort array A on digit i



基数排序时间复杂度为O(d*(n+k))。

6、桶排序

当数据的输入符合均匀分布时,可以以线性期望时间运行。


BUCKET_SORT(A, n)
    for i in 1 to n:
        do insert A[i] into list B[ |n*A[i]|下界 ]
    for i in 0 to n-1:
        do sort B[i] with insertion sort;
    concatenate the list B[0], B[1], ..., B[n-1] together in order



时间复杂度为O(n* (2-1/n)),即O(n).

7、归并排序

归并排序是一种分治合并策略。


int sort_merge(int *a, int p, int r){
    if (p >= r){
        return 0;
    }
    int q = (p + r + 1) / 2;
    int *b1 = new int[q - p + 1];
    int *b2 = new int[r - q + 1 + 1];
    memcpy(b1, a, (q - p)*sizeof(int));
    memcpy(b2, a + q, (r - q + 1)*sizeof(int));
    sort_merge(b1, 0, q - p - 1);
    sort_merge(b2, 0, r - q);
    b1[q - p] = b2[r - q + 1] = 0x7fffffff;
    for (int k = p, i = 0, j = 0; k <= r; k++){
        if (b1[i] < b2[j]){
            a[k] = b1[i];
            i++;
        }
        else{
            a[k] = b2[j];
            j++;
        }
    }
    delete[]b1;
    delete[]b2;
    return 0;
}



归并排序时间复杂度为O(nlogn)


8、堆排序

//a[1:n]
int max_heap(int *a, int i, int n){
    while (i < n){
        if (a[i] < a[i * 2] && i * 2 == n){
            swap(a[i], a[i * 2]);
            break;
        }
        else if (a[i] < a[i * 2] && i * 2 + 1 <= n && a[i * 2] >= a[i * 2 + 1]) {
            swap(a[i], a[i * 2]);
            i = i * 2;
        }
        else if (a[i]<a[i * 2 + 1] && i * 2 + 1 <= n && a[i * 2 + 1]>a[i * 2]){
            swap (a[i], a[i * 2 + 1]);
            i = i * 2 + 1;
        }
        else{
            break;
        }
    }
    return 0;
}

int bulid_max_heap(int *a, int n){
    for (int i = n / 2; i >= 1; i--){
        max_heap(a, i, n);
    }
    return 0;
}

int heap_sort(int *a, int n){
    bulid_max_heap(a, n);
    for (int i = n; i >= 1; i--){
        swap (a[i], a[1]);
        max_heap(a, 1, i - 1);
    }
    return 0;
}


堆排序时间复杂度为O(nlogn)。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值