NC140排序——手写快排

NC140排序

知识点:排序
题目链接

题目描述
给定一个数组,请你编写一个函数,返回该数组排序后的形式。
示例1
输入:[5,2,3,1,4]
返回值:[1,2,3,4,5]

示例2
输入:[5,1,6,2,5]
返回值:[1,2,5,5,6]

备注:
数组的长度不大于100000,数组中每个数的绝对值不超过109

解题思路
快排思想:用到了分治思想,和分治算法一样为了进行排序需要先对其划分的子区间进行排序。

  • 基本思想:在待排序的序列中选取一个值作为一个基准值,按照这个基准值得大小将这个序列划分成两个子序列,基准值会在这两个子序列的中间,一边是比基准小的,另一边就是比基准大的。

  • 这样快速排序第一次排完,我们选取的这个基准值就会出现在它该出现的位置上。这就是快速排序的单趟算法,也就是完成了一次快速排序。然后再对这两个子序列按照同样的方法进行排序,直到只剩下一个元素或者没有元素的时候就停止,这时候所有的元素都出现在了该出现的位置上。

  • 左右指针法实现思路

  • 在一段区间内我们有一个值key(基准),一般会选择数组的头或者尾

  • 从右向左边区间进行遍历,直到找到一个大于key的值就停下

  • 然后再从右边找小于key的值,找到一个也停下来

  • 我们将左右的值进行交换,这样左边那个大于key的值就被换到了右边,而右边那个比key小的值就被换到了左边

  • 左右两个指针相遇的时候就说明所有元素都与key做过了比较。然后再将左指针所在的元素赋值给key
    -此时按照上述方法进行递归实现[left, key-1]和[key+1, right]

代码

#include "cheader.h"
class Solution {
public:
    vector<int> MySort(vector<int>& arr){
        MySort_qsort(arr,0,arr.size()-1);
        return arr;
    }
    //快排 时间复杂度O(logn)。空间复杂度是O(n) 不稳定算法
    void MySort_qsort(vector<int>& arr,int left,int right){
        if(left >= right)
            return ;
        int i = left, j = right;
        int base = arr[left];//基准假设是第一个值
        while(i < j){
            //从右往左找  找到比base小的
            while(i < j && arr[j] >= base)
                j--;
            // 从左往右找 找到比base大的
            while(i < j && arr[i] <= base)
                i++;
            swap(arr[i],arr[j]);
        }
        //把基准值放到该放的位置
        swap(arr[i],arr[left]);
        MySort_qsort(arr, left, i-1);
        MySort_qsort(arr, i+1, right);
    }
    //堆排序 时间复杂度O(logn)。空间复杂度是O(n) 不稳定算法
    void MySort_heapsort(vector<int>& arr){
        priority_queue<int,vector<int>,greater<int>> q; //小顶堆
        for(int x:arr)
            q.push(x);
        for(int i = 0; i < arr.size(); i++) {
            arr[i] = q.top();
            q.pop();
        }
    }
    //归并排序 时间复杂度O(logn)。空间复杂度是O(n) 稳定算法
    void mergeSort(vector<int> &arr, int left, int right) {
        if(left >= right)
            return;
        int mid = left + (right - left) / 2;
        mergeSort(arr, left, mid); // 递归 左半边
        mergeSort(arr, mid+1, right); // 递归 右半边
        
        merge(arr, left, mid, right); // 合并两个有序的数组(参考合并两个有序的链表)
    }
    
    void merge(vector<int> &arr, int left, int mid, int right) {
        vector<int> tmp(right-left+1); // 开辟新的数组
        int i = left, j = mid+1, k = 0; // i左边数组的起始位置,j右边数组的起始位置,k已经放入新数组的个数
        while(i <= mid && j <= right){  // 比较左右数组,数值小的放入新数组中
            tmp[k++] = arr[i] < arr[j] ? arr[i++] : arr[j++];
        }
        while(i <= mid)
            tmp[k++] = arr[i++];  // 如果左半边数组没有排序完,加入新数组
        while(j <= right)
            tmp[k++] = arr[j++]; // 如果右半边数组没有排序完,加入新数组
        for(i = left, k = 0; i <= right;)
            arr[i++] = tmp[k++]; // 新数组数据放回到原来的数组中
    }
};
int main()
{
    vector<int> arr{5,2,3,1,4};
    Solution s;
    s.MySort(arr);
    for(int x:arr)
        cout<<x<<endl;
    return 0;
}



已标记关键词 清除标记
相关推荐
©️2020 CSDN 皮肤主题: 1024 设计师:白松林 返回首页