常用排序算法

1.快速排序(使用最常见的排序算法)

算法分析
  • 快速排序是一个分治思想,平均复杂度是n*lg(n)。
    Divide:数组A[p…r]分为两个子数组A[p…q-1],A[q+1…r],使得A[p…q-1]上所有元素小于A[q];A[q+1…r]上所有的元素都大于A[q]。
    Conquer:通过对快排的递归,对两个子数组A[p…q-1]和A[q+1…r]进行排序。
    Combine:分完就已经有序。
实现
//=========快排算法=========
//使得arr[low]..arr[q-1]中的每一个元素都小于等于arr[q], arr[q]也小于等于arr[q+1]..arr[high]。
//简而言之,让左边的数字都小于右边的数字
//最坏时间复杂度:n^2 , 平均时间复杂度:n*lg(n)
//优化:为了使得输入均匀的分布,对输入使用随机数
//排序一个数组,初始调用Qsort(A,0,A.size()-1).
//=========================
int partirtion(int A[],int low,int high){
    int x = A[high];
    int i = low - 1;
    for(int j = low;j < high; j++){
        //左边的数字如果大于右边的数字,就交换位置
        if(A[j] <= x){
            i++;
            //互换A[i]和A[j]
            int tmp = A[i];
            A[i] =A[j];
            A[j] = tmp;
        }
    }
    //将主元(pivot)给到i的下一个
    int temp = A[i+1];
    A[i+1] = A[high];
    A[high] = temp;
    return i+1;
}
void Qsort(int arr[], int low, int high){
    if(low < high){
        int q =partirtion(arr,low,high);
        Qsort(arr,low,q-1);
        Qsort(arr,q+1,high);
    }
}

2.插入排序

算法分析
  • 适用于少量元素的排序,工作方式就像是排序一副扑克牌,每次从右向左对每一张牌进行比较。最坏情况是n2
实现
//=============插入排序==========
//从插入的位置起步,往前作比较,输入n指长度
//===============================
void insertSort(int A[],int n){
    for(int i = 1;i < n;i++){
        //把A[i]插入到A[1..i-1]中
        int key = A[i];
        int j = i - 1;
        while(j >0 && A[j] > key){
            A[j+1] = A[j];
            j--;
        }
        //j+1就是需要插入的位置
        A[j + 1] = key;
    }
}

3.并归排序

算法分析
  • 归并排序完全按照分治的思想,关键的操作在于合并步骤,需要时间复杂度为n。
实现
//===========归并排序==========
//Merge就是合并的过程,相当于在两堆排好序的牌中,每次选取最上面的两张进行比较,选取其中较小的一张
//A是数组,p<=q<r,Merge过程假设A[p..q]和A[q+1..r]都已经排好序了,元素的总数是:n = r-p+1
//r,q,p都是指的下标
//=============================
void merge(int A[], int p, int q, int r){
    //n1 n2 就是两个新数组的界
    int n1 = q - p +1;
    int n2 = r - q;
    //将这两个赋值为左右两个新数组,最后一个数放入一个最大数作为结尾标志
    int *L = new int[n1+1];
    int *R = new int[n2+1];
    for(int i = 0; i < n1; i++){
        L[i] = A[p+i];
    }
    for(int i = 0; i < n2; i++){
        R[i] = A[q+i+1];
    }
    L[n1] = INT8_MAX;
    R[n2] = INT8_MAX;
    //i记录左边数组的下标,j记录右边数组的下标
    int i = 0, j = 0;
    for(int k = p; k < r; k++){
        if(L[i] <= R[j]){
            A[k] = L[i];
            i++;
        } else{
            A[k] = R[j];
            j++;
        }
    }
}
void mergeSort(int A[], int p, int r){
    if(p < r){
        int q = (p+r)/2;
        mergeSort(A,p,q);
        mergeSort(A,q+1,r);
        merge(A,p,q,r);
    }
}

4.计数排序

算法分析
  • 计数排序的基本思想是:对每一个输入元素x,确定小于x的元素个数。利用这个性质就可以直接把x放到指定输出数组的位置上了。适用于数组中的元素都小于数组中的最大元素的情况。
实现
//===========计数排序==============
//函数输入为:input输入数组、n是输入和输出数组的长度、k是数组中的最大数
//================================
void countSort(int input[], int n, int k){
    int* counter = new int[k+1];
    int* output = new int[n];
    //初始化计数器
    for(int i = 0; i <= k;i++){
        counter[i] = 0;
    }
    //记录输入有多少个当前counter下标的值
    for(int i = 0;i < n;i++){
        counter[input[i]]++;
    }
    //对每一个下标记录与之前的求和,求和的结果就是下标在输出数组的位置
    for(int i = 1; i <= k;i++){
        counter[i] = counter[i]+counter[i-1];
    }
    //通过计数器寻址,对输出赋值
    for(int i = n-1;i >=0;i--){
        //个数还需要减1,成为下标
        output[counter[input[i]]-1] = input[i];
        counter[input[i]]--;
    }
    //将输出给输入
    for(int i = 0;i < n;i++){
        input[i] = output[i];
    }
}

5.基数排序

算法分析
  • 基数排序是对每一个数的每一位进行排序,运行时间为n,比快排的n*lg(n)要好。
实现
//=========基数排序===============
//先求出所有数中最大数字的位数
//再根据键值的每一位数字,来分配一个桶
//===============================
int maxbit(int data[], int n) //辅助函数,求数据的最大位数
{
    int maxData = data[0];              ///< 最大数
    /// 先求出最大数,再求其位数,这样有原先依次每个数判断其位数,稍微优化点。
    for (int i = 1; i < n; ++i)
    {
        if (maxData < data[i])
            maxData = data[i];
    }
    int d = 1;
    int p = 10;
    while (maxData >= p)
    {
        //p *= 10; // Maybe overflow
        maxData /= 10;
        ++d;
    }
    return d;
}
void radixsort(int data[], int n) //基数排序
{
    int d = maxbit(data, n);
    int *tmp = new int[n];
    int *count = new int[10]; //计数器
    int i, j, k;
    int radix = 1;
    for(i = 1; i <= d; i++) //进行d次排序
    {
        for(j = 0; j < 10; j++)
            count[j] = 0; //每次分配前清空计数器
        for(j = 0; j < n; j++)
        {
            k = (data[j] / radix) % 10; //统计每个桶中的记录数
            count[k]++;
        }
        for(j = 1; j < 10; j++)
            count[j] = count[j - 1] + count[j]; //将tmp中的位置依次分配给每个桶
        for(j = n - 1; j >= 0; j--) //将所有桶中记录依次收集到tmp中
        {
            k = (data[j] / radix) % 10;
            tmp[count[k] - 1] = data[j];
            count[k]--;
        }
        for(j = 0; j < n; j++){
            data[j] = tmp[j];
        }

        radix = radix * 10;
    }
    delete []tmp;
    delete []count;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值