学过的算法中最快捷——快速排序法

前言

       上次总结了其他的三种算法:选择排序、冒泡排序和插入排序,这次总结一个更加高效的排序算法——快速排序法,如果想要了解其余三种算法,请移步c#版选择法、冒泡法、插入法和快速排序法分析与对比


快速排序法

步骤:

  • 1.随便找一个基准数,一般都拿左边第一个数当做基准数
  • 2.给基准数找到一个合适的位置,让其左边的数都小于它,右边的数都大于它
  • 3.这个基准数的位置自然将队列分为了两部分,再对这两部分分别进行步骤一和步骤二,直到排序完成
现在我们来看看如何实现:
  • 首先我们以第一个数为基准,也就是5
  • 定义两个变量i和j,j从右往左找一个比5小的数,找到4停止;i从左向右找一个比5大的数,也就是7停止;
  • 将4和7交换位置
  • 两个变量继续寻找,这里需要强调一点,一定是让j先从右边开始找,这个之后再做解释
  • 这是j找到了1,而i与j相遇了,代表探测结束,这时让基准数与1进行位置交换,通过第一次的探测,我们已经找到了基准数在队列中的位置,这时的队列为1,4,0,3,5,7,9,6,,可以发现,5对左边都是比他小的数,而右边都是比他大的数
  • 队列以“5”为分界点,分成了两部分,我们在分别对这两部分应用之前的步骤,知道队列排序完成

学过的算法中最快捷——快速排序法_第1张图片

为什么一定要J先找?
我们看下边这种情况,如果i先找,那么i和j将会在“7”相遇,这时将二者交换,那么5的左边就不是都比他小的数了


学过的算法中最快捷——快速排序法_第2张图片


之后左边再次执行之前的步骤:(右边同理)
画下划线的数字是基准数,红色的是分界点


学过的算法中最快捷——快速排序法_第3张图片

注意:
       队列不断的被归为的基准数分为两部分的时候,左右两部分通过递归调用来完成排序,也就是说不断的调用自己来完成排序


代码

 /// 
        /// 快速排序法
        /// 
        /// 
        /// 
        private void button4_Click(object sender, EventArgs e)
        {
            //哈希表转整数数组
            int[] s = hs.ToArray();
            DateTime time1 = DateTime.Now;

            int low=0;                 //记录目标数组的起始位置
            int high=s.Length-1;   //记录目标数组的结束位置

            QuickSortFunction(s, low, high);

            DateTime time2 = DateTime.Now;
            textBox4.Text = DateDiff(time1, time2);

            for (int i = listBox1.Items.Count - 1; i >= 0; i--)
            {
                listBox1.Items.RemoveAt(i);
            }
            for (int i = 0; i < s.Length; i++)
            {

                this.listBox1.Items.Add(s[i]);
            }
        }


         /// 
         /// 快速排序过程
         /// 
         /// 数组
         /// 低位目标数组下标
         /// 高位目标数组下边
        private static void QuickSortFunction(int[] array, int low, int high)
         {
                 int keyValuePosition;   //记录关键值的下标
 
                 //当传递的目标数组含有两个以上的元素时,进行递归调用。(即:当传递的目标数组只含有一个元素时,此趟排序结束)
                 if (low < high) 
                 {
                     keyValuePosition = keyValuePositionFunction(array, low, high);  //获取关键值的下标(快排的核心)
 
                     QuickSortFunction(array, low, keyValuePosition - 1);    //递归调用,快排划分出来的左区间
                     QuickSortFunction(array, keyValuePosition + 1, high);   //递归调用,快排划分出来的右区间
                 }
         }

        /// 
        /// 找出关键值位置
        /// 
        /// 数组
        /// 低位下标
        /// 高位下标
        /// 关键值下标
        private static int keyValuePositionFunction(int[] array, int low, int high)
         {
             int i = low;        //记录目标数组的起始位置(后续动态的左侧下标)
             int j = high;      //记录目标数组的结束位置(后续动态的右侧下标)
 
             int keyValue = array[low];  //数组的第一个元素作为关键值
             int temp;
 
             //当 (左侧动态下标 == 右侧动态下标) 时跳出循环
             while (i< j)
             {
                 while (i < j && array[j] > keyValue)  //必须先从右边开始,逐渐向左移动,直至找到<=keyValue的下标
                 {
                     j--;
                 }
                 while (i < j && array[j] <= keyValue)  //从左边开始,直至找到>=keyValue的下标
                 {
                     i++;
                 }
                 if(i < j)  //如果leftIndex < rightIndex,则交换左右动态下标所指定的值;当leftIndex==rightIndex时,跳出整个循环
                 {
                     temp = array[i];
                     array[i] = array[j];
                     array[j] = temp;
                 }
             }
 
             //当左右两个动态下标相等时(即:左右下标指向同一个位置),此时便可以确定keyValue的准确位置
             temp = keyValue;
             if (temp < array[j])   //当keyValue < 左右下标同时指向的值,将keyValue与rightIndex - 1指向的值交换,并返回rightIndex - 1
             {
                 array[low] = array[j - 1];
                 array[j - 1] = temp;
                 return j - 1;
             }
             else //当keyValue >= 左右下标同时指向的值,将keyValue与rightIndex指向的值交换,并返回rightIndex
             {
                 array[low] = array[j];
                 array[j] = temp;
                 return j;
             }
         }
    


总结:

      之所以快速排序法比较高效是因为他交换的位置不是相邻的交换,而是跨度更宽的位置的交换,这样可以更加精准的确定数的位置,算法很有意思,希望可以学习更多的内容



你可能感兴趣的:(-----,【排序算法】)