zoukankan      html  css  js  c++  java
  • 排序---快速排序

    一、概念

    快速排序由C.A.R.Hoare在1962年提出,是冒泡排序的一种改进。其基本思想为:通过一趟排序将待排序数据分割成独立的两部分,其中一部分的所有值都比另一部分的所有值都小,然后再对分割的两部分分别进行快速排序,整个过程可以递归进行,最终所有数据变为有序序列。

    二、算法要点

    假设待排序数组为a[0], a[1],…a[n-1],快速排序步骤以下:

    1、初始化两个变量i、j,刚开始i = 1,j=n-1。

    2、将第一个元素a[0]作为基准数。

    3、从i开始向后搜索,找到第一个大于基准数的元素a[i]。

    4、从j开始向前搜索,找到第一个小于等于基准数的元素a[j]。

    5、将a[i]与a[j]互换。

    6、重复3到5步骤,直到i = j + 1,此时,j指向的元素是最后一个(从左边算起)小于等于中轴的元素,然后将a[0]与a[j]对换。

    7、序列被基准数分割成两个分区,前面分区全部小于等于基准数,后面分区全部大于基准数。

    8、递归对分区子序列进行快速排序,最终完成整个排序工作。

    每趟快速排序的核心工作是:

    选一个元素作为基准数,然后将所有比它小的数都放到它前面,大于它的数都放在它后面。

    三、算法实现

    实现一:

     1 using System;
     2 using System.Collections.Generic;
     3 
     4 namespace QuickSort
     5 {
     6     class Program
     7     {
     8         static void Main(string[] args)
     9         {
    10             QuickSortUnitTest(13);
    11 
    12         }
    13         private static void QuickSort(List<int>dataList, int left, int right)
    14         {
    15             if(left < right)//递归的边界条件,当left等于right时,元素个数为1个
    16                 {
    17                 int pivot = dataList[left];//最左边的元素作为中轴
    18                 int i = left + 1;
    19                 int j = right;
    20                 int tmp = 0;
    21                 //当i == j时,i和j同时指向的元素还没有与中轴元素判断,
    22                 //小于等于中轴元素,i++,大于中轴元素j--,
    23                 //当循环结束时,一定有i = j + 1, 且i指向的元素大于中轴,j指向的元素小于等于中轴
    24                 while (i <= j)
    25                 {
    26                     while(i <= j && dataList[i] <= pivot)//从前向后找到第一个大于pivot的元素
    27                     {
    28                         i++;
    29 
    30                     }
    31                     while(i <= j && dataList[j] > pivot)
    32                     {
    33                         j--;
    34 
    35                     }
    36                     if(i < j)
    37                     {
    38                         tmp = dataList[i];
    39                         dataList[i] = dataList[j];
    40                         dataList[j] = tmp;
    41                     }                    
    42                 }
    43                 //当循环结束时,j指向的元素是最后一个(从左边算起)小于等于中轴的元素
    44                 //将中轴元素和j所指的元素互换
    45                 tmp = dataList[left];
    46                 dataList[left] = dataList[j];
    47                 dataList[j] = tmp;
    48                 Console.WriteLine();
    49                 foreach (var item in dataList)
    50                 {
    51                     Console.Write($" {item} ");
    52                 }
    53                 Console.WriteLine();
    54                 QuickSort(dataList, left, j - 1);
    55                 QuickSort(dataList, j + 1  , right);
    56             }
    57         }
    58         private static void QuickSortUnitTest(int loopNum)
    59         {
    60             Random random = new Random();
    61             List<int> dataList = new List<int>();
    62             for (int i = 0; i < loopNum; i++)
    63             {
    64                 dataList.Add(random.Next(100));
    65             }
    66             Console.Write("Original data:");
    67             foreach(var item in dataList)
    68             {
    69                 Console.Write($" {item} ");
    70             }
    71 
    72             QuickSort(dataList, 0, dataList.Count - 1);
    73             Console.Write("Quick sorted data:");
    74 
    75             foreach (var item in dataList)
    76             {
    77                 Console.Write($" {item} ");
    78             }
    79             Console.WriteLine();
    80         }
    81     }
    82 }

     实现二:

    基本思想:“挖坑填坑”

    使用两个变量i和j分别指向最左边和最右边的元素,我们将首元素作为中轴,并复制到变量pivot中,这时我们可以将首元素i所在的位置看成一个坑,我们从j的位置从右向左扫描,找一个小于等于中轴

    的元素A[j],来填补A[i]这个坑,填补完成后,拿去填坑的元素所在的位置j又可以看做一个坑,这时我们在以i的位置从前往后找一个大于中轴的元素来填补A[j]这个新的坑,如此往复,直到

    i和j相遇(i == j,此时i和j指向同一个坑)。

    最后我们将中轴元素放到这个坑中。然后,我们按照相同的方法分别对左右两个数组执行相同的操作。

    private static void QuickSort2(List<int>dataList, int left, int right)
            {
                if(left < right)
                {
                    //最左边的元素作为中轴复制到pivot,这时最左边的元素可以看做一个坑
                    int pivot = dataList[left];
                    //注意这里 i = L,而不是 i = L+1, 因为i代表坑的位置,当前坑的位置位于最左边
                    int i = left;
                    int j = right;
                    while(i < j)
                    {
                        //下面面两个循环的位置不能颠倒,因为第一次坑的位置在最左边
                        while (i < j && dataList[j] > pivot)
                        {
                            j--;
                        }
                        //填A[i]这个坑,填完后A[j]是个坑
    
                        //注意不能是A[i++] = A[j],当因i==j时跳出上面的循环时
    
                        //坑为i和j共同指向的位置,执行A[i++] = A[j],会导致i比j大1,
    
                        //但此时i并不能表示坑的位置 
                        dataList[i] = dataList[j];
                        while(i < j && dataList[i] <= pivot)
                        {
                            i++;
                        }
                        dataList[j] = dataList[i];
                    }
                    //循环结束后i和j相等,都指向坑的位置,将中轴填入到这个位置
                    dataList[i] = pivot;
                    QuickSort2(dataList, left, i - 1);
                    QuickSort2(dataList, i + 1, right);
                   
    
                }
            }

     更多方法请参考:

    https://www.cnblogs.com/nullzx/p/5880191.html

  • 相关阅读:
    Linux之基础系统优化
    Linux之shell命令
    Django解决跨域问题
    Django中使用geetest验证
    python2与python3的区别
    一个长得很丑的登录和注册
    Django组件-forms组件
    Django组件-中间件
    cookie、session与用户认证组件
    jquery练习
  • 原文地址:https://www.cnblogs.com/3xiaolonglong/p/10375022.html
Copyright © 2011-2022 走看看