C++快速排序和归并排序思路+实现

1、快速排序:O(NlogN),不稳定。

基本思路:
1.1、设置两个变量 left、right。
1.2、整个数组找基准正确位置,所有元素比基准值小的摆放在基准前面,所有元素比基准值大的摆在基准的后面。

在数据随机情况下,默认数组的第一个数为基准数据,赋值给key,即key = array[left]。

  • 因为默认数组的第一个数为基准,所以从后面开始向前搜索(right),找到第一个小于key的array[right],(循环条件是array[right] >= key;结束时 array[right] < key)。
  • 此时从前面开始向后搜索(left++),找到第一个大于key的array[left](循环条件是 array[left] <= key;结束时array[left] > key)。

找到第一对i ,j,然后swap。

循环 1-3 步骤,直到 left >= right,该位置就是基准位置。把基准数据赋给当前位置。
1.3、第一趟找到的基准位置,作为下一趟的分界点。
1.4、递归调用分界点前和分界点后的子数组排序,重复1.2、1.3、1.4的步骤。

选择基准的方式决定了两个分割后两个子序列的长度,进而对整个算法的效率产生决定性影响。最理想的方法是,选择的基准恰好能把待排序序列分成两个等长的子序列

1.1、数组随机可以选择第一个或最后一个为基准O(NlogN)。有序为O(N^2)
写法1
void QuickSort(vector<int>& nums, int l, int r)
{
	if(nums.size() == 0)return;
	if(l >= r)return;
	int i = l, j = r;
	while(i < j)
	{
		while(i < j && nums[j] >= nums[l]) j--;
		while(i < j && nums[i] <= nums[l]) i++;
		swap(nums[i], nums[j]);
	}
	swap(nums[i], nums[l]);
	QuickSort(nums, l, i - 1);
	QuickSort(nums, i + 1, r);
}
写法2
int partition(vector<int>&arr, int l, int r)
{
	if(arr.size() == 0 || l < 0 || r< 0)return -1;
	int key = arr[l];
		int i = l, j = r;
        while (i < j) {
            while (i < j && arr[j] >= key) j--;
            while (i < j && arr[i] <= key) i++;
            swap(arr[i], arr[j]);
        }
        swap(arr[i], key);
        return i;
}
void Quicksort(vector<int>& arr, int l,int r)
{
	  if (l >= r) return;
	  int i = partition(arr, l ,r);
	  Quicksort(arr, l, i - 1);
      Quicksort(arr, i + 1, r);
}
1.2、随机选取,减少出现不好分割的几率,但是还是最坏情况下(全相等)还是O(n^2)
class Solution{
public:
    vector<int> sortArray(vector<int>& nums) {
        int n=nums.size();
        srand((unsigned)time(nullptr));  随机
        quickSort(nums,0,n-1);
        return nums;
    }
    
    void quickSort(vector<int>& nums,int l,int r)
    {
    		if(l >= r)return;
            int i = partition(nums,l,r);
            quickSort(nums,l,i - 1);
            quickSort(nums,i + 1,r);
    }
    int patition(vector<int>& nums, int l, int r)
    {
        int i = l;
        int j = r;
        int mid = rand()%(r - l + 1) + l; //交换
        swap(nums[l],nums[mid]);
        int key = nums[l];
        while(i < j)
        {
            while(i < j && nums[j] >= key) j--;
            while(i < j && nums[i] <= key) i++;
            swap(nums[i], nums[j]);
        }
        swap(nums[l], nums[i]);
        return i;
    }
};

为什么与轴点相等也要换位置;

  • 虽然相同元素交换多次,好处是 i 和 j 在中间交错,枢纽被替代时,分割建立了两个几乎相等的子数组。O(NlogN)
  • 如果不停止,枢纽被交换到 i 最后到的位置,这样会产生两个不均衡的子数组,数据相同时,O(N^2)复杂度,

2、归并排序:O(N*logN) /O(N) 稳定

从局部有序到整体有序。具体来说,就是可以将原数组进行分割(分治),分别进行运算(递归),实现局部有序,然后通过一个外排进而实现整体有序

分治到只有一个数字,两两比较,借助辅助数组,a和b中的较小值填入辅助数组,并且右移,直到其中一个指针遍历了其所在的子数组的全部元素,结束并将另外的数组的剩余元素全部拷贝到辅助数组。

#include<iostream>
#include<vector>
using namespace std;

void mergeSort(vector<int>& nums, int l, int mid, int r) {
    vector<int>tmp(r - l + 1, 0);
    int i = l;   //左边第一个
    int j = mid + 1;//右边第一个
    int index = 0;
    while (i <= mid && j <= r) {
        if (nums[i] <= nums[j]) {
            tmp[index++] = nums[i++];
        }
        else {
            tmp[index++] = nums[j++];
        }
    }
    //把左边剩余的数移入数组
    while (i <= mid) {
        tmp[index++] = nums[i++];
    }
    //把右边剩余的数移入数组
    while (j <= r) {
        tmp[index++] = nums[j++];
    }
    //把新数组中的数覆盖nums数组
    for (int k = 0; k < tmp.size(); k++) {
        nums[k + l] = tmp[k];
    }
}
void merge(vector<int>& nums, int l, int r) {
    if (l >= r)return;
    int mid = l + ((r - l) >> 1);
    merge(nums, l, mid);
    merge(nums, mid + 1, r);
    mergeSort(nums, l, mid, r);
}

int main()
{
    vector<int>nums = {7,3,2,6,0,1,5,4};
    int n = nums.size();
    merge(nums, 0, n - 1);
    for (int i = 0; i < n; i++)
    {
        cout << nums[i] << " ,";
    }
    return 0;
}

稳定排序:如果 a 原本在 b 的前面,且 a == b,排序之后 a 仍然在 b 的前面,则为稳定排序。
冒泡+插入+归并稳定。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值