十大基础排序算法

这篇具有很好参考价值的文章主要介绍了十大基础排序算法。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

排序算法分类

排序:将一组对象按照某种逻辑顺序重新排列的过程。

  • 按照待排序数据的规模分为:

    1. 内部排序:数据量不大,全部存在内存中;
    2. 外部排序:数据量很大,无法一次性全部存在内存中,因此排序中需要访问外存。
  • 按照排序是否稳定分为:

    1. 稳定排序:相等的元素在排序前后的相对位置不变。例如,a等于b,且原序列a在b前,排序后a仍在b前,则为稳定排序。
    2. 不稳定排序:相等元素在排序前后的相对位置可能发生变化。
  • 按照是否需要额外内存分为:

    1. 原地排序:在排序过程中不申请多余的存储空间,只利用原来存储待排数据的存储空间进行比较和交换的数据排序。
    2. 非原地排序:需要额外内存空间存储数组副本以辅助排序。
  • 按照排序方式分为:

    1. 比较类排序:通过比较来决定元素间的相对次序。
    2. 非比较类排序:不通过元素间的比较进行排序。
      十大基础排序算法,排序算法,算法,数据结构

比较类排序

冒泡排序

冒泡排序是一种典型的交换排序

算法原理:

  • 比较相邻的元素。如果第一个比第二个大,就交换它们两个;
  • 对每一对相邻元素做同样的工作,从开始第一对到结尾的最后一对。这一步结束后,排在最后的元素会是所有数据中最大的数;
  • 针对所有的元素重复以上的步骤,除了最后一个;
  • 持续每次对越来越少的元素重复上面的步骤,直到没有任何一对数字需要比较。

冒泡排序基本代码如下:

void BubbleSort(vector<int>& nums){
    const int size = nums.size();
    for(int i = 0; i < size; ++i)
        for(int j = 0; j < size-i-1; ++j)
            if(nums[j] > nums[j+1])
                swap(nums[j], nums[j+1]);
}

性能评价:

  • nums[j] == nums[j+1]时,我们并不交换它们。所以冒泡排序是稳定的;
  • 共循环了(n-1)+(n-2)+…+2+1=n(n-1)/2,所以时间复杂度是O(n^2)。

快速排序

快速排序是从冒泡排序演变而来的,实际上是在冒泡排序基础上的递归分治法。
快速排序在每一轮挑选一个基准元素,并让其他比它大的元素移动到数列一边,比它小的元素移动到数列的另一边,从而把数列拆解成了两个部分。

快排也用了分治策略,其本质框架类似二叉树的前序遍历。

其实现代码如下:

void QuickSort(std::vector<int>& nums, int left, int right){
    if(left >= right){
        return;
    }
    //"治"
    int i = left;
    int j = right;
    while(i < j){
        while(i < j && nums[j] > nums[left])     --j;
        while(i < j && nums[i] <= nums[left])    ++i;
        std::swap(nums[i], nums[j]);
    }
    std::swap(nums[i], nums[left]);
    //“分”
    QuickSort(nums, left, i - 1);
    QuickSort(nums, i + 1, right);
}

注意事项

  1. 如果选取数列的第一个元素为基准元素,则从right所指向的元素开始与基准元素进行比较;如果选取数列的最后一个元素为基准元素,则从left所指向的元素开始与基准元素进行比较。
  2. 如果选取数列的第一个元素为基准元素,left所指向的元素与基准元素第一次对比时,left下标与基准元素下标相等(即:判断条件中添加等号);如果选取数列的最后一个元素为基准元素,right所指向的元素与基准元素第一次对比时,right下标与基准元素下标相等。

时间复杂度:O(nlogn)
空间复杂度:O(1)
稳定性:不稳定

插入排序

基本思想:将待排序数据看成由已排序未排序两部分组成。对于未排序数据,在已排序序列中从后向前扫描,找到相应位置并插入。

算法流程:

  1. 从第一个元素开始,该元素可以认为已经被排序;
  2. 取出下一个元素,在已经排序的元素序列中从后向前扫描;
  3. 如果该元素(已排序)大于新元素,将该元素移到下一位置;
  4. 重复步骤3,直到找到已排序的元素小于或者等于新元素的位置;
  5. 将新元素插入到该位置后;
  6. 重复步骤2~5。

其实现代码如下:

void InsertSort(vector<int>& nums){
    const int size = nums.size();
    for(int i = 1; i < size; ++i){
        int curr = nums[i];
        int j = i - 1;
        while(j >= 0 && curr < nums[j]){
            nums[j+1] = nums[j];
            --j;
        }
        nums[j+1] = curr;
    }
}

性能评价:

  • 插入排序是稳定的。
  • 时间复杂度为O(n^2)。

希尔排序

在插入排序中,当需要插入的数是较小的数时,后移的次数明显增多,对效率有影响.

希尔排序是对插入排序的优化。它与插入排序的不同之处在于,它会优先比较距离较远的元素。希尔排序又叫缩小增量排序
十大基础排序算法,排序算法,算法,数据结构

其实现代码如下:

void ShellSort(std::vector<int>& nums){
    const int size = nums.size();
    for(int gap = size / 2; gap > 0; gap /= 2){
        for(int i = gap; i < size; ++i){
            int curr = nums[i];
            int j = i - gap;
            while(j >= 0 && curr < nums[j]){
                nums[j+gap] = nums[j];
                j -= gap;
            }
            nums[j+gap] = curr;
        }
    }
}

选择排序

基本思想:首先在未排序数据找到最小的数,然后把该最小数放到排序序列的末尾,直到所有数据排序完毕。

其实现代码如下:

void SelectionSort(vector<int>& nums){
    const int size = nums.size();
    for(int i = 0; i < size-1; ++i){
        int minIndex = i;
        for(int j = i+1; j < size; ++j)
            if(nums[j] < nums[minIndex])
                minIndex = j;
        swap(nums[i], nums[minIndex]);
    }
}

性能评价:

  • 简单选择排序是不稳定排序;
  • 无论什么数据进去,它的比较次数都是n(n-1)/2,所以时间复杂度是O(n^2)。

堆排序

首先将等待排序的数组构造成一个大根堆,构造结束后整个数组当中的最大值就是堆顶元素;
然后将堆顶元素与数组末尾元素交换位置,交换结束后数组末尾元素为最大值,剩下其他的待排序的数组个数为n-1个;
将剩余的n-1个数再次构造成一个大根堆,再将堆顶元素与数组第n-1个位置的元素交换位置,重复上述步骤可以最终得到一个有序数组。

其实现代码如下:

//堆调整
void Heapify(std::vector<int>& nums, int index, int heap_size){
    int parent_index = index;
    int leftChild_index = 2 * parent_index + 1;
    while(leftChild_index < heap_size){
        int maxValue_index = leftChild_index+1 < heap_size && nums[leftChild_index+1] > nums[leftChild_index] ? leftChild_index+1 : leftChild_index;
        maxValue_index = nums[maxValue_index] > nums[parent_index] ? maxValue_index : parent_index;
        if(maxValue_index == parent_index)
            return;
        std::swap(nums[maxValue_index], nums[parent_index]);
        parent_index = maxValue_index;
        leftChild_index = 2 * parent_index + 1;
    } 
}
//堆排序
void HeapSort(std::vector<int>& nums){
    if(nums.size() < 2)
        return;
    int heap_size = nums.size();
    //从下标最大的父节点开始。(最后一个元素的下标是n-1,最后一个父节点的下标是n/2-1)
    for(int i = heap_size/2 - 1; i >= 0; --i)
        Heapify(nums, i, heap_size);

    std::swap(nums[0], nums[--heap_size]);

    while(heap_size > 0){
        Heapify(nums, 0, heap_size);
        std::swap(nums[0], nums[--heap_size]);
    }
}

时间复杂度:O(nlogn)
空间复杂度:O(1)
稳定性:不稳定

归并排序

简单归并排序即二路归并排序。

归并排序采用分治策略,其本质框架类似二叉树的后序遍历,左右子树的递归就是“分”,根结点的处理部分就是“治”。

十大基础排序算法,排序算法,算法,数据结构

其实现代码如下:

std::vector<int> temp;
void MergeSort(std::vector<int>& nums, int left, int right){
    if(left >= right){
        return;
    }
    int mid = left + (right - left) / 2;

    //“分”
    MergeSort(nums, left, mid);
    MergeSort(nums, mid + 1, right);

    //"治"
    int i = left;
    int j = mid + 1;
    int t = left;
    while(i <= mid && j <= right){
        if(nums[i] <= nums[j]){
            temp[t++] = nums[i++];
        }
        else{
            temp[t++] = nums[j++];
        }
    }
    while(i <= mid){
        temp[t++] = nums[i++];
    }
    while(j <= right){
        temp[t++] = nums[j++];
    }
    for(int k = left; k <= right; ++k){
        nums[k] = temp[k];
    }
}

时间复杂度:O(nlogn)
空间复杂度:O(n)
稳定性:稳定

非比较类排序

基数排序

计数排序

桶排序

总结

十大基础排序算法,排序算法,算法,数据结构

不稳定排序记忆口诀:一堆(堆排序)作业,心态不稳,快(快速排序)选择(选择排序)一些(希尔排序)朋友出去玩。文章来源地址https://www.toymoban.com/news/detail-836958.html

到了这里,关于十大基础排序算法的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 头歌数据结构实训参考---十大经典排序算法

    可通过 目录 快速查阅对应排序算法

    2024年02月04日
    浏览(62)
  • 数据结构基础之排序算法

    在数据结构中,常见的排序算法有以下几种: 冒泡排序(Bubble Sort):通过比较相邻元素并交换它们的位置,每轮将最大(或最小)的元素冒泡到末尾,重复执行直到排序完成。 特点:简单易懂,但对于大型数据集效率较低。 时间复杂度: 最优情况:O(n)(当数组已经排序好

    2024年02月15日
    浏览(37)
  • 数据结构:一篇拿捏十大排序(超详细版)

    排序: 所谓排序,就是使一串记录,按照其中的某个或某些的大小,递增或递减的排列起来的操作。 稳定性: 假定在待排序的记录序列中,存在多个具有相同的的记录,若经过排序,这些记录的相对次序保持不变,即在原序列中,r[i]=r[j],且r[i]在r[j]之前, 而

    2024年02月08日
    浏览(50)
  • C++基础-介绍·数据结构·排序·算法

    C++是一门风格严谨又不失自由的开发语言,提供了完整的内存管理、支持函数式编程和面向对象编程,支持模板、多继承、多实现、重载、重写等多态特性。 优势在于目前90%的操作系统、数据库、应用基础架构、硬件嵌入式等都是使用C/C++制作的,而C++是对C的标准扩展,掌握

    2024年02月03日
    浏览(43)
  • 数据结构与算法基础(王卓)(28):排序概述(分类)、直接插入排序思路

    目录 排序分类:(本章目录) 按数据存储介质:(学习内容) 内部排序: 外部排序: 按比较器个数:(学习内容) 串行排序: 并行排序: 按主要操作:(学习内容、里面的排序都会重点学) 比较排序: 基数排序: 按辅助空间: 原地排序: 非原地排序: 按稳定性: 稳

    2023年04月26日
    浏览(39)
  • DSt:数据结构的最强学习路线之数据结构知识讲解与刷题平台、刷题集合、问题为导向的十大类刷题算法(数组和字符串、栈和队列、二叉树、堆实现、图、哈希表、排序和搜索、动态规划/回溯法/递归/贪心/分治)总

    Algorithm:【算法进阶之路】之算法面试刷题集合—数据结构知识和算法刷题及其平台、问题为导向的十大类刷题算法(数组和字符串、链表、栈和队列、二叉树、堆、图、哈希表、排序和搜索、回溯算法、枚举/递归/分治/动态规划/贪心算法)总结 目录 相关文章

    2024年02月08日
    浏览(52)
  • 数据结构——排序算法——归并排序

    在第二个列表向第一个列表逐个插入的过程中,由于第二个列表已经有序,所以后续插入的元素一定不会在前面插入的元素之前。在逐个插入的过程中,每次插入时,只需要从上次插入的位置开始,继续向后寻找插入位置即可。这样一来,我们最多只需要将两个有序数组遍历

    2024年02月09日
    浏览(42)
  • 【排序算法】数据结构排序详解

    前言: 今天我们将讲解我们数据结构初阶的最后一部分知识的学习,也是最为“炸裂”的知识---------排序算法的讲解!!!! 排序 :所谓排序,就是使一串记录,按照其中的某个或某些的大小,递增或递减的排列起来的操作。 稳定性 :假定在待排序的记录序列中,

    2023年04月08日
    浏览(49)
  • 数据结构和算法笔记4:排序算法-归并排序

    归并排序算法完全遵循分治模式。直观上其操作如下: 分解:分解待排序的n个元素的序列成各具n/2个元素的两个子序列。 解决:使用归并排序递归地排序两个子序列。 合并:合并两个已排序的子序列以产生已排序的答案。 我们直接来看例子理解算法的过程,下面是要排序

    2024年01月21日
    浏览(62)
  • 数据结构——排序算法之快速排序

        个人主页: 日刷百题 系列专栏 : 〖C/C++小游戏〗 〖Linux〗 〖数据结构〗   〖C语言〗 🌎 欢迎各位 → 点赞 👍+ 收藏 ⭐️+ 留言 📝  ​ ​ 快速排序是Hoare于1962年提出的一种二叉树结构的交换排序方法。 基本思想: 任取待排序元素序列中 的某元素作为基准值,按照

    2024年01月21日
    浏览(54)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包