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]