zoukankan      html  css  js  c++  java
  • 【算法】归并排序与快排

    归并排序

    归并排序是另一种不同的排序方法,因为归并排序使用了递归分治的思想,所以理解起来比较容易。其基本思想是,先递归划分子问题,然后合并结果。把待排序列看成由两个有序的子序列,然后合并两个子序列,然后把子序列看成由两个有序序列。。。。。倒着来看,其实就是先两两合并,然后四四合并。。。最终形成有序序列。空间复杂度为O(n),时间复杂度为O(nlogn)。
    举个栗子:
    #include <iostream>
    #include <vector>
    #include <algorithm>
    #include <limits.h>
    #include "Solution.h"
    
    using namespace std;
    
    void MergeArray(int array[], int start, int mid, int end, int temp[]) {
        int i = start;
        int j =  mid + 1;
        int k = 0;
        while (i <= mid && j <= end ) {
            if (array[i] < array[j]) {
                temp[k++] = array[i++];
            }else {
                temp[k++] = array[j++];
            }
        }
        while (i <= mid) {
            temp[k++] = array[i++];
        }
        while (j <= end) {
            temp[k++] = array[j++];
        }
        for (int i = 0; i < k; i ++) {
            array[start + i] = temp[i];
        }
    
    }
    // 归并排序,将数组前半部分后半部分分成最小单元,然后在合并
    void MergeSort(int array[], int start,  int end, int temp[]) {
        if(start < end) {
            int mid = (start + end)/ 2;
            MergeSort(array, start, mid, temp);
            MergeSort(array, mid + 1, end, temp);
            MergeArray(array, start, mid, end, temp);
        }
    
    }
    // 在这里创建临时数组,节省内存开销,因为以后的temp都是在递归李使用的。
    void MergeSortmain(int array[], int len) {
        int start = 0;
        int end = len - 1;
        int *temp = new int[len];
        MergeSort(array, start, end, temp);
    }
    
    void PrintArray(int array[], int len) {
        for (int i = 0 ; i < len; ++i) {
            cout << array[i] << " " ;
    
        }
        cout << endl;
    }
    
    int main() {
    
        int array[] = {3,5,3,6,7,3,7,8,1,2};
    
        MergeSortmain(array, 10);
        PrintArray(array, 10);
        
        return 0;
    }

    快速排序

    快速排序一听名字就觉得很高端,在实际应用当中快速排序确实也是表现最好的排序算法。冒泡排序虽然高端,但其实其思想是来自冒泡排序,冒泡排序是通过相邻元素的比较和交换把最小的冒泡到最顶端,而快速排序是比较和交换小数和大数,这样一来不仅把小数冒泡到上面同时也把大数沉到下面。
    举个栗子:对5,3,8,6,4这个无序序列进行快速排序,思路是右指针找比基准数小的,左指针找比基准数大的,交换之。
    5,3,8,6,4 用5作为比较的基准,最终会把5小的移动到5的左边,比5大的移动到5的右边。
    5,3,8,6,4 首先设置i,j两个指针分别指向两端,j指针先扫描(思考一下为什么?)4比5小停止。然后i扫描,8比5大停止。交换i,j位置。
    5,3,4,6,8 然后j指针再扫描,这时j扫描4时两指针相遇。停止。然后交换4和基准数。
    4,3,5,6,8 一次划分后达到了左边比5小,右边比5大的目的。之后对左右子序列递归排序,最终得到有序序列。
    上面留下来了一个问题为什么一定要j指针先动呢?首先这也不是绝对的,这取决于基准数的位置,因为在最后两个指针相遇的时候,要交换基准数到相遇的位置。一般选取第一个数作为基准数,那么就是在左边,所以最后相遇的数要和基准数交换,那么相遇的数一定要比基准数小。所以j指针先移动才能先找到比基准数小的数。
    快速排序是不稳定的,其时间平均时间复杂度是O(nlgn)。
    实现代码:
    #include <iostream>
    #include <vector>
    #include <algorithm>
    #include <limits.h>
    #include "Solution.h"
    
    using namespace std;
    int partition(vector<int> &vi, int low, int up)
    {
        int pivot = vi[up];//选择最后一个元素作为比较元素
        int i = low-1;//这个慢速移动下标必须设定为比最小下表p小1,否则两个元素的序列比如2,1无法交换
        for (int j = low; j < up; j++)
        {
            if(vi[j] <= pivot)
            {
                i++;
                swap(vi[i], vi[j]);
            }
        }
        swap(vi[i+1], vi[up]);
        return i+1;
    }
    
    //C++'s array range should be [low, up], the same as [low, up+1)
    void quickSort(vector<int> &vi, int low, int up)
    {
        if(low < up)
        {
            int mid = partition(vi, low, up);
            //Watch out! The mid position is on the place, so we don't need to consider it again.
            //That's why below is mid-1, not mid! Otherwise it will occur overflow error!!!
            quickSort(vi, low, mid-1);
            quickSort(vi, mid+1, up);
        }
    }
    
    void qSort(vector<int> &vi)
    {
        quickSort(vi, 0, vi.size()-1);
    }
    
    int main() {
    
        int a[] = {3,5,7,9,2,3,1,0,7,5,4};
        vector<int> va(a, a+11);
    
        cout<<"Before quicksort:
    ";
        for(auto x:va)
            cout<<x<<" ";
        cout<<endl;
    
        qSort(va);
    
        cout<<"After quicksort:
    ";
        for(auto x:va)
            cout<<x<<" ";
        cout<<endl;
    
        return 0;
    }
  • 相关阅读:
    react篇章-React State(状态)
    react篇章-React 组件-复合组件
    react篇章-React 组件-向组件传递参数
    react篇章-React 组件-ES6 class 来定义一个组件
    React篇章-React 组件
    复习常用算法_冒泡算法
    项目管理小结(如何做好一个百万级项目甚至千万级别的项目)
    AOP切点切面内容
    Spring 框架
    Spring MVC 框架
  • 原文地址:https://www.cnblogs.com/ygh1229/p/10438880.html
Copyright © 2011-2022 走看看