排序
文章目录
最优解:先满足时间复杂度最优,再满足最小空间
稳定性:相同元素在排序时的先后位置不变
递归:在调用子过程的时候,会把父过程放入栈中,当子过程结束会回到父的栈中找到中断行号,接着运行。
排序 | 时间复杂度 | 额外空间复杂度 | 稳定性 | 最好情况 | 最坏情况 |
---|---|---|---|---|---|
冒泡排序 | N^2 | 1 | 可以稳定 | ||
选择排序 | N^2 | 1 | 不稳定 | ||
插入排序 | N^2 | 1 | 可以稳定 | N(已排序) | N^2(逆序) |
归并排序 | NlogN | N | 可以稳定 | ||
快速排序 | NlogN | logN | 不稳定 | 每次划分值刚好在中间区域 | 阈值左右两侧不平均 |
堆排序 | NlogN | 1 | 不稳定 | ||
桶排序 | N | N | 稳定 |
一、冒泡排序
从小到大排序:从第一个数开始,两两比较,大的数往后放。
范围从0N-1…0N-2…0N-3…01,0
稳定性:可以稳定,相等的时候让后面的数做交换即可
void bubble_sort(vector<int> &a) {
if (a.size() < 2) return;
//每次找到的最小的元素被放到末尾
for (int end = a.size() - 1; end > 0; --end)
{
for (int i = 0; i < end; i++)
{
if (a[i] < a[i + 1]) swap(a[i], a[i + 1]);
}
}
}
二、选择排序
找到最小值的下标,和最后的元素交换
稳定性:不稳定,因为需要最小值需要交换
void select_sort(vector<int> &a) {
if (a.size() < 2)return;
for (int end = a.size()-1; end > 0; --end)
{
int min = end;
for (int j = 0; j < end; j++)
{
if (a[j] < a[min]) min = j;
}
swap(a[min], a[end]);
}
}
三、插入排序
扑克牌插牌:新进来的牌和之前的元素依次比较确定插入的位置
稳定性:可以稳定,插入的时候只需放在相同的后面即可
void insert_sort(vector<int> &a) {
if (a.size() < 2)return;
for (int i = 1; i < a.size(); i++)
{
for (int j = i-1; j >=0; j--)
{
if (a[j] < a[j + 1])swap(a[j], a[j + 1]);
else break;
}
}
}
更优质的写法:
void insert_sort(vector<int> &a) {
if (a.size() < 2)return;
for (int i = 1; i < a.size(); i++)
{
for (int j = i-1; j >=0 && a[j]<a[j+1]; j--)
{
swap(a[j], a[j + 1]);
}
}
}
四、归并排序:左排右排合并
递归,函数在调用的时候先分别排序自己的左右,然后再把左右合并起来
额外空间复杂度:O(N),需要额外的数组进行拷贝
稳定性:在merge的过程,只要小于等于就拷贝左边部分
void merge(vector<int> &a, int left,int mid, int right) {
if (left >= right || a.size() < 2) return;
vector<int> temp;
int l = left;
int r = mid + 1;
while (l<=mid && r <= right)