排序之交换排序(快排)

1、冒泡排序:稳定
冒泡排序(Bubble Sort),是一种计算机科学领域的较简单的排序算法。它重复地走访过要排序的元素列,一次比较两个相邻的元素,如果他们的顺序(如从大到小、首字母从A到Z)错误就把他们交换过来。走访元素的工作是重复地进行直到没有相邻元素需要交换,也就是说该元素已经排序完成。

基本思想: (1)比较相邻的元素。如果第一个比第二个大,就交换他们两个。
(2)对每一对相邻元素做同样的工作,从开始第一对到结尾的最后一对。在这一点,最后的元素应该会是最大的数。
(3)针对所有的元素重复以上的步骤,除了最后一个。 (4)持续每次对越来越少的元素重复上面的步骤,直到没有任何一对数字需要比较

void BubbleSort(int *a, int n) {   
    for (int i = 0; i < n - 1; i++)          //外层循环控制趟数,总趟数为len-1
        for (int j = 0; j < n - 1 - i; j++)  //内层循环为当前i趟数 所需要比较的次数
            if (a[j] > arr[j + 1])  
                Swap(arr[j], arr[j + 1]);          
}  

2、快速排序(最重要:必须掌握):分治

(1)左右下标寻找法
这里写图片描述

//方法一:左右下标寻找法
int partSort1(int* a,int left,int right)
{
      int key = a[right];
      int begin = left;
      int end = right;   //int end = right-1的反例为:1 2 3 4 5 6 7 8 9
      while (begin < end)
      {
            while (begin <end && a[begin] <= key)  // 从左到右依次寻找比key大的值
            {
                  begin++;
            }
            while (begin < end && a[end] >= key)   //从右到左依次寻找比key小的值
            {
                  end--;
            }
            // 找到之后交换
            if (begin < end)
                  Swap(a[begin],a[end]);
      }
      // begin只会有两个位置:(1)a[begin]>key; (2)a[begin]就是right(key所在的位置)
      Swap(a[begin], a[right]);
      // 返回begin;begin就是哨兵数所在的下标
      return begin;
}
void QuickSortRecursion(int* a, int left, int right)
{
      //left == right时表示区间内只有一个数;left>right时表示区间内已经没有数了
      if (left >= right)
            return;
      // 排序结束条件:[left,right)之间数目只剩0个或1个
      // [left, div)这里面的数都比div小
      // (div, right] 这里面的数都比div大
      int div = partSort1(a, left, right);

      QuickSortRecursion(a, left, div - 1);
      QuickSortRecursion(a, div + 1, right);
}
void QuickSort(int *a, size_t n)
{
      //递归
      QuickSortRecursion(a, 0, n - 1);
}

(2)挖坑法

// 方法二:挖坑法
int partSort2(int* a, int left, int right)
{
      int key = a[right];
      int begin = left;
      int end = right;
      while (begin < end)
      {
            while (begin < end && a[begin] <= key)
                  begin++;
            a[end] = a[begin];
            while (begin < end && a[end] >= key)
                  end--;
            a[begin] = a[end];
      }
      a[begin] = key;    //将key填到这个坑
      return begin;      //哨兵所在的下标
}

(3)前后下标

基本思想:
定义两个指针,prev和cur,再定义key的值,cur指针从left开始,遇到比key大的就过滤掉,比key小的,就停下来,prev++,判断prev和cur是否相等,如果不相等,就将两个值进行交换,最后一趟排序下来,比key小的,都留在了key的左边,比key大的都在key的右边。

int partSort3(int*a, int left, int right)
{
      int key = a[right - 1];
      int cur = left;
      int pre = cur - 1;
      while (cur < right)
      {
            if (a[cur] < key&& ++pre != cur)
            {
                  Swap(a[cur], a[pre]);
            }
            cur++;
      }
      if (++pre != right)
      {
            Swap(a[pre], a[right - 1]);
      }
      return pre;
}

优化:
三数取中法:

int GetMidIndex(int *a,int left,int right)
{
      int mid = left + (right - left) / 2;
      if (a[left] < a[mid])
      {
            if (a[left]>a[right])
            {
                  return left;
            }
            else if (a[mid] > a[right])
            {
                  return right;
            }
            else
            {
                  return mid;
            }
      }
      else
      {
            if (a[mid] > a[right])
            {
                  return mid;
            }
            else if (a[left] > a[right])
            {
                  return right;
            }
            else
            {
                  return left;
            }
      }
}
int partSort(int *a, int left, int right)
{
      int key = 0;
      int cur = left;
      int firstBigger = left;
      int index = GetMidIndex(a,left,right);
      Swap(a[index],a[right-1]);
      key = a[right - 1];
      while (cur < right)
      {
            if (a[cur] < key)
            {
                  Swap(a[firstBigger], a[cur]);
                  firstBigger++;
            }
            cur++;
      }
      Swap(a[firstBigger],a[right-1]);
      return firstBigger;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值