排序算法(下)
文章目录
![img](https://i-blog.csdnimg.cn/blog_migrate/1d812d79f52462554e54381c8a2042ba.jpeg)
快速排序
快排的思想是这样的:如果要排序数组中下标从 p 到 r 之间的一组数据,我们选择 p 到 r 之间的任意一个数据作为 pivot(分区点)。我们遍历 p 到 r 之间的数据,将小于 pivot 的放到左边,将大于 pivot 的放到右边,将 pivot 放到中间。经过这一步骤之后,数组 p 到 r 之间的数据就被分成了三个部分,前面 p 到 q-1 之间都是小于 pivot 的,中间是 pivot,后面的 q+1 到 r 之间是大于 pivot 的。
1. 找到分界点,两边进行排序
2. 原地排序
这时候分析一下快速排序算法
快速排序是原地排序吗
是的,没有借助额外的空间,所以空间复杂度是0(1),是原地排序算法,所以占用空间小,但是缺点就是不稳定
快速排序是稳定的排序算法吗
因为分区的过程涉及交换操作,如果数组中有两个相同的元素,比如序列 6,8,7,6,3,5,9,4,在经过第一次分区操作之后,两个 6 的相对先后顺序就会改变。所以,快速排序并不是一个稳定的排序算法。
快速排序算法的时间复杂度度
- 最好的情况
原本顺序就是有序的,都要遍历一遍不进行交换0(nlogn)
- 最坏的情况
原本是倒叙的,那么就要遍历n次里面也要交换n次时间复杂度是0(n*n)
算法实现
#include <iostream>
#include <vector>
int quicksort(int p, int q, std::vector<int>& data) {
int i = p, j = p;
while (j != q) {
if (data[j] < data[q]) {
std::swap(data[i], data[j]);
i++;
j++;
} else {
j++;
}
}
std::swap(data[i], data[q]);
return i;
}
void QuickSort(std::vector<int>& data, int p,
int q) { // 这里维持左闭右闭的区间
if (p >= q) {
return;
}
int index = quicksort(p, q, data);
QuickSort(data, p, index - 1);
QuickSort(data, index + 1, q);
}
int main() {
std::vector<int> data = {2, 5, 36, 14, 38, 7, 5, 1, 2, 14};
QuickSort(data, 0, data.size() - 1);
for (auto value : data) {
std::cout << value << " ";
}
std::cout << std::endl;
}
归并排序
归并排序的核心思想还是蛮简单的。如果要排序一个数组,我们先把数组从中间分成前后两部分,然后对前后两部分分别排序,再将排好序的两部分合并在一起,这样整个数组就都有序了。
![](https://i-blog.csdnimg.cn/blog_migrate/85e158299950aa1141db4a5b9fe296f7.jpeg)
这时候分析一下归并排序算法
归并排序是原地排序吗
是的,没有借助额外的空间,所以空间复杂度是0(1),是归并排序算法,所以占用空间小,但是缺点就是不稳定
归并排序是稳定的排序算法吗
归并排序并是一个稳定的排序算法。看你Merge()函数怎么写
归并排序算法的时间复杂度度
- 最好的情况
原本顺序就是有序的,都要遍历一遍不进行交换0(nlogn)
- 最坏的情况
原本是倒叙的,那么就要遍历n次里面也要交换n次时间复杂度是0(n*n)
算法实现
#include <iostream>
#include <vector>
using namespace std;
void Merge(vector<int>& data, int p, int mid, int q) {
// 函数的功能是什么呢?
// 函数的功能在于合并这两个区间内的数值,根据从小到大的规则
// 开辟一块内存
// cout << "start================" << endl;
// for (int h = p; h <= mid; h++) {
// cout << data[h] << " ";
// }
// cout << endl;
// for (int h = mid + 1; h <= q; h++) {
// cout << data[h] << " ";
// }
// cout << endl;
vector<int> tmp(q - p + 1);
int i = p, j = mid + 1, k = 0;
while (i <= mid && j <= q) {
// cout << "i: " << i << " j: " << j << " mid: " << mid << endl;
if (data[i] < data[j]) {
tmp[k++] = data[i++];
} else {
tmp[k++] = data[j++];
}
}
// 看哪一个数组还有残余
while (j <= q) {
tmp[k++] = data[j++];
}
while (i <= mid) {
tmp[k++] = data[i++];
}
// 开始还原
for (int num = 0; num < tmp.size(); num++) {
data[num + p] = tmp[num];
// cout << tmp[num] << " ";
}
// cout << endl;
// cout << "stop================" << endl;
// for (int h = p; h <= q; h++) {
// cout << data[h] << " ";
// }
// cout << endl;
return;
}
void Sort(vector<int>& data, int p, int q) {
// 递归归并排序,归并排序的难点就在于一分一合
if (q - p <= 0) {
return;
}
int mid = p + (q - p) / 2;
// 这里方便起我们一直维持左闭右闭的区间
Sort(data, p, mid);
Sort(data, mid + 1, q);
Merge(data, p, mid, q);
}
int main() {
vector<int> data = {1, 45, 3, 8, 12, 6, 47, 8, 245, 3, 12, 78};
Sort(data, 0, data.size() - 1);
for (auto value : data) {
cout << value << " ";
}
cout << endl;
}
归并排序的算法其实不算很难,难点在于先用递归分离区间,再用合并函数重新合并覆盖区间