排序算法

Posted cimuhuashuimu

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了排序算法相关的知识,希望对你有一定的参考价值。

目前不断更新中

每种算法的思想以及复杂度都在描述代码上方,算法描述图有时间会补上

template<class T>
class sort {
public :
    //插入排序:
    void InsertSort(T r[], int n) {  
        //思想:将数列分为有序和无序,从前往后逐个增加有序数列个数,每次将无序数列第一个划入有序数列最后一个,在有序数列进行排序
        //最坏情况比较Σi[2,n]换位Σ(i+1)[2,n] n(n+1)/2-1+n(n+1)/2-3 = n(n+1)-4
        //最好情况求和(n-1)
        //平均时间 (n(n+1)-4)+(n-1)/2 ≈ n^2 空间 1   稳定排序
        //适合小于千规模排序 基本有序数列
        for (int i = 2; i <= n; i++) {   //逐个将无序序列第一个元素加入有序序列,初始默认第一个已在有序序列
            if (r[i] < r[i - 1]) {
                r[0] = r[i];
                int j ;
                for (j = i-1; r[0] < r[j]; j--) {    //将有序序列新加入的元素进行排序,使用哨兵优化
                    r[j + 1] = r[j];
                }
                r[j + 1] = r[0];
            }
        }
    }
    void ShellInsertSort(T r[], int n) {
        //思想:将数列分为几组,每组每个元素间隔n/2,对每组进行简单插入排序,再将间隔变为n/4 ……,直到间隔为1即只有一组
        //时间复杂度不定 在n^2与nlog2 3 之间(大概为n^1.3) 空间 1 不稳定(相同的关键码会变换位置)
        //比简单插入排序更优
        for (int d = n / 2; d >= 1; d = d / 2) {   //对距离d=n/2进行分组,(1,n/2+1,n/2*2+1,……),(2,n/2+2,……),最后为1,2,……,n
            for (int i = d + 1; i <= n; i++) {      
        //对分好组的直接插入排序,默认每个分组第一个在有序数列,从第一个分组的第二元素开始逐个加入第一分组有序数列,第二个分组第二元素……
                if (r[i] < r[i - d]) {
                    r[0] = r[i];
                    int j;
                    for ( j = i - d; j > 0 && r[0] < r[j]; j = j - d) {
                        r[j + d] = r[j];
                    }
                    r[j + d] = r[0];
                }
            }
        }
    }

    //交换排序:
    void BubbleSort(T r[], int n) {
        //思想:将数列分为有序和无序,有序数列为从后往前逐个增加,在无序中遍历一趟找到最大加入到新增加的有序数列位置
        //最好情况 比较 (n-1)n/2  最坏情况 比较(n-1)n/2 换位 3(n-1)n/2
        //平均时间 5(n-1)n/4 ≈ n^2 空间 1 稳定
        for (int i = 1; i < n; i++) {   //逐步增加有序区的个数,增加到n-1个最后一个自动到有序区
            for (int j = 1; j <= n - i; j++) {  // 交换一趟无序区,将无序区最大加到新增的有序区n-i+1位置(有序区从后往前增加)
                if (r[j] > r[j + 1]) {
                    r[0] = r[j];
                    r[j] = r[j + 1];
                    r[j + 1] = r[0];
                }
            }
        }
    }
    void ImprovBubbleSort(T r[], int n) {
        //思想:在冒泡排序基础上,用pos来指定进入有序区前最后一个交换的位置,来避免无序区的有序部分重复比较
        //在每次对无序区交换一趟已经对部分位置进行交换排序,如果每次pos为无序最后一个则与冒泡相同,如果出现不是无序最后一个,那么pos之后的都可以直接划入有序区
        //最好情况 比较n-1 最坏情况 比较(n-1)n/2 交换3(n-1)n/2
        //平均时间复杂度 (n-1)(2n+1)/2 ≈ n^2 空间复杂度 1 稳定
        int pos = n;
        while (pos != 0) {  //pos及之前的部分为无序区
            int bound = pos;
            pos = 0;
            for (int i = 1; i < bound; i++) {   // 交换一趟无序区,bound位置是每次新增的有序区部分
                if (r[i] > r[i + 1]) {
                    r[0] = r[i];
                    r[i] = r[i + 1];
                    r[i + 1] = r[0];
                    pos = i;            //指向发生交换的位置
                }
            }
        }
    }

    //快速排序:
    //思想:将无序数列进行分块,找到首个元素在有序数列中位置,然后分得左无序数列和右无序数列,再找左和右数列的首个元素的位置,以此类推
    //每次得到的左数列都小于等于轴值pivot,右边大于等于pivot,所以最终将获得整个有序数列
    //最好的情况,每次分区的元素的左右分区个数相等,此时栈层数为log2 n,定位元素时间复杂度为n,总复杂度为nlog2 n
    //最坏情况,正序或逆序,递归栈层数为n-1,定位元素时间复杂度为n,总复杂度为n(n-1) ≈ n^2
    //平均来说复杂度为nlog2 n 栈层数为log2 n  不稳定
    int Partion(T r[], int i, int j) { //分区作用,找到数组首个元素在有序数列中的位置
        //将第一个元素定为pivot,先从后往前比较,如果遇到小的就将值赋给前面的比较位,然后前比较位从前往后遇到大的给后比较位(往返),最后pivot给i=j位
        int pivot = r[i];
        while (i < j) {
            while (i<j && r[j]>=pivot) {
                j--;
            }
            r[i] = r[j];
            while (j > i&& r[i] <= pivot) {
                i++;
            }
            r[j] = r[i];
        }
        r[i] = pivot;        //哨兵优化交换次数
        return i;
    }
    void Qsort(T r[], int i, int j) { // 利用分区函数快速排序
        if (i < j) {
            int pivotloc = Partion(r, i, j);//找到每次的中间位,进行递归
            Qsort(r, i, pivotloc - 1);
            Qsort(r, pivotloc + 1, j);
        }
    }

    //选择排序:

};

以上是关于排序算法的主要内容,如果未能解决你的问题,请参考以下文章

排序算法概述

十大经典排序算法总结(归并排序)

十大经典排序算法总结(桶排序)

十大经典排序算法总结(希尔排序)

十大经典排序算法总结(快速排序)

十大经典排序算法总结(冒泡排序)