常见排序 总结(我的学习笔记)

插入排序

简介:最简单的插入排序,利用了这样的事实:位置0—P的元素是排序的,后边N-P+1个元素向前面已经
排序的元素中插入,需要嵌套循环,第一层P—N(P的初始值为1,即前一个元素是排序的),第二层1—P,
即第一层每个元素需要跟已经排序的元素比较,进而在合适的位置插入,插入….biubiubiu
效率:由于是嵌套循环,每次都要N次比较,所以效率是(O (N*N))
稳定性:稳定的
看代码:

void InsertSort(int A[], int N)
{
    int j = 0;
    int P = 0;
    for(P = 1; P < N; ++P)
    {
        // 记录A[P],找到合适位置后,将其插入 biubiubiu
        int Tmp = A[P];
        // 找到合适位置:如果A[P] 小于前边的值,则将前面已经排序的后移,即挪出来一个位置
        for(j = P; j > 0 && A[j-1] > Tmp; --j)
            A[j] = A[j-1];
        // 在挪出位置上插入Tmp
        A[j] = Tmp;
    }
}

希尔排序

简介:是冲破二次时间屏障的第一批算法之一,原理:通过比较相距一定间隔的元素工作,各趟比较
所用的距离随着算法的进行而减小,知道只比较相邻元素的最后一趟排序为止—在每个增量上进行一次子
数组插入排序;
效率:O(nlogn)~O(n2),效率依赖增量的设计
稳定性:不稳定;原因:我们知道插入排序是稳定的,但是每个增量上的插入排序可能打乱稳定性
看代码:

void ShellSort(int A[], int N)
{
    int i = 0;
    int P = 0;
    // 首先确定一个增量
    int d = N/2;
    // 在每个增量上进行插入排序,所以要增加一个循环控制增量的缩小
    for(d; d > 0; d /= 2)
    {
        // 在每个增量上进行一次子数组的插入排序
        for(P = d; P < N; ++P)
        {
            // 记录,以便在合适位置插入
            int Tmp = A[P];
            // 跟Tmp比较,大于则向后移动,给Tmp挪出位置
            for(i = P; i > 0; i -= d)
            {
                if(A[i-d] > Tmp)
                    A[i] = A[i-d];
                else
                    break;
            }
            // 在合适的位置插入
            A[i] = Tmp;
        }
    }
}

快速排序

简介:正如名字,实践中最快的排序算法;原理:选出一个枢纽元素P,待排序数组前后两个标记i,j,
A[i]向后移动,A[j]向前移动,如果A[i] > P && A[j] < P 则交换i,j,那么一趟排序后,数据被分为两份,前边的都小于枢纽元素,后边的都大于枢纽元素,然后分而治之,分别对前后做相同的处理;
效率:(O(N*logN))
稳定性:不稳定
看代码:

void QuickSort(int A[], int left, int right)
{
    int i = 0;
    int j = 0;
    // 选取枢纽元素,这里就按最简单的,取第一个元素
    int q = A[left];
    // 记录前后元素
    i = left;
    j = right;
    while(i < j)
    {
        // 顺序比较重要,要先从后向前
        while(i < j && A[j] > q)
            --j
        while(i < j && A[i] < q)
            --i
        // 停了,可以交换了
        if(i < j)
        {
            int tmp = A[i];
            A[i] = A[j];
            A[j] = A[i];
        }
    }
    // 一趟比较结束了,我们枢纽元素还在A[left]位置上
    // 可以确定的是A[i] 一定是小于等于枢纽元素的,进行交换,这样
    // 枢纽左边都是小于他的元素,右边都是大于他的元素
    A[left] = A[i];
    A[i] = q;
    // 分而治之
    QuickSort(A, left, i - 1);
    QucikSort(A, i + 1, right);
}

这里有篇文章配图讲的挺形象的:
http://developer.51cto.com/art/201403/430986.htm

快排延伸:
(1)听过这样一个问题,给你一个大数组,炒鸡大(不能借助辅助数组什么的)!有奇数有偶数,
以O(N)时间复杂度,处理以下数据,使得左边都是奇数,右边都是偶数。看完快排很快就能想到解题思路,
即:省去“分治”的快排,具体就是定义两个变量,分别从两个方向同时遍历数据,然后进行数据交换;
(2)实践中,在对少量元素排序时(3 <= N <= 20),插入排序效率要高于快速排序,所以一个改进的方式
是,快排中元素在比较少时,用插入排序;

不行,我还要默写一遍快排,八嘎!

void QuickSort(int A[], int left, int right)
{
    int low = left;
    int high = right;
    int qvoit = A[left]; // 记录枢纽元素
    while(low < high)
    {
        while(low < high && qvoit < A[high])
            --high;
        while(low < high && qvoit > A[low])
            ++low;
        if(low < high)
        {
            int tmp = A[low];
            A[low] = A[high];
            A[high] = tmp;
        }
    } 
    A[left] = A[low];
    A[low] = tmp;

    QuickSort(A, left, low - 1);
    QuickSort(A, low + 1, right);
}

// TODO

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值