快速排序 实现 精要 代码 注释

本文主旨

  • 论述快排的要点
  • 证明快排是如何完成排序的
  • 提供更容易理解的分割方法,帮助同学们更好的理解快排的思想和过程

要点

  • 把元素分为小于中值的和大于中值的2段元素分别放到数据段的两边
  • 在对上面的2段元素分别使用快排
  • 当无法分段的时候,因为所有的数据段都是按照由小到大放的,故所有的数据都是由小到大排好序的

精要

  • 分治,分治是好理解的
  • 分割方法,想要理解这个过程,去证明一次原始的快排算法的分割方法能够完成数据分类即可,具体说明看代码注释

分割

  • 找一个中值,随机找,或者用数据段第一个,或者用数据段最后一个
  • 对一段数据的元素进行分类,小的放左边,大的放右边
  • 更好理解的分割函数
    /*
    这个分割函数更加好理解,先把元素分类,然后按照类别逐个放到原始数组对应的数据段
    这个分类函数消耗更多内存
     */
    public int Split2(int[] array, int start, int end)
    {
      var smallBuf = new int[end - start];
      var smallCnt = 0;
      var bigBuf = new int[end - start];
      var bigCnt = 0;
      var midVal = array[end];
    
      for (var i = start; i < end; i++)
      {
        if (array[i] < midVal)
        {
          smallBuf[smallCnt] = array[i];
          smallCnt++;
        }
        else
        {
          bigBuf[bigCnt] = array[i];
          bigCnt++;
        }
      }
    
      var j = start;
      for (var i = 0; i < smallCnt; i++)
      {
        array[j] = smallBuf[i];
        j++;
      }
      array[j] = midVal;
      j++;
      for (var i = 0; i < bigCnt; i++)
      {
        array[j] = bigBuf[i];
        j++;
      }
      return start + smallCnt;
    }
    

实现

namespace DataStructure
{
  /*
  分治法
  
  1 随机找一个值,让要排序的数组范围内的数据比这个值大的放右边,其它放左边
  2 对这个值左边的范围和右边的范围应用操作1

   */
  public class QuickSort
  {
    public int[] Sort(int[] array)
    {
      return Sort(array, 0, array.Length - 1);
    }

    //include start and end
    public int[] Sort(int[] array, int start, int end)
    {
      //数组无法再分割,此时结束
      //一段数据不能分割表明该段数据已经排序完成,又因为每段数据都是按照从小到大放置的,故所有数据排序完成
      if (start < end)
      {
        //分割数组,小的在左边,大的在右边
        var split = Split2(array, start, end);
        //对分割的数组递归调用快速排序
        //当数组无法分割的时候,相当于2个数据被排好序了
        //当数组能分割,说明2段数据已经分大小了
        Sort(array, start, split - 1);
        Sort(array, split + 1, end);
      }
      return array;
    }

    /*
    这个分割函数更加好理解,先把元素分类,然后按照类别逐个放到原始数组对应的数据段
    这个分类函数消耗更多内存
     */
    public int Split2(int[] array, int start, int end)
    {
      var smallBuf = new int[end - start];
      var smallCnt = 0;
      var bigBuf = new int[end - start];
      var bigCnt = 0;
      var midVal = array[end];

      for (var i = start; i < end; i++)
      {
        if (array[i] < midVal)
        {
          smallBuf[smallCnt] = array[i];
          smallCnt++;
        }
        else
        {
          bigBuf[bigCnt] = array[i];
          bigCnt++;
        }
      }

      var j = start;
      for (var i = 0; i < smallCnt; i++)
      {
        array[j] = smallBuf[i];
        j++;
      }
      array[j] = midVal;
      j++;
      for (var i = 0; i < bigCnt; i++)
      {
        array[j] = bigBuf[i];
        j++;
      }
      return start + smallCnt;
    }

    public int Split3(int[] array, int start, int end)
    {
      var smallBuf = new int[end - start];
      var smallCnt = 0;
      var bigBuf = new int[end - start];
      var bigCnt = 0;
      var midVal = array[end];

      for (var i = start; i < end; i++)
      {
        if (array[i] < midVal)
        {
          smallBuf[smallCnt] = array[i];
          smallCnt++;
        }
        else
        {
          bigBuf[bigCnt] = array[i];
          bigCnt++;
        }
      }

      for (var i = 0; i < end - start + 1; i++)
      {
        if (i < smallCnt)
        {
          array[start + i] = smallBuf[i];
          continue;
        }
        if (i == smallCnt)
        {
          array[start + i] = midVal;
          continue;
        }
        var big = bigBuf[i - smallCnt - 1];
        array[start + i] = big;
      }
      return start + smallCnt;
    }

    /*
    分割一个数据段,在数据段中找一个值,这里我们之间用数据段中最后那个值
    把比这个值小的放这个值前面
    把比这个值大的放这个值后面
     */
    public int Split(int[] array, int start, int end)
    {
      var midVal = array[end];
      var i = start;
      var j = end;
      //第一个空位
      var empPos = end;
      //不断的找,直到所有数据都被分类成大或者小
      while (i < j)
      {
        //search a val > midVal from start to end
        //从前往后找到比中值大的
        while (i < j && array[i] <= midVal)
        {
          i++;
        }
        //找到了,换到空位上,此时小的部分空出一个位置,更新空位
        if (i < j)
        {
          array[empPos] = array[i];
          empPos = i;
        }
        //search a val < midVal from end to start
        //从后往前找一个比中值小的
        while (j > i && array[j] >= midVal)
        {
          j--;
        }
        //找到了,换到空位上,此时大的部分空出一个位置,更新空位
        if (j > i)
        {
          array[empPos] = array[j];
          empPos = j;
        }
      }
      //最后的空位正好用来放中值,因为能跳出循环说明所有的元素都遍历到了,小的都在左边,大的都在右边
      array[empPos] = midVal;
      return i;
    }

  }

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值