排序算法总结(推荐)

笔者最近的笔试题目中大量涉及到排序算法的问题,今天在微信公众号“芋道源码”中看到了这篇比较好的关于排序算法的总结,觉得挺不错的,分享给大家!

原文公众号链接:https://mp.weixin.qq.com/s/b09DexoFsAi36TWKtMNu2g

排序算法总结

来源:http://yikun.github.io/2014/11/20/algorithm_sort/

 

1. 概述

算法名称复杂度实现关键
冒泡排序O(n^2)(无序区,有序区)。从无序区通过交换找出最大元素放到有序区前端。
选择排序O(n^2)(有序区,无序区)。在无序区里选择一个最小的元素跟在有序区的后面。
插入排序O(n^2)(有序区,无序区)。把无序区的第一个元素插入到有序区的合适的位置。
希尔排序nlog^2(n)每一轮按照事先决定的间隔进行插入排序,间隔会依次缩小,最后一次一定要是1(插入)。
快速排序nlog(n)(小数,枢纽元,大数)。
堆排序nlog(n) 
桶排序O(n)将值为i的元素放入i号桶,最后依次把桶里的元素倒出来。

不稳定的排序:
稳定性一个形象的比喻,本来有两个并列第三,一排序把原来并列的顺序给变了。
比如:选择排序、快速排序、堆排序、希尔排序;
参考链接

2. 冒泡排序

img

每次都把未排序的第一个作为起始点,然后逐渐冒泡上升,之后未排序区越来越少,最终排序完成

 

img

 1// 冒泡排序
 2void bubble_sort(int a[], int n)
 3{
 4    int i = 0;
 5    int j = 0;
 6    for (i=0; i<n-1; i++)
 7    {
 8        // 比较相邻元素,若a[j]比a[j+1]大,则交换
 9        // a[j]就像一个气泡一样“浮”到合适位置了
10        for(j=0; j<n-1-i; j++)
11        {
12            if(a[j]>a[j+1])
13            {
14                swap(&a[j], &a[j+1]);
15            }
16        }
17    }
18}

3. 选择排序

 

img

每一趟从待排序的数据元素中选出最小(或最大)的一个元素,顺序放在已排好序的数列的最后,直到全部待排序的数据元素排完。

img

 1// 选择排序
 2void select_sort(int a[], int n)
 3{
 4    int i=0,j=0,min=0;
 5    for (i=0; i < n-1; i++)
 6    {
 7        min = i;
 8        // 找到最小值
 9        for (j=i+1; j <= n-1; j++)
10        {
11            if (a[min] > a[j])
12                min = j;
13        }
14        if(min != i)
15        {
16            swap(&a[min], &a[i]);
17        }
18    }
19}

4. 插入排序

img

每次排序从未排序区取一个“牌”,然后往前插入(包括了两步:大的往后移,把牌放到合适位置)。

img

 1// 插入排序
 2void insert_sort(int a[], int n)
 3{
 4    int i=0;
 5    int j=0;
 6    int tmp=0;
 7    for (i = 1; i < n; i++)
 8    {
 9        // 取牌
10        tmp = a[i];
11        // 往前插的起始位置
12        j = i - 1;
13
14        // 大的a[j]都放后面,寻找出j
15        while ((j >= 0) && a[j] > tmp)
16        {
17            // 往后放一个
18            a[j+1] = a[j];
19            j--;
20        }
21
22        // 放到该放的位置
23        a[j+1]=tmp;
24    }
25}

另外还有种思路,把数据后移的过程换成交换的过程

 1// 插入排序,选中的牌冒泡向前插入
 2void insert_sort_2(int a[], int n)
 3{
 4    int i=0;
 5    int j=0;
 6    //通过i选牌
 7    for (i=1; i < n; i++)
 8    {
 9        // 冒泡向前插入(i-1 --> 0)
10        for (j=i-1; j>=0 && a[j] > a[j + 1]; j--)
11        {
12            swap(&a[j], &a[j+1]);
13        }
14    }
15    print_a(a, n);
16}
17`

5. 希尔排序

对插入排序再加一个步长的循环就是希尔排序了,例如

1[ 13 14 94 33 82 25 59 94 65 23 45 27 73 25 39 10 ]

按照5步长排序,则相当于按列先进行排序(实际是通过下标实现的)

113 14 94 33 82
225 59 94 65 23
345 27 73 25 39
410

排序后结果为

110 14 73 25 23
213 27 94 33 39
325 59 94 65 82
445

多次循环后,只需要最终步长为1即可。

 1// 希尔排序
 2void shell_sort(int a[], int n)
 3{
 4    int i=0;
 5    int j=0;
 6    int tmp=0;
 7    int gap=0;
 8    while (gap <= n)
 9    {
10        gap = gap*3 + 1;
11    }
12    while (gap > 0)
13    {
14        // 取牌
15        for (i = gap; i < n; i++)
16        {
17            // 冒泡向前插入(i-gap : gap : 0), 保证每列ok
18            for (j = i - gap; (j >= 0) && (a[j] > a[j + gap]); j = j - gap)
19            {
20                swap(&a[j], &a[j+gap]);
21            }
22        }
23        gap = (gap-1) / 3;
24    }
25}

6. 快速排序

img


每次迭代都选出一个基准,左边放小的,右边放大的,最终迭代完成。

img

 1// 快速排序分区
 2static int partition(int a[], int p, int r)
 3{
 4    int x=0;
 5    int i=0;
 6    int j=0;
 7    // x为基准
 8    x = a[r];
 9    // i为界限,发现小于x的,就i++,再放到i处
10    i = p-1;
11    for (j=p; j<= r-1; j++)
12    {
13        if (a[j]<=x)
14        {
15            i++;
16            swap(&a[i], &a[j]);
17        }
18    }
19    // 至此,所有小于x的都到i左边了(a[0]~a[i-1]),a[r]是x,因此交换a[i+1]和a[r]
20    swap(&a[i+1], &a[r]);
21    return i+1;
22}
23
24// 快速排序
25void quick_sort(int a[], int p, int r)
26{
27    int q=0;
28    if (p < r)
29    {
30        // 在数据集之中,选择一个元素作为"基准"(pivot)
31        // 所有小于"基准"的元素,都移到"基准"的左边;所有大于"基准"的元素,都移到"基准"的右边
32        q = partition(a, p, r);
33        // 对"基准"左边和右边的两个子集,不断重复第一步和第二步,直到所有子集只剩下一个元素为止。
34        quick_sort(a, p, q-1);
35        quick_sort(a, q+1, r);
36    }
37}

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值