十大排序算法

1. 排序算法简介

1.1排序算法简介

排序算法可以分为内部排序和外部排序,内部排序是数据记录在内存中进行排序,而外部排序是因排序的数据很大,一次不能容纳全部的排序记录,在排序过程中需要访问外存。常见的内部排序算法有:插入排序、希尔排序、选择排序、冒泡排序、归并排序、快速排序、堆排序、基数排序等。

下面这张图是对排序算法复杂度和稳定性的总结。
在这里插入图片描述

1.2 稳定性

(1)稳定性是什么?
稳定性是指:两个值相同的元素在相对位置在排序后保持不变。也就是说举个例子,数列

a1,  c , b, a2 //a1 == a2 

经过排序之后,若变为

a1, a2, b, c

可以看到a1 和 a2的相对位置保持不变,a1仍然排在a2前面,因此这样的排序是稳定的。

因此,稳定的排序算法将保持相同元素的相对位置不变,而不问你定的排序算法不能保证相同元素的相对位置保持不变。

(2)稳定性应用

什么情况下需要排序算法具有稳定性?举个例子你有明白了

题目描述:
工人搬运一批水果,用一维数组存储工人编号和水果名称以及搬运重量,要求先按照水果分组,然后按照搬运重量排序输出

输出描述
先按照水果分组,然后按照工人的搬运重量从小到大进行排序,并将排序后的信息打印出来,如果工人的搬运重量相同,则按照编号的大小升序排列,并且要求水果的输出次序同输入次序

注意:输出描述中写的,要求输出次同输入次序,在这样一个多维度排序的场景下,就有可能会用到稳定性排序这一特点。在我们的数列表示中,我们常常会按照输入次序对数组有一个初始的排列,我们在对其它维度的数据进行排列是,如果使用稳定排序,那么,就可完全不管最后一个要求——要求水果的输出次序同输入次序。

2. 排序算法

2.1选择排序

选择排序是指,每次从当前的数列中选择一个最小值防止到最前面。这是升序排列,降序排列就是选择一个最大值,放置到最前面。假设数列长度为n,第一次就对整个数列进行选择,就可以选出整个数列的最小值放在整个数列第一个位置,第二次,则可以在剩下的n-1个数字中选出一个最小值,放到整个数列第2个位置,如此重复,直到最终剩下的数列长度为1。

void selectsort(int *nums, int len)
{
   
    for (int i = 0; i < len; i++)
    {
   
        int min_index = i;
        for (int j = i; j < len; j++)
        {
   
            if (nums[min_index] > nums[j])
                min_index = j;
        }
        
        if (min_index != i)
            swap(nums[i], nums[min_index]);
    }
}

时间复杂度分析
基本运算是比较,总共有n轮,每一轮进行 n - i 次比较,则有
时间复杂度为 O(n^2)

空间复杂度分析
不占用额外的空间,因此为O(1)

稳定性分析
由于选择得到最小的元素a后,会与当前选择的数列中的第一个元素b交换位置,而如果在元素a的前面存在另一个元素b,那么这两个b的相对位置就发生了变化,因此,选择排序是不稳定的。

这里假设一个数列:

5 8 5 2 9

在第一轮中,第一个5会和2交换位置,此时两个5的相对位置发生了变化。

2.1 插入排序

插入排序是指从左至右遍历数列,依次为每个元素找到合适位置。当遍历到底n个元素时,前面的n-1个元素已经按照升序排列,将第n个元素插入到前n-1个中,使其保持升序。

void insertsort(int *nums, int len)
{
   
    for (int i = 1; i < len; i++)
    {
   
        int tmp = nums[i];
        int j = i - 1;
        for (j = i - 1; j >= 0 && nums[j] > tmp; j--)
            nums[j + 1] = nums[j];
        nums[j + 1] = tmp;
    }
}

时间复杂度分析
总共有n轮,第i轮需要进行i - 1次比较,因此时间复杂度为O(n^2)

空间复杂度分析
不需要占用额外的空间,因此空间复杂度为O(1)

稳定性分析
插入排序是稳定的,这是因为,遇到相同的元素时,选择插入到它的后面,因此是稳定的。而如果将内层循环中的 nums[j] > tmp 改为 nums[j] >= tmp,那么对相同元素的处理,就变为了插入到前面,因此就变为不稳定的了,不过不会多此一举,将其插入到前面。可以列一个具有相同元素的数列手动排列一下就可以明白。

优化
可以利用插入排序前面i-1个数字顺序性,利用二分查找的方法,降低时间复杂度。

2.3 冒泡排序

冒泡排序,对于数列规模为n,需要进行n轮比较,对于第i轮比较(i从0开始),数列范围是0~n-i,从左至右,对相邻元素ab进行比较,若a>b,则将a和b交换位置,每一轮可以将当前数列范围的最大元素移动至末尾。最大的元素会像泡泡一样浮到最右侧,因此被称为冒泡排序。

void bubblesort(int *nums, int len)
{
   
    for (int i = 0; i < len; i++)
        for (int j = 0; j < len - i - 1; j++)
        {
   
            if (nums[j] > nums[j + 1])
                swap(nums[j], nums[j + 1]
  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值