纯C语言实现两种快速排序(挖坑填补法,以及二分交换法)

建议结合画图进行理解

1.挖坑填补法实现快速排序(遇到逆序直接扑街):

void quicksort(int *arr,unsigned int len)(挖坑填补方法实现)
{
  if (len<2) return;  // 数组的元素小于2个就不用排序了。

  int temp=arr[0];  // 选取最左边的数作为基准。
  int left=0;      // 左下标。
  int right=len-1; // 右下标。
  int moving=2;    // 当前应该移动的下标,1-左下标;2-右下标。

  while (left<right)
  {
    if (moving==2) // 移动右下标的情况。
    {
      // 如果右下标位置元素的值大于等于中心轴,继续移动右下标。
      if (arr[right]>=temp) { right--; continue; }
      
      // 如果右下标位置元素的值小于中心轴,把它填到左下标的坑中。
      arr[left]=arr[right];
      left++;    // 左下标向右移动。
      moving=1;  // 下次循环将移动左下标。
      continue;
    }

    if (moving==1) // 移动左下标的情况。
    {
      // 如果左下标位置元素的值小等于中心轴,继续移动左下标。
      if (arr[left]<=temp) { left++; continue; }

      // 如果左下标位置元素的值大于中心轴,把它填到右下标的坑中。
      arr[right]=arr[left];
      right--;   // 右下标向左移动。
      moving=2;  // 下次循环将移动右下标。
      continue;
    }
  }

  // 如果循环结束,左右下标重合,把中心轴的值填进去。
  arr[left]=temp;

  quicksort(arr,left);             // 对中心轴左边的序列进行排序。
  quicksort(arr+left+1,len-left-1); // 对中心轴右边的序列进行排序。
/*对arr进行加减操作,传入相应首元素地址,以及对应的数组长度,
实现相当于将原数组切片再传入的感觉。
递归深度一直到达切片的数组长度为 1 */
}

2.二分交换法(逆序状况仍旧无敌):

void quicksort(int* nums,int l,int r)//应用二分思想
{
    int mid=nums[(l+r)/2];//中间数
    int i=l,j=r;
    while(i<=j){//这里注意要有'='(可结合后面的递归传参进行思考)
        while(nums[i]<mid) i++;//查找左半部分比中间数大的数
        while(nums[j]>mid) j--;//查找右半部分比中间数小的数
        if(i<=j)//如果有一组不满足排序条件(左小右大)的数
        {/*交换值:这里注意有一个小坑,
        不能用加法或者异或来实现值的交换,
        因为当nums[i]和nums[j]指的是同一个变量时(i=j时),
        就会出现bug。*/
            int temp = nums[j];
            nums[j] = nums[i];
            nums[i] = temp;
            i++;
            j--;/*实际上这种交换思想得到的不一定将基准值排好位置,
            但是在最后一次执行上面两个循环搜索后,r的右边一定是大于等于基准值的,l的左边一定是小于等于基准值的。
            还有就是记住当执行l=r的交换,要过前面两道循环坎,所以若为l=r的情况进行交换那么只有可能是该对应的值就是基准值,
            所以此时便相当于将基准值排好了,而后再执行此交换是有利于l和r的正确位置,
            相当于无论哪种情况,r都会指向左待排数列的尾部,l则指向右待排数列的首部。*/
        }
    }
    if(l<j) quicksort(nums,l,j);//递归搜索左半部分
    if(i<r) quicksort(nums,i,r);//递归搜索右半部分
}

我个人常用的快排:

void quicksort(int* nums,int n)//应用二分思想
{ if (n<2)return;
   int l=0,r=n-1;
    int mid=nums[(l+r)/2];//中间数
    
    while(l<=r){//这里和下面的'='千万不能省,这是让最后l和r的指向可能性只会有两种可能,要么l和r相邻(r左l右),要么l和r中间隔了一个数(那么这个数肯定是确定好位置的。l右r左)
        while(nums[l]<mid) l++;//查找左半部分比中间数大的数
        while(nums[r]>mid) r--;//查找右半部分比中间数小的数
        if(l<=r)//如果有一组不满足排序条件(左小右大)的数
        {/*交换值:这里注意有一个小坑,
        不能用加法或者异或来实现值的交换,
        因为当nums[i]和nums[j]指的是同一个变量时(i=j时),
        就会出现bug。*/
            int temp = nums[r];
            nums[r] = nums[l];
            nums[l] = temp;
            l++;
            r--;
        }
    }
     quicksort(nums,r+1);//递归搜索左半部分
     quicksort(nums+l,n-l);//递归搜索右半部分
     //最后这个左右搜索部分元素一定不能重合,或者少包含了一些元素(除非是这一轮已经排好的这一个),就算你的左右搜索部分包含了原本已经确定了位置的元素,也没关系。
}


int* sortArray(int* nums,int numSize,int* returnSize){
    *returnSize = numSize;
    quicksort(nums,numSize);
    return nums;
}
  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值