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