本期脑图:
1.前言:谈算法色变?Duck不必!
不知你是否有这种感受?一提到算法,第一反应就是:太难了,我不会!一开始我也有过这种感受,不过耐心学下去之后发现,算法并没有那么复杂。至少入门是一件很容易的事情,只需要:
1.耐心看完本篇推文!
2.开始思考任意一个算法实现思路!
3.自己尝试写任意一个实现代码!
只要成功写出一个,你就入门了,你一定可以做到!至于后期深入到什么程度,就取决于你付出的时间多久了~
2.一定要掌握算法吗?
个人认为:这取决于对自己的要求,如果对自我的要求是做一个普通的开发人员,不学算法问题不大。日常应付CRUD简单需求就可以了(一般月薪2W就是天花板了)。
但是如果想成为一个高级开发工程师或者想入大厂,年薪50W以上,算法是必过的一个门槛,大厂的面试中光是算法板块就可以卡掉很多人~所以算法重要与否,主要取决于对自己的要求!
下图为一位面试过某跳动大厂遇到的两个算法题的其中一个:
3.开始入门:排序算法
算法有很多,本篇入门主讲排序算法;生活当中有很多场景需要用到排序,比如经常逛淘宝,有人就需要按照价格从低到高来排序;再比如我们经常看到的微博热搜排名,其实也是一种根据用户点击量进行的排序,可以说生活无处不排序,那么多排序,底层到底怎么做的呢?排序算法走起~
排序算法按照不同标准可以分为不同类,不过就入门而言知道这些分类名称帮助不大,所以省掉那些复杂的,直接按照难易程度分成两类:
一 简单排序:1.冒泡排序 2.选择排序 3.插入排序(适合入门)
二 复杂排序:1.希尔排序 2.归并排序 3.快速排序(适合进阶)
3.1 冒泡排序
建议:算法学习三步走:(偶尔四步)
第一步:什么是冒泡排序?
冒泡排序(Bubble Sort):重复地访问要排序的元素列,依次比较两个相邻的元素,如果顺序符合要求(如从大到小)就把他们交换过来。此过程重复地进行直到没有相邻元素需要交换,也就是说该元素列已经排序完成。
这个算法的名字由来是因为越大的元素会经由交换慢慢“浮”到数列的顶端(升序或降序排列),就如同水中气泡最终会上浮到顶端一样,故名“冒泡排序”。上例子:
一个数组长这样:
Integer[] arr = {85, 7, 9, 56, 47, 1, 2, 8, 5};
假如竖着看,就变成这样:
所以现在要做的就是将数组中的 数值大的元素“浮”到上面,就像吐泡泡,上面的泡泡更大(数值更大);(配图仅仅为了更便于理解)
第二步:冒泡排序算法图解
需求,一串数组:3 5 9 7 2 1,要求排序后结果从小到大:1 2 3 5 7 9。
先看一下冒泡排序整体过程,有个整体印象:
第一轮冒泡分解步骤(每一轮过程相似):
1.元素3和相邻元素5比较,3<5,不交换位置;
2.元素5和元素9比较大小:5<9,不交换位置;
3.元素9和元素7比较大小:9>7,交换位置;
4.换到新位置的元素9和元素2比较大小:9>2,交换位置;
5.换到新位置的元素9和元素1比较大小:9>1,交换位置,右边没有元素,第一轮结束;
6.第一轮冒泡结束后数组现状:最大元素找到相应位置;
第二轮冒泡排序:将第二大的元素放在对应位置;
第三轮冒泡排序:将第三大的元素放在对应位置;
第四轮冒泡排序:将第四大的元素放在对应位置;
第五轮冒泡排序:将第五大的元素放在对应位置;
也就是说有N个元素,就会有N-1轮排序;每一轮交换过程类似,在此不做赘述;
第三步 手写代码实现冒泡排序
需要实现的API:(建议先自己先code一下,过程比结果更重要)
1.sort(Comparable[] a):遍历, 调用greater和exchange方法完成排序;
2.greater(Comparable c1, Comparable c2):比较两个相邻元素的大小;
3.exchange(Comparable[] a, int b, int c) :交换两个元素的位置;
后续排序算法实现均需要greater();exchange();后续将不再列出;
public class MyBubble {
//排序
public static void sort(Comparable[] a) {
//有length-1个元素需要进行交换的过程
for (int i = 0; i < a.length - 1; i++) {
//要从索引0处的元素开始交换,最坏情况一直交换到length-1次;
for (int j = 0; j < a.length - 1 - i; j++) {
//比较假如a[j]比a[j+1]大,则交换位置
if (greater(a[j], a[j + 1])) {
exchange(a, j, j + 1);
}
}
}
}
//比较大小
public static boolean greater(Comparable c1, Comparable c2) {
/*
//return c1.compareTo(c2) > 0; 的拆解版:
int compare = c1.compareTo(c2);
return compare > 0;*/
return c1.compareTo(c2) > 0;
}
//交换位置
public static void exchange(Comparable[] a, int b, int c) {
//建立一个临时元素,用于交换中转
//第一个函数等号后面的元素就是下一个函数的等号前面的元素,首尾衔接,即完成交换
Comparable num = a[b];
a[b] = a[c];
a[c] = num;
}
}
补充:精力充沛的可以思考一下冒泡排序的时间复杂度是多少?
提示,假设冒泡排序的最坏情况:一个含有N个元素的完全倒序的数组需要交换多少次完成排序?
推导过程(过程比结果更重要!)
第一个元素需要交换的次数:N-1
第二个元素需要交换的次数:N-2
第三个元素需要交换的次数:N-3
......
第N-1个元素需要交换的次数:1
第N个元素不需要交换,此时已经正序了;
最后一共需要交换次数:1+2+3+...+N-1 = (N*(N-1))/2=N^2/2 - N/2;
按照时间复杂度的去杂规则,最后时间复杂度简化为:
F(N)= O(N^2);
3.2 选择排序
第一步 什么是选择排序?
选择排序(Selection sort)的工作原理是:第一次从待排序的数据元素中选出最小(或最大)的一个元素,存放在序列的起始位置,然后再从剩余的未排序元素中寻找到最小(大)元素,然后放到已排序的序列的末尾。以此类推,直到全部待排序的数据元素的个数