#include <iostream>
#include <string.h>
#include <stdio.h>
using namespace std;
// 比较排序算法
// 冒泡排序 最差 O(n^2) - 大的往上小的往下,不断交换 - 稳定
void BobbleSort(int *a, int n){
for(int i=0;i<n;i++){
int flag = 0;
for(int j=1;j<n-i;j++){
if(a[j-1] > a[j]){
swap(a[j-1], a[j]);
flag = 1;
}
}
if(!flag) break;
}
}
// 鸡尾酒排序 最差 O(n^2) - 每次把大的往上,小的往下, - 稳定
void CocktailSort(int *a, int n){
int l = 0, r = n-1;
while(l<=r){
for(int i=l+1;i<=r;i++){
if(a[i]<a[i-1]) swap(a[i], a[i-1]);
}
r --;
for(int i=r-1;i>=l;i--){
if(a[i]>a[i+1]) swap(a[i], a[i+1]);
}
l ++;
}
}
// 选择排序 最差 O(n^2) - 每次选出最大的或最小的与第一个或最后一个未排序位置交换 - 不稳定
// 相对于冒泡排序,交换次数减少
void SelectionSort(int *a, int n){
for(int i=0;i<n;i++){
int mi = i;
for(int j=i;j<n;j++) {
if(a[j]<a[mi]) mi = j;
}
swap(a[i], a[mi]);
}
}
// 插入排序 最差 O(n^2) - 稳定
// 不适合数据量比较大的排序,少量的排序还是很好的,在sort中将此作为补充永远少量元素的排序(通常<=8)
void InsertionSort(int *a, int n){
for(int i=1;i<n;i++){
int val = a[i], pos = i-1;
// 找到有序序列中第一个大于a[i]的位置
// 找的操作可以用二分查找来代替,但依旧要交换
for(;pos>=0;pos--){
if(a[pos]<=val) break;
a[pos+1] = a[pos];
}
a[pos+1] = val;
}
}
// 插入排序改进 - 希尔排序(递减增量排序)
// 根据步长来决定 最差时间复杂度
// 最好 O(n)
// 不稳定
// 针对插入排序下述特点进行改进
// 1、每次只能将数据移动一位 2、对几乎有序的数据效率较高
// 一次可以移动很多位,后面移动的步数逐步减小,最后一次移动步数为1,此时几乎已经有序,插入排序效率较高
void ShellSort(int *a, int n){
int h = 0; // 增量
while(h * 3 + 1 < n) h = h * 3 + 1;
// 基础的插入排序就是 h = 1
while(h >= 1){
for(int i=h; i<n; i++){
int pos = i - h, val = a[i];
while(pos>=0 && a[pos]>val){
a[pos+h] = a[pos];
pos = pos - h;
}
a[pos+h] = val;
}
h = (h-1) / 3; // 令增量递减
}
}
// 归并排序 - 稳定
// 时间复杂度 O(nlogn) 辅助空间O(n);
void Merge(int *a,int l,int mid,int r){
int len = r - l + 1;
int *temp = new int[len];
int sz = 0, p1 = l, p2 = mid + 1;
while(p1<=mid && p2<=r){
if(a[p1]<=a[p2]) temp[sz++] = a[p1++]; // 等号保证了稳定性
else temp[sz++] = a[p2++];
}
while(p1<=mid) temp[sz++] = a[p1++];
while(p2<=r) temp[sz++] = a[p2++];
for(int i=0;i<sz;i++) a[l+i] = temp[i];
}
void MergeSortMain(int *a, int l, int r){ // 递归实现
if(l == r) return;
int mid = (l+r)>>1;
MergeSortMain(a, l, mid); // 对左边排序
MergeSortMain(a, mid+1, r); // 对右边排序
Merge(a, l, mid, r); // 连接两个有序数列
}
void MergeSrotMain2(int *a, int n){ // 非递归实现
int l, r, mid;
for(int i=1;i<n;i<<=1){ // 排序组的长度,每次相邻两对长度为i的进行排序,然后合并
l = 0;
while(l+i < n){
mid = l + i - 1;
r = mid + i;
r = min(r, n-1);
Merge(a, l, mid, r);
l = r + 1;
}
}
}
// 堆排序 时间O(nlogn) 不稳定
// 最大堆(大根堆、大顶堆),父节点比子节点大,是一个近似完全二叉树的结构
void Heapify(int *a, int i, int sz){ // 调整堆 从上往下调整
int l = i<<1, r = i<<1|1, mx = i;
if(l<=sz && a[l] > a[mx]) mx = l;
if(r<=sz && a[r]>a[mx]) mx = r;
if(mx == i) return; // 从左右子节点,和本身找最大的,若为子节点则交换
swap(a[i], a[mx]);
Heapify(a, mx, sz); // 递归找到该点应该在的位置
}
void BuildHeap(int *a, int n){ // 建堆 O(n) 从下往上建
// n/2 的由来,为最右下的非叶子结点,最后一个叶子结点为n,其父节点为n/2,就是最后一个非叶子结点
for(int i=n/2;i>0;i--) Heapify(a, i, n);
}
void HeapSort(int *a, int n){
int sz = n; BuildHeap(a, n);
while(sz>1){
swap(a[1], a[sz--]); // 每次找到最大的和最后一个换,然后堆就不断减小
Heapify(a, 1, sz);
}
}
// 快速排序 平均 O(nlogn) 最差 O(n^2)
int Partition(int *a,int l,int r){
int p = a[r]; // 选择最后一个作为基准
int tail = l - 1;
for(int i=l;i<r;i++){
if(a[i]<p) swap(a[++tail], a[i]);
}
swap(a[++tail], a[r]);
return tail;
}
void QuickSort(int *a, int l, int r){
if(l>=r) return;
int index = Partition(a, l, r);
QuickSort(a, l, index - 1);
QuickSort(a, index + 1, r);
}
// 非比较排序
// 计数排序 O(n+mx) 空间 O(n+mx)
// 适用于0-99之间的排序,数据范围较大并不适合(除非类型较少可以用离散化来处理
void CountSort(int *a, int n){
int b[15], c[15];
memset(c, 0, sizeof c);
for(int i=0;i<n;i++) c[a[i]] ++; // 先记录每个数字出现的次数
int mx = 9; // 记录最大值
for(int i=1;i<=mx;i++) c[i] += c[i-1]; // 记录每个数字的最后排名
for(int i=n-1;i>=0;i--) b[-- c[a[i]]] = a[i]; // 从后往前确保稳定性
for(int i=0;i<n;i++) a[i] = b[i]; // 赋值
}
// 基数排序 (基于计数排序) (大整数排序也可用)
// 利用每个数的每位来排序
int p = 10; // 基数 每一位都是[0,9]的整数
int dn = 3; // 要排序的数的位数
int C[15]; // C[p];
int get_pos(int x, int d){ // 数 x 的第 d 位数
int radix[] = {1,1,10,100};
return (x/radix[d]) % p;
}
// 对第d位数计数排序部分
void Counting_sort(int *A, int n, int d){ // 对A数组进行在第d为的计数排序
for(int i=0;i<p;i++) C[i] = 0;
for(int i=0;i<n;i++) C[get_pos(A[i], d)] ++;
for(int i=1;i<p;i++) C[i] += C[i-1];
int *B = new int [n];
for(int i=n-1;i>=0;i--) {
int digit = get_pos(A[i], d);
B[-- C[digit]] = A[i];
}
for(int i=0;i<n;i++) A[i] = B[i];
delete[] B;
}
// 最低位优先基数排序
void LsdRadixSort(int *A,int n){
for(int i=1;i<=dn;i++) Counting_sort(A, n, i);
}
// 桶排序
int main()
{
int a[15] = {1,3,5,7,9,8,6,4,2,0};
int b[15] = {0,1,3,5,7,9,8,6,4,2,0};
// BobbleSort(a, 10);
// CocktailSort(a, 10);
// SelectionSort(a, 10);
// InsertionSort(a, 10);
// ShellSort(a, 10);
// MergeSortMain(a, 0, 9);
// MergeSrotMain2(a, 10);
// HeapSort(b, 10);
// QuickSort(a, 0, 9);
// CountSort(a, 10);
// LsdRadixSort(a, 10);
for(int i=0;i<10;i++) cout<<a[i]<<" ";
cout<<endl;
for(int i=1;i<=10;i++) cout<<b[i]<<" ";
cout<<endl;
return 0;
}