美文网首页
算法:排序(一)

算法:排序(一)

作者: 熊白白 | 来源:发表于2017-07-02 16:57 被阅读17次

    部分图片来源:牛客网
    本文如果涉嫌侵权,请告知笔者第一时间做处理。

    排序问题可以说是最经典的算法问题了。从排序问题上可以看到人们对效率孜孜不倦的渴求,也算是算法进化史的一个小小的缩影。

    冒泡排序、选择排序与插入排序

    早期的算法时间复杂度为O(N^2),它们用笨拙和单纯的方式,跨出了算法历史上小小的一步。

    冒泡排序

    通过依次比较两两相邻的元素,并把两者中较大值交换[注1]至右侧,这样遍历过一次数组后,就会把最大值移动到队尾。对数组剩下的部分继续做此操作,直至排序完成。


    CODE

    int* bubbleSort(int* A, int n) {
        //长度为n的数组需要遍历n-1次
        for(int i=0;i<n-1;++i){
            //遍历开始时右侧已排好i个元素,故待处理区间为[0,n-i)
            //因为需要j+1<n-i所以j的取值是[0,n-i-1)
            for(int j=0;j<n-i-1;++j){
                if(A[j]>A[j+1]){
                    swap(A[j],A[j+1]);
                }
            }
        }
        return A;
    }
    

    要点

    • 两层循环
    • 外层每次循环选出当前范围内的最大值移至队尾
    • 内层依次遍历当前范围,两两比较相邻元素
    • 外层计数范围:[0,n-1)
    • 内层计数范围:[0,n-i-1)

    选择排序

    通过选出当前范围内的最小值并交换到队首,对剩下的部分不断重复该操作直至排序结束。

    CODE

    int* selectionSort(int* A, int n) {
        //长度为n的数组需要遍历n-1次
        for(int i=0;i<n-1;++i){
            //每次找出最小值的下标
            int min=i;
            //A[i]暂定为最小值,故j遍历范围是[i+1,n)
            for(int j=i+1;j<n;++j){
                if(A[j]<A[min])
                    min=j;
            }
            //交换
            swap(A[min],A[i]);
        }
        return A;
    }
    

    要点

    • 两层循环
    • 外层每次循环把当前范围内的最小值移至队尾
    • 内层依次遍历当前范围,选出最小值
    • 外层计数范围:[0,n-1)
    • 内层计数范围:[i+1,n)

    插入排序

    待处理元素左侧是一个已经排好序的数组(初始长度为1),从右向左遍历该有序数组,找到合适的位置插入待处理元素,直至所有元素处理完毕。

    CODE

    int* insertionSort(int* A, int n) {
        //初始时认为A[0]是有序数列,待处理元素范围是[1,n)
        for(int i=1;i<n;i++){
            int get=A[i];
            //待处理元素的插入位置从i-1到0逆序搜索
            int j=i-1;
            //搜索条件:j未越界且位置j上的元素大于待处理元素
            while(j>=0&&A[j]>get){
                //相当于元素右移一位
                A[j+1]=A[j];
                j--;
            }
            //循环结束时若j越界:需插入到A[0]处;
            //否则A[j]<=get需要插入到A[j+1]处
            A[j+1]=get;
        }
        return A;
    }
    

    要点

    • 两层循环
    • 外层循环遍历待处理的元素
    • 内层循环遍历左侧有序序列,找到合适的位置插入待处理元素
    • 插入位置的选择:大于待处理元素的部分右移一位,直至越界或遇见不大于待处理元素的部分。
    • 特别需要提出的是,对于一个近乎有序的序列,插入排序的效率很高

    附注

    [1] 交换代码如下

    void swap(int& a,int& b){
            //加上不等判断来提高性能
            if(a!=b){
                int t=a;
                a=b;
                b=t;
            }
        }
    

    相关文章

      网友评论

          本文标题:算法:排序(一)

          本文链接:https://www.haomeiwen.com/subject/floncxtx.html