zoukankan      html  css  js  c++  java
  • (一)排序

    排序算法几乎是面试最常考的算法题目.
    参考:

    • 《STL源码剖析》6.7.9 sort 章节
      STL的 sort 算法,数据量大时采用Quick Sort,分段递归排序;一旦分段的数据量小于某个门槛,为避免Quick Sort 的递归调用带来过大的额外负荷,就改用 Insertion Sort.

    1. 冒泡排序

    冒泡排序是以双层循环的形式:外循环遍历整个序列,每次迭代决定出一个子区间,不断缩小;内循环遍历子区间,将子区间内的每个“逆转对”倒转过来。算法复杂的为O(N^2)。

    void BubbleSort(std::vector<int> &v){
        int len = v.size();
        for (int i = len - 1; i >= 0; --i){
            for (int j = 0; j < i; j++){
                if (v[j] > v[j + 1]){
                    int tmp = v[j];
                    v[j] = v[j + 1];
                    v[j + 1] = tmp;
                }
            }
        }
    }
    
    // test
    void BubbleSortTest(){
        std::vector<int> v = { 1, 5, 3, 7, 9, 2, 5 };
        BubbleSort(v);
        for (auto e : v){
            std::cout << e << std::endl;
        }
    }
    

    2. 插入排序(Insertion Sort)

    插入排序是以双层循环的形式:外循环遍历整个序列,每次迭代决定出一个子区间;内循环遍历子区间,将子区间内的每个“逆转对”倒转过来。算法复杂的为O(N^2)。

    C++实现

    #include <vector>
    #include <iostream>
    
    void InsertionSort(std::vector<int> &v){
        int len = v.size();
        int i = 1, j = 0;
        for (; i < len; ++i){
            int tmp = v[i];
            for (j=i-1; j >= 0 && v[j] > tmp; --j){
                v[j+1] = v[j];
            }
            v[j+1] = tmp;
        }
    }
    
    // test
    void InsertionSortTest()
    {
        std::vector<int> v = { 1, 5, 3, 7, 9, 2, 5 };
        InsertionSort(v);
        for (auto e : v){
            std::cout << e << std::endl;
        }
    }
    
    

    python实现

    
    def insert_sort(nums):
        length = len(nums)
        for j in range(1, length):
            temp = nums[j]
            for i in range(j-1,-1,-1):
                if nums[i]>=temp:
                    nums[i+1]=nums[i]
                else:
                    break
            nums[i+1]=temp
    
    
    arr = [1,4,2,5,4,8,4]
    sl = arr[:]
    insert_sort(sl)
    print(sl)
    

    3. 快速排序(Quick Sort)

    大数据量的情况下有许多排序算法可供选择,Quick Sort 正如其名,是目前已知最快的排序法(大数据量的情况下),平均复杂度为O(NlogN),最坏情况下达O(N^2),可通过 media-of-three 或 random 选取pivot 方式,将最坏情况推进到O(NlgN)。

    Quick Sort 算法,精神在于将大区间分割为小区间,分段排序:

    1. 如果S的元素个数为0或1,结束;
    2. 取S中的任何一个元素,当做枢轴(pivot);
    3. 将S分割为L/R(左/右)两段,使L内的每一个元素都小于或等于pivot,R内的每一个元素都大于或等于pivot;
    4. 对LR递归执行QuickSort。

    Patition分割方法:
    令头端迭代器first向尾部移动,尾端迭代器last向头部移动。当*first大于或等于pivot时停下来,当*last小于或等于pivot时也停下来,然后校验两个迭代器是否交错,如果first<last,将两元素互换,然后各自调整位置(向中央逼近),再继续相同的行为。

    #include <vector>
    #include <iostream>
    
    int Partition(std::vector<int> &v, int first, int last){
        int pivot = v[first];
        while (first < last){
            while (first<last && v[first] < pivot){
                first++;
            }
            while (last > first && !(v[last] < pivot)){
                last--;
            }
    
            int tmp = v[first];
            v[first] = v[last];
            v[last] = tmp;
    
            first++;
            last--;
        }
        return --first;
    }
    
    void QuickSort(std::vector<int> &v, int first, int last){
        if (first >= last){
            return;
        }
        int mid = Partition(v, first, last);
        QuickSort(v, first, mid);
        QuickSort(v, mid + 1, last);
    }
    
    void QuickSort(std::vector<int> &v){
        int len = v.size();
        QuickSort(v, 0, len - 1);
    }
    
    // test
    void QuickSortTest(){
        std::vector<int> v = { 1, 5, 3, 7, 9, 2, 5 };
        QuickSort(v);
        for (auto e : v){
            std::cout << e << std::endl;
        }
    }
    

    4. 归并排序(Merge Sort)

    有一个算法题:将两个有序区间归并成一个有序区间。
    基于这个想法,我们可以利用“分而治之”(devide and conquer)的概念,以各个击破的方式来对一个区间进行排序。首先,将区间对半分割,左右两端各自排序,再利用merge重新组合为一个完整的有序序列。对半分割的操作可以递归进行,直到每一小段的长度为0或1。

    Merge Sort 的复杂度为O(NlgN),虽然这和Quick Sort是一样的,但因为Merge Sort 需要额外的内存,而且在内存之间移动(复制)数据也会耗费不少时间,所以Merge Sort 的效率比不上 Quick Sort。
    实现简单,概念简单,是Merge Sort的两大优点。

    #include <vector>
    #include <iostream>
    
    void Merge(std::vector<int> &v, int first, int mid, int last){
        std::vector<int> tmp;
        int first1 = first;
        int first2 = mid + 1;
        while (first1 <= mid && first2 <= last){
            if (v[first1] < v[first2]){
                tmp.push_back(v[first1]);
                first1++;
            }
            else{
                tmp.push_back(v[first2]);
                first2++;
            }
        }
        while (first1 <= mid){
            tmp.push_back(v[first1]);
            first1++;
        }
        while (first2 <= last){
            tmp.push_back(v[first2]);
            first2++;
        }
    
        for (auto e : tmp){
            v[first++] = e;
        }
    }
    
    void MergeSort(std::vector<int> &v, int first, int last)
    {
        if (first >= last){
            return;
        }
        int mid = (first + last) / 2;
        MergeSort(v, first, mid);
        MergeSort(v, mid + 1, last);
        Merge(v, first, mid, last);
    }
    
    void MergeSort(std::vector<int> &v){
        int len = v.size();
        MergeSort(v, 0, len-1);
    }
    
    // test
    void MergeSortTest(){
        std::vector<int> v = { 1, 5, 3, 7, 9, 2, 5 };
        MergeSort(v);
        for (auto e : v){
            std::cout << e << std::endl;
        }
    }
    
  • 相关阅读:
    虚函数/纯虚函数/抽象类/接口/虚基类
    泛型编程
    C++解题报告 : 迭代加深搜索之 ZOJ 1937 Addition Chains
    C++题解:Matrix Power Series ——矩阵套矩阵的矩阵加速
    C++矩阵加速经典题目:Warcraft III 守望者的烦恼 [vijos 1067]
    C++数论板题(弹药科技):Lengendre定理和欧拉函数
    Java并发工具包提供了哪些并发工具类
    Mac OS X系统深入了解--系统文件结构篇(二)
    Mac OS X系统深入了解--系统文件结构篇(一)
    Java Web(一) Servlet详解!!
  • 原文地址:https://www.cnblogs.com/walkinginthesun/p/9521577.html
Copyright © 2011-2022 走看看