(一)排序

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

  • 《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;
    }
}
posted @ 2018-08-23 07:29  yvhqbat  阅读(155)  评论(0编辑  收藏  举报