Contents

基础算法

1. 排序算法

1.1 冒泡排序

冒泡排序意思就是每一次遍历,将最大/的最小元素移动到末尾. 显然对于长度为len的输入而言,最多需要遍历len -1 次. 时间复杂度O(n^2) 空间复杂度O(1)

template<typename T>
void bubble_sort(T arr[], size_t len){
    bool swap = true;   // 若是当前的遍历没有发生交换说明已经是正序的,不需要继续下去
    for(size_t loop_num = 0; loop_num < len -1 && swap; ++loop_num) {
        swap = false;
        for(size_t index = 0; index < len -1 - loop_num; ++index) {
            if(arr[index] > arr[index+1]) {
                const T tmp = arr[index];
                arr[index] = arr[index+1];
                arr[index+1] = tmp;
                swap = true;
            }
        }
    }
}

1.2 选择排序

选择排序的意思是每次选择一个指定的位置,将通过一次遍历之后取得的值放入指定位置 时间复杂度O(n^2) 空间复杂度O(1)

template<typename T>
void selection_sort(T arr[], size_t len){
    for(size_t location = 0; location < len -1; ++location){
        for(size_t index = location + 1; index < len; ++index){
            if(arr[index] < arr[location]){
                T tmp = arr[location];
                arr[location] = arr[index];
                arr[index] = tmp;
            }
        }
    }
}

1.3 插入排序

插入排序保证已经遍历过的串是已经排好序的,对于新出现的元素则通过比较插入到正常位置 时间复杂度O(n^2) 空间复杂度O(1)

template<typename T>
void insertion_sort(T arr[], size_t len){
    // finial_location 当前遍历位置,该位置之前是有序的
    for(size_t finial_location = 1; finial_location < len; ++finial_location){
        for(int pre_index = finial_location - 1; pre_index >= 0; --pre_index){
            // 从后向前比较,将当前元素插入到正确位置
            if(arr[pre_index+1] < arr[pre_index]){
                T tmp = arr[pre_index+1];
                arr[pre_index+1] = arr[pre_index];
                arr[pre_index] = tmp;
            }
        }
    }
}

1.4 快排

快排的核心思想是分治,每次选定一个元素Key,经过一次排序后使得Key左侧元素均小于Key,而右侧元素均大于Key Key选择也很重要

template<typename T>
void quick_sort(T arr[], int start, int finished){
    if(start >= finished) return;
    size_t start_copy = start, finished_copy = finished;
    T key = arr[start];// 选定Key为最左侧元素
    while(start < finished) {
        // 从右侧开始遍历,直到碰到一个小于Key的元素
        while (start < finished && arr[finished] >= key) {
            --finished;
        }
        arr[start] = arr[finished];
        // 从左侧开始遍历,直到碰到一个大于Key的元素
        while (start < finished && arr[start] <= key) {
            ++start;
        }
        // 交换left right
        arr[finished] = arr[start];
    }
    // 将key填入正确位置
    arr[start] = key;
    // 递归 分治
    quick_sort(arr, start_copy, start-1);
    quick_sort(arr, start+1, finished_copy);
}

1.5 堆排

1.6 归并

归并分为两个过程, 首先将数组不断二分,直到每组仅含一个元素, 然后开始两两有序合并

// 合并两个有序数组
template<typename T>
void merge(T arr[], int start, int middle, int finished){
    int left_start = start;
    int right_start = middle + 1;
    T arr_tmp[finished - start +1];
    int index = 0;
    while (left_start <= middle && right_start <=finished){
        arr_tmp[index++] = arr[left_start] < arr[right_start] ? arr[left_start++] : arr[right_start++];
    }
    while(left_start <= middle){
        arr_tmp[index++] = arr[left_start++];
    }
    while(right_start <= finished){
        arr_tmp[index++] = arr[right_start++];
    }
    // copy
    for(int index = start; index <= finished;++index){
        arr[index] = arr_tmp[index - start];
    }
}
template<typename T>
void merge_sort(T arr[], int start, int finished){
    if(start >= finished) return;
    int middle = start + (finished - start)/2;
    merge_sort(arr, start, middle);
    merge_sort(arr, middle+1, finished);
    merge(arr,start, middle,finished);
}