Java 基础
异常捕获
异常捕获是典型的Plan B思想——设想程序执行过程中可能出现的问题,然后对此问题准备一套解决方案,让整体目标仍然能够得到实现。
我们可以把程序类比成做某件事的计划,我们事先会准备一套方案,但是有些方案谁也没把握会不会出问题,那么为了增加方案的鲁棒性,我们必须思考可能出现的问题,然后准备plan B。
主动抛出异常
有些方案在执行过程中可能并不会出现引人注目的问题,但是不等于没有问题。这个时候就要预测那些可能觉察不到的问题,并且保持关注。
所以要增强方案的鲁棒性,既要为可能出现的问题提供Plan B,也要思考问题能不能被觉察,以何种方式被觉察。
封装
一个造汽车的公司没有必要了解轮胎的技术细节,他应该集中精力于利用零件组装出更适合市场需求的汽车。封装是生产力发展的必然结果。其实他的另一个叫法是:分工合作。
编程发展到一定阶段,必然面领着生产力的瓶颈,这时候人们意识到,只有通过封装,每个人专注于不同层面问题的解决,才能够产生更大的生产力。
从这个视角出发,面向对象编程希望我们不要自己造轮子,多多利用好的轮子,然后组装出更好地机器。
当然从另外一个角度出发,它也希望我们把问题分层,一个团队专注于一个层面的问题解决,合起来解决更大的问题。这就是公司的管理思想。从这个角度看,一个公司要想发挥更大的效率,就要让每个人专注于解决一类问题,然后通过耦合解决更大的问题。这个社会是倾向于分工细化的,个人一定要思考自己是那个层面的问题解决者。
总之分工最大的好处在于每个人可以专注于自己那一小块问题领域,精耕细作,把问题的解决方案做到极致。
继承
一个产品的可扩展性也是很重要的性能。因为一个产品不可能满足所有人的需求,要留有余地让别人个性化自己的产品,使之更好地服务于他。
根本矛盾是生产与需求的矛盾。
所以任何一个解决方案在解决一个核心问题外还要留有其他的可能性,使之能够满足更多人的需求。
团队里的任何一个人在专注于自己的核心业务之外也要根据团队的需求不同发展额外的业务。
这是解决供需的一个折中方案。
接口
接口是为了解决多重继承的问题。
一个物体会有很多种属性,其中有共性也有个性。对于其中的共性我们可以抽象出一个超物体作为这个物体的母体。但共性和个性也是相对的,拿性格举个例子。每个人都有各种各样的性格,其中乐观的人可以分为一类,作为这一类里面的共性,这时候慷慨就变成了个性;如果慷慨的人分为一类,乐观就变成了个性。因此,一个物体对应有很多个抽象的超物体。因而理论上,一个物体可以继承自很多母体。
那么为什么要关心物体可能存在的母体呢?
这个时候可能出现的问题是多个母体有相同的属性和方法,这就要出问题了。所以java不允许多重继承,但是想出了接口这个完美的解决方案——接口作为抽象类,完全不实现任何方法,因而及时方法与继承类重合,也不会发生冲突。
算法分析
加一点限制,可以大幅度缩减所需信息,进而优化算法。
最大连续子序列和实例探讨基本思想
简单穷举搜索算法(<img src="http://chart.googleapis.com/chart?cht=tx&chl=O(N^3)" style="border:none;">)
- 列举出所有可能的结果通常是及其低下的。
- for循环尽量少用,一层嵌套意味着一个次方。
利用丢弃信息(<img src="http://chart.googleapis.com/chart?cht=tx&chl= O(N^2)" style="border:none;">)
- 计算过程中很多信息可以重复利用,不要直接舍弃。但是本质没有变。
线性算法
- 学会分析:最大子序列和一定不会从负数开始。也一定不会从负的子序列和开始。
- 学会证明:用数学语言证明严谨性。
形式化分析语言
- 大O规则:给出上限,T(N) = O(F(N))意味着从某个点N0开始,T(N) <=cF(N)。
- 大<img src="http://chart.googleapis.com/chart?cht=tx&chl=\Omega" style="border:none;">规则:给出下限
- 大<img src="http://chart.googleapis.com/chart?cht=tx&chl=\Theta" style="border:none;">规则:给出精确值
- 小o规则:给出严格上限
静态查找问题
静态数据是不允许改变的数据
评判好坏的三个维度
- 查找不成功所需要的开销
- 最坏情况下查找成功的开销
- 平均情况下查找成功的开销
顺序查找
- 数据无序,一个地方一个地方找,我们平时找东西最多用的方法,因为这个世界是熵增的。
- 顺序查找是线性的。
二分法查找
- 数据有序,每次与中位值比较然后缩小一半的范围。
- 数据量很小的时候并不比顺序查找有效,生活中也是这样,当我们把查找范围减少到一定程度时,我们倾向于使用简单的顺序查找。
- 现实中用二分可能不是很容易,因为不是所有性质都可以排序。
插值查找
- 总是用中点进行二分有的时候有点傻。比如电话簿中查找Casablanca,从中间字母二分显然有点愚蠢,我们应该根据被查找对象的自身性质这一信息尽可能多的排除不可能数据,上面的例子从C附近开始就比较合理。
- 把数据分布看成均匀分布进行均匀插值求取下一个点是一个典型的建模思想。
永远没有最佳的解法,只有更好的解法。
实证分析
- 改变N,观察增长率
- 改变N,观察T(N)/F(N)是收敛与常数,0,还是发散?
大O分析局限性
- 不适合少量输入的分析,对于少量输入,使用最简单的算法。
- 忽略常数和低阶项有的时候会产生问题。