十大基础排序 · 四 --- 快速排序(不稳定)挖坑填补法+区间分割法+3种优化方法

来源:互联网 发布:软件安装手册 编辑:程序博客网 时间:2024/05/17 10:27

1. 分析

/*4. 快速排序(QuickSort)#平均时间复杂度: O(nlogn) #最坏时间复杂度:O(n2) (有序的情况)#空间复杂度:需要一个栈空间,    若每趟排序将记录均匀分割成两个相近的子序列,则栈的最大深度为 向下取整[logn]+1;    若偏向一边, 最坏情况,栈最大深度为n;    在一趟分割后比较分割后的长度,先对短序列排序,则栈最大深度为O(logn);#特点: 快速排序是比较次数最少的排序,当待排数组基本有序时退化为冒泡排序。#基本思想: 快速排序是对冒泡排序的一种改进。    通过一趟排序将待排记录分割成独立两部分,其中一部分记录关键字均比另一部分记录的关键字小。    则可分别对这两部分记录继续进行排序,以达整个序列有序。实现方法:递归#方法一:挖坑填补法        1. 选取一个标记(第一个点)        2. 从后向前找第一个比标记小的,然后放到 空出来的位置        3. 从前向后遍历,找第一个比标记大的,然后放到空出来的位置        4. 继续从后向前找,重复2        5. 继续从前向后找大的,重复3        6. 直到 前后的 遇到,该位置就是被标记数字的位置;        7. 一趟完成,把数组分为大于标记和小于标记两部分;        8,重复1-7#方法二:区间分割法        1. 取最后一个位置标记,用nSmall标记小区间大小,i 用来遍历数组;        2. 遍历值小于标记值:小区间的下一个不是当前位置,需要交换,否则直接小区间位置+1        3. 如此循环到  标记位置(最后一个元素)        4. 最后一个元素放到 s+1 的位置;优化1:降低小概率事件(最后一个元素就是最大值)        可取“前中后”三个位置的值进行比较,把中间值交换到最后一个元素位置;优化2:减少系统异常(递归带来的问题)        可用 栈+循环 代替递归优化3:元素过少,选择插入排序。*/

2. 源码

int Sort(int *arr, int nLow, int nHigh);int Sort2(int *arr, int nLow, int nHigh);void QuickSort(int*arr, int nLow, int nHigh){    if(arr == NULL || nLow < 0 || nHigh < 0)        {        return ;    }    //递归结束条件    if( nLow >= nHigh)        return ;    int nStandard = Sort(arr, nLow, nHigh);    QuickSort(arr, nLow, nStandard -1);    QuickSort(arr, nStandard+1, nHigh);}//方法1: 挖坑填补法int Sort(int *arr, int nLow, int nHigh){        //1. 选取一个标记(第一个点)        int nMark = arr[nLow];        while(nLow < nHigh)        {            //2. 从后向前找第一个比标记小的,然后放到 空出来的位置            while(nLow < nHigh && arr[nHigh] >= nMark)                nHigh--;            arr[nLow] = arr[nHigh];            //3. 从前向后遍历,找第一个比标记大的,然后放到空出来的位置            while(nLow < nHigh && arr[nLow] < nMark)                nLow++;            arr[nHigh] = arr[nLow];             //4. 继续从后向前找,重复2            //5. 继续从前向后找大的,重复3        }//6. 直到 前后的 遇到,该位置就是被标记数字的位置;        arr[nLow] = nMark;        //7. 一趟完成,把数组分为大于标记和小于标记两部分;        return nLow;}//方法2: 区间分割法int Sort2(int *arr, int nLow, int nHigh){    //1. 取最后一个位置标记,用nSmall标记小区间大小,i 用来遍历数组;    int nMark = arr[nHigh];    int nSmallIndex = nLow-1;    int i;    for(i = nLow; i< nHigh; i++)    {        //2. 遍历值小于标记值:小区间的下一个不是当前位置,需要交换,否则直接小区间位置+1        if(arr[i] < nMark)        {            if(++nSmallIndex != i)            {                arr[i] = arr[nSmallIndex] ^ arr[i];                arr[nSmallIndex] = arr[nSmallIndex] ^ arr[i];                arr[i] = arr[nSmallIndex] ^ arr[i];            }        }        //3. 如此循环到  标记位置(最后一个元素)    }//i = nHigh;    //4. 最后一个元素放到 s+1 的位置;    if(++nSmallIndex != nHigh)    {        arr[nHigh] = arr[nHigh] ^ arr[nSmallIndex];        arr[nSmallIndex] = arr[nHigh] ^ arr[nSmallIndex];        arr[nHigh] = arr[nHigh] ^ arr[nSmallIndex];    }    return nSmallIndex;}
阅读全文
0 0
原创粉丝点击