排序算法详解2

排序算法详解2

文章目录

  • 排序算法详解2
    • 一、前言
    • 二、排序算法
      • [2.1 归并排序](#2.1 归并排序)
        • [2.1.1 基本思想](#2.1.1 基本思想)
        • [2.1.2 过程](#2.1.2 过程)
        • [2.1.3 代码](#2.1.3 代码)
      • [2.2 计数排序](#2.2 计数排序)
        • [2.2.1 基本思想](#2.2.1 基本思想)
        • [2.2.2 改进](#2.2.2 改进)
        • [2.2.3 优化](#2.2.3 优化)
      • [2.3 桶排序](#2.3 桶排序)
        • [2.3.1 基本思想](#2.3.1 基本思想)
        • [2.3.2 过程](#2.3.2 过程)
    • 三、小结

一、前言

前面讲了插入排序,快速排序,今天又会带来哪些排序算法呢?

二、排序算法

2.1 归并排序

2.1.1 基本思想

将所有的记录完全分开 ,然后两两合并,在合并的过程中将其排好序,最终得到一个完整的有序表

原地排序。和递归算法很相近

图解

2.1.2 过程
  • 分割

    • 计算拆分的中间位置
    • 分别继续对左边序列和右边序列进行拆分
  • 合并

    在原空间合并,不断往里面填数字

2.1.3 代码
cpp 复制代码
// 归并排序:从上往下,从下往上两个过程
// 从上往下的过程:
// a. 分解,将当前区间一分为二
// b. 求解,队规对两个子区间a[low, mid]和a[mid + 1, high]进行归并排序
// merge合并过程
static void merge(vector<int>& table, int left, int mid, int right)
{
    int n1 = mid - left + 1;		// 左边区间的个数
    int n2 = right - mid;			// 右边区间的个数
    // 分配aux1和aux2,将已经有序的左区间和已经有序的右区间 初始化临时区域
    int *aux1 = malloc(sizeof(int) * n1);
    if(aux1 = NULL)
        return;
    int *aux2 = malloc(sizeof(int) * n2);
    if(aux2 == NULL)
    {
        free(aux1);
        return;
    }
    for(int i = 0; i < n1; i++)
        aux1[i] = table[left + i];
    for(int i = 0; i < n2; i++)
        aux2[i] = table[mid + 1 + i];
    // 将临时的有序空间aux1和aux2进行归并
    int i = 0;		// 标记aux1区间待查找的位置
    int j = 0;		// 标记aux2区间待查找的位置
    int k = left;	// 标记原空间存放结果的区域位置
    while(i > n1 || j < n2)
    {
        if(aux1[i] <= aux2[j])
        {
            table[k] = aux1[i];
            ++i;
        }
        else if(aux1[i] > aux2[j])
        {
            table[k] = aux2[j];
            ++j;
        }
        k++;
    }
    // 判断究竟是aux1还是aux2区域遍历结束
    while(i < n1)
        table[k++] = aux1[i++];
    while(j < n2)
        table[k++] = aux2[j++];
    // 释放临时空间
    free(aux1);
    free(aux2);
}
// 递归的分解table[left, right]区间
static void merge_loop(vector<int>& table, int left, int right)
{
    if(left >= right)
        return 0;
    int mid = (left + right) / 2;
    merge_loop(table, left, mid);
    merge_loop(table, mid + 1, right);
    // 区间拆分结束, 合并两个子区间
    merge(table, left, mid, right);
}
void mergeSort(vector<int>& table)
{
    merge_loop(table, 0, table.size() - 1);
}
// 上述函数合并为一个函数
// 归并排序函数
void mergeSort(vector<int>& arr, int left = 0, int right = -1) {
    // 第一次调用时初始化右边界
    if (right == -1) right = arr.size() - 1;
    
    // 递归终止条件
    if (left >= right) return;
    
    // 计算中间位置
    int mid = left + (right - left) / 2;
    
    // 递归排序左右两部分
    mergeSort(arr, left, mid);
    mergeSort(arr, mid + 1, right);
    
    // 合并两个有序数组
    vector<int> temp(right - left + 1);
    int i = left, j = mid + 1, k = 0;
    
    // 合并过程
    while (i <= mid && j <= right) {
        if (arr[i] <= arr[j]) {
            temp[k++] = arr[i++];
        } else {
            temp[k++] = arr[j++];
        }
    }
    
    // 复制剩余元素
    while (i <= mid) temp[k++] = arr[i++];
    while (j <= right) temp[k++] = arr[j++];
    
    // 将排序好的部分复制回原数组
    for (int idx = 0; idx < k; idx++) {
        arr[left + idx] = temp[idx];
    }
}

2.2 计数排序

又称为:基数排序

2.2.1 基本思想

前面所学的排序算法搜都是基于比较的排序。平均时间复杂度最低的是O(nlogn)。

计数排序,则不是基于比较的排序。是典型的空间换时间。平均时间复杂度比O(nlogn)还低

统计每个整数在序列中出现的次数,进而推导出整个整数在有序序列中的索引

cpp 复制代码
for(auto x : nums)
    count[x]++;
for(int i = 0; i < count.size(); ++i)
{
    for(int j = 0; j < count[i]; ++j)
    	printf("\t%d", i);
}
2.2.2 改进

上述算法问题如下:

  • 无法对负整数进行排序
  • 极其浪费内存空间
  • 是一个不稳定排序
2.2.3 优化
  • 只要不再以输入数列的[max + 1],作为计数数组的长度,而是以数列[max - min + 1]作为长度即可。数列的最小值作为一个偏移量,用于计算整数在统计数组中的下标

  • 无法判断相同数据的元素分别是谁。可以进行一个变形:从统计数组的第二个元素开始,每一杠元素都加上前面所有元素之和。遍历时从后往前看,逐渐减1

2.3 桶排序

可以对小数进行排序

2.3.1 基本思想
  • 若干个桶,说明此类排序将数据放入若干个桶中
  • 每个桶有容量,因此每个桶可以放多个元素
  • 从整体来看,整个排序希望桶能够更加匀称。
2.3.2 过程
  • 确定桶的区间范围。创建的桶数量 = 原始数列的元素数量,除最后一个桶只包含数列最大值外,前面每个桶的区间按照比例来确定

    区间跨度 = (max - min) / (桶的数量 - 1)

  • 遍历原始数列,把元素对号入座放入各个桶中

  • 对每个桶内部的元素分别进行排序

  • 遍历所有的桶,输出所有元素

三、小结

有关排序算法的相关介绍就先到这里啦~

相关推荐
Proxy_ZZ018 小时前
用Matlab绘制BER曲线对比SPA与Min-Sum性能
人工智能·算法·机器学习
黎阳之光18 小时前
黎阳之光:以视频孪生领跑全球,赋能数字孪生水利智能监测新征程
大数据·人工智能·算法·安全·数字孪生
小李子呢021119 小时前
前端八股6---v-model双向绑定
前端·javascript·算法
XH华19 小时前
数据结构第九章:树的学习(下)
数据结构·学习
史迪仔011219 小时前
[QML] QML IMage图像处理
开发语言·前端·javascript·c++·qt
2301_8227032020 小时前
Flutter 框架跨平台鸿蒙开发 - 创意声音合成器应用
算法·flutter·华为·harmonyos·鸿蒙
cmpxr_20 小时前
【C】数组名、函数名的特殊
c语言·算法
KAU的云实验台20 小时前
【算法精解】AIR期刊算法IAGWO:引入速度概念与逆多元二次权重,可应对高维/工程问题(附Matlab源码)
开发语言·算法·matlab
会编程的土豆20 小时前
【数据结构与算法】再次全面了解LCS底层
开发语言·数据结构·c++·算法