快速排序测试(QuickSort)

一. 目的
进行快速排序练习,掌握快速排序的原理。
算法证明:
第一步,数组分为四个区,无序小于关键值区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
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值