快速排序测试(QuickSort)

来源:互联网 发布:simulink数据库 编辑:程序博客网 时间:2024/06/02 13:49

一. 目的
进行快速排序练习,掌握快速排序的原理。
算法证明:
第一步,数组分为四个区,无序小于关键值区A[1]-A[i],无序大于关键值区A[i+1]-A[j],待划分区A[j+1]-A[N-1],关键值区A[N],第一步时,只有两个区域不为空,即带划分区A[1]-A[N-1],关键值区A[N]
第二步:进入循环处理,若存在可以放在无序小区的元素,则将无序大区则将无序大区的下界元素与A[j]交换,此时无序小区的上界增长一。到循环结束序列存在三个不为空区,A[1]-A[i],A[i+1]-A[N-1],将A[i+1]与A[N]交换,此时关键值已经放在合适位置,前面的元素小于关键值,后面的元素大于关键值。
第三步:对前后两个区域进行相同划分,最终每个元素都处在自己的合适位置,算法证明完毕。

二. 实现代码
1、单向划分

        //快速排序标准算法        void QuickSort(T testArray[], int nSize){            LogInfo<T> log = LogInfo<T>();            log.ShowState("原始数组为:");            log.ShowArray(testArray, nSize);            QuickSortSub(testArray, 0, nSize - 1);            log.ShowState("最终数组为:");            log.ShowArray(testArray, nSize);        }        void QuickSortSub(T testArray[], int Begin, int End){            if (Begin < End){                //获取中轴位置,该位置元素以及在位,且区分了两个部分,前面为小值区,后面为大值区                int pivot = QuickSortPartition(testArray, Begin, End);                //对两个区域进行快速排序                QuickSortSub(testArray, Begin, pivot - 1);                QuickSortSub(testArray, pivot + 1, End);            }        }        //快速排序的划分,返回划分位置,划分位置的元素已经在该在的位置        int QuickSortPartition(T testArray[], int Begin, int End){            //单个元素或者没有元素则退出            if (Begin >= End) return 0;            T key = testArray[End];            T tmp(0);            //i记录已经放小于哨兵的元素位置            int i = Begin - 1;            for (int j = Begin; j < End; j++){                //若J元素小于少哨兵值,则将i+1与j交换。                if (testArray[j] < key){                    i++;                    tmp = testArray[i];                    testArray[i] = testArray[j];                    testArray[j] = tmp;                }            }            testArray[End] = testArray[i + 1];            testArray[i + 1] = key;            return i + 1;        }

2、双向遍历,将大元素放在后端,小元素放在前端

        //快速排序双向遍历算法        void QuickSortVerTwoDirection(T testArray[], int nSize){            LogInfo<T> log = LogInfo<T>();            log.ShowState("原始数组为:");            log.ShowArray(testArray, nSize);            QuickSortSubVerTwoDirection(testArray, 0, nSize - 1);            log.ShowState("最终数组为:");            log.ShowArray(testArray, nSize);        }        //双向遍历快速排序        void QuickSortSubVerTwoDirection(T testArray[],int Begin,int End){            if (Begin < End){                //获取划分点                int pivot = QuickSortPartitionTwoDirection(testArray, Begin, End);                QuickSortSubVerTwoDirection(testArray, Begin, pivot - 1);                QuickSortSubVerTwoDirection(testArray, pivot + 1, End);            }        }        //快速排序双向交换法        int QuickSortPartitionTwoDirection(T testArray[], int Begin, int End){            T key = testArray[Begin];//记录划分值            T tmp(0);            while (Begin < End){                //从尾部寻找小于划分值的位置,将该元素放在头部                while (Begin<End && testArray[End]>key)End--;                tmp = testArray[End];                testArray[End] = testArray[Begin];                testArray[Begin] = tmp;                //从头部寻找大于划分元素的位置,将该元素放在尾部                while (Begin < End && testArray[Begin] <= key)Begin++;                tmp = testArray[End];                testArray[End] = testArray[Begin];                testArray[Begin] = tmp;            }            return Begin;        }

3、随机快速排序

        //随机化快速排序        void QuickSortVerRandom(T testArray[], int nSize){            LogInfo<T> log = LogInfo<T>();            log.ShowState("原始数组为:");            log.ShowArray(testArray, nSize);            QuickSortSubVerRandom(testArray, 0, nSize - 1);            log.ShowState("最终数组为:");            log.ShowArray(testArray, nSize);        }        //随机版本快速排序        void QuickSortSubVerRandom(T testArray[], int Begin, int End){            if (Begin < End){                //产生随机下标与关键值(结尾元素)交换                int Index = RandomKeyIndex(Begin, End);                if (Index != End){                    T tmp = testArray[End];                    testArray[End] = testArray[Index];                    testArray[Index] = tmp;                }                //获取划分点                int pivot = QuickSortPartitionTwoDirection(testArray, Begin, End);                QuickSortSubVerRandom(testArray, Begin, pivot - 1);                QuickSortSubVerRandom(testArray, pivot + 1, End);            }        }        //随机版本快速排序划分        int QuickSortPartitionRandom(T testArray[], int Begin, int End){            T key = testArray[End];            T tmp(0);            //i记录已经放小于哨兵的元素位置            int i = Begin - 1;            for (int j = Begin; j < End; j++){                //若J元素小于少哨兵值,则将i+1与j交换。                if (testArray[j] < key){                    i++;                    tmp = testArray[i];                    testArray[i] = testArray[j];                    testArray[j] = tmp;                }            }            testArray[End] = testArray[i + 1];            testArray[i + 1] = key;            return i + 1;        }        //产生一个数据在Begin与End之间        int RandomKeyIndex(int Begin, int End){            srand((unsigned int)time(NULL));//产生一个随机种子。            int Index = rand() % (End - Begin + 1) + Begin;            return Index;        }

输出结果
这里写图片描述

三. 遇到难题
1、初次看到标准快速算法,由于太多变量,导致看起来很费力。
2、对于双向快速排序,只需要划分三个区,没有四个区,用四区划分来看着这个算法有些困难。
四. 经验总结
1、快速排序适用和要求序列相同的序列,就会发生退化,退化为冒泡排序,复杂度O(N^2)
2、随机化快速排序不再将指定特定元素作为关键值。产生更好的效果,对待已经有序的序列不再那么糟糕。
3、快速排序主要影响因素是划分的平衡性。
4、快速排序的平均复杂度为O(nlog(n)),算法不稳地。
五. 后续处理
今天要写另外两篇日记,完成排序算法这一块,然后来一个总结。

六. 参考文献
1、算法导论
2、 八大排序算法 http://blog.csdn.net/abcbig/article/details/42774333

0 0