十大經典排序算法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;
}