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;
        }
    }
    
  • 相关阅读:
    组装query,query汇总,query字段
    POJ 1276, Cash Machine
    POJ 1129, Channel Allocation
    POJ 2531, Network Saboteur
    POJ 1837, Balance
    POJ 3278, Catch That Cow
    POJ 2676, Sudoku
    POJ 3126, Prime Path
    POJ 3414, Pots
    POJ 1426, Find The Multiple
  • 原文地址:https://www.cnblogs.com/walkinginthesun/p/9521577.html
Copyright © 2011-2022 走看看