美文网首页
排序算法

排序算法

作者: 小张同学_loveZY | 来源:发表于2018-08-17 15:38 被阅读0次

    十大排序算法总结


    基础交换函数

    void swap(int& temp1, int& temp2)
    {
        temp1 = temp1 ^ temp2;
        temp2 = temp1 ^ temp2;
        temp1 = temp1 ^ temp2;
    }
    

    冒泡排序

    算法流程
    • 比较相邻元素,如果满足条件则交换(视从小到大排,和从大到小排定)
    • 顺序比较,直到最后一位,则最后一位已排好序
    • 重复以上步骤,但已经排好的不参与比较。
    复杂度分析
    • 时间复杂度(平均): O(n^2)
    • 时间复杂度(最好): O(n) 初始已排序(改进算法才可以)
    • 时间复杂度(最坏): O(n^2)
    • 是否稳定: 稳定
    C代码

    冒泡排序

    void bubbleSort(int array[], int length) 
    {
    
        for (int i = 0; i<length-1; i++)  // 这一步控制步长
        {
            for (int j = 0; j < length -1 -i;j++) // 这一步前后排序
            {
                if (array[j] > array[j+1])
                {
                    swap(array[j], array[i]);
                }
            }
        }
    }
    

    选择排序

    算法流程
    • 遍历比较确定数组中最小值所在的下标
    • 最小值与第一位未排序好的数交换
    • 重复以上步骤,但已经排好的不参与比较。
    复杂度分析
    • 时间复杂度(平均): O(n^2)
    • 时间复杂度(最好): O(n) 初始已排序(改进算法才可以)
    • 时间复杂度(最坏): O(n^2)
    • 是否稳定: 稳定
    C代码

    选择排序

    void selectSort(int array[], int length) {
        int minIndex;
        for (int i = 0; i < length - 1; i++) {
            minIndex = i;
            for (int j = i + 1; j < length; j++) {
                if ( array[j] < array[minIndex] ) {     // 寻找最小的数
                    minIndex = j;                       // 将最小数的索引保存
                }
            }
            swap(array[i], array[minIndex]);
        }
    }
    

    插入排序

    算法流程
    • 类似斗地主叠排
    • 默认第一个已经排好,待插入的值与前面的比较,若小于,则前后的后移
    • 直到待插入的值大于前一个值
    • 未排序的数重复以上步骤。
    复杂度分析
    • 时间复杂度(平均): O(n^2)
    • 时间复杂度(最好): O(n)
    • 时间复杂度(最坏): O(n^2)
    • 是否稳定: 稳定
    C代码

    插入排序

    void insertSort(int array[], int length)
    {
        int preIndex, current;
        for (int i = 1; i < length; i++) {
            preIndex = i - 1;
            current = array[i];
            while (preIndex >= 0 && array[preIndex] > current) {
                array[preIndex + 1] = array[preIndex];
                preIndex--;
            }
            array[preIndex + 1] = current;
        }
    }
    

    希尔排序

    算法流程
    • 确定间隔数组,这里采用3的倍数递增法,可换,最后一个间隔需为1
    • 按照不同的间隔进行直接插入排序
    复杂度分析
    • 时间复杂度(平均): O(n^1.3) 统计结果
    • 时间复杂度(最好): O(n)
    • 时间复杂度(最坏): O(n^2)
    • 是否稳定: 不稳定 间隔排序导致
    C代码

    希尔排序

    void  shellSort(int array[], int length)
    {
        int gap = 1, current;
        int i, preIndex;
        while (gap < length / 3) {          // 动态定义间隔序列
            gap = gap * 3 + 1;              // 保证除3的时候会取到1
        }
        for ( ; gap > 0; gap = floor(gap / 3 ) ) {
            // 间隔为gap的直接插入排序,这里除了前几个数外,都需要与之前的比较
            for (i = gap; i < length; i++) {
                current = array[i];
                preIndex = i - gap;
                // 注意取值范围
                while (preIndex >= 0 && array[preIndex] > current) {
                    array[preIndex + gap] = array[preIndex];
                    preIndex = preIndex - gap;
                }
                array[preIndex + gap] = current;
            }
        }
        
    }
    

    归并排序

    算法流程
    • 参考算法导论的分而治之的思想
    • 递归将大的数组分为左右两部分,一直分到只剩最后一个值
    • 逆递归merge排序,开辟新空间将两个数组最小值比较,排序到原数组空间中
    • 技巧是设置无穷大的哨兵值,毕竟不断的判断是否数组已经遍历到结尾
    复杂度分析
    • 时间复杂度(平均): O(nlog(n))
    • 时间复杂度(最好): O(nlog(n))
    • 时间复杂度(最坏): O(nlog(n))
    • 是否稳定: 稳定
    C代码

    合并函数

    void merge(int array[], int begin, int middle, int end) {
        int len1 = middle - begin + 1;
        int len2 = end - middle;
        int i, j;
        // 定义中间变量
        int *arr1 = new int[len1 + 1];
        int *arr2 = new int[len2 + 1];
    
        // 赋初值
        for (i = 0; i < len1; i++)
        {
            *(arr1 + i) = array[begin + i];
        }
        for (j = 0; j < len2; j++)
        {
            *(arr2 + j) = array[middle + j + 1];
        }
        // 设置哨兵
        arr1[len1] = 10000;
        arr2[len2] = 10000;
    
        // 从最前面遍历
        i = 0;
        j = 0;
        for (int k = begin; k <= end; k++)
        {
            if (arr1[i] < arr2[j])
            {
                array[k] = arr1[i];
                i++;
            }
            else
            {
                array[k] = arr2[j];
                j++;
            }
        }
    
        delete arr1;
        delete arr2;
    }
    

    归并排序

    void mergeSort(int array[], int begin, int end)
    {
        int middle = floor((end + begin) / 2);
        // 先分后和
        if (begin < end) {
            mergeSort(array, begin, middle);
            mergeSort(array, middle + 1, end);
            merge(array, begin, middle, end);
        }
    
    }
    

    快速排序

    算法流程
    • 选择第一个为基数,将余下的数按照是否大于或者小于,归于两边
    • 为了使用原空间,采用左右震荡比较方式比较
    • 最小值与第一位未排序好的数交换
    • 分左右递归以上步骤。
    复杂度分析
    • 时间复杂度(平均): O(nlog(n))
    • 时间复杂度(最好): O(n^2) 初始无序
    • 时间复杂度(最坏): O(nlog(n))
    • 是否稳定: 不稳定 左右震荡导致
    C代码

    快速排序

    void quickSort(int array[], int left, int right)
    {
    
        if (left < right) {
            int temp = array[left];
            int indexL = left;
            int indexR = right;
            while (indexR > indexL)
            {
                // 只要有涉及下标运算,都需要判断
                // 右振荡
                while (indexR > indexL && array[indexR] >= temp)
                {
                    indexR--;
                }
                if(indexR > indexL)
                    array[indexL++] = array[indexR];
    
                // 左振荡
                while (indexR > indexL  && array[indexL] < temp)
                {
                    indexL++;
                }
                if (indexR > indexL)
                    array[indexR--] = array[indexL];
            }
    
            // 计算完后 indexR = indexL = 最中间的下标 
            array[indexR] = temp;
    
            // 递归
            quickSort(array, left, indexR - 1);
            quickSort(array, indexR + 1, right);
        }
    
    }
    

    堆排序

    算法流程
    • 主要过程分为调整堆,将为排好序的最大值交换到已排好序的最后
    • 重复以上步骤,但已经排好的不参与比较。
    • 这里一个技巧就是利用 二叉堆,根节点与子节点的关系。
    复杂度分析
    • 时间复杂度(平均): O(nlog(n))
    • 时间复杂度(最好): O(nlog(n))
    • 时间复杂度(最坏): O(nlog(n))
    • 是否稳定: 不稳定 调整导致
    C代码

    堆排序

    void adjustHeap(int array[], int len)
    {
        int maxIndex, rootIndex, subLeftIndex, subRightIndex;
        // 从下往上调整
        for (int i = len / 2; i > 0; i--){
            // C的下标从0开始
            rootIndex = i - 1;
            maxIndex = rootIndex;
            subLeftIndex = 2 * i -1;  
            subRightIndex = 2 * i;
            if (array[maxIndex] < array[subLeftIndex])
                maxIndex = subLeftIndex;
            // 右子节点需要判断是否越界
            if ( subRightIndex< len && array[maxIndex] < array[subRightIndex])
                maxIndex = subRightIndex;
            // 根节点与最大节点交换
            if( maxIndex != rootIndex)
                swap(array[rootIndex], array[maxIndex]);
        }
    }
    
    void heapSort(int array[], int len)
    {
        int adjustLen = len;
        for (int i = 0; i < len - 1 ; i++) {
            adjustHeap(array, adjustLen);
            // C的下标从0开始的
            swap(array[0], array[adjustLen-1]);
            adjustLen--;
        }
    
    }
    

    计数排序

    算法流程
    • 条件限制: 待排序数组一定是一定范围内的整数
    • 首先取得最大最小值,确定辅助数组大小k。
    • 遍历待排序数组,与值对应,辅助数组相应位置+1。遍历后辅助数组相应下标存放值的数目
    • 遍历将值按顺序存回原数组,则排序完成
    复杂度分析
    • 时间复杂度(平均): O(n+k)
    • 时间复杂度(最好): O(n+k) 初始已排序(改进算法才可以)
    • 时间复杂度(最坏): O(n+k)
    • 是否稳定: 稳定
    C代码

    计数排序

    void countSort(int array[], int len)
    {
    
        int minValue = array[0];
        int maxValue = array[0];
        // 获得最小最大值,确定排序边界
        for (int i = 1; i < len; i++) {
            if (array[i] < minValue)
                minValue = array[i];
            if (array[i] > maxValue)
                maxValue = array[i];
        }
        
        int countLen = maxValue - minValue + 1;
        int * countArray = new int[countLen];
        // 清0
        for (int i = 0; i < countLen; i++) {
            countArray[i] = 0;
        }
        // 计算数目
        for (int i = 0; i < len; i++) { 
            countArray[array[i] - minValue] ++;
        }
    
        // 计算数目
        int j = 0;
        for (int i = 0; i < countLen; i++) {
            while ( countArray[i] != 0 )
            {
                array[j++] = i + minValue;
                countArray[i]--;
            }
        }
    
        delete countArray;
    }
    

    桶排序

    算法流程
    • 基于分组排序思想
    • 设置一个定量的数组当作空桶
    • 遍历输入数据,并且把数据一个一个放到对应的桶里去
    • 对每个不是空的桶进行排序;
    • 把排好序的数据拼接起来
    复杂度分析
    • 时间复杂度(平均): O(n+k)
    • 时间复杂度(最好): O(n)
    • 时间复杂度(最坏): O(n^2)
    • 是否稳定: 稳定
    C代码

    基数排序

    算法流程
    • 取得数组中的最大数,并取得位数
    • 从最低位开始取每个位组成 待排数组
    • 待排数组进行计数排序
    复杂度分析
    • 时间复杂度(平均): O(n*k)
    • 时间复杂度(最好): O(n*k)
    • 时间复杂度(最坏): O(n*k)
    • 是否稳定: 稳定
    C代码

    相关文章

      网友评论

          本文标题:排序算法

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