0.关于排序
相关概念:
- 稳定 :如果a原本在b前面,而a=b,排序之后a仍然在b的前面。
- 不稳定 :如果a原本在b的前面,而a=b,排序之后a可能会出现在b的后面。
- 时间复杂度:执行算法所需要的计算工作量,是关于数据规模n的函数。
- 空间复杂度:执行算法所需要的内存空间,也是关于数据规模n的函数。
- 比较类排序:通过比较来决定元素间的相对次序,由于其时间复杂度不能突破O(nlogn),因此也称为非线性时间比较类排序。
- 非比较类排序:不通过比较来决定元素间的相对次序,它可以突破基于比较排序的时间下界,以线性时间运行,因此也称为线性时间非比较类排序。
算法分类:
算法总结:
注: 对于稳定的排序算法,在实现过程中要特别注意"<"、">“和”<="、">="的使用,不然可能会导致不稳定。
1. 冒泡排序(Bubble Sort)
冒泡排序是一种计算机科学领域的较简单的排序算法。它重复地走访过要排序的元素列,依次比较两个相邻的元素,如果顺序(如从大到小、首字母从Z到A)错误就把他们交换过来。走访元素的工作是重复地进行直到没有相邻元素需要交换,也就是说该元素列已经排序完成。这个算法的名字由来是因为越大(或越小)的元素会经由交换慢慢“浮”到数列的顶端(升序或降序排列),就如同碳酸饮料中二氧化碳的气泡最终会上浮到顶端一样,故名“冒泡排序”。
算法描述:
- 从第一个元素开始依次比较相邻的元素对,若顺序错误则将它们交换。
- 当比较完最后一对相邻元素,此时最大(或最小的元素)已经"浮"到元素列末尾。
- 对除去最后一个元素的元素列重复1~2,直到没有任何元素对需要比较则排序完成。
代码实现:
vector<int> bubbleSort(vector<int>& nums)
{
int len = nums.size();
if (!len) return nums;
for (int i = len - 1; i > 0; i--)
{
int flag = true;
for (int j = 0; j < i; j++)
{
if (nums[j] > nums[j + 1])
{
swap(nums[j] , nums[j + 1]);
flag = false;
}
}
if(flag == true) //如果没有元素进行交换,则代表此时元素已经有序,则不必进行后续比较
return nums;
}
return nums;
}
算法分析: 若序列初始状态为正序的,则一趟扫描之后即可结束循环,此时最好时间复杂度为O(n)。若序列初始状态为反序,则共需n-1次排序,每次排序需进行n-i次比较,此时最坏时间复杂度为O( n 2 n^2 n2)。因此平均时间复杂度为O( n 2 n^2 n2)。
注: 冒泡排序可进行优化,例如记录下上一次交换的最后位置,下一次遍历终点即设置为标志位置;或者每次循环进行正反两次扫描分别确定最小值和最大值等。
2.选择排序(Selection Sort)
选择排序是一种简单直观的排序算法。它的工作原理:首先在未排序序列中找到最小(大)元素,存放到排序序列的起始位置,然后,再从剩余未排序元素中继续寻找最小(大)元素,然后放到已排序序列的末尾。以此类推,直到所有元素均排序完毕。
算法描述:
- 从待排序的数据元素中选出最小(或最大)的一个元素,交换到序列的起始位置。
- 从剩余的未排序元素中寻找到最小(或最大)的元素,然后交换到已排序的序列的末尾。
- 重复步骤2直到待排序元素个数为零则排序完成。
代码实现:
vector<int> selectionSort(vector<int>& nums)
{
int len = nums.size();
if (!len) return nums;
for (int i = 0; i < len-1; i++)
{
int minNum = nums[i];
int minIndex = i;
for (int j = i + 1; j < len; j++)
{
if (nums[j] < minNum)
{
minNum = nums[j];
minIndex = j;
}
}
swap(nums[i], nums[minIndex]);
}
return nums;
}
算法分析: 表现最稳定的排序算法之一,无论什么数据进去都是O( n 2 n^2 n2)的时间复杂度,所以用到它的时候,数据规模越小越好。但优点是原理简单,并且不占用额外内存空间。
3. 插入排序(Insertion Sort)
插入排序,一般也被称为直接插入排序。对于少量元素的排序,它是一个有效的算法 。插入排序是一种最简单的排序方法,它的基本思想是将一个记录插入到已经排好序的有序表中,从而变成一个新的、记录数增1的有序表。
算法描述:
- 将元素列第一个元素视为已排序。
- 从剩余的未排序元素中取出第一个元素,然后从后向前扫描已排序序列,找到合适的位置后将该元素插入。
- 重复步骤2直到未排序元素个数为零则排序完成
代码实现:
vector<int> insertionSort(vector<int>& nums) {
int len = nums.size();
if (!len) return nums;
for (int i = 1; i < len; i++) {
int temp = nums[i];