十大經典排序算法-C++

十大經典排序算法C++實現

參考:https://www.cnblogs.com/onepixel/p/7674659.html

TODO:
1.計數排序
2.基數排序
3.桶排序

/***********************************************
 * @brief   排序算法
 *          1. 冒泡排序
 *          2. 選擇排序
 *          3. 插入排序
 *          4. 希爾排序
 *          5. 歸併排序
 *          6. 快速排序
 *          7. 堆排序
 ***********************************************/
#include <iostream>
#include <vector>
#include <cmath>
using std::cout;
using std::endl;
using std::vector;
using std::memcpy;
using std::floor;

void showArray(const int *(&arr), int n);
void swap(int arr[], int n, int i, int j);
void bubbleSort(int a[], int n);
void selectSort(int a[], int n);
void insertSort(int a[], int n);
void shellSort(int a[], int n);
void mergeSort(int a[], int left, int right);
void quickSort(int a[], int n);
void heapSort(int a[], int n);


/**
 * @brief   打印數組
 *
 **/
void showArray(const int *arr, int n) {
    for (int i = 0; i < n; ++i) {
        cout << *(arr + i) << " ";
    }
    cout << endl;
}

/**
 * @brief   交換數組中的兩個位置
 *
 **/
void swap(int arr[], int n, int i, int j) {
    if (i >= n || j >= n) {
        throw "Invalid input";
    }
    int tmp = arr[i];
    arr[i] = arr[j];
    arr[j] = tmp;
}

/**
 * @brief   冒泡排序
 *          冒泡,顧名思義,從下到上,將最小(大)的
 *          數升到最上面
 *
 **/
void bubbleSort(int arr[], int n) {
    if (arr == nullptr || n <= 0) {
        throw "Invalid input";
    }
    for (int i = 0; i < n; ++i) {
        // j < n - i的目的是,沒輪冒泡結束,
        // 第n - i位置的數就確定了,無需再
        // 次遍歷. n - 1的目的是確保j + 1
        // 不越界.
        for (int j = 0; j < n - i - 1; ++j) {
            if (arr[j] > arr[j + 1]) {
                swap(arr, n, j, j + 1); 
            }
        }
    }
}

/**
 * @brief   選擇排序
 *          顧名思義,從左到右,從數據中選擇一個最小(大)
 *          的數放到左邊(或右邊)
 *
 **/
 void selectSort(int arr[], int n) {
    if (arr == nullptr || n <= 0) {
        throw "Invalid input";
    }
    for (int i = 0; i < n; ++i) {
        int minIndex = i;
        // 將最小的數依次放在左邊
        for (int j = i + 1; j < n; ++j) {
            if (arr[j] < arr[minIndex]) {
                minIndex = j;
            }
        }
        swap(arr, n, i, minIndex);
    }
 }

/**
 * @brief   插入排序
 *          從左到右,把第一個元素看作只包含一個元素的有序
 *          數組s1,把剩下的元素看作無序數組s2,從s2中取第一個
 *          元素插入s1中,使s1保持有序,直到s2數組爲空
 **/
void insertSort(int arr[], int n) {
    if (arr == nullptr || n <= 0) {
        throw "Invalid input";
    }
    for (int i = 1; i < n; ++i) {
        int current = arr[i];
        int preIndex = i - 1;
        while (preIndex >= 0 && arr[preIndex] > current) {
            arr[preIndex + 1] = arr[preIndex];
            --preIndex;
        }
        arr[preIndex + 1]= current;
    }
}

/**
 * @brief   希爾排序
 *          按步長拆分,再插入排序。每輪排序過後步長減半,直到步
 *          長爲1.初始步長爲數組長度的一半.
 *          爲啥要先分步再插入?因爲插入排序較好的數據效率高
 **/
void shellSort(int arr[], int n) {
    if (arr == nullptr || n <= 0) {
        throw "Invalid input";
    }
    for (int gap = n / 2; gap >= 1; gap /= 2) {
        for (int i = gap; i < n; i += gap) {
            int current = arr[i];
            int preIndex = i - gap;
            while (preIndex >= 0 && arr[preIndex] > current) {
                arr[preIndex + gap] = arr[preIndex];
                preIndex -= gap;
            }
            arr[preIndex + gap] = current;
        }
    }
}


/**
 * @brief   合併左右兩個數組
 *
 **/
void merge(int arr[], int start, int mid, int end) {
    if (arr == nullptr || start >= mid || mid >= end) {
        return;
    }

    int n = end - start; // 臨時數組的長度
    int *tmpArr = new int[n]; // new int[] 而不是 new int()

    int i = start;
    int j = mid;
    int k = 0;

    while (i < mid && j < end) {
        tmpArr[k++] = arr[i] < arr[j] ? arr[i++] : arr[j++];
    }

    while (i < mid) {
        tmpArr[k++] = arr[i++];
    }

    while (j < end) {
        tmpArr[k++] = arr[j++];
    }

    // 將排序好的數組拷貝回原數組的相應位置
    memcpy(arr + start, tmpArr, n * sizeof(int));    

    // 釋放內存空間和指針
    delete []tmpArr;
    tmpArr = nullptr;
}


/**
 * @brief   歸併排序
 *             5 4 1 2 9 6 7 0 8 3
 *             /                \
 *        5 4 1 2 9          6 7 0 8 3
 *        /    \             /       \
 *      5 4  1 2 9         6 7     0 8 3
 *      / \   /  \        / \       /  \
 *     5   4 1   2 9     6   7     0   8 3
 *               / \                   / \
 *              2   9                 8   3
 **/
void mergeSort(int arr[], int start, int end) {
    if (arr == nullptr || end - start < 2) {
        return;
    }
    int mid = (start + end) / 2;
    mergeSort(arr, start, mid);
    mergeSort(arr, mid, end);
    merge(arr, start, mid, end);
}

/**
 * @brief   分割數組
 *
 **/
int partition(int arr[], int left, int right) {
    if (arr == nullptr || left >= right) {
        throw "Invalid input";
    }
    int i = left;
    int j = right;
    int pivot = arr[i];

    while (i < j) {
        while (arr[j] > pivot) {
            --j;
        }

        while (arr[i] < pivot) {
            ++i;
        }
        int tmp = arr[i];
        arr[i] = arr[j];
        arr[j] = tmp;
    }
    arr[i] = pivot;
    return i;
}

/**
 * @brief   快速排序
 *
 **/
void quickSort(int arr[], int start, int end) {
    if (arr == nullptr || start >= end) {
        return;
    }
    int mid = partition(arr, start, end);
    quickSort(arr, start, mid);
    quickSort(arr, mid + 1, end);
}

/**
 * @ breif  堆排序操作
 **/
void heapify(int arr[], int n, int i) {
    int largest = i;
    int left = 2 * i + 1;
    int right = 2 * i + 2;

    if (left < n && arr[left] > arr[largest]) {
        largest = left;
    }

    if (right < n && arr[right] > arr[largest]) {
        largest = right;
    }

    if (largest != i) {
        swap(arr, n, i, largest);
        heapify(arr, n, largest);
    }
}

void buildHeap(int arr[], int n) {
    if (arr == nullptr || n <= 0) {
        return;
    }

    for (int i = floor(n / 2); i >= 0; --i) {
        heapify(arr, n, i);
    }
}

/**
 * @brief   堆排序
 *          5 4 1 2 9 6 7 0 8 3
 *
 *          原始堆(非堆)
 *               5
 *             /    \
 *           4        1
 *          /  \     /  \
 *        2     9   6    7
 *       / \    /
 *      0   8  3
 *
 **/
void heapSort(int arr[], int n) {
    buildHeap(arr, n);

    for (int i = n - 1; i > 0; --i) {
        swap(arr, n, 0, i);
        --n;
        heapify(arr, n, 0);
    }
}


int main() {
    const int n = 10;
    int arr[n] = {5, 4, 1, 2, 9, 6, 7, 0, 8, 3};
    cout << "原始數組: ";
    showArray(arr, n);
    
    // 有序排序會改變數組原有的順序,所以創建一個臨時數組
    // new int() 和 new int[] 是有區別的,別搞錯
    int *tmpArr = new int[n];

    // 冒泡排序
    std::memcpy(tmpArr, arr, n * sizeof(int));
    bubbleSort(tmpArr, n);
    cout << "冒泡排序: ";
    showArray(tmpArr, n);

    // 選擇排序
    cout << "選擇排序: ";
    std::memcpy(tmpArr, arr, n * sizeof(int));
    selectSort(tmpArr, n);
    showArray(tmpArr, n);

    // 插入排序
    cout << "插入排序: ";
    std::memcpy(tmpArr, arr, n * sizeof(int));
    insertSort(tmpArr, n);
    showArray(tmpArr, n);

    // 希爾排序
    cout << "希爾排序: ";
    std::memcpy(tmpArr, arr, n * sizeof(int));
    shellSort(tmpArr, n);
    showArray(tmpArr, n);

    // 歸併排序
    cout << "歸併排序: ";
    std::memcpy(tmpArr, arr, n * sizeof(int));
    mergeSort(tmpArr, 0, n);
    showArray(tmpArr, n);

    // 快速排序
    cout << "快速排序: ";
    std::memcpy(tmpArr, arr, n * sizeof(int));
    quickSort(tmpArr, 0, n - 1);
    showArray(tmpArr, n);

    // 堆排序
    cout << "堆排序  : ";
    std::memcpy(tmpArr, arr, n * sizeof(int));
    heapSort(tmpArr, n);
    showArray(tmpArr, n);
    return 0;
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章