# Road Map
升级路线:
模板题:912
数组排序:15 -> 18
快速排序:215 -> 786
归并排序:493 -> 315 -> 327
桶排序:1122 -> 164
堆排序(即优先队列):
- 前 K 个最大的数:347 ->
- 贪心:56 -> 252
# 排序算法
我们常说八大排序算法,实际上排序有非常多的算法
这里我们列举常用排序算法极其应用进行说明:
# 板子题
# 快排
快排的思想:递归+分治
不稳定排序,中间交换过程会打乱顺序
时间复杂度:最差 O(N^2),平均 O(N^logN)
# 算法 1
- 取中点为轴(也可以选择其他点)
- 找到左边第一个大于等于轴的元素 A,找到右边第一个小于等于轴的元素 B
- 当 A 的下标小于 B 的下标时,交换
- 递归上述过程
void quick_sort(int q[], int l, int r) {
if (l >= r) return;
int i = l - 1, j = r + 1, x = q[l + r >> 1]; // 定义左右游标+轴
while (i < j) {
do i++; while (q[i] < x); // 找到左边第一个大于等于轴的位置
do j--; while (q[j] > x); // 找到右边第一个小于等于轴的位置
if (i < j) swap(q[i], q[j]); // 交换
}
quick_sort(q, l, j), quick_sort(q, j + 1, r); // 递归;注意这里要以j为基准(或者用i—1,i)防止出现死循环
}
1
2
3
4
5
6
7
8
9
10
2
3
4
5
6
7
8
9
10
# 算法 2
此算法更为直观
- 选择一个轴(pivot),下标 i, j,通过不断移动下标、比较、交换,使得轴左边所有数据小于轴,右边所有数据大于轴;
- 递归进行上述过程,直到所有数列长度为 0 或 1,排序结束;
- 由于每次迭代过程,至少有一个值(轴)排好序,所以最终算法会终止;
class Solution {
public:
vector<int> sortArray(vector<int>& nums) {
int l =0, r= nums.size()-1;
recursive(nums, l, r);
return nums;
}
void recursive(vector<int>& nums, int l, int r){
if (l >= r) return;
int pivot = partition(nums, l, r);
recursive(nums, l, pivot-1);
recursive(nums, pivot+1, r);
}
int partition(vector<int>& nums, int l, int r){
int pivot = nums[l];
while (l < r){
while (nums[r] >= pivot && l < r) r--;
nums[l] = nums[r];
while (nums[l] < pivot && l <r) l++;
nums[r] = nums[l];
}
nums[l] = pivot;
return l;
}
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
# 题目
- Top-K 问题
# 归并排序
- 归并排序的思想:递归+分治
- 稳定排序
- 时间复杂度:O(N^logN)
# 分治算法
将一个规模为 N 的问题分解为 K 个规模较小的子问题,这些子问题相互独立,且与原问题性质相同。求出子问题的解后进行合并,就可以得到原问题的解
一般步骤:
- 分解:将要解决的问题划分成若干规模较小的同类问题
- 求解:当子问题划分得足够小的时候,用较简单的方法解决
- 合并,按原问题的要求,将子问题的解逐层合并构成原问题的解
# 算法模板
int t[100001];
void mergesort(int a[], int l, int r){
if (l >= r) return;
int mid = l+r>> 1;
mergesort(a, l, mid), mergesort(a, mid+1, r); // 递归 + 分治
int i = l, j = mid+1, k= 0;
while (i <= mid && j <= r){
if (a[i] < a[j] ) t[k++] = a[i++];
else t[k++] = a[j++];
}
while (i <= mid) t[k++] = a[i++];
while (j <= r) t[k++] = a[j++];
for (int i = l, j = 0; i<=r; i++, j++) a[i] = t[j];
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 冒泡排序
# 算法思路
- 进行
len-1
次冒泡- 第 k 次冒泡将倒数第 k 个元素排好序
# 代码实现
function bubbleSort(nums) {
for (let i = 0; i < nums.length - 1; i++) {
// len - 1次冒泡
for (let j = 0; j < nums.length - i - 1; j++) {
// 依次比较相邻元素,进行冒泡,比较区间[0,len - 1 - i]
if (nums[j] > nums[j + 1]) {
let tmp = nums[j];
nums[j] = nums[j + 1];
nums[j + 1] = tmp;
}
}
}
return nums;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
2
3
4
5
6
7
8
9
10
11
12
13
14
# 桶排序
桶排序 的两个步骤:
- 分桶
- 合并
# 基数排序
- 先按个位进行桶排序
- 然后按十位进行桶排序
- 然后按百位进行桶排序 ...
- 直到所有位完成桶排序,最后的序列就是排好序的
比如:452,897,472,385,752
- 按个位:452,472,752,385,897
- 按十位:452,752,472,385,897