#include<iostream>
using std::cout;
using std::endl;
using std::move;
#include<Random>
using std::uniform_int_distribution;
using std::default_random_engine;
#include<cTime>
#include<vector>
using std::vector;
#include<algorithm>
using std::swap;
#include<windows.h>
#pragma comment(lib,"winmm.lib")
void BubbleSort(vector<int> arr) {
/*
* 冒泡排序原理:
* 将数组最大元素逐一交换到最后的位置,再将次大元素放到倒数第二个位置......
* 时间复杂度为 O(n*n)
*/
DWORD start, end;
start = timeGetTime();//开始排序
for (int i = 0; i < arr.size() - 1; ++i)
{
bool flag = true;
for (int j = 0; j < arr.size() - i - 1; ++j)
{
if (arr[j] > arr[j + 1])
{
swap(arr[j], arr[j + 1]);
flag = false;
}
}
if (flag) {
break;
}
}
//排序结束
end = timeGetTime() - start;
cout << "冒泡排序用时(毫秒):" << end << endl;;
}
void SelectionSort(vector<int>arr) {
/*
* 选择排序原理:
* 遍历找到最小元素,放到第一位;再找次小元素放到第二位.....
* 可以用来找前几个最大或最小的元素
* 时间复杂度为 O(n*n)
*/
DWORD start, end;
start = timeGetTime();//开始排序
for (int i = 0; i < arr.size(); ++i)
{
int index = i;
for (int j = i+1; j < arr.size(); ++j)
{
if (arr[j] < arr[index])
{
index = j;
}
}
swap(arr[i], arr[index]);
}
//for (auto i : arr)
//{
// cout << i << " ";
//}
//排序结束
end = timeGetTime() - start;
cout << "选择排序用时(毫秒):" << end << endl;
}
void InsertionSort(vector<int>arr)
{
/*
* 插入排序原理:
* 从第二个元素开始,往回比较,比他大的元素往后挪,比他小那就把他放到比他小的那个数的后面
* 时间复杂度为 O(n*n)
*/
DWORD start, end;
start = timeGetTime();//开始排序
for (int i = 1; i < arr.size(); ++i)
{
auto temp = arr[i];
int j = i - 1;
for (; j >= 0; --j)
{
if (arr[j] > temp) {
swap(arr[j], arr[j + 1]);
}
else
{
break;
}
}
arr[j + 1] = temp;
}
//for (auto i : arr)
//{
// cout << i << " ";
//}
//排序结束
end = timeGetTime() - start;
cout << "插入排序用时(毫秒):" << end << endl;
}
void ShellSort(vector<int>arr)
{
/*
* 希尔排序原理:
* 把数组分为子数组,子数组使用插入排序使得整个数组相对有序,从而下一轮插入排序消耗更小
* 不稳定算法,时间复杂度不确定,最差为O(n*n)
*/
DWORD start, end;
start = timeGetTime();//开始排序
for (int gap = arr.size() / 2; gap > 0; gap /= 2)
{
for (int i = gap; i < arr.size(); ++i)
{
auto temp = move(arr[i]);
int j = i;
for (; j >= gap && arr[j - gap] > temp; j -= gap) {
arr[j] = move(arr[j - gap]);
}
arr[j] = move(temp);
}
}
//for (auto i : arr)
//{
// cout << i << " ";
//}
//排序结束
end = timeGetTime() - start;
cout << "希尔排序用时(毫秒):" << end << endl;
}
void percDown(vector<int>&arr, int i, int n);
void HeapSort(vector<int>arr)
{
/*
* 堆排序原理:
* 以数组构造堆,然后将堆中的数据取出放到另外一个数组,得到有序数组
* 空间复杂度:O(n) 时间复杂度:O(nlog n)
* 不具有稳定性
*/
DWORD start, end;
start = timeGetTime();//开始排序
//构造堆
for (int i = arr.size() / 2 - 1; i >= 0; --i)
{
percDown(arr, i, arr.size());
}
for (int j = arr.size() - 1; j > 0; --j)
{
swap(arr[0], arr[j]);
percDown(arr, 0, j);
}
//for (auto i : arr)
//{
// cout << i << " ";
//}
//排序结束
end = timeGetTime() - start;
cout << "堆排序用时(毫秒):" << end << endl;
}
void mergeSort(vector<int>&arr,vector<int>&tempArr,int left,int right);
void merge(vector<int>& arr, vector<int>& tempArr, int leftPos, int rightPos, int rightEnd);
void MergeSort(vector<int>arr)
{
DWORD start, end;
start = timeGetTime();//开始排序
vector<int>tempArr(arr.size());
mergeSort(arr, tempArr, 0, arr.size() - 1);
//for (auto i : arr)
//{
// cout << i << " ";
//}
//排序结束
end = timeGetTime() - start;
cout << "归并排序用时(毫秒):" << end << endl;
}
void quickSort(vector<int>& ar, int left, int right);
void QuickSort(vector<int>arr)
{
DWORD start, end;
start = timeGetTime();//开始排序
quickSort(arr, 0, arr.size() - 1);
//for (auto i : arr)
//{
// cout << i << " ";
//}
//排序结束
end = timeGetTime() - start;
cout << "快速排序用时(毫秒):" << end << endl;
}
void SortTest() {
vector<int> arr;
//随机生成一个数组进行测试
uniform_int_distribution<int>u(0, 100000);
default_random_engine e(time(0));
for (int i = 0; i < 20000; ++i)
arr.emplace_back(u(e));
//for (auto i : arr)
//{
// cout << i << " ";
//}
cout << endl;
BubbleSort(arr);
SelectionSort(arr);
InsertionSort(arr);
ShellSort(arr);
HeapSort(arr);
MergeSort(arr);
QuickSort(arr);
}
int main() {
SortTest();
}
void percDown(vector<int>&arr, int i, int n)
{
//这是最大堆的下滤操作,将最大元素放到最上面
//i表示要下滤的空洞,n表示堆中有多少个元素
int child;
int temp;
for (temp = move(arr[i]); 2 * i + 1 < n; i = child)
{
//2*i+1表示结点i的左子节点(从0开始)
//2*i+1<n表示i结点的左子节点存在
//最右边表示如果i要下滤,那么就要将下滤到的字节点位置设置为新空洞(元素还是原来i位置那个元素)
child = 2 * i + 1;
if (child + 1 != n && arr[child] < arr[child + 1])
{
//这里左边的条件是判断右子节点是否存在
//右边的条件是判断右子节点是否比左子节点小
//是的话就将右子节点设置为结点i的最小字节点
++child;
}
if (temp < arr[child])//决定结点i是否要下滤
{
arr[i] = move(arr[child]);//要下滤
}
else
{
break;//这里表示这个堆已经满足条件,无需继续下滤
}
}
arr[i] = move(temp);
}
void merge(vector<int>& arr, vector<int>& tempArr, int leftPos, int rightPos, int rightEnd)
{
int leftEnd = rightPos - 1;
int tmpPos = leftPos;
int numElements = rightEnd - leftPos + 1;
//从左右两个子数组中逐一比较将小的元素放到临时数组
while (leftPos <= leftEnd && rightPos <= rightEnd)
if (arr[leftPos] <= arr[rightPos])
tempArr[tmpPos++] = move(arr[leftPos++]);
else
tempArr[tmpPos++] = move(arr[rightPos++]);
//将没有取完的数组剩下的元素放到临时数组
while (leftPos <= leftEnd)
tempArr[tmpPos++] = move(arr[leftPos++]);
while (rightPos <= rightEnd)
tempArr[tmpPos++] = move(arr[rightPos++]);
//将排好序的数组放回原数组中
for (int i = 0; i < numElements; ++i, --rightEnd)
arr[rightEnd] = move(tempArr[rightEnd]);
}
void mergeSort(vector<int>& arr, vector<int>& tempArr, int left, int right)
{
if (right - left <= 10) //如果子数组太小可以直接用插入排序
{
for (int i = left+1; i <= right; ++i)
{
auto temp = arr[i];
int j = i - 1;
for (; j >= left; --j)
{
if (arr[j] > temp) {
swap(arr[j], arr[j + 1]);
}
else
{
break;
}
}
arr[j + 1] = temp;
}
return;
}
int center = (left + right) / 2;
mergeSort(arr, tempArr, left, center);
mergeSort(arr, tempArr, center + 1, right);
merge(arr, tempArr, left, center + 1, right);
}
int median3(vector<int>& arr, int left, int right)
{
//找到一个枢纽元素
//要求首元素和枢纽元素和尾元素从小到大排列
//然后将枢纽元素放到倒数第二位的位置
int center = (right + left) / 2;
if (arr[center] < arr[left])
swap(arr[center], arr[left]);
if (arr[right] < arr[left])
swap(arr[right], arr[left]);
if (arr[center] > arr[right])
swap(arr[center], arr[right]);
swap(arr[center], arr[right - 1]);
return arr[right - 1];
}
void quickSort(vector<int>& arr, int left, int right)
{
if (left + 10 <= right)//如果数组较小就直接使用插入排序
{
int pivot = median3(arr, left, right);
int i = left, j = right - 1;
//实际上i从left+1的位开始,j从right-2的位置开始
//因为left,right的元素大小必定符合要求
for (;;)
{
while (arr[++i] < pivot) {}
while (pivot < arr[--j]) {}
if (i < j)
swap(arr[i], arr[j]);
else
break;
}
swap(arr[i], arr[right - 1]);//恢复枢纽元素
//将枢纽元素左边和右边的元素进行排序
quickSort(arr, left, i - 1);
quickSort(arr, i + 1, right);
}
else
{
for (int i = left + 1; i <= right; ++i)
{
auto temp = arr[i];
int j = i - 1;
for (; j >= left; --j)
{
if (arr[j] > temp) {
swap(arr[j], arr[j + 1]);
}
else
{
break;
}
}
arr[j + 1] = temp;
}
return;
}
}