#include <iostream>
#include <algorithm>
using namespace std;
/** 排序相关算法
* 插入排序:
* 1.直接插入排序 稳定
* 2.折半插入排序 稳定
* 3.希尔排序 不稳定
* 快速排序:
* 4.冒泡排序 稳定
* 5.快速排序 不稳定
* 选择排序:
* 6.简单选择排序 不稳定
* 7.堆排序 不稳定
* 归并排序:
* 8.二路归并排序 稳定
*/
/**1.直接插入排序
* 思想:(1)第一个记录是有序的
* (2)从第二个记录开始,按关键字的大小将每个记录插入到已排好序的序列中
* (3)一直进行到第n个记录
*/
void InsertionSort(int list[], int length)
{
if (!length || !(length - 1)) //空数组或只有一个元素直接返回
return;
for (int i = 1; i < length; i++)
{
int j;
int shell = list[i]; //设当前元素为哨兵
for (j = i - 1; j >= 0 && list[j] > shell; j--)
list[j + 1] = list[j]; //比哨兵大,后移
list[j + 1] = shell; //找到恰当位置了,插入
}
}
//折半插入排序
void BiInsertionSort(int list[], int length)
{
if (!length || !(length - 1))
return;
for (int i = 1; i < length; i++)
{
int j;
int shell = list[i];
int low = 0, high = i - 1;
while (low <= high) //与直接插入排序相比,多了一个二分查找插入位置
{
int m = (low + high) / 2;
if (shell > list[m])
low = m + 1;
else
high = m - 1;
}
for (j = i - 1; j >= high + 1; j--)
list[j + 1] = list[j];
list[j + 1] = shell;
}
}
//希尔排序
void ShellInsert(int *list, int length, int dk)
{
if (!length || !(length - 1))
return;
for (int i = dk; i < length; i++)
{
int shell = list[i];
int j;
for (j = i - dk; j >= 0 && shell < list[j]; j -= dk)
list[j + dk] = list[j];
list[j + dk] = shell;
}
}
void ShellSort(int *delta, int k, int *list, int length)
{
for (int i = 0; i < k; i++)
ShellInsert(list, length, delta[i]); //进行增量为delta[i]的直接插入排序
}
//冒泡排序
void BubbleSort(int *list, int length)
{
int i = length, lastEx;
while (i > 0)
{
lastEx = 0;
for (int j = 0; j < i; j++)
{
if (list[j] > list[j + 1]) //把未排序部分的最大值上浮,使得每趟排序后完成的部分至少加一
{
int temp = list[j];
list[j] = list[j + 1];
list[j + 1] = temp;
lastEx = j;
}
}
i = lastEx; //最后一次交换后面的已经完成排序
}
}
//快速排序
void QuickSort(int *list, int low, int high)
{
int Olow = low, Ohigh = high; //记录原来的上界和下界
if (low < high)
{
auto midOfThree = [](int a, int b, int c) { return min(a, max(b, c)); };
int shell = midOfThree(list[low], list[high], list[(low + high) / 2]); //用low,high以及中间的数三个数的中位数做轴
while (low < high) //根据轴将左右分为小于轴的部分和大于轴的部分
{
while (low < high && list[high] >= shell) //找到比轴小的数,放低半区
--high;
list[low] = list[high]; //low原来的值已经拷贝,放心赋值
while (low < high && list[low] <= shell) //找到比轴大的数,放高半区
++low;
list[high] = list[low]; //high原来的值赋给了上面,不用担心丢失
}
list[low] = shell;
QuickSort(list, Olow, low - 1); //对低半区递归
QuickSort(list, low + 1, Ohigh); //对高半区递归
}
}
//简单选择排序
void SelectSort(int *list, int length)
{
for (int i = 0; i < length - 1; i++)
{
int shell = list[i], minindex = i; //记录当前的值
for (int j = i; j < length; j++)
{
if (list[j] < list[minindex]) //寻找未排序部分最小值
minindex = j;
}
if (i != minindex) //如果当前值不是未排序部分最小值,进行交换
{
list[i] = list[minindex];
list[minindex] = shell;
}
}
}
//堆排序
//对于从0开始的数组
//parent = [(i - 1)/2] [x]表示对x向下取整
//lChild = 2*i + 1
//rChild = 2*i + 2
void Heapify(int *list, int root, int high)
{
if (root >= high) //越界了,直接返回
return;
int lChild = 2 * root + 1;
int rChild = 2 * root + 2;
int maxi = root;
if (lChild < high && list[lChild] > list[maxi])
maxi = lChild;
if (rChild < high && list[rChild] > list[maxi])
maxi = rChild;
//找到了三者最大值,若不是根节点
if (maxi != root)
{
int temp = list[maxi];
list[maxi] = list[root];
list[root] = temp; //最大者上浮
Heapify(list, maxi, high); //可能破坏了交换的那一边的堆结构,重新heapify一下
}
}
void HeapSort(int *list, const int length)
{
for (int i = length / 2; i >= 0; i--) //length/2之后的都是叶子节点,已经符合要求,不需要heapify
{
Heapify(list, i, length); //一定是自底向上开始建堆,因为只有两个孩子都是堆的情况下才能heapify整体,而叶子节点我们认为已经heapify
}
for (int i = length - 1; i >= 0; i--) //上面建的大根堆,最大值在头上
{
int temp = list[i];
list[i] = list[0];
list[0] = temp; //交换0,i位置的值,让未排序最大值加入到排好序的地方,未排序部分长度减一
Heapify(list, 0, i); //对0->i-1重新建堆
}
}
//归并排序
void MSort(int *list, int *helper, int low, int high)
{
if (low == high)//递归结束
return;
int mid = (low + high) / 2;
MSort(list, helper, low, mid);//前一半排好序
MSort(list, helper, mid + 1, high);//后一半排好序
int i = low, j = mid + 1;
int k = low;
while (k <= high)
{
if (j > high || i <= mid && helper[i] <= helper[j])//前后两半归并在一起
{
list[k++] = helper[i++];
}
else
{
list[k++] = helper[j++];
}
}
for (int i = low; i <= high; i++)
helper[i] = list[i];
}
void MergeSort(int *list, int length)
{
int *helper = (int *)malloc(sizeof(int) * length);
for (int i = 0; i < length; i++)
helper[i] = list[i];
MSort(list, helper, 0, length - 1);
free(helper);
}