排序算法C#实现之快速排序详解

【任务目标】

将一组大规模无序数组变为有序

【快速排序原理】

  1. 在数组中随机选择一个数作为基准数temp,
  2. 在数组中从后往前找一个比temp小的数lo,交换lo和temp
  3. 在数组中从前往后找一个比temp大的数hi,交换temp和hi
  4. 重复2、3找lo和hi,直到找不到这样的数lo,hi。此时temp左边的数都<=它,右边的数都>=它。此时temp所在位置就是数组有序后其应该在的位置
  5. 将temp左边的数看做一个无序数组,重复步骤1-4,又会得到一个新的temp
  6. 将temp右边的数看做一个无序数组,重复步骤1-4,又会得到一个新的temp
  7. 得到新的temp后再重复步骤5、6,直到temp左边和右边都没有无序数组了,此时整个数组有序

将上述步骤转换为程序语言时,有些地方要注意:

  1. 在步骤2,3中,temp的位置在不停地被交换,只有在步骤4中找到位置时才确定其所在。而在程序中把temp取出,相当于空出来一个位置,把接下来要和temp交换的位置处的数值赋值给这个空位置即可。
  2. 在步骤2中从后往前找,实际上就是数组索引从最大值不断减小找;在步骤3中从前往后找,实际上就是数组索引从最小值不断增大来找
  3. 步骤5,6中的左边无序数组的索引最小值就是当前数组的最小值,最大值是temp所在位置索引减1;右边无序数组的索引最小值是temp所在位置索引加1,最大值是当前数组的最大值
  4. 步骤5-7显然是要递归

【快速排序原理概括】

通过不断比较将小数前移大数后移来将随机选取的基准数放置在其在有序数组中应该在的位置,通过递归调用将不断地把随机选取的基准数放置在其所在数组有序时应该在的位置。

【代码实现】

using System;

namespace Sort
{
    class Program
    {
        static void Main(string[] args)
        {
            int[] A = new int[30];
            Random ra = new Random();
            for (int i = 0; i < 30; i++)
            {
                A[i] = ra.Next(200);
            }
            Program ps = new Program();
            ps.QuickSort(A,0,A.Length-1);
            Console.WriteLine("排序结果:");
            foreach (int a in A)
            {
                Console.Write(a + " ");
            }
            bool isSorted = true;
            for (int i = 0; i < A.Length - 1; i++)
            {
                if (A[i] > A[i + 1])
                    isSorted = false;
            }
            Console.Write(isSorted);
            Console.ReadKey();
        }

        public void QuickSort(int[] A,int lo,int hi)
        {
            if (lo > hi)//递归退出条件
            {
                return;
            }
            int i = lo;
            int j = hi;
            int temp = A[i];//取得基准数,空出一个位置
            while (i<j)//当i=j时推出,表示temp左边的数都比temp小,右边的数都比temp大
            {
                while (i<j&&temp<=A[j])//从后往前找比temp小的数,将比temp小的数往前移
                {
                    j--;
                }
                A[i] = A[j];//将比基准数小的数放在空出的位置,j的位置又空了出来
                while (i<j&&temp>=A[i])//从前往后找比temp大的数,将比temp大的数往后移
                {
                    i++;
                }
                A[j] = A[i];//将比基准数大的数放在hi空出来的位置,如此,i所在的位置又空了出来
            }
            A[i] = temp;
            QuickSort(A,lo,i-1);//对lo到i-1之间的数再使用快速排序,每次快速排序的结果是找到了基准数应该在的位置
            //其左边的数都<=它,右边的数都>=它,它此时在数组中的位置就是排序好时其应该在的位置。
            QuickSort(A,i+1,hi);//对i+1到hi之间的数再使用快速排序
        }
   }
}

【实现结果】

【快速排序改进】

1.虽然文中说基准数可以随机选取,但在代码时对递归调用时的每个无序数组选取的都是其第一个元素。你当然也可以选择中间的元素,temp=A[(lo+hi)/2]即可。面对不同的数据,具体怎么来选择这个随机基准数没有特定的方法。一般就取第一个元素或中间元素即可。

随机基准数选取的不好,可能出现这样的结果(以选取第一个元素为例):比较了一圈发现,基准数只向后移动了两三位就到了其应在位置。那么其左边的无序数组很小,右边的无序数组很大。在为右边的无序数组选择的基准数找位置时,要找很多次。这就增加了计算时间。最好是每次为基准数找好位置时,其位置为当前数组的最中间,那样左右两边的无序数组大小相同。

2.不断递归调用时,当前的无序数组规模是在不断减小的,当规模减小到一定程度可以用插入排序代替快速排序。插入排序在小规模数据中排序速度更快。

 

 

 

  • 3
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值