各种排序

#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;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值