我人生中第一次接触算法是在课本上看到的冒泡排序,这是我第一次叩开算法的大门,排序应该是所有初学者最先接触到的算法,他也是很多高级算法必不可少的一部分,今天介绍一些适合初学者学习的排序算法。
冒泡排序
for (int i = 0; i < n - 1; i++) // 外层控制趟数
{
for (int j = 0; j < n - 1 - i; j++) // 每趟把最大值“冒”到最后
{
if (a[j] > a[j + 1])
{
swap(a[j], a[j + 1]);
}
}
}
首先,单论这个算法,在排序里并不算效率高的,但确实很适合初学者了解算法思想。如果大家不理解这个算法死记硬背也是可以的,因为这个算法没什么变化,多敲几遍自然会理解了,下面讲一下这个算法的原理:
冒泡核心在于交换:
5 3 8 4
我们做的事情只有一件:
两两比较
如果前面大,就交换 (5比3大所以3就要放前面)
好了到这其实你已经完全掌握冒泡了,借下来演示一下里面的遍历过程
假设数组里依旧5384。。。。
第一趟过程
原数组:
5 3 8 4
第1步
比较 5 和 3
5 > 3 → 交换
3 5 8 4
第2步
比较 5 和 8
5 < 8 → 不动
3 5 8 4
第3步
比较 8 和 4
8 > 4 → 交换
3 5 4 8
第一趟结束后:
最大的数 8 已经到最后了
3 5 4 | 8
比较:
- 3 和 5 → 不动
- 5 和 4 → 交换
变成:
3 4 5 8
第二趟结束后:
第二大的数 5 到了倒数第二
第三趟
3 4 | 5 8
- 3 和 4 → 不动
规律就是
-
第一趟比较 n-1 次
-
第二趟比较 n-2 次
-
第三趟比较 n-3 次
这就是n-i-1的来历
ok,这个算法不难在于大家弄两个数组自己画一画理解理解,当然这个算法是可以优化的这里不赘叙,因为效率低,只了解思想即可。
快速排序
void quick_sort(int q[], int l, int r)
{
if (l >= r) return;
int i = l, j = r;
int x = q[(l + r) >> 1]; // 中间值
while (i <= j)
{
while (q[i] < x) i++;
while (q[j] > x) j--;
if (i <= j)
{
swap(q[i], q[j]);
i++;
j--;
}
}
if (l < j) quick_sort(q, l, j);
if (i < r) quick_sort(q, i, r);
}
解释:q是要求的数据,lr分别为左右指针,x是数据的中心位置。
思想:分治
快速排序的结构:
- 选择一个基准值(pivot)
- 把数组按 pivot 分成两部分
- 递归排序左右两部分
可以理解为:
[整个数组]
↓
选 pivot 分裂
/ \
左区间 右区间
这就是典型的 分治思想。
展示一轮递归
第一次循环
① while(q[i] < 4)
q[0] = 5
5 < 4 ❌
i 不动 → i=0
② while(q[j] > 4)
q[4] = 3
3 > 4 ❌
j 不动 → j=4
③ i <= j → 0 <= 4
交换 q[0] 和 q[4]
3 1 4 2 5
然后:
i = 1
j = 3
第二次循环
现在数组:
3 1 4 2 5
i=1
j=3
① while(q[i] < 4)
q[1] = 1 < 4 → i=2
q[2] = 4 < 4 //不符合
停在 i=2
② while(q[j] > 4)
q[3] = 2
2 > 4
j 还是 3
③ i <= j → 2 <= 3
交换 q[2] 和 q[3]
3 1 2 4 5
然后:
i = 3
j = 2
第三次判断
i <= j ?
3 <= 2 //不符合哦哦哦哦哦哦吼吼吼吼
循环结束。
最终分区结果
3 1 2 4 5
哈哈,接下来就进入递归了。
你会发现他是在找中间值,然后小于中间值的仍左边,大于扔右边
哈哈哈弄倒了,那就倒者看吧呜呜呜呜。。。 ok,排序的效率是比冒泡高的,这些算是一种底层,大多数直接sort(底层:快速排序 + 堆排序 + 插入排序)了。。 累了,选择和归并下一个发吧啊啊啊啊。。。