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

来源:互联网 发布:资本结构优化 编辑:程序博客网 时间:2024/06/01 08:25

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

在数据的组织中,排序因为能将数据变得有序,往往能带来访问效率的提高。另一方面,在有些时候,排序算法中前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)。

0 0
原创粉丝点击