随机快速排序(内嵌插入排)

来源:互联网 发布:小学生笔顺软件下载 编辑:程序博客网 时间:2024/06/05 19:01

1.思路
在快速排序算法的递归实现中,存在一种不太好的现象:随着递归层层深入,大量数据被分割成了小数组;快排对于大数组的划分可以迅速地将元素移动到它正确位置的附近,比如说对1024进行一次均等划分,那么某个元素可能会移动数百个单位位置,若进行4次均等划分,元素在正确位置上的概率就从1/1024骤升到1/64,考虑到64与1024的绝对数值,这是相当高的效率;然而对于小数组,快速排序的效率就不那么理想了,对于16个元素的数组,快速排序也要划分4次才能把它移动到正确的位置上,相对于之前几百个位置的移动,小数组排序一次只能移动几个单位的位置。

换句话说,快速排序对少量数据的划分远不如它对大量数据的划分这么划算,当排序进入到小数组阶段后,它将多次因为这些小数组而频繁调用自身,但获得的收益并不大。我姑且把这种现象叫做“小数组的边际效益“

因此,在待排序数组长度小于某一阈值K时(代码中K = 3),用插入排序替代快速排序,取长补短让代码效率达到最高,其中任然选用随即快速排序。

2.完整代码

#include <iostream>#include <ctime>using namespace std;const int K = 3;void InitArr(int *nArr, int nLen) {     //初始化数组    //srand(time(NULL));    for(int i = 0; i < nLen; ++i) {        //nArr[i] = rand() % 100;        nArr[i] = i;    }}void PrintArr(int *nArr, int nLen) {    for(int i = 0; i < nLen; ++i) {        cout << nArr[i] << " ";    }    cout << endl;}void Swape(int *p1, int *p2) {    int nTmp = *p1;    *p1 = *p2;    *p2 = nTmp;}void RandomSort(int *nArr, int nLen) {    srand(time(NULL));    for(int i = 0; i < nLen; ++i) {        int nIndex = rand() % nLen;        Swape(&nArr[i], &nArr[nIndex]);        //Sleep(2000);                       //等待2s,更新随机种子    }}//递增排序int PartitionUp(int *nArr, int nLeft, int nRight) {    int nKey = nArr[nRight];    int i = nLeft - 1;    for(int j = nLeft; j < nRight; ++j) {        if(nArr[j] < nKey) {    //反正不稳定,就用<代替≤,省取相等情况下多余的交换运行时间            i++;            Swape(&nArr[j], &nArr[i]);     //不稳定排序的原因 eg:1 5 8 8 6 11 7        }    }    Swape(&nArr[i + 1], &nArr[nRight]); //将主元素插入到中间    return i + 1;}//递减排序int PartitionDown(int *nArr, int nLeft, int nRight) {    int nKey = nArr[nRight];    int i = nLeft - 1;    for(int j = nLeft; j < nRight; ++j) {        if(nArr[j] > nKey) {            ++i;            Swape(&nArr[i], &nArr[j]);          //不稳定排序的原因        }    }    Swape(&nArr[i + 1], &nArr[nRight]);       //将主元素插入到中间    return i + 1;}int RandomPartition(int *nArr, int nLeft, int nRight) {    srand(time(NULL));    int nKey = rand() % (nRight - nLeft + 1) + nLeft;   //随机选择【nLeft, nRight】内的某一个数    Swape(&nArr[nKey], &nArr[nRight]);                    //将选择的数与nArr[nRight]交换,即将选择的数作为Key值进行排序    return PartitionUp(nArr, nLeft, nRight);}void InsertSort(int *nArr, int nLeft, int nRight) {    for(int i = nLeft + 1; i <= nRight; ++i) {        int nTmp = nArr[i];        int j;        for(j = i - 1; j >= nLeft && nArr[j] > nTmp; --j) {            nArr[j + 1] = nArr[j];        }        nArr[j + 1] = nTmp;    }}void QuickSort(int *nArr, int nLeft, int nRight) {    if(nLeft < nRight) {        //分解        int nTmpPos = PartitionUp(nArr, nLeft, nRight);        //解决、合并        QuickSort(nArr, nLeft, nTmpPos - 1);        QuickSort(nArr, nTmpPos + 1, nRight);    }}void QuickSortRandom(int *nArr, int nLeft, int nRight) {    if(nLeft < nRight) {        int nTmpPos = RandomPartition(nArr, nLeft, nRight);        QuickSortRandom(nArr, nLeft, nTmpPos - 1);        QuickSortRandom(nArr, nTmpPos + 1, nRight);    }}void QuickInsertSortRandom(int *nArr, int nLeft, int nRight) { //主要代码    if(nLeft < nRight) {        if(nRight - nLeft > K) {            int nTmpPos = RandomPartition(nArr, nLeft, nRight);            QuickInsertSortRandom(nArr, nLeft, nTmpPos - 1);            QuickInsertSortRandom(nArr, nTmpPos + 1, nRight);        } else {            InsertSort(nArr, nLeft, nRight);  //换用插入排序        }    }}int main() {    int Arr[1000];    int Len = 20;    InitArr(Arr, Len);//    PrintArr(Arr, Len);    RandomSort(Arr, Len);    PrintArr(Arr, Len);//    QuickSort(Arr, 0, Len - 1);    QuickInsertSortRandom(Arr, 0, Len - 1);//    InsertSort(Arr, 0, Len - 1);    PrintArr(Arr, Len);    return 0;}

3.运行结果与算法效率同前文。

阅读全文
0 0
原创粉丝点击