Merge pull request #1 from CyC2018/master

更新
This commit is contained in:
Andrew-chh 2019-04-08 16:55:01 +08:00 committed by GitHub
commit 25ce95c45b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1068 changed files with 16835 additions and 58311 deletions

1
.gitignore vendored
View File

@ -1,2 +1,3 @@
.DS_Store .DS_Store
*.txt *.txt
!tencent13147342467085209222.txt

View File

@ -1,139 +0,0 @@
作者CyC2018
链接https://www.nowcoder.com/discuss/137593
来源:牛客网
## 前言
2018有过迷茫有过努力也有很多收获。为了记录这一年以来的感受于是有了这篇文章。
## Offer 情况
经过了长达一年左右的复习,秋招也收到了几个比较满意的 Offer参加面试的都通过了。
- 百度,企业智能平台;
- 阿里,高德地图,部门已联系,目前还在申报 Offer 中;
- 腾讯IEG 游戏平台后台研发SP
- 字节跳动头条后台研发SSP
- 华为Cloud Bu
- 网易游戏,梦幻事业部;
- 顺丰科技。
## 前期准备
也是在去年十一月份左右,看着身边两年制的同学经历了长时间而又艰难的秋招,我开始意识到自己应该提前准备了,否则自己的秋招会很惨。
本科的时候,虽然学过计算机网络、操作系统和数据结构等课程,而且 Leetcode 也刷了一两百题,但是离招聘要求还差的很远,学的都很浅只够应付考试,也没有实际的项目经验。
我的研究生方向是计算机图形学,研究生期间主要做一些科研项目。在选择招聘方向的时候,我也纠结了是不是找图形学相关方向的,但是考虑到图形学的选择不是很多,所以还是决定投后台研发相关的岗位。
于是开始收集各种学习资料,也买了很多纸质书。最开始的学习效率并不是很高,很迷茫,觉得要学的内容很多无从下手。那时候看别人的面经,感觉自己太弱了,很多内容都没接触过,于是更加迷茫。迷茫的时候总想着逃避,要是不复习多好,玩玩游戏每天多简单。但是游戏玩的越多,那种焦虑感越是强烈。解决焦虑的唯一办法就是想办法解决当前问题。当慢慢地从消极的学习态度中调整过来,掌握的知识越多,那种焦虑感也随之消失。当然这个过程并不容易,不仅需要很好的毅力,也要根据自身情况找到问题的有效解决方法。
## 春招开始
三月份各个公司就开始春招了那时候刚把一些基础知识简单地复习了一下Leetcode 刷到了三四百题。但是没有后台研发相关的项目,于是花了一个星期左右用 PHP 做了一个微博系统。当时做简历特别痛苦,没内容可以写,看着其他人简历各种新技术,自己都没掌握,所以很虚。
## 阿里一轮游
最开始投的阿里实验室大几届有个师兄在天猫精灵团队所以给我内推了。于是我人生中第一场面试就是阿里很自然地被虐了一遍。记得当时约好下午两点电话面试午饭都没吃怕吃完之后犯困影响状态然后找了一个很安静又没人的地方呆到了两点调整自己的状态。可是面试官突然打电话来说有个会议要开所以推迟了大概一个小时。苦苦等到三点左右面试正式开始不出所料面得非常糟糕。首先自己表述的很有问题很多内容没回答到关键点上自己会的内容也不怎么继续扩展回答。其次知识掌握得确实不够连线程安全、ThreadLocal、函数式编程都不会。虽然被虐的很惨但是也有好处知道了面试到底是怎样的自己还有哪方面的不足该怎么准备。
## 腾讯被鞭尸
第二场面试是腾讯,在经历了阿里的面试之后,并且又继续复习了一段时间,我对面试就比较有信心了。一面其实回答的挺理想的,虽然很多问题没有立马回答出来,但是经过面试官的耐心提示之后都能回答一些内容。当时面了一个半小时,面试体验特别好。印象比较深刻的题目有,阅读一个 Redis 源码,分析存在哪些问题。其实就是一个计数器实现的限流算法,会有临界值的问题,但是当时没回答出来,只能听面试官给我解释。还有一个微信扫二维码,这个过程发生了什么,也没回答得很好,不过面试官也很耐心地纠正我回答上的错误。一面顺利通过了,但是总监面挂了。总监面没有问什么技术问题,就是问了问项目和职业规划。自己的项目确实比较 Low我自己在介绍的时候也说得很不堪。职业规划我说自己希望在一些方面深入学习因为自己现在在这些方面还很薄弱... 面完之后我就知道挂了,因为整个面试过程我都特别虚,还主动说自己技术能力不行。不出所料,面完的当天晚上,状态变成了不合适。
但是过了几天,突然收到腾讯的电话,问我是否愿意去深圳参加面试(笔者学校在广州)。当然我毫不犹豫地答应了,很开心腾讯还能给我机会。经过了上一场面试的启示,这次面试我表现地非常自信,自己知道的知识都很有信心地表达出来,被问到不会的内容也不会那么慌张,和面试官探讨一些细节,然后说说自己的想法,还有自己看过相关的内容。由于这是腾讯云部门,对 Linux 内核和 C++ 有很高的要求问了几个相关的问题我都没回答出来比如如何实现守护进程Linux 信号机制Linux 线程的不可中断阻塞状态如何进入等等。除了这些问题,其它地回答的都还行。遗憾的是,当天晚上面试官打电话告知我面试没通过。但是他说我其它方面都很不错,所以问我愿不愿意参加腾讯云 Java 部门的招聘,于是第二天我又去了一个新的部门面试。
这次面试是在部门的会议室进行的,进到公司之后说实话没有自己想象中那么好,工位很挤环境一般。一开始就先随便聊聊,学校的研究工作,学习之类的。然后看了看项目,看完之后我就知道凉了一半,这个项目确实太水了,面试官看了之后没有接着问,也能感受到面试官有点嫌弃。然后他就问了一些基础知识,问到进程调度算法,面试官让我实现一个任务调度系统。因为是第一次手写代码,而且之前确实没考虑过这个问题,然后就胡乱写了一堆代码,特别乱,而且到处涂改。显然面试官是不满意的,写了也有十几分钟之后,我自己都知道已经凉了,然后面试官没让我接着写,也没给我任何提示,说就到这里,面试结束了,还有没有什么问题想问的。当然看过任务调度系统相关的文章会觉得挺容易的,比如使用时间轮实现等等。我依然记得面试官送我出门时候的热情,送我坐电梯的时候还很热情地和我说,非常感谢参加本次面试,辛苦了。
## 虎牙过于自信
经过了阿里和腾讯的面试之后,我觉得自己大概已经知道该怎么面试了,面试时候该注意什么,该怎么表达等等。而且腾讯面试表现也不差,虽然最后没通过。所以在虎牙面试的时候特别放松,觉得应该能通过。前面面的也都还行,虽然有几个问题没回答好,比如分析一下微博的时间线。通过了第一轮面试直接等第二轮,等到了晚上七点多才等到我。虎牙面试还是很注重技术的,虽然问的都不是很深入,只要简单回答到点上就不会接着问下去。二面也有一些问题没回答好,比如 ConcurrentHashMap 的并发机制,问 Spring 直接说不会。也有一些问题回答得比较乱,没有条理。但是我觉得大部分问题都回答的不错,应该能通过。可是面试完之后,面试官问有没有什么问题要问他,由于太过放松,我就问你们都加班到这么晚不吃饭吗,好饿啊,周六周日还加班吗... 问完之后面试官就很严肃了,说平常不加班的,我突然意识到了问题的严重性... 最后还是凉了。
## 百度第一个 Offer
被三家连续拒了之后,都开始怀疑自己了,不过还是提醒自己要保持信心。
幸运的是,百度的面试非常适合我,三轮都是技术面,而且手写算法题目居多,而我准备最多的是算法,所以很顺利通过了面试。但是面试表现并没有特别好,过了比较长的时间才被捞,而且是工程效率部门,做内部工具的,对个人成长并不好,所以不是特别满意。
## 网易游戏最好的面试体验
其实最开始没有打算投网易游戏的,因为被脉脉洗脑,已经放弃了做游戏。但是因为前面面试基本被拒了,担心没有实习 Offer因此就试试看。
因为没有特别想去网易游戏,所以面试过程也比较放松,就当去聊聊天。面试官非常 nice那天下午挤了很久地铁比较口渴然后面试官看我说得沙哑了到门口帮我买了一瓶可乐非常感激。面试之前我就提出我对 C++ 不熟悉,最近主要看 Java 的内容。面试官还是说没关系,尽量回答就好。当然最后我都把问题往 Java 那里回答了,比如 Map 的实现,内存管理等等。最后聊了一些玩过的游戏,就让我回去等消息。网易游戏就一轮面试,确实就一轮。周五参加的面试,下周一就给 Offer 了,效率特别高。
## 微众玄学面试
通过微众面试我自己都非常吃惊,一面的时候就简单自我介绍了一下,然后面试官开始介绍他自己的工作经历,以及现在部门在做的内容。之后问了我一个场景分析问题,我想了一会儿没想出来,于是面试官拿起草稿纸把各种需求详细说了一遍,然后把系统架构图也画了出来... 最后他问还有什么我优势的地方他没问到的我问他怎么不问问算法题他说笔试都通过了没必要再问。面完之后我觉得聊得很开心但是技术问题没回答好出乎意料收到了二面通知。二面没问技术就让介绍了项目再问问家住哪之类的问题也顺利通过了。HR 面就不用介绍。收到了微众的 Offer得知了部门是贷款科技部非常核心很吃香近几年也在扩展一些业务还是有点小心动的。虽然最后没选择去微众实习但是一面面试官加了我微信我很感谢他一面非常耐心给我讲解并让我通过。他说我是他面试的第一顺位也就是第一个面试者所以会放宽很多也希望我秋招能加入他们。
## 实习选择
其实最理想的是去百度实习,秋招也会容易很多。但是考虑到百度是在北京,部门很边缘,而且需要实习很长时间也不一定能转正,所以还是放弃了。最后只能在网易游戏和微众选,虽然自己不想做游戏,但是考虑到网易游戏的平台认可程度比微众好,秋招肯定会更容易一些。而且秋招如果还想进微众的话也会比较容易,因为面试官和 HR 都说秋招的时候会优先考虑我,所以最后还是去了网易游戏实习。
## 实习之前的快速学习期
经历了春招之后,认识到了自己身上的不足,比如交流表达能力的欠缺,知识积累得不够,项目深度不够。因此在实习之前的两三个月,开始针对这些问题逐个解决。
- 交流表达能力欠缺,就提前准备好各种非技术问题,然后对着镜子回答,把自己当成听众,并且也用录音机录下来。
- 知识积累不够,采取的策略是保证广度优先,并且在重要的内容上保证深度。其实之前基础知识已经掌握的比较好了,再学其它技术的时候都有很多相同的地方,所以学起来很快。
- 项目深度不够,就把那个微博系统做了一点改进,学了 Spring 之后改用 Java 实现。
## 不那么安心的实习
去实习的时候还是挺惊喜的,因为我被安排的工作是游戏引擎相关的,和自己的研究生方向紧密相关,我觉得做完实习项目之后自己的毕业论文也会比较有灵感。
但不幸的是,在去的第一天部门接待聚餐上,服务端主程就说,我们部门工作制是九九六,现在互联网都是九九六。在实习之前我了解的是实习生六点就可以走,而且只用上五天班,听到他这么一说心都凉透了,因为已经想好了晚上和周末时间用来复习。如果知道是九九六,我会选择去百度。
其实网易游戏部门氛围还是不错的,对员工很好,而且我的实习导师人也很好,在我生病的那几天很关心我。但是九九六的工作制对秋招复习还是有很大影响的,而且每天上下班花在路上的时间超过了两个小时,下班回寝室之后总想着看会儿视频休息一下,然后又要早早睡觉赶着第二天上班。没办法只能在上下班地铁上复习,还有就是午休时间接着复习。
## 秋招开始
实习之后已经是九月份了,那时候已经错过了所有提前批。而且实习的时候没怎么复习,九月初还是感觉没怎么准备充分,所以就又等了半个月才开始投简历。
但是这个时候和春招相比,已经把大部分后台研发相关的知识点过了一遍,很多重要的内容前前后后也看了十几遍,没有春招时候那么迷茫和焦虑。即使被问到没有掌握的知识,我也有把握通过讨论的方式,给出大概的思路,因为很多技术确实是相通的。
## 阿里看不懂的内部流程
秋招第一个投递的依然是阿里,最开始系统自动发起了一个新的流程,然后过了几天自动回绝了... 八月末的时候也找人内推了,但是又被阿里直接回绝了... 那时候已经觉得可能是春招面试表现太差,此生无缘阿里了。可是过了一段时间,正式校招的时候,阿里又发起了一个新的流程戏弄我,收到笔试通知的时候,我还犹豫了到底参不参加,因为那时候已经九月中旬,听说阿里已经没有 HC 了。而且按前面回绝我的态度,感觉即使笔试通过面试也通过不了。笔试那天晚上,本来准备看个电影放松一下,后来想了想还是参加了笔试,笔试各种机器学习和数学题,感觉拿错了试卷,笔试完我已经把阿里从我的公司进度列表中删除了,不再纠结阿里。可是过了一段时间收到阿里的面试通知,我以为是走走形式,可能参加笔试的人很少了,所以才选中我参加面试。那时候阿里招聘官网状态一排的已回绝,让我对阿里有一种恐惧感,觉得面试肯定挂。但是真正面试的时候却意外的顺利,收到二面通知的时候特别激动,然后面完二面又让直接等 HR 面HR 面虽然不是很理想,但是没有很大的问题。又过了很长一段时间,在我去深圳参加腾讯招聘的高铁上,收到了高德地图 HR 的电话,问是否愿意去。虽然得知部门在北京有点小失落,但是还是很开心终于被阿里认可了,摆脱了对阿里的恐惧。
实验室上届毕业在阿里云的大佬某天突然和我说,他们部门有新的 HC让我把简历发给他他要帮我内推会帮我安排一场线下面试如果通过的话到时候和高德的 HR 沟通一下,直接把我从高德捞过来。很感谢大佬向他老大极力推荐我,给我了这次面试机会。线下面试也很顺利,聊聊实习项目,问问我的开源博客,然后问些 Paxos 等分布式的问题,还有就是手写代码,信号量实现生产者消费者,以及一个位运算的问题。其实位运算的问题面试的时候写的不完善,面试官让我之后完善了再发给他,因为面试一个多小时有点长了。过后我写了详细文档讲解了思路,以及使用 JUnit 进行了详细的单元测试,把文档和代码都发给了他。现在面试已经通过了,但是最近阿里集团 HC 比较紧张,也不知道能不能批到 HC。
## 百度又是不那么满意的部门
虽然阿里是最先开始流程,但是第一个参加面试的是百度。因为实习的时候通过了百度的面试,所以这次面试还是比较有信心的。百度面试连续三天,都在同一个地方,最后签约也在同一个地方。还记得每次都坐一个小时左右的地铁去那里,路线已经非常熟悉了,和每天去实习的感觉类似。百度面试比较注重技术,三轮面试基本都是问技术问题,而且问的也比较深入,内容也非常广。但是面的不是那么理想,有两点原因,首先是因为确实有些知识点还没掌握好,比如 AC 自动机,系统故障分析等等;其次是对实习项目的描述上还不够好,没有把实习内容的闪光点描述出来,也没有讲清楚为什么做这个项目,自己通过什么方法去做,以及最后的结果。
最后百度给了白菜价,部门是企业智能平台,主要是内部系统,虽然会接触到机器学习和大数据。
## 腾讯虐我千百遍
秋招腾讯第一场面试和实习参加腾讯面试的感觉非常像,第一轮技术面感觉很好,手写堆排序算法,二部图分析等等。面完之后通知待会儿二面,听到之后还是很激动的,觉得这次应该没问题了。我在等二面的时候,碰到了室友(他经常不住宿舍,所以不清楚他也去面试),聊着聊着居然发现我两是同一个面试官,而且他是来二面的,也就是等一下我两就要一前一后进去面试。二面的感觉和实习二面非常像,非技术问题回答的支支吾吾,然后面试官开始质疑我说的内容,给我压力,我没有当场反驳,就说了哦,好像是这样的。因为面试官全程都绷着脸,所以我也比较紧张,很多问题没回答好。过了几天,室友和我说收到 HR 面试通知了,我去官网看了一下状态,已经变成了熟悉的不合适。这次面试失败的主要原因是自己在应对这种压力时处理地不是很好,主要体现在失去信心以及紧张。解决方法也简单,做好充分准备来保持信心,受到质疑的时候积极反驳,紧张的时候计时调整心态,可以试试深呼吸或者喝水。
因为实习有被捞起来的经历,所以被拒之后我特别希望能继续被捞起来,然后把简历上的面试城市改成了深圳。苦苦等到深圳场面试的前几天,在不经意的一个下午手机突然响了,我记得是短信邮件同时收到面试通知。于是又开始了新一轮被腾讯虐的面试之旅。
一面和之前一样也是意外地顺利,虽然问了一些 C++ 的问题,但是我都说到 Java 相关的实现上。在一些问题上确实回答的深度不够比如网络编程里面的水平触发和边缘触发等问题。然后问了几个算法本来要求手写我说我实现过所以就讲了讲思路。面试和腾讯第一场面试一样持续了一个半小时面试官也很好很多问题都会给提示即使最开始回答的有问题。二面面试官也很好问了问实习项目然后再聊一聊一些技术经过了之前的面试到这次面试真的就像在聊天一样而不是面试我们都会说一些对技术上的理解。HR 面其实面得很差,对于非技术问题的吹水能力我还是不太行。最终和我预期的一样,给了我 SP 的 Offer因为觉得自己面得还可以但是也不够好到给 SSP有些 C++ 问题还是没回答的特别好。
## 头条意外的惊喜
之前看到学弟收到头条的 Offer薪资非常诱人所以也想去试试。也听说头条面试难度非常大主要考察手写算法因为自己算法方面准备得比较充分所以觉得会比较顺利但是也没有特别高的预期。前两面中规中矩算法题和其它问题我都回答的比较好到三面的时候问了一个错排问题其实最开始我给了正确的递推公式但不是面试官想要的答案所以让我再想想。我想了十几分钟还是觉得没问题那时候觉得自己已经凉了因为面试官一直不满意。后面的几个问题也没回答的很好分析一个 SQL 语句的具体执行过程,比如会怎么利用索引,怎么优化之类的,虽然在他的提示下还是回答了,但是感觉并不好。面完之后我立马查了一下那个错排问题,证实了我的答案是正确的,于是写了一个详细的文档,联系 HR 让她发给面试官。出乎意料的是HR 让我不用担心,他说面试官对我的评价很好... 不过最后还是让她把文档发给了面试官。之后收到了加面通知,头条加面有两种情况,一是三轮评级都是 4 可以评 SSP二是面试官评价差别很大再面一轮决定是否录用。收到加面的时候完全不知道自己属于哪一种感觉两种情况都有可能。加面回答的也不好主要是问项目面了 25 分钟就草草结束,最后面试官说有些内容需要找一些文献参考参考。面完之后我觉得,即使我属于第一种要评 SSP 的情况,加面面的那么差应该也没希望了。苦苦等了好多天之后,最后确定是 SSP 之后,还是很惊喜的,感觉是对自己这么长时间复习的一个认可。
## 顺丰最后的保底
投顺丰是因为九月中旬很多公司都结束了招聘,所以那时候比较慌,就投了顺丰当做保底,顺便也练练手。最开始还担心顺丰笔试没通过,因为编程题最后一题没做出来,那题的题目都出错了,而且题目是网上直接 copy 过来的,网上的源码都不能通过,更别说我自己的实现了。顺丰面试主要问了数据库的内容,而且问的特别深,几乎把每种日志的实现和作用都问了一遍。面顺丰的时候也比较早,那时候有些问题的回答上没有组织好,回答得比较凌乱,虽然最后也算给了一个小 SP。
## 华为特别纠结的部门
去华为面试确实是没有压力的,因为都知道华为面试不怎么问技术,虽然还是问了我一些技术问题,不过不是问的很深。面试主要介绍项目,我对自己的实习项目还是比较有信心的,因为觉得做的确实不错,而且面了很多场了,知道该怎么介绍项目。面试官问我个人意愿,我说自己对分布式中间件等比较感兴趣,于是面试官把我推荐到了 Cloud Bu。本来没打算签华为的现场签约也就去看看到底给我开多少。最开始其实给我开了十四级最高的薪资我本来不是很想去虽然对这个部门感兴趣但是薪资确实比不上头条。然后随口问了一句可不可以给十五级本来 HR 说是可以试着申请一下,不过最后没申请成功。
## 技术博客
最后安利一下自己的技术博客:[CS-Notes](https://github.com/CyC2018/CS-Notes),虽然现在还有很多不完善的地方,但以后会不断改进。
## 小结
很多人都说,面试和考试一样,要背很多没用的东西。最开始我也认同这种看法,可是参加了几场面试之后,我就不这么认为了。因为面试出的问题,有很多是实际开发中碰到的,所以准备面试相当于提前做入职准备。而且面试中考察的思维能力、交流表达能力、应对压力能力,都是真正工作中所需要的。
我觉得自己比别人做的好的地方是,有很强烈的想找到好工作的意愿,才驱使我不断学习,所以态度很重要。
信心源自于充分准备,有了信心,面试的时候才能游刃有余。而毫无依据的自我感觉良好,在每次失败之后都看不到自身的不足,而是怪罪于外界因素。
做好自己的简历,我在简历上花了很长时间,只要允许,我都会用这个简历给面试官演示:[个人简历](https://cyc2018.github.io)。

View File

@ -1,46 +0,0 @@
# 前言
本文档提供博客内容的补充资料,记录一些还没写又很重要的内容。欢迎补充!
格式:\[资料名称\]\[标签1\]\[标签2\]...
# 系统设计
- [[system-design-primer][Github]](https://github.com/donnemartin/system-design-primer)
- [[Leetcode / Interview Questions][题集]](https://leetcode.com/discuss/interview-question/?orderBy=most_votes)
- [[系统设计面试题精选][Gitbook]](https://soulmachine.gitbooks.io/system-design/content/cn/)
- [[海量数据面试题]](https://samanthachen.github.io/2016/08/01/%E6%B5%B7%E9%87%8F%E6%95%B0%E6%8D%AE%E9%9D%A2%E8%AF%95%E9%A2%98/)
- [[前端经典面试题: 从输入 URL 到页面加载发生了什么?][具体问题]](https://segmentfault.com/a/1190000006879700)
- [[秒杀系统架构分析与实战][具体问题]](https://my.oschina.net/xianggao/blog/524943)
- [[微信二维码登录原理][具体问题]](https://zhuanlan.zhihu.com/p/22325152?refer=bittiger)
- [[Create a TinyURL System][具体问题]](https://github.com/CyC2018/CS-Notes)
- [[Design a Key-Value Store (Part I)][具体问题]](http://blog.gainlo.co/index.php/2016/06/14/design-a-key-value-store-part-i/)
- [[坦率地讲 服务熔断 & 服务降级][知识点]](http://lexuslee.me/2018/02/01/2018-01-18-Service-fallback/)
- [[理解 HTTP 幂等性][知识点]](https://www.cnblogs.com/weidagang2046/archive/2011/06/04/idempotence.html)
- [[接口限流算法][知识点]](https://blog.csdn.net/ljj821061514/article/details/52512943)
- [[微服务学习资料汇总][知识点]](https://www.infoq.cn/article/2014%2F07%2Fmicroservice-learning-resources)
- [[理解 RESTful 架构][知识点]](http://www.ruanyifeng.com/blog/2011/09/restful.html)
- [[MapReduce 算法][知识点]](https://github.com/xuelangZF/CS_Offer/blob/master/Others/Hadoop_Spark.md)
# Spring
- [[Spring 揭秘][书籍]](https://book.douban.com/subject/3897837/)
- [[69 道 Spring 面试题和答案][面试题集锦]](http://ifeve.com/spring-interview-questions-and-answers/)
- [[Spring 面试题][面试题集锦]](https://github.com/Homiss/Java-interview-questions/blob/master/%E6%A1%86%E6%9E%B6/Spring%20%E9%9D%A2%E8%AF%95%E9%A2%98.md)
# 中间件
- [[RabbitMQ 实战][书籍]](https://book.douban.com/subject/26649178/)
- [[从 Paxos 到 Zookeeper][书籍]](https://book.douban.com/subject/26292004/)]
- [[Apache Dubbo][文档]](http://dubbo.apache.org/zh-cn/)
- [[nginx 快速入门之基本原理篇][入门]](https://zhuanlan.zhihu.com/p/31196264)
- [[深入理解 Nginx][书籍]](https://book.douban.com/subject/22793675/)
# 编程语言思想
- [[函数式编程初探][入门]](http://www.ruanyifeng.com/blog/2012/04/functional_programming.html)]
- [[函数式编程][全面]](https://coolshell.cn/articles/10822.html)
- [[闭包][文档]](https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Closures)
- [[尾调用优化]](http://www.ruanyifeng.com/blog/2015/04/tail-call.html)

View File

@ -1,83 +0,0 @@
# 数据结构与算法
- [算法](https://book.douban.com/subject/19952400/)
- [数据结构与算法分析](https://book.douban.com/subject/3351237/)
- [编程珠玑](https://book.douban.com/subject/3227098/)
- [剑指 Offer](https://book.douban.com/subject/25910559/)
# 操作系统
- [现代操作系统](https://book.douban.com/subject/3852290/)
- [深入理解计算机系统](https://book.douban.com/subject/26912767/)
- [鸟哥的 Linux 私房菜](https://book.douban.com/subject/4889838/)
- [Unix 环境高级编程](https://book.douban.com/subject/25900403/)
- [Unix/Linux 编程实践教程](https://book.douban.com/subject/1219329/)
- [Operating Systems: Three Easy Pieces (OSTEP)](http://pages.cs.wisc.edu/~remzi/OSTEP/)
# 计算机网络
- [计算机网络](https://book.douban.com/subject/2970300/)
- [计算机网络 自顶向下方法](https://book.douban.com/subject/1391207/)
- [图解 HTTP](https://book.douban.com/subject/25863515/)
- [TCP/IP 详解 卷 1协议](https://book.douban.com/subject/1088054/)
- [UNIX 网络编程](https://book.douban.com/subject/1500149/)
- [Linux 多线程服务端编程](https://book.douban.com/subject/20471211/)
# 面向对象
- [Head First 设计模式](https://book.douban.com/subject/2243615/)
- [设计模式 可复用面向对象软件的基础](https://book.douban.com/subject/1052241/)
- [敏捷软件开发 原则、模式与实践](https://book.douban.com/subject/1140457/)
# 数据库
- [数据库系统概念](https://book.douban.com/subject/10548379/)
- [MySQL 必知必会](https://book.douban.com/subject/3354490/)
- [高性能 MySQL](https://book.douban.com/subject/23008813/)
- [Redis 设计与实现](https://book.douban.com/subject/25900156/)
- [Redis 实战](https://book.douban.com/subject/26612779/)
# Java
- [Java 编程思想](https://book.douban.com/subject/2130190/)
- [Effective java 中文版](https://book.douban.com/subject/3360807/)
- [深入Java虚拟机(原书第2版)](https://book.douban.com/subject/1138768/)
- [深入理解 Java 虚拟机](https://book.douban.com/subject/24722612/)
- [Java 并发编程实战](https://book.douban.com/subject/10484692/)
- [精通 Spring 4.x](https://book.douban.com/subject/26952826/)
- [Spring 揭秘](https://book.douban.com/subject/3897837/)
# C++
- [C++ Primer](https://book.douban.com/subject/25708312/)
- [Effective C++](https://book.douban.com/subject/1842426/)
- [C++ 编程规范](https://book.douban.com/subject/1480481/)
- [STL 源码剖析](https://book.douban.com/subject/1110934/)
- [深度探索 C++ 对象模型](https://book.douban.com/subject/1091086/)
# 系统设计
- [大规模分布式存储系统](https://book.douban.com/subject/25723658/)
- [从 Paxos 到 Zookeeper](https://book.douban.com/subject/26292004/)
- [大型网站系统与 Java 中间件开发实践](https://book.douban.com/subject/25867042/)
- [淘宝技术这十年](https://book.douban.com/subject/24335672/)
- [深入理解 Nginx](https://book.douban.com/subject/22793675/)
# 开发工具
- [Pro Git](https://git-scm.com/book/zh/v2)
- [正则表达式必知必会](https://book.douban.com/subject/2269648/)
# 编码实践
- [重构](https://book.douban.com/subject/4262627/)
- [代码大全](https://book.douban.com/subject/1477390/)
- [人月神话](https://book.douban.com/subject/1102259/)
- [程序员的职业素养](https://book.douban.com/subject/11614538/)
- [编写可读代码的艺术](https://book.douban.com/subject/10797189/)
# 其它
- [JavaScript 语言精粹](https://book.douban.com/subject/3590768/)
- [利用 Python 进行数据分析](https://book.douban.com/subject/25779298/)
- [概率论与数理统计](https://book.douban.com/subject/2201479/)

194
README.md
View File

@ -1,212 +1,140 @@
| | Ⅱ | Ⅲ | Ⅳ | | Ⅵ | Ⅶ | Ⅷ | Ⅸ | | <!--| | Ⅱ | Ⅲ | Ⅳ | | Ⅵ | Ⅶ | Ⅷ | Ⅸ | |
| :--------: | :---------: | :---------: | :---------: | :---------: | :---------:| :---------: | :-------: | :-------:| :------:| | :--------: | :---------: | :---------: | :---------: | :---------: | :---------:| :---------: | :-------: | :-------:| :------:|
| 算法[:pencil2:](#pencil2-算法) | 操作系统[:computer:](#computer-操作系统)|网络[:cloud:](#cloud-网络) | 面向对象[:couple:](#couple-面向对象) |数据库[:floppy_disk:](#floppy_disk-数据库)| Java [:coffee:](#coffee-java)| 系统设计[:bulb:](#bulb-系统设计)| 工具[:hammer:](#hammer-工具)| 编码实践[:speak_no_evil:](#speak_no_evil-编码实践)| 后记[:memo:](#memo-后记) | | 算法[:pencil2:](#pencil2-算法) | 操作系统[:computer:](#computer-操作系统)|网络[:cloud:](#cloud-网络) | 面向对象[:art:](#art-面向对象) |数据库[:floppy_disk:](#floppy_disk-数据库)| Java [:coffee:](#coffee-java)| 系统设计[:bulb:](#bulb-系统设计)| 工具[:wrench:](#wrench-工具)| 编码实践[:watermelon:](#watermelon-编码实践)| 后记[:memo:](#memo-后记) | -->
| &nbsp;算法&nbsp; | 操作系统 | &nbsp;网络&nbsp; | 面向对象 | &nbsp;&nbsp;数据库&nbsp;&nbsp; | &nbsp;&nbsp;&nbsp;Java&nbsp;&nbsp;&nbsp; | 系统设计 | &nbsp;&nbsp;&nbsp;工具&nbsp;&nbsp;&nbsp; | 编码实践 | &nbsp;&nbsp;&nbsp;后记&nbsp;&nbsp;&nbsp; |
| :--------: | :---------: | :---------: | :---------: | :---------: | :---------:| :---------: | :-------: | :-------:| :------:|
| [:pencil2:](#pencil2-算法) | [:computer:](#computer-操作系统)|[:cloud:](#cloud-网络) | [:art:](#art-面向对象) |[:floppy_disk:](#floppy_disk-数据库)| [:coffee:](#coffee-java)| [:bulb:](#bulb-系统设计)| [:wrench:](#wrench-工具)| [:watermelon:](#watermelon-编码实践)| [:memo:](#memo-后记) |
<br> <br>
<div align="center"> <div align="center">
<img src="other/LogoMakr_0zpEzN.png" width="150px"> <img src="assets/LogoMakr_0zpEzN.png" width="200px">
<br> <br>
<a href="other/Group.md"> <img src="https://img.shields.io/badge/>-group-4ab8a1.svg"></a> <a href="https://legacy.gitbook.com/book/cyc2018/interview-notebook/details"> <img src="https://img.shields.io/badge/_-gitbook-4ab8a1.svg"></a> <a href="https://cyc2018.github.io/CS-Notes"> <img src="https://img.shields.io/badge/>-read-4ab8a1.svg"></a> <a href="https://xiaozhuanlan.com/CyC2018"> <img src="https://img.shields.io/badge/_-more-4ab8a1.svg"></a>
<br> <br>
</div> </div>
### :pencil2: 算法 🎓 本项目包含了技术面试必备的基础知识,内容浅显易懂,你不需要花很长的时间去阅读和理解成堆的技术书籍就可以快速掌握这些知识,从而节省宝贵的面试复习时间。
- [剑指 Offer 题解](https://github.com/CyC2018/CS-Notes/blob/master/docs/notes/剑指%20offer%20题解.md) 🎨 推荐使用 https://cyc2018.github.io/CS-Notes 进行阅读,从而获得更好的阅读体验。如果访问速度比较慢,可以考虑国内的 http://cyc2018.gitee.io/cs-notes/ 。
目录根据原书第二版进行编排,代码和原书有所不同,尽量比原书更简洁 💯你也可以订阅 <a href="https://xiaozhuanlan.com/CyC2018">面试进阶指南</a>,包含了学习指导和面试技巧,让你更轻松拿到满意的 Offer
- [Leetcode 题解](https://github.com/CyC2018/CS-Notes/blob/master/docs/notes/Leetcode%20题解.md) ⭐️欢迎关注我的公众号 CyC2018在公众号后台回复关键字 📚 **资料** 可领取复习大纲,这份大纲是我花了一整年时间整理的面试知识点列表,不仅系统整理了面试知识点,而且标注了各个知识点的重要程度,从而帮你理清多而杂的面试知识点。可以说我基本是按照这份大纲来进行复习的,这份大纲对我拿到了 BAT 头条等 Offer 起到很大的帮助。你们完全可以和我一样根据大纲上列的知识点来进行复习,就不用看很多不重要的内容,也可以知道哪些内容很重要从而多安排一些复习时间。
对题目做了一个大致分类,并对每种题型的解题思路做了总结。 <div align="center">
<img src="https://cyc-1256109796.cos.ap-guangzhou.myqcloud.com/%E5%85%AC%E4%BC%97%E5%8F%B7.jpg" width="200px">
</div>
- [算法](https://github.com/CyC2018/CS-Notes/blob/master/docs/notes/算法.md)
排序、并查集、栈和队列、红黑树、散列表。 ## :pencil2: 算法
### :computer: 操作系统 - [剑指 Offer 题解](https://github.com/CyC2018/CS-Notes/blob/master/docs/notes/剑指%20Offer%20题解%20-%20目录.md)
- [Leetcode 题解](https://github.com/CyC2018/CS-Notes/blob/master/docs/notes/Leetcode%20题解%20-%20目录.md)
- [算法](https://github.com/CyC2018/CS-Notes/blob/master/docs/notes/算法%20-%20目录.md)
- [计算机操作系统](https://github.com/CyC2018/CS-Notes/blob/master/docs/notes/计算机操作系统.md) ## :computer: 操作系统
进程管理、内存管理、设备管理、链接。
- [计算机操作系统](https://github.com/CyC2018/CS-Notes/blob/master/docs/notes/计算机操作系统%20-%20目录.md)
- [Linux](https://github.com/CyC2018/CS-Notes/blob/master/docs/notes/Linux.md) - [Linux](https://github.com/CyC2018/CS-Notes/blob/master/docs/notes/Linux.md)
基本实现原理以及基本操作。 ## :cloud: 网络
### :cloud: 网络
- [计算机网络](https://github.com/CyC2018/CS-Notes/blob/master/docs/notes/计算机网络.md)
物理层、链路层、网络层、运输层、应用层。
- [计算机网络](https://github.com/CyC2018/CS-Notes/blob/master/docs/notes/计算机网络%20-%20目录.md)
- [HTTP](https://github.com/CyC2018/CS-Notes/blob/master/docs/notes/HTTP.md) - [HTTP](https://github.com/CyC2018/CS-Notes/blob/master/docs/notes/HTTP.md)
方法、状态码、Cookie、缓存、连接管理、HTTPs、HTTP 2.0。
- [Socket](https://github.com/CyC2018/CS-Notes/blob/master/docs/notes/Socket.md) - [Socket](https://github.com/CyC2018/CS-Notes/blob/master/docs/notes/Socket.md)
I/O 模型、I/O 多路复用。 ## :art: 面向对象
### :couple: 面向对象
- [设计模式](https://github.com/CyC2018/CS-Notes/blob/master/docs/notes/设计模式.md) - [设计模式](https://github.com/CyC2018/CS-Notes/blob/master/docs/notes/设计模式.md)
实现了 Gof 的 23 种设计模式。
- [面向对象思想](https://github.com/CyC2018/CS-Notes/blob/master/docs/notes/面向对象思想.md) - [面向对象思想](https://github.com/CyC2018/CS-Notes/blob/master/docs/notes/面向对象思想.md)
三大原则(继承、封装、多态)、类图、设计原则。 ## :floppy_disk: 数据库
### :floppy_disk: 数据库
- [数据库系统原理](https://github.com/CyC2018/CS-Notes/blob/master/docs/notes/数据库系统原理.md) - [数据库系统原理](https://github.com/CyC2018/CS-Notes/blob/master/docs/notes/数据库系统原理.md)
事务、锁、隔离级别、MVCC、间隙锁、范式。
- [SQL](https://github.com/CyC2018/CS-Notes/blob/master/docs/notes/SQL.md) - [SQL](https://github.com/CyC2018/CS-Notes/blob/master/docs/notes/SQL.md)
SQL 基本语法。
- [Leetcode-Database 题解](https://github.com/CyC2018/CS-Notes/blob/master/docs/notes/Leetcode-Database%20题解.md) - [Leetcode-Database 题解](https://github.com/CyC2018/CS-Notes/blob/master/docs/notes/Leetcode-Database%20题解.md)
Leetcode 上数据库题目的解题记录。
- [MySQL](https://github.com/CyC2018/CS-Notes/blob/master/docs/notes/MySQL.md) - [MySQL](https://github.com/CyC2018/CS-Notes/blob/master/docs/notes/MySQL.md)
存储引擎、索引、查询优化、切分、复制。
- [Redis](https://github.com/CyC2018/CS-Notes/blob/master/docs/notes/Redis.md) - [Redis](https://github.com/CyC2018/CS-Notes/blob/master/docs/notes/Redis.md)
五种数据类型、字典和跳跃表数据结构、使用场景、和 Memcache 的比较、淘汰策略、持久化、文件事件的 Reactor 模式、复制。 ## :coffee: Java
### :coffee: Java
- [Java 基础](https://github.com/CyC2018/CS-Notes/blob/master/docs/notes/Java%20基础.md) - [Java 基础](https://github.com/CyC2018/CS-Notes/blob/master/docs/notes/Java%20基础.md)
不会涉及很多基本语法介绍,主要是一些实现原理以及关键特性。
- [Java 容器](https://github.com/CyC2018/CS-Notes/blob/master/docs/notes/Java%20容器.md) - [Java 容器](https://github.com/CyC2018/CS-Notes/blob/master/docs/notes/Java%20容器.md)
源码分析ArrayList、Vector、CopyOnWriteArrayList、LinkedList、HashMap、ConcurrentHashMap、LinkedHashMap、WeakHashMap。
- [Java 并发](https://github.com/CyC2018/CS-Notes/blob/master/docs/notes/Java%20并发.md) - [Java 并发](https://github.com/CyC2018/CS-Notes/blob/master/docs/notes/Java%20并发.md)
线程使用方式、两种互斥同步方法、线程协作、JUC、线程安全、内存模型、锁优化。
- [Java 虚拟机](https://github.com/CyC2018/CS-Notes/blob/master/docs/notes/Java%20虚拟机.md) - [Java 虚拟机](https://github.com/CyC2018/CS-Notes/blob/master/docs/notes/Java%20虚拟机.md)
运行时数据区域、垃圾收集、类加载。
- [Java I/O](https://github.com/CyC2018/CS-Notes/blob/master/docs/notes/Java%20IO.md) - [Java I/O](https://github.com/CyC2018/CS-Notes/blob/master/docs/notes/Java%20IO.md)
NIO 的原理以及实例。 ## :bulb: 系统设计
### :bulb: 系统设计
- [系统设计基础](https://github.com/CyC2018/CS-Notes/blob/master/docs/notes/系统设计基础.md) - [系统设计基础](https://github.com/CyC2018/CS-Notes/blob/master/docs/notes/系统设计基础.md)
性能、伸缩性、扩展性、可用性、安全性
- [分布式](https://github.com/CyC2018/CS-Notes/blob/master/docs/notes/分布式.md) - [分布式](https://github.com/CyC2018/CS-Notes/blob/master/docs/notes/分布式.md)
分布式锁、分布式事务、CAP、BASE、Paxos、Raft
- [集群](https://github.com/CyC2018/CS-Notes/blob/master/docs/notes/集群.md) - [集群](https://github.com/CyC2018/CS-Notes/blob/master/docs/notes/集群.md)
负载均衡、Session 管理
- [攻击技术](https://github.com/CyC2018/CS-Notes/blob/master/docs/notes/攻击技术.md) - [攻击技术](https://github.com/CyC2018/CS-Notes/blob/master/docs/notes/攻击技术.md)
XSS、CSRF、SQL 注入、DDoS
- [缓存](https://github.com/CyC2018/CS-Notes/blob/master/docs/notes/缓存.md) - [缓存](https://github.com/CyC2018/CS-Notes/blob/master/docs/notes/缓存.md)
缓存特征、缓存位置、缓存问题、数据分布、一致性哈希、LRU、CDN
- [消息队列](https://github.com/CyC2018/CS-Notes/blob/master/docs/notes/消息队列.md) - [消息队列](https://github.com/CyC2018/CS-Notes/blob/master/docs/notes/消息队列.md)
消息处理模型、使用场景、可靠性 ## :wrench: 工具
### :hammer: 工具
- [Git](https://github.com/CyC2018/CS-Notes/blob/master/docs/notes/Git.md) - [Git](https://github.com/CyC2018/CS-Notes/blob/master/docs/notes/Git.md)
一些 Git 的使用和概念。
- [Docker](https://github.com/CyC2018/CS-Notes/blob/master/docs/notes/Docker.md) - [Docker](https://github.com/CyC2018/CS-Notes/blob/master/docs/notes/Docker.md)
- [构建工具](https://github.com/CyC2018/CS-Notes/blob/master/docs/notes/构建工具.md)
Docker 基本原理。
- [正则表达式](https://github.com/CyC2018/CS-Notes/blob/master/docs/notes/正则表达式.md) - [正则表达式](https://github.com/CyC2018/CS-Notes/blob/master/docs/notes/正则表达式.md)
正则表达式基本语法。 ## :watermelon: 编码实践
- [构建工具](https://github.com/CyC2018/CS-Notes/blob/master/docs/notes/构建工具.md)
构建工具的基本概念、主流构建工具介绍。
### :speak_no_evil: 编码实践
- [重构](https://github.com/CyC2018/CS-Notes/blob/master/docs/notes/重构.md)
参考 重构 改善既有代码的设计。
- [代码可读性](https://github.com/CyC2018/CS-Notes/blob/master/docs/notes/代码可读性.md) - [代码可读性](https://github.com/CyC2018/CS-Notes/blob/master/docs/notes/代码可读性.md)
参考 编写可读代码的艺术。
- [代码风格规范](https://github.com/CyC2018/CS-Notes/blob/master/docs/notes/代码风格规范.md) - [代码风格规范](https://github.com/CyC2018/CS-Notes/blob/master/docs/notes/代码风格规范.md)
Google 开源项目的代码风格规范。 ## :memo: 后记
### :memo: 后记 ### License
#### About 本仓库内容 **不是** 将网上的资料随意拼凑而来,除了少部分引用书上和技术文档的原文,其余都是我的原创。在您引用本仓库内容或者对内容进行修改演绎时,请署名并以相同方式共享,谢谢。
本仓库主要是根据计算机经典书籍以及官方技术文档进行总结的学习笔记,希望对大家有所帮助 转载文章请在开头明显处标明该页面地址。如果是公众号转载,也请在合适的位置贴上 [CyC2018 公众号二维码海报](https://github.com/CyC2018/CS-Notes/blob/master/assets/%E5%85%AC%E4%BC%97%E5%8F%B7%20%E6%B5%B7%E6%8A%A5.png)
学习笔记不是从网上到处拼凑而来,除了少部分引用书上和技术文档的原文,其余都是笔者的原创。在您引用本仓库内容或者对内容进行修改演绎时,请遵循文末的开源协议,谢谢。 <a rel="license" href="http://creativecommons.org/licenses/by-nc-sa/4.0/"><img alt="知识共享许可协议" style="border-width:0" src="https://i.creativecommons.org/l/by-nc-sa/4.0/88x31.png" /></a>
#### How To Contribute ### 内推信息
笔记内容是笔者一个字一个字打上去的,难免会有一些笔误,如果发现笔误可直接对相应文档进行编辑修改。 [Job-Recommend](https://github.com/CyC2018/Job-Recommend)
如果想要提交一个仓库现在还没有的全新内容,可以先将相应的文档放到 other 目录下。 ### QQ 群
欢迎在 Issue 中提交对本仓库的改进建议~ 为大家提供一个学习交流平台,在这里你可以自由地讨论技术问题。
#### BookList <img src="assets/group1.png" width="150px">
本仓库参考的书目:[BOOKLIST](https://github.com/CyC2018/Interview-Notebook/blob/master/BOOKLIST.md)。 ### 后端面试指南
#### Typesetting <a href="https://xiaozhuanlan.com/CyC2018">
<img src="assets/小专栏.jpg" width="80px">
</a>
笔记内容按照 [中文文案排版指北](https://mazhuang.org/wiki/chinese-copywriting-guidelines/) 进行排版,以保证内容的可读性。 ### 排版
笔记不使用 `![]()` 这种方式来引用图片,而是用 `<img>` 标签。一方面是为了能够控制图片以合适的大小显示,另一方面是因为 GFM 不支持 `<center> ![]() </center>` 让图片居中显示,只能使用 `<div align="center"> <img src=""/> </div>` 达到居中的效果 笔记内容按照 [中文文案排版指北](https://github.com/sparanoid/chinese-copywriting-guidelines) 进行排版,以保证内容的可读性
笔者将自己实现的文档排版功能提取出来,放在 Github Page 中,无需下载安装即可免费使用:[Text-Typesetting](https://github.com/CyC2018/Markdown-Typesetting) 不使用 `![]()` 这种方式来引用图片,而是用 `<img>` 标签。一方面是为了能够控制图片以合适的大小显示,另一方面是因为 [GFM](https://github.github.com/gfm/) 不支持 `<center> ![]() </center>` 这种方法让图片居中显示,只能使用 `<div align="center"> <img src=""/> </div>` 达到居中的效果
#### Uploading 在线排版工具:[Text-Typesetting](https://github.com/CyC2018/Text-Typesetting)。
笔者在本地使用为知笔记软件进行书写,为了方便将本地笔记内容上传到 Github 上实现了一整套自动化上传方案包括文本文件的导出、提取图片、Markdown 文档转换、Git 同步。 ### 上传方案
进行 Markdown 文档转换是因为 Github 使用的 GFM 不支持 MathJax 公式和 TOC 标记,所以需要替换 MathJax 公式为 CodeCogs 的云服务和重新生成 TOC 目录。 为了方便将本地笔记内容上传到 Github 上实现了一整套自动化上传方案包括提取图片、Markdown 文档转换、Git 同步。进行 Markdown 文档转换是因为 Github 使用的 GFM 不支持 MathJax 公式和 TOC 标记,所以需要替换 MathJax 公式为 CodeCogs 的云服务和重新生成 TOC 目录。
笔者将自己实现文档转换功能提取出来,方便大家在需要将本地 Markdown 上传到 Github或者制作项目 README 文档时生成目录时使用[GFM-Converter](https://github.com/CyC2018/GFM-Converter)。 GFM 转换工具[GFM-Converter](https://github.com/CyC2018/GFM-Converter)。
#### Logo
### Logo
Power by [logomakr](https://logomakr.com/). Power by [logomakr](https://logomakr.com/).
#### Statement ### 致谢
本仓库不参与商业行为,不向读者收取任何费用。(This repository is not engaging in business activities, and does not charge readers any fee.) 感谢以下人员对本仓库做出的贡献,当然不仅仅只有这些贡献者,这里就不一一列举了。如果你希望被添加到这个名单中,并且提交过 Issue 或者 PR请与我联系。
#### Acknowledgements
感谢以下人员对本仓库做出的贡献,当然不仅仅只有这些贡献者,这里就不一一列举了。如果你希望被添加到这个名单中,并且提交过 Issue 或者 PR请与笔者联系。
<a href="https://github.com/linw7"> <a href="https://github.com/linw7">
<img src="https://avatars3.githubusercontent.com/u/21679154?s=400&v=4" width="50px"> <img src="https://avatars3.githubusercontent.com/u/21679154?s=400&v=4" width="50px">
@ -214,6 +142,9 @@ Power by [logomakr](https://logomakr.com/).
<a href="https://github.com/g10guang"> <a href="https://github.com/g10guang">
<img src="https://avatars1.githubusercontent.com/u/18458140?s=400&v=4" width="50px"> <img src="https://avatars1.githubusercontent.com/u/18458140?s=400&v=4" width="50px">
</a> </a>
<a href="https://github.com/Sctwang">
<img src="https://avatars3.githubusercontent.com/u/33345444?s=400&v=4" width="50px">
</a>
<a href="https://github.com/ResolveWang"> <a href="https://github.com/ResolveWang">
<img src="https://avatars1.githubusercontent.com/u/8018776?s=400&v=4" width="50px"> <img src="https://avatars1.githubusercontent.com/u/8018776?s=400&v=4" width="50px">
</a> </a>
@ -236,10 +167,3 @@ Power by [logomakr](https://logomakr.com/).
<img src="https://avatars1.githubusercontent.com/u/21008209?s=400&v=4" width="50px"> <img src="https://avatars1.githubusercontent.com/u/21008209?s=400&v=4" width="50px">
</a> </a>
#### License
在对本作品进行演绎时,请署名并以相同方式共享。
<a rel="license" href="http://creativecommons.org/licenses/by-nc-sa/4.0/"><img alt="知识共享许可协议" style="border-width:0" src="https://i.creativecommons.org/l/by-nc-sa/4.0/88x31.png" /></a>

View File

@ -1,49 +0,0 @@
This file used to generate gitbook catalogue.
# Summary
* 算法
* [剑指 Offer 题解](/notes/剑指 offer 题解.md)
* [Leetcode 题解](/notes/Leetcode 题解.md)
* [算法](/notes/算法.md)
* 操作系统
* [计算机操作系统](/notes/计算机操作系统.md)
* [Linux](/notes/Linux.md)
* 网络
* [计算机网络](/notes/计算机网络.md)
* [HTTP](/notes/HTTP.md)
* [Socket](/notes/Socket.md)
* 面向对象
* [设计模式](/notes/设计模式.md)
* [面向对象思想](/notes/面向对象思想.md)
* 数据库
* [数据库系统原理](/notes/数据库系统原理.md)
* [SQL](/notes/SQL.md)
* [Leetcode-Database 题解](/notes/Leetcode-Database 题解.md)
* [MySQL](/notes/MySQL.md)
* [Redis](/notes/Redis.md)
* Java
* [Java 基础](/notes/Java 基础.md)
* [Java 虚拟机](/notes/Java 虚拟机.md)
* [Java 并发](/notes/Java 并发.md)
* [Java 容器](/notes/Java 容器.md)
* [Java I/O](/notes/Java IO.md)
* 系统设计
* [系统设计基础](/notes/系统设计基础.md)
* [分布式](/notes/分布式.md)
* [集群](/notes/集群.md)
* [攻击技术](/notes/攻击技术.md)
* [缓存](/notes/缓存.md)
* [消息队列](/notes/消息队列.md)
* 工具
* [Git](/notes/Git.md)
* [Docker](/notes/Docker.md)
* [正则表达式](/notes/正则表达式.md)
* [构建工具](/notes/构建工具.md)
* 编码实践
* [重构](/notes/重构.md)
* [代码可读性](/notes/代码可读性.md)
* [代码风格规范](/notes/代码风格规范.md)
* 参考书目
* [BOOKLIST](/BOOKLIST.md)

View File

Before

Width:  |  Height:  |  Size: 33 KiB

After

Width:  |  Height:  |  Size: 33 KiB

BIN
assets/column.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.1 KiB

BIN
assets/group1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

BIN
assets/公众号 海报.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 506 KiB

BIN
assets/公众号.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

BIN
assets/公众号1.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

BIN
assets/公众号海报.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 506 KiB

BIN
assets/小专栏.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 628 KiB

BIN
assets/牛客网.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

BIN
assets/知乎.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

BIN
assets/知识星球.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

View File

@ -1,53 +1,63 @@
## ✏️ 算法 - [点击订阅面试进阶指南](https://xiaozhuanlan.com/CyC2018)
> [剑指 Offer 题解](notes/剑指%20offer%20题解.md) </br> ## ✏️ 算法
> [Leetcode 题解](notes/Leetcode%20题解)
> [算法](notes/算法.md) - [剑指 Offer 题解](notes/剑指%20Offer%20题解%20-%20目录1.md) </br>
- [Leetcode 题解](notes/Leetcode%20题解%20-%20目录1.md) </br>
- [算法](notes/算法%20-%20目录1.md) </br>
- [点击订阅面试进阶指南](https://xiaozhuanlan.com/CyC2018)
## 💻 操作系统 ## 💻 操作系统
> [计算机操作系统](notes/计算机操作系统.md) </br> - [计算机操作系统](notes/计算机操作系统%20-%20目录1.md) </br>
> [Linux](notes/Linux.md) - [Linux](notes/Linux.md)
## ☁️ 网络 ## ☁️ 网络
> [计算机网络](notes/计算机网络.md) </br> - [计算机网络](notes/计算机网络%20-%20目录1.md) </br>
> [HTTP](notes/HTTP.md) </br> - [HTTP](notes/HTTP.md) </br>
> [Sockets](notes/Sockets.md) - [Socket](notes/Socket.md)
## 👫 面向对象 ## 🎨 面向对象
> [设计模式](notes/设计模式.md) </br> - [设计模式](notes/设计模式.md) </br>
> [面向对象思想](notes/面向对象思想.md) - [面向对象思想](notes/面向对象思想.md)
## 💾 数据库 ## 💾 数据库
> [数据库系统原理](notes/数据库系统原理.md) </br> - [数据库系统原理](notes/数据库系统原理.md) </br>
> [SQL](notes/SQL.md) </br> - [SQL](notes/SQL.md) </br>
> [Leetcode-Database 题解](notes/Leetcode-Database%20题解.md) </br> - [Leetcode-Database 题解](notes/Leetcode-Database%20题解.md) </br>
> [MySQL](notes/MySQL.md) </br> - [MySQL](notes/MySQL.md) </br>
> [Redis](notes/Redis.md) - [Redis](notes/Redis.md)
## ☕️ Java ## ☕️ Java
> [Java 基础](notes/Java%20基础.md) </br> - [Java 基础](notes/Java%20基础.md) </br>
> [Java 容器](notes/Java%20容器.md) </br> - [Java 容器](notes/Java%20容器.md) </br>
> [Java 并发](notes/Java%20并发.md) </br> - [Java 并发](notes/Java%20并发.md) </br>
> [Java 虚拟机](notes/Java%20虚拟机.md) </br> - [Java 虚拟机](notes/Java%20虚拟机.md) </br>
> [Java I/O](notes/Java%20IO.md) - [Java I/O](notes/Java%20IO.md)
## 💡 系统设计 ## 💡 系统设计
> [系统设计基础](notes/系统设计基础.md) </br> - [系统设计基础](notes/系统设计基础.md) </br>
> [分布式](notes/分布式.md) </br> - [分布式](notes/分布式.md) </br>
> [集群](notes/集群.md) </br> - [集群](notes/集群.md) </br>
> [攻击技术](notes/攻击技术.md) </br> - [攻击技术](notes/攻击技术.md) </br>
> [缓存](notes/缓存.md) </br> - [缓存](notes/缓存.md) </br>
> [消息队列](notes/消息队列.md) - [消息队列](notes/消息队列.md)
## 🔨 工具 ## 🔧 工具
- [Git](notes/Git.md) </br>
- [Docker](notes/Docker.md) </br>
- [正则表达式](notes/正则表达式.md) </br>
- [构建工具](notes/构建工具.md)
<!--⭐️欢迎关注我的公众号 CyC2018在公众号后台回复关键字 📚 **资料** 可领取复习大纲,这份大纲是我花了一整年时间整理的面试知识点列表,不仅系统整理了面试知识点,而且标注了各个知识点的重要程度,从而帮你理清多而杂的面试知识点。可以说我基本是按照这份大纲来进行复习的,这份大纲对我拿到了 BAT 头条等 Offer 起到很大的帮助。你们完全可以和我一样根据大纲上列的知识点来进行复习,就不用看很多不重要的内容,也可以知道哪些内容很重要从而多安排一些复习时间。
<br/><br/>
<div align="center">
<img src="https://cyc-1256109796.cos.ap-guangzhou.myqcloud.com/%E5%85%AC%E4%BC%97%E5%8F%B7.jpg" width="200px">
</div> -->
> [Git](notes/Git.md) </br>
> [Docker](notes/Docker.md) </br>
> [正则表达式](notes/正则表达式.md) </br>
> [构建工具](notes/构建工具.md)

View File

@ -1,13 +1,12 @@
<img width="150px" src="_media/LogoMakr_1J56bI.png"> <img width="180px" src="https://cyc-1256109796.cos.ap-guangzhou.myqcloud.com/LogoMakr_1J56bI.png">
# CS-Notes # CS-Notes
> Computer Sicence Learning Notes. - 本项目包含了技术面试必备的基础知识,内容浅显易懂,你不需要花很长的时间去阅读和理解成堆的技术书籍就可以快速掌握这些知识,从而节省宝贵的面试复习时间。
- Algorithm <!--<span id="busuanzi_container_site_pv">Site View : <span id="busuanzi_value_site_pv">-->
- Computer Networks
- Operating System [![stars](https://badgen.net/github/stars/CyC2018/CS-Notes?icon=github&color=4ab8a1)](https://github.com/CyC2018/CS-Notes) [![forks](https://badgen.net/github/forks/CyC2018/CS-Notes?icon=github&color=4ab8a1)](https://github.com/CyC2018/CS-Notes)
- ...
[Get Started](README.md) [Get Started](README.md)

BIN
docs/_media/公众号.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -1,330 +0,0 @@
/*!
* Bootstrap Reboot v4.0.0 (https://getbootstrap.com)
* Copyright 2011-2018 The Bootstrap Authors
* Copyright 2011-2018 Twitter, Inc.
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
* Forked from Normalize.css, licensed MIT (https://github.com/necolas/normalize.css/blob/master/LICENSE.md)
*/
*,
*::before,
*::after {
box-sizing: border-box;
}
html {
font-family: sans-serif;
line-height: 1.15;
-webkit-text-size-adjust: 100%;
-ms-text-size-adjust: 100%;
-ms-overflow-style: scrollbar;
-webkit-tap-highlight-color: transparent;
}
@-ms-viewport {
width: device-width;
}
article, aside, dialog, figcaption, figure, footer, header, hgroup, main, nav, section {
display: block;
}
body {
margin: 0;
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";
font-size: 1rem;
font-weight: 400;
line-height: 1.5;
color: #212529;
text-align: left;
background-color: #fff;
}
[tabindex="-1"]:focus {
outline: 0 !important;
}
hr {
box-sizing: content-box;
height: 0;
overflow: visible;
}
h1, h2, h3, h4, h5, h6 {
margin-top: 0;
margin-bottom: 0.5rem;
}
p {
margin-top: 0;
margin-bottom: 1rem;
}
abbr[title],
abbr[data-original-title] {
text-decoration: underline;
-webkit-text-decoration: underline dotted;
text-decoration: underline dotted;
cursor: help;
border-bottom: 0;
}
address {
margin-bottom: 1rem;
font-style: normal;
line-height: inherit;
}
ol,
ul,
dl {
margin-top: 0;
margin-bottom: 1rem;
}
ol ol,
ul ul,
ol ul,
ul ol {
margin-bottom: 0;
}
dt {
font-weight: 700;
}
dd {
margin-bottom: .5rem;
margin-left: 0;
}
blockquote {
margin: 0 0 1rem;
}
dfn {
font-style: italic;
}
b,
strong {
font-weight: bolder;
}
small {
font-size: 80%;
}
sub,
sup {
position: relative;
font-size: 75%;
line-height: 0;
vertical-align: baseline;
}
sub {
bottom: -.25em;
}
sup {
top: -.5em;
}
a {
color: #007bff;
text-decoration: none;
background-color: transparent;
-webkit-text-decoration-skip: objects;
}
a:hover {
color: #0056b3;
text-decoration: underline;
}
a:not([href]):not([tabindex]) {
color: inherit;
text-decoration: none;
}
a:not([href]):not([tabindex]):hover, a:not([href]):not([tabindex]):focus {
color: inherit;
text-decoration: none;
}
a:not([href]):not([tabindex]):focus {
outline: 0;
}
pre,
code,
kbd,
samp {
font-family: monospace, monospace;
font-size: 1em;
}
pre {
margin-top: 0;
margin-bottom: 1rem;
overflow: auto;
-ms-overflow-style: scrollbar;
}
figure {
margin: 0 0 1rem;
}
img {
vertical-align: middle;
border-style: none;
}
svg:not(:root) {
overflow: hidden;
}
table {
border-collapse: collapse;
}
caption {
padding-top: 0.75rem;
padding-bottom: 0.75rem;
color: #6c757d;
text-align: left;
caption-side: bottom;
}
th {
text-align: inherit;
}
label {
display: inline-block;
margin-bottom: .5rem;
}
button {
border-radius: 0;
}
button:focus {
outline: 1px dotted;
outline: 5px auto -webkit-focus-ring-color;
}
input,
button,
select,
optgroup,
textarea {
margin: 0;
font-family: inherit;
font-size: inherit;
line-height: inherit;
}
button,
input {
overflow: visible;
}
button,
select {
text-transform: none;
}
button,
html [type="button"],
[type="reset"],
[type="submit"] {
-webkit-appearance: button;
}
button::-moz-focus-inner,
[type="button"]::-moz-focus-inner,
[type="reset"]::-moz-focus-inner,
[type="submit"]::-moz-focus-inner {
padding: 0;
border-style: none;
}
input[type="radio"],
input[type="checkbox"] {
box-sizing: border-box;
padding: 0;
}
input[type="date"],
input[type="time"],
input[type="datetime-local"],
input[type="month"] {
-webkit-appearance: listbox;
}
textarea {
overflow: auto;
resize: vertical;
}
fieldset {
min-width: 0;
padding: 0;
margin: 0;
border: 0;
}
legend {
display: block;
width: 100%;
max-width: 100%;
padding: 0;
margin-bottom: .5rem;
font-size: 1.5rem;
line-height: inherit;
color: inherit;
white-space: normal;
}
progress {
vertical-align: baseline;
}
[type="number"]::-webkit-inner-spin-button,
[type="number"]::-webkit-outer-spin-button {
height: auto;
}
[type="search"] {
outline-offset: -2px;
-webkit-appearance: none;
}
[type="search"]::-webkit-search-cancel-button,
[type="search"]::-webkit-search-decoration {
-webkit-appearance: none;
}
::-webkit-file-upload-button {
font: inherit;
-webkit-appearance: button;
}
output {
display: inline-block;
}
summary {
display: list-item;
cursor: pointer;
}
template {
display: none;
}
[hidden] {
display: none !important;
}
/*# sourceMappingURL=bootstrap-reboot.css.map */

File diff suppressed because one or more lines are too long

View File

@ -1,8 +0,0 @@
/*!
* Bootstrap Reboot v4.0.0 (https://getbootstrap.com)
* Copyright 2011-2018 The Bootstrap Authors
* Copyright 2011-2018 Twitter, Inc.
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
* Forked from Normalize.css, licensed MIT (https://github.com/necolas/normalize.css/blob/master/LICENSE.md)
*/*,::after,::before{box-sizing:border-box}html{font-family:sans-serif;line-height:1.15;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%;-ms-overflow-style:scrollbar;-webkit-tap-highlight-color:transparent}@-ms-viewport{width:device-width}article,aside,dialog,figcaption,figure,footer,header,hgroup,main,nav,section{display:block}body{margin:0;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol";font-size:1rem;font-weight:400;line-height:1.5;color:#212529;text-align:left;background-color:#fff}[tabindex="-1"]:focus{outline:0!important}hr{box-sizing:content-box;height:0;overflow:visible}h1,h2,h3,h4,h5,h6{margin-top:0;margin-bottom:.5rem}p{margin-top:0;margin-bottom:1rem}abbr[data-original-title],abbr[title]{text-decoration:underline;-webkit-text-decoration:underline dotted;text-decoration:underline dotted;cursor:help;border-bottom:0}address{margin-bottom:1rem;font-style:normal;line-height:inherit}dl,ol,ul{margin-top:0;margin-bottom:1rem}ol ol,ol ul,ul ol,ul ul{margin-bottom:0}dt{font-weight:700}dd{margin-bottom:.5rem;margin-left:0}blockquote{margin:0 0 1rem}dfn{font-style:italic}b,strong{font-weight:bolder}small{font-size:80%}sub,sup{position:relative;font-size:75%;line-height:0;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}a{color:#007bff;text-decoration:none;background-color:transparent;-webkit-text-decoration-skip:objects}a:hover{color:#0056b3;text-decoration:underline}a:not([href]):not([tabindex]){color:inherit;text-decoration:none}a:not([href]):not([tabindex]):focus,a:not([href]):not([tabindex]):hover{color:inherit;text-decoration:none}a:not([href]):not([tabindex]):focus{outline:0}code,kbd,pre,samp{font-family:monospace,monospace;font-size:1em}pre{margin-top:0;margin-bottom:1rem;overflow:auto;-ms-overflow-style:scrollbar}figure{margin:0 0 1rem}img{vertical-align:middle;border-style:none}svg:not(:root){overflow:hidden}table{border-collapse:collapse}caption{padding-top:.75rem;padding-bottom:.75rem;color:#6c757d;text-align:left;caption-side:bottom}th{text-align:inherit}label{display:inline-block;margin-bottom:.5rem}button{border-radius:0}button:focus{outline:1px dotted;outline:5px auto -webkit-focus-ring-color}button,input,optgroup,select,textarea{margin:0;font-family:inherit;font-size:inherit;line-height:inherit}button,input{overflow:visible}button,select{text-transform:none}[type=reset],[type=submit],button,html [type=button]{-webkit-appearance:button}[type=button]::-moz-focus-inner,[type=reset]::-moz-focus-inner,[type=submit]::-moz-focus-inner,button::-moz-focus-inner{padding:0;border-style:none}input[type=checkbox],input[type=radio]{box-sizing:border-box;padding:0}input[type=date],input[type=datetime-local],input[type=month],input[type=time]{-webkit-appearance:listbox}textarea{overflow:auto;resize:vertical}fieldset{min-width:0;padding:0;margin:0;border:0}legend{display:block;width:100%;max-width:100%;padding:0;margin-bottom:.5rem;font-size:1.5rem;line-height:inherit;color:inherit;white-space:normal}progress{vertical-align:baseline}[type=number]::-webkit-inner-spin-button,[type=number]::-webkit-outer-spin-button{height:auto}[type=search]{outline-offset:-2px;-webkit-appearance:none}[type=search]::-webkit-search-cancel-button,[type=search]::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{font:inherit;-webkit-appearance:button}output{display:inline-block}summary{display:list-item;cursor:pointer}template{display:none}[hidden]{display:none!important}
/*# sourceMappingURL=bootstrap-reboot.min.css.map */

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -1,330 +0,0 @@
/*!
* Bootstrap Reboot v4.0.0 (https://getbootstrap.com)
* Copyright 2011-2018 The Bootstrap Authors
* Copyright 2011-2018 Twitter, Inc.
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
* Forked from Normalize.css, licensed MIT (https://github.com/necolas/normalize.css/blob/master/LICENSE.md)
*/
*,
*::before,
*::after {
box-sizing: border-box;
}
html {
font-family: sans-serif;
line-height: 1.15;
-webkit-text-size-adjust: 100%;
-ms-text-size-adjust: 100%;
-ms-overflow-style: scrollbar;
-webkit-tap-highlight-color: transparent;
}
@-ms-viewport {
width: device-width;
}
article, aside, dialog, figcaption, figure, footer, header, hgroup, main, nav, section {
display: block;
}
body {
margin: 0;
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";
font-size: 1rem;
font-weight: 400;
line-height: 1.5;
color: #212529;
text-align: left;
background-color: #fff;
}
[tabindex="-1"]:focus {
outline: 0 !important;
}
hr {
box-sizing: content-box;
height: 0;
overflow: visible;
}
h1, h2, h3, h4, h5, h6 {
margin-top: 0;
margin-bottom: 0.5rem;
}
p {
margin-top: 0;
margin-bottom: 1rem;
}
abbr[title],
abbr[data-original-title] {
text-decoration: underline;
-webkit-text-decoration: underline dotted;
text-decoration: underline dotted;
cursor: help;
border-bottom: 0;
}
address {
margin-bottom: 1rem;
font-style: normal;
line-height: inherit;
}
ol,
ul,
dl {
margin-top: 0;
margin-bottom: 1rem;
}
ol ol,
ul ul,
ol ul,
ul ol {
margin-bottom: 0;
}
dt {
font-weight: 700;
}
dd {
margin-bottom: .5rem;
margin-left: 0;
}
blockquote {
margin: 0 0 1rem;
}
dfn {
font-style: italic;
}
b,
strong {
font-weight: bolder;
}
small {
font-size: 80%;
}
sub,
sup {
position: relative;
font-size: 75%;
line-height: 0;
vertical-align: baseline;
}
sub {
bottom: -.25em;
}
sup {
top: -.5em;
}
a {
color: #007bff;
text-decoration: none;
background-color: transparent;
-webkit-text-decoration-skip: objects;
}
a:hover {
color: #0056b3;
text-decoration: underline;
}
a:not([href]):not([tabindex]) {
color: inherit;
text-decoration: none;
}
a:not([href]):not([tabindex]):hover, a:not([href]):not([tabindex]):focus {
color: inherit;
text-decoration: none;
}
a:not([href]):not([tabindex]):focus {
outline: 0;
}
pre,
code,
kbd,
samp {
font-family: monospace, monospace;
font-size: 1em;
}
pre {
margin-top: 0;
margin-bottom: 1rem;
overflow: auto;
-ms-overflow-style: scrollbar;
}
figure {
margin: 0 0 1rem;
}
img {
vertical-align: middle;
border-style: none;
}
svg:not(:root) {
overflow: hidden;
}
table {
border-collapse: collapse;
}
caption {
padding-top: 0.75rem;
padding-bottom: 0.75rem;
color: #6c757d;
text-align: left;
caption-side: bottom;
}
th {
text-align: inherit;
}
label {
display: inline-block;
margin-bottom: .5rem;
}
button {
border-radius: 0;
}
button:focus {
outline: 1px dotted;
outline: 5px auto -webkit-focus-ring-color;
}
input,
button,
select,
optgroup,
textarea {
margin: 0;
font-family: inherit;
font-size: inherit;
line-height: inherit;
}
button,
input {
overflow: visible;
}
button,
select {
text-transform: none;
}
button,
html [type="button"],
[type="reset"],
[type="submit"] {
-webkit-appearance: button;
}
button::-moz-focus-inner,
[type="button"]::-moz-focus-inner,
[type="reset"]::-moz-focus-inner,
[type="submit"]::-moz-focus-inner {
padding: 0;
border-style: none;
}
input[type="radio"],
input[type="checkbox"] {
box-sizing: border-box;
padding: 0;
}
input[type="date"],
input[type="time"],
input[type="datetime-local"],
input[type="month"] {
-webkit-appearance: listbox;
}
textarea {
overflow: auto;
resize: vertical;
}
fieldset {
min-width: 0;
padding: 0;
margin: 0;
border: 0;
}
legend {
display: block;
width: 100%;
max-width: 100%;
padding: 0;
margin-bottom: .5rem;
font-size: 1.5rem;
line-height: inherit;
color: inherit;
white-space: normal;
}
progress {
vertical-align: baseline;
}
[type="number"]::-webkit-inner-spin-button,
[type="number"]::-webkit-outer-spin-button {
height: auto;
}
[type="search"] {
outline-offset: -2px;
-webkit-appearance: none;
}
[type="search"]::-webkit-search-cancel-button,
[type="search"]::-webkit-search-decoration {
-webkit-appearance: none;
}
::-webkit-file-upload-button {
font: inherit;
-webkit-appearance: button;
}
output {
display: inline-block;
}
summary {
display: list-item;
cursor: pointer;
}
template {
display: none;
}
[hidden] {
display: none !important;
}
/*# sourceMappingURL=bootstrap-reboot.css.map */

File diff suppressed because one or more lines are too long

View File

@ -1,8 +0,0 @@
/*!
* Bootstrap Reboot v4.0.0 (https://getbootstrap.com)
* Copyright 2011-2018 The Bootstrap Authors
* Copyright 2011-2018 Twitter, Inc.
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
* Forked from Normalize.css, licensed MIT (https://github.com/necolas/normalize.css/blob/master/LICENSE.md)
*/*,::after,::before{box-sizing:border-box}html{font-family:sans-serif;line-height:1.15;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%;-ms-overflow-style:scrollbar;-webkit-tap-highlight-color:transparent}@-ms-viewport{width:device-width}article,aside,dialog,figcaption,figure,footer,header,hgroup,main,nav,section{display:block}body{margin:0;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol";font-size:1rem;font-weight:400;line-height:1.5;color:#212529;text-align:left;background-color:#fff}[tabindex="-1"]:focus{outline:0!important}hr{box-sizing:content-box;height:0;overflow:visible}h1,h2,h3,h4,h5,h6{margin-top:0;margin-bottom:.5rem}p{margin-top:0;margin-bottom:1rem}abbr[data-original-title],abbr[title]{text-decoration:underline;-webkit-text-decoration:underline dotted;text-decoration:underline dotted;cursor:help;border-bottom:0}address{margin-bottom:1rem;font-style:normal;line-height:inherit}dl,ol,ul{margin-top:0;margin-bottom:1rem}ol ol,ol ul,ul ol,ul ul{margin-bottom:0}dt{font-weight:700}dd{margin-bottom:.5rem;margin-left:0}blockquote{margin:0 0 1rem}dfn{font-style:italic}b,strong{font-weight:bolder}small{font-size:80%}sub,sup{position:relative;font-size:75%;line-height:0;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}a{color:#007bff;text-decoration:none;background-color:transparent;-webkit-text-decoration-skip:objects}a:hover{color:#0056b3;text-decoration:underline}a:not([href]):not([tabindex]){color:inherit;text-decoration:none}a:not([href]):not([tabindex]):focus,a:not([href]):not([tabindex]):hover{color:inherit;text-decoration:none}a:not([href]):not([tabindex]):focus{outline:0}code,kbd,pre,samp{font-family:monospace,monospace;font-size:1em}pre{margin-top:0;margin-bottom:1rem;overflow:auto;-ms-overflow-style:scrollbar}figure{margin:0 0 1rem}img{vertical-align:middle;border-style:none}svg:not(:root){overflow:hidden}table{border-collapse:collapse}caption{padding-top:.75rem;padding-bottom:.75rem;color:#6c757d;text-align:left;caption-side:bottom}th{text-align:inherit}label{display:inline-block;margin-bottom:.5rem}button{border-radius:0}button:focus{outline:1px dotted;outline:5px auto -webkit-focus-ring-color}button,input,optgroup,select,textarea{margin:0;font-family:inherit;font-size:inherit;line-height:inherit}button,input{overflow:visible}button,select{text-transform:none}[type=reset],[type=submit],button,html [type=button]{-webkit-appearance:button}[type=button]::-moz-focus-inner,[type=reset]::-moz-focus-inner,[type=submit]::-moz-focus-inner,button::-moz-focus-inner{padding:0;border-style:none}input[type=checkbox],input[type=radio]{box-sizing:border-box;padding:0}input[type=date],input[type=datetime-local],input[type=month],input[type=time]{-webkit-appearance:listbox}textarea{overflow:auto;resize:vertical}fieldset{min-width:0;padding:0;margin:0;border:0}legend{display:block;width:100%;max-width:100%;padding:0;margin-bottom:.5rem;font-size:1.5rem;line-height:inherit;color:inherit;white-space:normal}progress{vertical-align:baseline}[type=number]::-webkit-inner-spin-button,[type=number]::-webkit-outer-spin-button{height:auto}[type=search]{outline-offset:-2px;-webkit-appearance:none}[type=search]::-webkit-search-cancel-button,[type=search]::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{font:inherit;-webkit-appearance:button}output{display:inline-block}summary{display:list-item;cursor:pointer}template{display:none}[hidden]{display:none!important}
/*# sourceMappingURL=bootstrap-reboot.min.css.map */

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -3,10 +3,79 @@
display: none; display: none;
} }
#main>ul:nth-child(2) {
display: none;
}
.markdown-section h1 { .markdown-section h1 {
margin: 3rem 0 0 0; margin: 3rem 0 2rem 0;
}
.markdown-section h2 {
margin: 2rem 0 1rem;
}
.content,
.sidebar,
.markdown-section,
body,
.search input,
.sidebar-toggle {
background-color: rgba(243, 242, 238, 1) !important;
}
body {
/*font-family: Microsoft YaHei, Source Sans Pro, Helvetica Neue, Arial, sans-serif !important;*/
}
.markdown-section>p {
font-size: 16px !important;
}
.markdown-section pre>code {
font-family: Consolas, Roboto Mono, Monaco, courier, monospace !important;
font-size: .9rem !important;
} }
/*.anchor span { /*.anchor span {
color: rgb(66, 185, 131); color: rgb(66, 185, 131);
}*/ }*/
section.cover h1 {
margin: 0;
}
body>section>div.cover-main>ul>li>a {
color: #42b983;
}
.markdown-section img {
box-shadow: 7px 9px 10px #aaa !important;
}
pre {
background-color: #f3f2ee !important;
}
@media (min-width:600px) {
pre code {
/*box-shadow: 2px 1px 20px 2px #aaa;*/
/*border-radius: 10px !important;*/
padding-left: 20px !important;
}
}
@media (max-width:600px) {
pre {
padding-left: 0px !important;
padding-right: 0px !important;
}
}
.markdown-section pre {
padding-left: 0 !important;
padding-right: 0px !important;
box-shadow: 2px 1px 20px 2px #aaa;
}

View File

@ -3,28 +3,360 @@
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<title>Document</title> <title>CS-Notes</title>
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" /> <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
<meta name="description" content="Description"> <meta name="description" content="Description">
<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0"> <meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<link rel="stylesheet" href="//unpkg.com/docsify/lib/themes/vue.css"> <link rel="icon" href=" https://cyc-1256109796.cos.ap-guangzhou.myqcloud.com/LogoMakr_1J56bI.png">
<link rel="stylesheet" href="//unpkg.com/gitalk/dist/gitalk.css"> <link rel="stylesheet" href="https://cyc-1256109796.cos.ap-guangzhou.myqcloud.com/vue.css">
<link rel="stylesheet" href="_style/style.css"> <!-- <link rel="stylesheet" href="//unpkg.com/gitalk/dist/gitalk.css"> -->
<!-- <link rel="stylesheet" href="_style/style.css"> -->
<!--solarizedlight tomorrow coy--> <!--solarizedlight tomorrow coy-->
<link rel="stylesheet" href="_style/prism-master/themes/prism-coy.css"> <!-- <link rel="stylesheet" href="_style/prism-master/themes/prism-coy.css"> -->
<!-- 将自定义样式放在 Github 上会导致加载速度变得非常慢,所以采取直接内嵌的方式 -->
<style type="text/css">
/* 隐藏头部的目录 */
#main>ul:nth-child(1) {
display: none;
}
#main>ul:nth-child(2) {
display: none;
}
.markdown-section h1 {
margin: 3rem 0 2rem 0;
}
.markdown-section h2 {
margin: 2rem 0 1rem;
}
img,
pre {
border-radius: 8px;
}
.content,
.sidebar,
.markdown-section,
body,
.search input {
background-color: rgba(243, 242, 238, 1) !important;
}
@media (min-width:600px) {
.sidebar-toggle {
background-color: #f3f2ee;
}
}
.docsify-copy-code-button {
background: #f8f8f8 !important;
color: #7a7a7a !important;
}
body {
/*font-family: Microsoft YaHei, Source Sans Pro, Helvetica Neue, Arial, sans-serif !important;*/
}
.markdown-section>p {
font-size: 16px !important;
}
.markdown-section pre>code {
font-family: Consolas, Roboto Mono, Monaco, courier, monospace !important;
/*font-size: .9rem !important;*/
}
/*.anchor span {
color: rgb(66, 185, 131);
}*/
section.cover h1 {
margin: 0;
}
body>section>div.cover-main>ul>li>a {
color: #42b983;
}
.markdown-section img {
box-shadow: 7px 9px 10px #aaa !important;
}
pre {
background-color: #f3f2ee !important;
}
@media (min-width:600px) {
pre code {
/*box-shadow: 2px 1px 20px 2px #aaa;*/
/*border-radius: 10px !important;*/
padding-left: 20px !important;
}
}
@media (max-width:600px) {
pre {
padding-left : 0px !important;
padding-right : 0px !important;
}
}
.markdown-section pre {
padding-left: 0 !important;
padding-right: 0px !important;
box-shadow: 2px 1px 20px 2px #aaa;
}
</style>
<style type="text/css">
/**
* prism.js Coy theme for JavaScript, CoffeeScript, CSS and HTML
* Based on https://github.com/tshedor/workshop-wp-theme (Example: http://workshop.kansan.com/category/sessions/basics or http://workshop.timshedor.com/category/sessions/basics);
* @author Tim Shedor
*/
code[class*="language-"],
pre[class*="language-"] {
color: black;
background: none;
font-family: Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace;
text-align: left;
white-space: pre;
word-spacing: normal;
word-break: normal;
word-wrap: normal;
line-height: 1.5;
-moz-tab-size: 4;
-o-tab-size: 4;
tab-size: 4;
-webkit-hyphens: none;
-moz-hyphens: none;
-ms-hyphens: none;
hyphens: none;
}
/* Code blocks */
pre[class*="language-"] {
position: relative;
margin: .5em 0;
overflow: visible;
padding: 0;
}
pre[class*="language-"]>code {
position: relative;
border-left: 10px solid #358ccb;
box-shadow: -1px 0px 0px 0px #358ccb, 0px 0px 0px 1px #dfdfdf;
background-color: #fdfdfd;
background-image: linear-gradient(transparent 50%, rgba(69, 142, 209, 0.04) 50%);
background-size: 3em 3em;
background-origin: content-box;
background-attachment: local;
}
code[class*="language"] {
max-height: inherit;
height: inherit;
padding: 0 1em;
display: block;
overflow: auto;
}
/* Margin bottom to accommodate shadow */
:not(pre)>code[class*="language-"],
pre[class*="language-"] {
background-color: #fdfdfd;
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
margin-bottom: 1em;
}
/* Inline code */
:not(pre)>code[class*="language-"] {
position: relative;
padding: .2em;
border-radius: 0.3em;
color: #c92c2c;
border: 1px solid rgba(0, 0, 0, 0.1);
display: inline;
white-space: normal;
}
pre[class*="language-"]:before,
pre[class*="language-"]:after {
content: '';
z-index: -2;
display: block;
position: absolute;
bottom: 0.75em;
left: 0.18em;
width: 40%;
height: 20%;
max-height: 13em;
box-shadow: 0px 13px 8px #979797;
-webkit-transform: rotate(-2deg);
-moz-transform: rotate(-2deg);
-ms-transform: rotate(-2deg);
-o-transform: rotate(-2deg);
transform: rotate(-2deg);
}
:not(pre)>code[class*="language-"]:after,
pre[class*="language-"]:after {
right: 0.75em;
left: auto;
-webkit-transform: rotate(2deg);
-moz-transform: rotate(2deg);
-ms-transform: rotate(2deg);
-o-transform: rotate(2deg);
transform: rotate(2deg);
}
.token.comment,
.token.block-comment,
.token.prolog,
.token.doctype,
.token.cdata {
color: #7D8B99;
}
.token.punctuation {
color: #5F6364;
}
.token.property,
.token.tag,
.token.boolean,
.token.number,
.token.function-name,
.token.constant,
.token.symbol,
.token.deleted {
color: #c92c2c;
}
.token.selector,
.token.attr-name,
.token.string,
.token.char,
.token.function,
.token.builtin,
.token.inserted {
color: #2f9c0a;
}
.token.operator,
.token.entity,
.token.url,
.token.variable {
color: #a67f59;
background: rgba(255, 255, 255, 0.5);
}
.token.atrule,
.token.attr-value,
.token.keyword,
.token.class-name {
color: #1990b8;
}
.token.regex,
.token.important {
color: #e90;
}
.language-css .token.string,
.style .token.string {
color: #a67f59;
background: rgba(255, 255, 255, 0.5);
}
.token.important {
font-weight: normal;
}
.token.bold {
font-weight: bold;
}
.token.italic {
font-style: italic;
}
.token.entity {
cursor: help;
}
.namespace {
opacity: .7;
}
@media screen and (max-width: 767px) {
pre[class*="language-"]:before,
pre[class*="language-"]:after {
bottom: 14px;
box-shadow: none;
}
}
/* Plugin styles */
.token.tab:not(:empty):before,
.token.cr:before,
.token.lf:before {
color: #e0d7d1;
}
/* Plugin styles: Line Numbers */
pre[class*="language-"].line-numbers.line-numbers {
padding-left: 0;
}
pre[class*="language-"].line-numbers.line-numbers code {
padding-left: 3.8em;
}
pre[class*="language-"].line-numbers.line-numbers .line-numbers-rows {
left: 0;
}
/* Plugin styles: Line Highlight */
pre[class*="language-"][data-line] {
padding-top: 0;
padding-bottom: 0;
padding-left: 0;
}
pre[data-line] code {
position: relative;
padding-left: 4em;
}
pre .line-highlight {
margin-top: 0;
}
</style>
</head> </head>
<body> <body>
<nav> <!-- <nav>
<a href="#/README">HOME</a> <a href="#/README">HOME</a>
</nav> </nav> -->
<div id="app"></div> <div id="app"></div>
<script> <script>
window.$docsify = { window.$docsify = {
maxAge: 100, maxAge: 100,
name: 'CS-Notes', name: 'CS-Notes',
repo: 'https://github.com/CyC2018/CS-Notes', repo: 'https://github.com/CyC2018/CS-Notes',
// ga: 'UA-121566133-2',
search: { search: {
paths: 'auto', paths: 'auto',
placeholder: '🔍 Type to search ', placeholder: '🔍 Type to search ',
@ -36,19 +368,21 @@
coverpage: true coverpage: true
} }
</script> </script>
<script src="//unpkg.com/docsify/lib/docsify.min.js"></script> <script src="https://cyc-1256109796.cos.ap-guangzhou.myqcloud.com/docsify.min.js"></script>
<!-- <script src="//unpkg.com/docsify/lib/plugins/search.min.js"></script> --> <!-- <script src="//unpkg.com/docsify/lib/plugins/search.min.js"></script> -->
<!-- 上面的基本不可用,无法搜索 --> <!-- 上面的基本不可用,无法搜索 -->
<script src="https://cdn.bootcss.com/docsify/4.5.9/plugins/search.min.js"></script> <script src="https://cdn.bootcss.com/docsify/4.5.9/plugins/search.min.js"></script>
<script src="//unpkg.com/docsify/lib/plugins/gitalk.min.js"></script> <!-- <script src="//unpkg.com/docsify/lib/plugins/gitalk.min.js"></script> -->
<script src="//unpkg.com/gitalk/dist/gitalk.min.js"></script> <!-- <script src="//unpkg.com/gitalk/dist/gitalk.min.js"></script> -->
<script src="//unpkg.com/docsify-copy-code"></script> <script src="https://cyc-1256109796.cos.ap-guangzhou.myqcloud.com/docsify-copy-code.min.js"></script>
<script src="//unpkg.com/prismjs/components/prism-java.min.js"></script> <script src="https://cyc-1256109796.cos.ap-guangzhou.myqcloud.com/prism-java.min.js"></script>
<script src="//unpkg.com/prismjs/components/prism-c.min.js"></script> <script src="https://cyc-1256109796.cos.ap-guangzhou.myqcloud.com/prism-c.min.js"></script>
<script src="//unpkg.com/prismjs/components/prism-bash.min.js"></script> <script src="https://cyc-1256109796.cos.ap-guangzhou.myqcloud.com/prism-bash.min.js"></script>
<script src="//unpkg.com/docsify/lib/plugins/zoom-image.min.js"></script> <script src="https://cyc-1256109796.cos.ap-guangzhou.myqcloud.com/prism-sql.min.js"></script>
<script src="https://cyc-1256109796.cos.ap-guangzhou.myqcloud.com/zoom-image.min.js"></script>
<!-- <script src="//unpkg.com/docsify/lib/plugins/emoji.min.js"></script> --> <!-- <script src="//unpkg.com/docsify/lib/plugins/emoji.min.js"></script> -->
<script src="//unpkg.com/docsify-pagination/dist/docsify-pagination.min.js"></script> <!-- <script src="//unpkg.com/docsify/lib/plugins/ga.min.js"></script> -->
<script async src="//busuanzi.ibruce.info/busuanzi/2.3/busuanzi.pure.mini.js"></script>
<script> <script>
const gitalk = new Gitalk({ const gitalk = new Gitalk({
clientID: 'c6c02367e36ca6e2bb2d', clientID: 'c6c02367e36ca6e2bb2d',

View File

@ -1,62 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
<meta name="description" content="Description">
<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<link rel="stylesheet" href="//unpkg.com/docsify/lib/themes/vue.css">
<link rel="stylesheet" href="//unpkg.com/gitalk/dist/gitalk.css">
<link rel="stylesheet" href="_style/style.css">
</head>
<body>
<nav>
<a href="#/README">HOME</a>
</nav>
<div id="app"></div>
<script>
window.$docsify = {
name: 'CS-Notes',
repo: 'https://github.com/CyC2018/CS-Notes',
loadSidebar: false,
subMaxLevel: 2,
coverpage: true,
auto2top: true,
autoHeader: true,
search: {
placeholder: '馃攳 Type to search ',
noData: '馃槥 No Results! ',
// Headline depth, 1 - 6
depth: 2,
hideOtherSidebarContent: false, // whether or not to hide other sidebar content
}
}
</script>
<script src="//unpkg.com/docsify/lib/docsify.min.js"></script>
<script src="//unpkg.com/docsify/lib/plugins/gitalk.min.js"></script>
<script src="//unpkg.com/gitalk/dist/gitalk.min.js"></script>
<script src="//unpkg.com/docsify-copy-code"></script>
<script src="//unpkg.com/prismjs/components/prism-java.min.js"></script>
<script src="//unpkg.com/prismjs/components/prism-c.min.js"></script>
<script src="//unpkg.com/prismjs/components/prism-bash.min.js"></script>
<script src="//unpkg.com/docsify/lib/plugins/zoom-image.min.js"></script>
<script src="//unpkg.com/docsify/lib/plugins/emoji.min.js"></script>
<script src="//unpkg.com/docsify/lib/plugins/search.min.js"></script>
<script src="//unpkg.com/docsify-pagination/dist/docsify-pagination.min.js"></script>
<script>
const gitalk = new Gitalk({
clientID: 'c6c02367e36ca6e2bb2d',
clientSecret: '31a2700e3315b21c5e9f2e887709d8cf21f9ff8f',
repo: 'Gittalk-Issue',
owner: 'CyC2018',
admin: ['CyC2018'],
// distractionFreeMode: false
})
</script>
</body>
</html>

View File

@ -8,31 +8,29 @@
<!-- GFM-TOC --> <!-- GFM-TOC -->
<div align="center"> <img src="pics/011f3ef6-d824-4d43-8b2c-36dab8eaaa72-1.png"/> </div><br>
# 一、解决的问题 # 一、解决的问题
由于不同的机器有不同的操作系统,以及不同的库和组件,在将一个应用部署到多台机器上需要进行大量的环境配置操作。 由于不同的机器有不同的操作系统,以及不同的库和组件,在将一个应用部署到多台机器上需要进行大量的环境配置操作。
Docker 主要解决环境配置问题,它是一种虚拟化技术,对进程进行隔离,被隔离的进程独立于宿主操作系统和其它隔离的进程。使用 Docker 可以不修改应用程序代码,不需要开发人员学习特定环境下的技术,就能够将现有的应用程序部署在其他机器中。 Docker 主要解决环境配置问题,它是一种虚拟化技术,对进程进行隔离,被隔离的进程独立于宿主操作系统和其它隔离的进程。使用 Docker 可以不修改应用程序代码,不需要开发人员学习特定环境下的技术,就能够将现有的应用程序部署在其它机器上。
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/011f3ef6-d824-4d43-8b2c-36dab8eaaa72-1.png" width="400px"/> </div><br>
# 二、与虚拟机的比较 # 二、与虚拟机的比较
虚拟机也是一种虚拟化技术,它与 Docker 最大的区别在于它是通过模拟硬件,并在硬件上安装操作系统来实现。 虚拟机也是一种虚拟化技术,它与 Docker 最大的区别在于它是通过模拟硬件,并在硬件上安装操作系统来实现。
<div align="center"> <img src="pics/71f61bc3-582d-4c27-8bdd-dc7fb135bf8f.png"/> </div><br> <div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/be608a77-7b7f-4f8e-87cc-f2237270bf69.png" width="500"/> </div><br>
<div align="center"> <img src="pics/7e873b60-44dc-4911-b080-defd5b8f0b49.png"/> </div><br>
## 启动速度 ## 启动速度
启动虚拟机需要启动虚拟机的操作系统,再启动应用,这个过程非常慢; 启动虚拟机需要启动虚拟机的操作系统,再启动应用,这个过程非常慢;
而启动 Docker 相当于启动宿主操作系统上的一个进程。 而启动 Docker 相当于启动宿主操作系统上的一个进程。
## 占用资源 ## 占用资源
虚拟机是一个完整的操作系统,需要占用大量的磁盘、内存和 CPU一台机器只能开启几十个的虚拟机。 虚拟机是一个完整的操作系统,需要占用大量的磁盘、内存和 CPU 资源,一台机器只能开启几十个的虚拟机。
而 Docker 只是一个进程,只需要将应用以及相关的组件打包,在运行时占用很少的资源,一台机器可以开启成千上万个 Docker。 而 Docker 只是一个进程,只需要将应用以及相关的组件打包,在运行时占用很少的资源,一台机器可以开启成千上万个 Docker。
@ -42,11 +40,11 @@ Docker 主要解决环境配置问题,它是一种虚拟化技术,对进程
## 更容易迁移 ## 更容易迁移
提供一致性的运行环境可以在不同的机器上进行迁移,而不用担心环境变化导致无法运行。 提供一致性的运行环境。已经打包好的应用可以在不同的机器上进行迁移,而不用担心环境变化导致无法运行。
## 更容易维护 ## 更容易维护
使用分层技术和镜像,使得应用可以更容易复用重复部分。复用程度越高,维护工作也越容易。 使用分层技术和镜像,使得应用可以更容易复用重复部分。复用程度越高,维护工作也越容易。
## 更容易扩展 ## 更容易扩展
@ -76,7 +74,7 @@ Docker 轻量级的特点使得它很适合用于部署、维护、组合微服
构建容器时通过在镜像的基础上添加一个可写层writable layer用来保存着容器运行过程中的修改。 构建容器时通过在镜像的基础上添加一个可写层writable layer用来保存着容器运行过程中的修改。
<div align="center"> <img src="pics/docker-filesystems-busyboxrw.png"/> </div><br> <div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/docker-filesystems-busyboxrw.png"/> </div><br>
# 参考资料 # 参考资料
@ -89,3 +87,9 @@ Docker 轻量级的特点使得它很适合用于部署、维护、组合微服
- [What is Docker](https://www.docker.com/what-docker) - [What is Docker](https://www.docker.com/what-docker)
- [持续集成是什么?](http://www.ruanyifeng.com/blog/2015/09/continuous-integration.html) - [持续集成是什么?](http://www.ruanyifeng.com/blog/2015/09/continuous-integration.html)
</br><div align="center">⭐️欢迎关注我的公众号 CyC2018在公众号后台回复关键字 📚 **资料** 可领取复习大纲,这份大纲是我花了一整年时间整理的面试知识点列表,不仅系统整理了面试知识点,而且标注了各个知识点的重要程度,从而帮你理清多而杂的面试知识点。可以说我基本是按照这份大纲来进行复习的,这份大纲对我拿到了 BAT 头条等 Offer 起到很大的帮助。你们完全可以和我一样根据大纲上列的知识点来进行复习,就不用看很多不重要的内容,也可以知道哪些内容很重要从而多安排一些复习时间。</div></br>
<div align="center"><img width="180px" src="https://cyc-1256109796.cos.ap-guangzhou.myqcloud.com/%E5%85%AC%E4%BC%97%E5%8F%B7.jpg"></img></div>

View File

@ -18,6 +18,8 @@
Git 属于分布式版本控制系统,而 SVN 属于集中式。 Git 属于分布式版本控制系统,而 SVN 属于集中式。
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/fac3dfd6-1656-4329-9a80-7f6c51ef30c5_200.png"/> </div><br>
集中式版本控制只有中心服务器拥有一份代码,而分布式版本控制每个人的电脑上就有一份完整的代码。 集中式版本控制只有中心服务器拥有一份代码,而分布式版本控制每个人的电脑上就有一份完整的代码。
集中式版本控制有安全性问题,当中心服务器挂了所有人都没办法工作了。 集中式版本控制有安全性问题,当中心服务器挂了所有人都没办法工作了。
@ -34,49 +36,49 @@ Github 就是一个中心服务器。
# 工作流 # 工作流
<div align="center"> <img src="pics/a1198642-9159-4d88-8aec-c3b04e7a2563.jpg"/> </div><br>
新建一个仓库之后,当前目录就成为了工作区,工作区下有一个隐藏目录 .git它属于 Git 的版本库。 新建一个仓库之后,当前目录就成为了工作区,工作区下有一个隐藏目录 .git它属于 Git 的版本库。
Git 版本库有一个称为 stage 的暂存区,还有自动创建的 master 分支以及指向分支的 HEAD 指针 Git 的版本库有一个称为 Stage 的暂存区以及最后的 History 版本库History 中存有所有分支,使用一个 HEAD 指针指向当前分支
<div align="center"> <img src="pics/46f66e88-e65a-4ad0-a060-3c63fe22947c.png"/> </div><br> <div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/0f9b9d2a-c5cc-4a3f-b138-2c1035950f39_200.png"/> </div><br>
- git add files 把文件的修改添加到暂存区 - git add files 把文件的修改添加到暂存区
- git commit 把暂存区的修改提交到当前分支,提交之后暂存区就被清空了 - git commit 把暂存区的修改提交到当前分支,提交之后暂存区就被清空了
- git reset -- files 使用当前分支上的修改覆盖暂存区,用来撤销最后一次 git add files - git reset -- files 使用当前分支上的修改覆盖暂存区,用来撤销最后一次 git add files
- git checkout -- files 使用暂存区的修改覆盖工作目录,用来撤销本地修改 - git checkout -- files 使用暂存区的修改覆盖工作目录,用来撤销本地修改
<div align="center"> <img src="pics/17976404-95f5-480e-9cb4-250e6aa1d55f.png"/> </div><br> <div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/11a786f0-5e02-46a6-92f0-f302c9cf6ca3_200.png" width="400px"> </div><br>
可以跳过暂存区域直接从分支中取出修改,或者直接提交修改到分支中。 可以跳过暂存区域直接从分支中取出修改,或者直接提交修改到分支中。
- git commit -a 直接把所有文件的修改添加到暂存区然后执行提交 - git commit -a 直接把所有文件的修改添加到暂存区然后执行提交
- git checkout HEAD -- files 取出最后一次修改,可以用来进行回滚操作 - git checkout HEAD -- files 取出最后一次修改,可以用来进行回滚操作
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/b48b9a7a-f9f8-4cf9-90f1-5cddd685b782_200.png" width="600px"> </div><br>
# 分支实现 # 分支实现
使用指针将每个提交连接成一条时间线HEAD 指针指向当前分支指针。 使用指针将每个提交连接成一条时间线HEAD 指针指向当前分支指针。
<div align="center"> <img src="pics/fb546e12-e1fb-4b72-a1fb-8a7f5000dce6.jpg"/> </div><br> <div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/84d496d7-54b0-4a9b-9499-ce232057e499_200.png"/> </div><br>
新建分支是新建一个指针指向时间线的最后一个节点,并让 HEAD 指针指向新分支表示新分支成为当前分支。 新建分支是新建一个指针指向时间线的最后一个节点,并让 HEAD 指针指向新分支表示新分支成为当前分支。
<div align="center"> <img src="pics/bc775758-89ab-4805-9f9c-78b8739cf780.jpg"/> </div><br> <div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/7c5bcdbf-e656-4b7c-be82-b247a3589ed5_200.png"/> </div><br>
每次提交只会让当前分支指针向前移动,而其它分支指针不会移动。 每次提交只会让当前分支指针向前移动,而其它分支指针不会移动。
<div align="center"> <img src="pics/5292faa6-0141-4638-bf0f-bb95b081dcba.jpg"/> </div><br> <div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/13783e94-b481-4aea-9fa2-9d1973abd47e_200.png"/> </div><br>
合并分支也只需要改变指针即可。 合并分支也只需要改变指针即可。
<div align="center"> <img src="pics/1164a71f-413d-494a-9cc8-679fb6a2613d.jpg"/> </div><br> <div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/15699a17-5a69-4fbe-852e-9d2b7cf05e80_200.png"/> </div><br>
# 冲突 # 冲突
当两个分支都对同一个文件的同一行进行了修改,在分支合并时就会产生冲突。 当两个分支都对同一个文件的同一行进行了修改,在分支合并时就会产生冲突。
<div align="center"> <img src="pics/58e57a21-6b6b-40b6-af85-956dd4e0f55a.jpg"/> </div><br> <div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/7e82ce01-2afb-4c15-b720-b81049c875c2_200.png"/> </div><br>
Git 会使用 <<<<<<< ======= >>>>>>> 标记出不同分支的内容,只需要把不同分支中冲突部分修改成一样就能解决冲突。 Git 会使用 <<<<<<< ======= >>>>>>> 标记出不同分支的内容,只需要把不同分支中冲突部分修改成一样就能解决冲突。
@ -98,7 +100,7 @@ Creating a new branch is quick AND simple.
$ git merge --no-ff -m "merge with no-ff" dev $ git merge --no-ff -m "merge with no-ff" dev
``` ```
<div align="center"> <img src="pics/dd78a1fe-1ff3-4bcf-a56f-8c003995beb6.jpg"/> </div><br> <div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/fa1dc552-8501-439e-b85a-3d9eac704880_200.png"/> </div><br>
# 分支管理策略 # 分支管理策略
@ -106,7 +108,7 @@ master 分支应该是非常稳定的,只用来发布新版本;
日常开发在开发分支 dev 上进行。 日常开发在开发分支 dev 上进行。
<div align="center"> <img src="pics/245fd2fb-209c-4ad5-bc5e-eb5664966a0e.jpg"/> </div><br> <div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/245fd2fb-209c-4ad5-bc5e-eb5664966a0e.jpg"/> </div><br>
# 储藏Stashing # 储藏Stashing
@ -146,7 +148,7 @@ $ ssh-keygen -t rsa -C "youremail@example.com"
# Git 命令一览 # Git 命令一览
<div align="center"> <img src="pics/7a29acce-f243-4914-9f00-f2988c528412.jpg"/> </div><br> <div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/7a29acce-f243-4914-9f00-f2988c528412.jpg"/> </div><br>
比较详细的地址http://www.cheat-sheets.org/saved-copy/git-cheat-sheet.pdf 比较详细的地址http://www.cheat-sheets.org/saved-copy/git-cheat-sheet.pdf
@ -156,3 +158,9 @@ $ ssh-keygen -t rsa -C "youremail@example.com"
- [图解 Git](http://marklodato.github.io/visual-git-guide/index-zh-cn.html) - [图解 Git](http://marklodato.github.io/visual-git-guide/index-zh-cn.html)
- [廖雪峰 : Git 教程](https://www.liaoxuefeng.com/wiki/0013739516305929606dd18361248578c67b8067c8c017b000) - [廖雪峰 : Git 教程](https://www.liaoxuefeng.com/wiki/0013739516305929606dd18361248578c67b8067c8c017b000)
- [Learn Git Branching](https://learngitbranching.js.org/) - [Learn Git Branching](https://learngitbranching.js.org/)
</br><div align="center">⭐️欢迎关注我的公众号 CyC2018在公众号后台回复关键字 📚 **资料** 可领取复习大纲,这份大纲是我花了一整年时间整理的面试知识点列表,不仅系统整理了面试知识点,而且标注了各个知识点的重要程度,从而帮你理清多而杂的面试知识点。可以说我基本是按照这份大纲来进行复习的,这份大纲对我拿到了 BAT 头条等 Offer 起到很大的帮助。你们完全可以和我一样根据大纲上列的知识点来进行复习,就不用看很多不重要的内容,也可以知道哪些内容很重要从而多安排一些复习时间。</div></br>
<div align="center"><img width="180px" src="https://cyc-1256109796.cos.ap-guangzhou.myqcloud.com/%E5%85%AC%E4%BC%97%E5%8F%B7.jpg"></img></div>

View File

@ -1,6 +1,6 @@
<!-- GFM-TOC --> <!-- GFM-TOC -->
* [一 、基础概念](#一-基础概念) * [一 、基础概念](#一-基础概念)
* [URL](#url) * [URI](#uri)
* [请求和响应报文](#请求和响应报文) * [请求和响应报文](#请求和响应报文)
* [二、HTTP 方法](#二http-方法) * [二、HTTP 方法](#二http-方法)
* [GET](#get) * [GET](#get)
@ -34,11 +34,11 @@
* [多部分对象集合](#多部分对象集合) * [多部分对象集合](#多部分对象集合)
* [虚拟主机](#虚拟主机) * [虚拟主机](#虚拟主机)
* [通信数据转发](#通信数据转发) * [通信数据转发](#通信数据转发)
* [六、HTTPs](#六https) * [六、HTTPS](#六https)
* [加密](#加密) * [加密](#加密)
* [认证](#认证) * [认证](#认证)
* [完整性保护](#完整性保护) * [完整性保护](#完整性保护)
* [HTTPs 的缺点](#https-的缺点) * [HTTPS 的缺点](#https-的缺点)
* [七、HTTP/2.0](#七http20) * [七、HTTP/2.0](#七http20)
* [HTTP/1.x 缺陷](#http1x-缺陷) * [HTTP/1.x 缺陷](#http1x-缺陷)
* [二进制分帧层](#二进制分帧层) * [二进制分帧层](#二进制分帧层)
@ -58,25 +58,21 @@
# 一 、基础概念 # 一 、基础概念
## URL ## URI
URI 包含 URL 和 URN,目前 WEB 只有 URL 比较流行,所以见到的基本都是 URL URI 包含 URL 和 URN。
- URIUniform Resource Identifier统一资源标识符 <div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/417cb02e-853d-4288-a36e-9161ded2c9fd_200.png" width="600px"> </div><br>
- URLUniform Resource Locator统一资源定位符
- URNUniform Resource Name统一资源名称
<div align="center"> <img src="pics/urlnuri.jpg" width="600"/> </div><br>
## 请求和响应报文 ## 请求和响应报文
### 1. 请求报文 ### 1. 请求报文
<div align="center"> <img src="pics/HTTP_RequestMessageExample.png" width=""/> </div><br> <div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/HTTP_RequestMessageExample.png" width=""/> </div><br>
### 2. 响应报文 ### 2. 响应报文
<div align="center"> <img src="pics/HTTP_ResponseMessageExample.png" width=""/> </div><br> <div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/HTTP_ResponseMessageExample.png" width=""/> </div><br>
# 二、HTTP 方法 # 二、HTTP 方法
@ -92,7 +88,7 @@ URI 包含 URL 和 URN目前 WEB 只有 URL 比较流行,所以见到的基
> 获取报文首部 > 获取报文首部
和 GET 方法一样,但是不返回报文实体主体部分。 和 GET 方法类似,但是不返回报文实体主体部分。
主要用于确认 URL 的有效性以及资源更新的日期时间等。 主要用于确认 URL 的有效性以及资源更新的日期时间等。
@ -151,7 +147,7 @@ DELETE /file.html HTTP/1.1
查询指定的 URL 能够支持的方法。 查询指定的 URL 能够支持的方法。
会返回 Allow: GET, POST, HEAD, OPTIONS 这样的内容。 会返回 `Allow: GET, POST, HEAD, OPTIONS` 这样的内容。
## CONNECT ## CONNECT
@ -163,7 +159,7 @@ DELETE /file.html HTTP/1.1
CONNECT www.example.com:443 HTTP/1.1 CONNECT www.example.com:443 HTTP/1.1
``` ```
<div align="center"> <img src="pics/dc00f70e-c5c8-4d20-baf1-2d70014a97e3.jpg" width=""/> </div><br> <div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/dc00f70e-c5c8-4d20-baf1-2d70014a97e3.jpg" width=""/> </div><br>
## TRACE ## TRACE
@ -174,11 +170,12 @@ CONNECT www.example.com:443 HTTP/1.1
发送请求时,在 Max-Forwards 首部字段中填入数值,每经过一个服务器就会减 1当数值为 0 时就停止传输。 发送请求时,在 Max-Forwards 首部字段中填入数值,每经过一个服务器就会减 1当数值为 0 时就停止传输。
通常不会使用 TRACE并且它容易受到 XST 攻击Cross-Site Tracing跨站追踪 通常不会使用 TRACE并且它容易受到 XST 攻击Cross-Site Tracing跨站追踪
# 三、HTTP 状态码 # 三、HTTP 状态码
服务器返回的 **响应报文** 中第一行为状态行,包含了状态码以及原因短语,用来告知客户端请求的结果。 服务器返回的 **响应报文** 中第一行为状态行,包含了状态码以及原因短语,用来告知客户端请求的结果。
| 状态码 | 类别 | 原因短语 | | 状态码 | 类别 | 含义 |
| :---: | :---: | :---: | | :---: | :---: | :---: |
| 1XX | Informational信息性状态码 | 接收的请求正在处理 | | 1XX | Informational信息性状态码 | 接收的请求正在处理 |
| 2XX | Success成功状态码 | 请求正常处理完毕 | | 2XX | Success成功状态码 | 请求正常处理完毕 |
@ -305,7 +302,7 @@ CONNECT www.example.com:443 HTTP/1.1
## 连接管理 ## 连接管理
<div align="center"> <img src="pics/HTTP1_x_Connections.png" width="800"/> </div><br> <div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/HTTP1_x_Connections.png" width="800"/> </div><br>
### 1. 短连接与长连接 ### 1. 短连接与长连接
@ -634,11 +631,11 @@ HTTP/1.1 使用虚拟主机技术,使得一台服务器拥有多个域名,
- 用户察觉得到正向代理的存在。 - 用户察觉得到正向代理的存在。
<div align="center"> <img src="pics/a314bb79-5b18-4e63-a976-3448bffa6f1b.png" width=""/> </div><br> <div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/a314bb79-5b18-4e63-a976-3448bffa6f1b.png" width=""/> </div><br>
- 而反向代理一般位于内部网络中,用户察觉不到。 - 而反向代理一般位于内部网络中,用户察觉不到。
<div align="center"> <img src="pics/2d09a847-b854-439c-9198-b29c65810944.png" width=""/> </div><br> <div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/2d09a847-b854-439c-9198-b29c65810944.png" width=""/> </div><br>
### 2. 网关 ### 2. 网关
@ -648,7 +645,7 @@ HTTP/1.1 使用虚拟主机技术,使得一台服务器拥有多个域名,
使用 SSL 等加密手段,在客户端和服务器之间建立一条安全的通信线路。 使用 SSL 等加密手段,在客户端和服务器之间建立一条安全的通信线路。
# 六、HTTPs # 六、HTTPS
HTTP 有以下安全性问题: HTTP 有以下安全性问题:
@ -656,11 +653,11 @@ HTTP 有以下安全性问题:
- 不验证通信方的身份,通信方的身份有可能遭遇伪装; - 不验证通信方的身份,通信方的身份有可能遭遇伪装;
- 无法证明报文的完整性,报文有可能遭篡改。 - 无法证明报文的完整性,报文有可能遭篡改。
HTTPs 并不是新协议,而是让 HTTP 先和 SSLSecure Sockets Layer通信再由 SSL 和 TCP 通信,也就是说 HTTPs 使用了隧道进行通信。 HTTPS 并不是新协议,而是让 HTTP 先和 SSLSecure Sockets Layer通信再由 SSL 和 TCP 通信,也就是说 HTTPS 使用了隧道进行通信。
通过使用 SSLHTTPs 具有了加密(防窃听)、认证(防伪装)和完整性保护(防篡改)。 通过使用 SSLHTTPS 具有了加密(防窃听)、认证(防伪装)和完整性保护(防篡改)。
<div align="center"> <img src="pics/ssl-offloading.jpg" width="700"/> </div><br> <div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/ssl-offloading.jpg" width="700"/> </div><br>
## 加密 ## 加密
@ -671,7 +668,7 @@ HTTPs 并不是新协议,而是让 HTTP 先和 SSLSecure Sockets Layer
- 优点:运算速度快; - 优点:运算速度快;
- 缺点:无法安全地将密钥传输给通信方。 - 缺点:无法安全地将密钥传输给通信方。
<div align="center"> <img src="pics/7fffa4b8-b36d-471f-ad0c-a88ee763bb76.png" width="600"/> </div><br> <div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/7fffa4b8-b36d-471f-ad0c-a88ee763bb76.png" width="600"/> </div><br>
### 2.非对称密钥加密 ### 2.非对称密钥加密
@ -684,13 +681,13 @@ HTTPs 并不是新协议,而是让 HTTP 先和 SSLSecure Sockets Layer
- 优点:可以更安全地将公开密钥传输给通信发送方; - 优点:可以更安全地将公开密钥传输给通信发送方;
- 缺点:运算速度慢。 - 缺点:运算速度慢。
<div align="center"> <img src="pics/39ccb299-ee99-4dd1-b8b4-2f9ec9495cb4.png" width="600"/> </div><br> <div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/39ccb299-ee99-4dd1-b8b4-2f9ec9495cb4.png" width="600"/> </div><br>
### 3. HTTPs 采用的加密方式 ### 3. HTTPS 采用的加密方式
HTTPs 采用混合的加密机制,使用非对称密钥加密用于传输对称密钥来保证传输过程的安全性,之后使用对称密钥加密进行通信来保证通信过程的效率。(下图中的 Session Key 就是对称密钥) HTTPS 采用混合的加密机制,使用非对称密钥加密用于传输对称密钥来保证传输过程的安全性,之后使用对称密钥加密进行通信来保证通信过程的效率。(下图中的 Session Key 就是对称密钥)
<div align="center"> <img src="pics/How-HTTPS-Works.png" width="600"/> </div><br> <div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/How-HTTPS-Works.png" width="600"/> </div><br>
## 认证 ## 认证
@ -700,11 +697,9 @@ HTTPs 采用混合的加密机制,使用非对称密钥加密用于传输对
服务器的运营人员向 CA 提出公开密钥的申请CA 在判明提出申请者的身份之后,会对已申请的公开密钥做数字签名,然后分配这个已签名的公开密钥,并将该公开密钥放入公开密钥证书后绑定在一起。 服务器的运营人员向 CA 提出公开密钥的申请CA 在判明提出申请者的身份之后,会对已申请的公开密钥做数字签名,然后分配这个已签名的公开密钥,并将该公开密钥放入公开密钥证书后绑定在一起。
进行 HTTPs 通信时,服务器会把证书发送给客户端。客户端取得其中的公开密钥之后,先使用数字签名进行验证,如果验证通过,就可以开始通信了。 进行 HTTPS 通信时,服务器会把证书发送给客户端。客户端取得其中的公开密钥之后,先使用数字签名进行验证,如果验证通过,就可以开始通信了。
通信开始时,客户端需要使用服务器的公开密钥将自己的私有密钥传输给服务器,之后再进行对称密钥加密。 <div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/2017-06-11-ca.png" width=""/> </div><br>
<div align="center"> <img src="pics/2017-06-11-ca.png" width=""/> </div><br>
## 完整性保护 ## 完整性保护
@ -712,12 +707,13 @@ SSL 提供报文摘要功能来进行完整性保护。
HTTP 也提供了 MD5 报文摘要功能,但不是安全的。例如报文内容被篡改之后,同时重新计算 MD5 的值,通信接收方是无法意识到发生了篡改。 HTTP 也提供了 MD5 报文摘要功能,但不是安全的。例如报文内容被篡改之后,同时重新计算 MD5 的值,通信接收方是无法意识到发生了篡改。
HTTPs 的报文摘要功能之所以安全,是因为它结合了加密和认证这两个操作。试想一下,加密之后的报文,遭到篡改之后,也很难重新计算报文摘要,因为无法轻易获取明文。 HTTPS 的报文摘要功能之所以安全,是因为它结合了加密和认证这两个操作。试想一下,加密之后的报文,遭到篡改之后,也很难重新计算报文摘要,因为无法轻易获取明文。
## HTTPs 的缺点 ## HTTPS 的缺点
- 因为需要进行加密解密等过程,因此速度会更慢; - 因为需要进行加密解密等过程,因此速度会更慢;
- 需要支付证书授权的高额费用。 - 需要支付证书授权的高额费用。
# 七、HTTP/2.0 # 七、HTTP/2.0
## HTTP/1.x 缺陷 ## HTTP/1.x 缺陷
@ -732,7 +728,7 @@ HTTP/1.x 实现简单是以牺牲性能为代价的:
HTTP/2.0 将报文分成 HEADERS 帧和 DATA 帧,它们都是二进制格式的。 HTTP/2.0 将报文分成 HEADERS 帧和 DATA 帧,它们都是二进制格式的。
<div align="center"> <img src="pics/86e6a91d-a285-447a-9345-c5484b8d0c47.png" width="400"/> </div><br> <div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/86e6a91d-a285-447a-9345-c5484b8d0c47.png" width="400"/> </div><br>
在通信过程中,只会有一个 TCP 连接存在它承载了任意数量的双向数据流Stream 在通信过程中,只会有一个 TCP 连接存在它承载了任意数量的双向数据流Stream
@ -740,13 +736,13 @@ HTTP/2.0 将报文分成 HEADERS 帧和 DATA 帧,它们都是二进制格式
- 消息Message是与逻辑请求或响应对应的完整的一系列帧。 - 消息Message是与逻辑请求或响应对应的完整的一系列帧。
- 帧Frame是最小的通信单位来自不同数据流的帧可以交错发送然后再根据每个帧头的数据流标识符重新组装。 - 帧Frame是最小的通信单位来自不同数据流的帧可以交错发送然后再根据每个帧头的数据流标识符重新组装。
<div align="center"> <img src="pics/af198da1-2480-4043-b07f-a3b91a88b815.png" width="600"/> </div><br> <div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/af198da1-2480-4043-b07f-a3b91a88b815.png" width="600"/> </div><br>
## 服务端推送 ## 服务端推送
HTTP/2.0 在客户端请求一个资源时,会把相关的资源一起发送给客户端,客户端就不需要再次发起请求了。例如客户端请求 page.html 页面,服务端就把 script.js 和 style.css 等与之相关的资源一起发给客户端。 HTTP/2.0 在客户端请求一个资源时,会把相关的资源一起发送给客户端,客户端就不需要再次发起请求了。例如客户端请求 page.html 页面,服务端就把 script.js 和 style.css 等与之相关的资源一起发给客户端。
<div align="center"> <img src="pics/e3f1657c-80fc-4dfa-9643-bf51abd201c6.png" width="800"/> </div><br> <div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/e3f1657c-80fc-4dfa-9643-bf51abd201c6.png" width="800"/> </div><br>
## 首部压缩 ## 首部压缩
@ -756,24 +752,18 @@ HTTP/2.0 要求客户端和服务器同时维护和更新一个包含之前见
不仅如此HTTP/2.0 也使用 Huffman 编码对首部字段进行压缩。 不仅如此HTTP/2.0 也使用 Huffman 编码对首部字段进行压缩。
<div align="center"> <img src="pics/_u4E0B_u8F7D.png" width="600"/> </div><br> <div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/_u4E0B_u8F7D.png" width="600"/> </div><br>
# 八、HTTP/1.1 新特性 # 八、HTTP/1.1 新特性
详细内容请见上文 详细内容请见上文
- 默认是长连接 - 默认是长连接
- 支持流水线 - 支持流水线
- 支持同时打开多个 TCP 连接 - 支持同时打开多个 TCP 连接
- 支持虚拟主机 - 支持虚拟主机
- 新增状态码 100 - 新增状态码 100
- 支持分块传输编码 - 支持分块传输编码
- 新增缓存处理指令 max-age - 新增缓存处理指令 max-age
# 九、GET 和 POST 比较 # 九、GET 和 POST 比较
@ -786,7 +776,7 @@ GET 用于获取资源,而 POST 用于传输实体主体。
GET 和 POST 的请求都能使用额外的参数,但是 GET 的参数是以查询字符串出现在 URL 中,而 POST 的参数存储在实体主体中。不能因为 POST 参数存储在实体主体中就认为它的安全性更高因为照样可以通过一些抓包工具Fiddler查看。 GET 和 POST 的请求都能使用额外的参数,但是 GET 的参数是以查询字符串出现在 URL 中,而 POST 的参数存储在实体主体中。不能因为 POST 参数存储在实体主体中就认为它的安全性更高因为照样可以通过一些抓包工具Fiddler查看。
因为 URL 只支持 ASCII 码,因此 GET 的参数中如果存在中文等字符就需要先进行编码。例如 `中文` 会转换为 `%E4%B8%AD%E6%96%87`,而空格会转换为 `%20`。POST 参支持标准字符集。 因为 URL 只支持 ASCII 码,因此 GET 的参数中如果存在中文等字符就需要先进行编码。例如 `中文` 会转换为 `%E4%B8%AD%E6%96%87`,而空格会转换为 `%20`。POST 参支持标准字符集。
``` ```
GET /test/demo_form.asp?name1=value1&name2=value2 HTTP/1.1 GET /test/demo_form.asp?name1=value1&name2=value2 HTTP/1.1
@ -858,8 +848,6 @@ DELETE /idX/delete HTTP/1.1 -> Returns 404
- 在使用 XMLHttpRequest 的 POST 方法时,浏览器会先发送 Header 再发送 Data。但并不是所有浏览器会这么做例如火狐就不会。 - 在使用 XMLHttpRequest 的 POST 方法时,浏览器会先发送 Header 再发送 Data。但并不是所有浏览器会这么做例如火狐就不会。
- 而 GET 方法 Header 和 Data 会一起发送。 - 而 GET 方法 Header 和 Data 会一起发送。
# 参考资料 # 参考资料
- 上野宣. 图解 HTTP[M]. 人民邮电出版社, 2014. - 上野宣. 图解 HTTP[M]. 人民邮电出版社, 2014.
@ -889,3 +877,9 @@ DELETE /idX/delete HTTP/1.1 -> Returns 404
- [Symmetric vs. Asymmetric Encryption What are differences?](https://www.ssl2buy.com/wiki/symmetric-vs-asymmetric-encryption-what-are-differences) - [Symmetric vs. Asymmetric Encryption What are differences?](https://www.ssl2buy.com/wiki/symmetric-vs-asymmetric-encryption-what-are-differences)
- [Web 性能优化与 HTTP/2](https://www.kancloud.cn/digest/web-performance-http2) - [Web 性能优化与 HTTP/2](https://www.kancloud.cn/digest/web-performance-http2)
- [HTTP/2 简介](https://developers.google.com/web/fundamentals/performance/http2/?hl=zh-cn) - [HTTP/2 简介](https://developers.google.com/web/fundamentals/performance/http2/?hl=zh-cn)
</br><div align="center">⭐️欢迎关注我的公众号 CyC2018在公众号后台回复关键字 📚 **资料** 可领取复习大纲,这份大纲是我花了一整年时间整理的面试知识点列表,不仅系统整理了面试知识点,而且标注了各个知识点的重要程度,从而帮你理清多而杂的面试知识点。可以说我基本是按照这份大纲来进行复习的,这份大纲对我拿到了 BAT 头条等 Offer 起到很大的帮助。你们完全可以和我一样根据大纲上列的知识点来进行复习,就不用看很多不重要的内容,也可以知道哪些内容很重要从而多安排一些复习时间。</div></br>
<div align="center"><img width="180px" src="https://cyc-1256109796.cos.ap-guangzhou.myqcloud.com/%E5%85%AC%E4%BC%97%E5%8F%B7.jpg"></img></div>

View File

@ -97,7 +97,7 @@ Java I/O 使用了装饰者模式来实现。以 InputStream 为例,
- FileInputStream 是 InputStream 的子类,属于具体组件,提供了字节流的输入操作; - FileInputStream 是 InputStream 的子类,属于具体组件,提供了字节流的输入操作;
- FilterInputStream 属于抽象装饰者,装饰者用于装饰组件,为组件提供额外的功能。例如 BufferedInputStream 为 FileInputStream 提供缓存的功能。 - FilterInputStream 属于抽象装饰者,装饰者用于装饰组件,为组件提供额外的功能。例如 BufferedInputStream 为 FileInputStream 提供缓存的功能。
<div align="center"> <img src="pics/DP-Decorator-java.io.png" width="500"/> </div><br> <div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/c2c2b633-c03a-426e-b436-5719a194667b.png"/> </div><br>
实例化一个具有缓存功能的字节流对象时,只需要在 FileInputStream 对象上再套一层 BufferedInputStream 对象即可。 实例化一个具有缓存功能的字节流对象时,只需要在 FileInputStream 对象上再套一层 BufferedInputStream 对象即可。
@ -277,7 +277,7 @@ public static void main(String[] args) throws IOException {
- Socket客户端类 - Socket客户端类
- 服务器和客户端通过 InputStream 和 OutputStream 进行输入输出。 - 服务器和客户端通过 InputStream 和 OutputStream 进行输入输出。
<div align="center"> <img src="pics/ClienteServidorSockets1521731145260.jpg"/> </div><br> <div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/f77f06b6-7359-4066-b85d-3f6c09ddf425.jpg"/> </div><br>
## Datagram ## Datagram
@ -339,23 +339,23 @@ I/O 包和 NIO 已经很好地集成了java.io.\* 已经以 NIO 为基础重
① 新建一个大小为 8 个字节的缓冲区,此时 position 为 0而 limit = capacity = 8。capacity 变量不会改变,下面的讨论会忽略它。 ① 新建一个大小为 8 个字节的缓冲区,此时 position 为 0而 limit = capacity = 8。capacity 变量不会改变,下面的讨论会忽略它。
<div align="center"> <img src="pics/1bea398f-17a7-4f67-a90b-9e2d243eaa9a.png"/> </div><br> <div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/1bea398f-17a7-4f67-a90b-9e2d243eaa9a.png"/> </div><br>
② 从输入通道中读取 5 个字节数据写入缓冲区中,此时 position 为 5limit 保持不变。 ② 从输入通道中读取 5 个字节数据写入缓冲区中,此时 position 为 5limit 保持不变。
<div align="center"> <img src="pics/80804f52-8815-4096-b506-48eef3eed5c6.png"/> </div><br> <div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/80804f52-8815-4096-b506-48eef3eed5c6.png"/> </div><br>
③ 在将缓冲区的数据写到输出通道之前,需要先调用 flip() 方法,这个方法将 limit 设置为当前 position并将 position 设置为 0。 ③ 在将缓冲区的数据写到输出通道之前,需要先调用 flip() 方法,这个方法将 limit 设置为当前 position并将 position 设置为 0。
<div align="center"> <img src="pics/952e06bd-5a65-4cab-82e4-dd1536462f38.png"/> </div><br> <div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/952e06bd-5a65-4cab-82e4-dd1536462f38.png"/> </div><br>
④ 从缓冲区中取 4 个字节到输出缓冲中,此时 position 设为 4。 ④ 从缓冲区中取 4 个字节到输出缓冲中,此时 position 设为 4。
<div align="center"> <img src="pics/b5bdcbe2-b958-4aef-9151-6ad963cb28b4.png"/> </div><br> <div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/b5bdcbe2-b958-4aef-9151-6ad963cb28b4.png"/> </div><br>
⑤ 最后需要调用 clear() 方法来清空缓冲区,此时 position 和 limit 都被设置为最初位置。 ⑤ 最后需要调用 clear() 方法来清空缓冲区,此时 position 和 limit 都被设置为最初位置。
<div align="center"> <img src="pics/67bf5487-c45d-49b6-b9c0-a058d8c68902.png"/> </div><br> <div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/67bf5487-c45d-49b6-b9c0-a058d8c68902.png"/> </div><br>
## 文件 NIO 实例 ## 文件 NIO 实例
@ -413,7 +413,7 @@ NIO 实现了 IO 多路复用中的 Reactor 模型,一个线程 Thread 使用
应该注意的是,只有套接字 Channel 才能配置为非阻塞,而 FileChannel 不能,为 FileChannel 配置非阻塞也没有意义。 应该注意的是,只有套接字 Channel 才能配置为非阻塞,而 FileChannel 不能,为 FileChannel 配置非阻塞也没有意义。
<div align="center"> <img src="pics/4d930e22-f493-49ae-8dff-ea21cd6895dc.png"/> </div><br> <div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/8fdbb8f5-2cf8-41dc-b5f1-99d98abb52d9.jpg"/> </div><br>
### 1. 创建选择器 ### 1. 创建选择器
@ -618,3 +618,9 @@ NIO 与普通 I/O 的区别主要有以下两点:
- [NIO 与传统 IO 的区别](http://blog.csdn.net/shimiso/article/details/24990499) - [NIO 与传统 IO 的区别](http://blog.csdn.net/shimiso/article/details/24990499)
- [Decorator Design Pattern](http://stg-tud.github.io/sedc/Lecture/ws13-14/5.3-Decorator.html#mode=document) - [Decorator Design Pattern](http://stg-tud.github.io/sedc/Lecture/ws13-14/5.3-Decorator.html#mode=document)
- [Socket Multicast](http://labojava.blogspot.com/2012/12/socket-multicast.html) - [Socket Multicast](http://labojava.blogspot.com/2012/12/socket-multicast.html)
</br><div align="center">⭐️欢迎关注我的公众号 CyC2018在公众号后台回复关键字 📚 **资料** 可领取复习大纲,这份大纲是我花了一整年时间整理的面试知识点列表,不仅系统整理了面试知识点,而且标注了各个知识点的重要程度,从而帮你理清多而杂的面试知识点。可以说我基本是按照这份大纲来进行复习的,这份大纲对我拿到了 BAT 头条等 Offer 起到很大的帮助。你们完全可以和我一样根据大纲上列的知识点来进行复习,就不用看很多不重要的内容,也可以知道哪些内容很重要从而多安排一些复习时间。</div></br>
<div align="center"><img width="180px" src="https://cyc-1256109796.cos.ap-guangzhou.myqcloud.com/%E5%85%AC%E4%BC%97%E5%8F%B7.jpg"></img></div>

View File

@ -1,5 +1,6 @@
<!-- GFM-TOC --> <!-- GFM-TOC -->
* [一、数据类型](#一数据类型) * [一、数据类型](#一数据类型)
* [基本类型](#基本类型)
* [包装类型](#包装类型) * [包装类型](#包装类型)
* [缓存池](#缓存池) * [缓存池](#缓存池)
* [二、String](#二string) * [二、String](#二string)
@ -41,11 +42,8 @@
# 一、数据类型 # 一、数据类型
## 包装类型 ## 基本类型
八个基本类型:
- boolean/1
- byte/8 - byte/8
- char/16 - char/16
- short/16 - short/16
@ -53,6 +51,14 @@
- float/32 - float/32
- long/64 - long/64
- double/64 - double/64
- boolean/\~
boolean 只有两个值true、false可以使用 1 bit 来存储但是具体大小没有明确规定。JVM 会在编译时期将 boolean 类型的数据转换为 int使用 1 来表示 true0 表示 false。JVM 支持 boolean 数组,但是是通过读写 byte 数组来实现的。
- [Primitive Data Types](https://docs.oracle.com/javase/tutorial/java/nutsandbolts/datatypes.html)
- [The Java® Virtual Machine Specification](https://docs.oracle.com/javase/specs/jvms/se8/jvms8.pdf)
## 包装类型
基本类型都有对应的包装类型,基本类型与其对应的包装类型之间的赋值使用自动装箱与拆箱完成。 基本类型都有对应的包装类型,基本类型与其对应的包装类型之间的赋值使用自动装箱与拆箱完成。
@ -121,7 +127,7 @@ static {
} }
``` ```
编译器会在自动装箱过程调用 valueOf() 方法,因此多个 Integer 实例使用自动装箱来创建并且值相同,那么就会引用相同的对象。 编译器会在自动装箱过程调用 valueOf() 方法,因此多个值相同且值在缓存池范围内的 Integer 实例使用自动装箱来创建,那么就会引用相同的对象。
```java ```java
Integer m = 123; Integer m = 123;
@ -148,15 +154,31 @@ System.out.println(m == n); // true
String 被声明为 final因此它不可被继承。 String 被声明为 final因此它不可被继承。
内部使用 char 数组存储数据,该数组被声明为 final这意味着 value 数组初始化之后就不能再引用其它数组。并且 String 内部没有改变 value 数组的方法,因此可以保证 String 不可变 在 Java 8 中String 内部使用 char 数组存储数据
```java ```java
public final class String public final class String
implements java.io.Serializable, Comparable<String>, CharSequence { implements java.io.Serializable, Comparable<String>, CharSequence {
/** The value is used for character storage. */ /** The value is used for character storage. */
private final char value[]; private final char value[];
}
``` ```
在 Java 9 之后String 类的实现改用 byte 数组存储字符串,同时使用 `coder` 来标识使用了哪种编码。
```java
public final class String
implements java.io.Serializable, Comparable<String>, CharSequence {
/** The value is used for character storage. */
private final byte[] value;
/** The identifier of the encoding used to encode the bytes in {@code value}. */
private final byte coder;
}
```
value 数组被声明为 final这意味着 value 数组初始化之后就不能再引用其它数组。并且 String 内部没有改变 value 数组的方法,因此可以保证 String 不可变。
## 不可变的好处 ## 不可变的好处
**1. 可以缓存 hash 值** **1. 可以缓存 hash 值**
@ -167,7 +189,7 @@ public final class String
如果一个 String 对象已经被创建过了,那么就会从 String Pool 中取得引用。只有 String 是不可变的,才可能使用 String Pool。 如果一个 String 对象已经被创建过了,那么就会从 String Pool 中取得引用。只有 String 是不可变的,才可能使用 String Pool。
<div align="center"> <img src="pics/f76067a5-7d5f-4135-9549-8199c77d8f1c.jpg" width=""/> </div><br> <div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/474e5579-38b1-47d2-8f76-a13ae086b039.jpg"/> </div><br>
**3. 安全性** **3. 安全性**
@ -648,10 +670,29 @@ SuperExtendExample.func()
为了满足里式替换原则,重写有有以下两个限制: 为了满足里式替换原则,重写有有以下两个限制:
- 子类方法的访问权限必须大于等于父类方法; 使用 @Override 注解,可以让编译器帮忙检查是否满足上面的三个限制条件。
- 子类方法的返回类型必须是父类方法返回类型或为其子类型。
使用 @Override 注解,可以让编译器帮忙检查是否满足上面的两个限制条件。 下面的示例中SubClass 为 SuperClass 的子类SubClass 重写了 SuperClass 的 func() 方法。其中:
- 子类方法访问权限为 public大于父类的 protected。
- 子类的返回类型为 ArrayList<Integer>,是父类返回类型 List<Integer> 的子类。
- 子类抛出的异常类型为 Exception是父类抛出异常 Throwable 的子类。
- 子类重写方法使用 @Override 注解,从而让编译器自动检查是否满足限制条件。
```java
class SuperClass {
protected List<Integer> func() throws Throwable {
return new ArrayList<>();
}
}
class SubClass extends SuperClass {
@Override
public ArrayList<Integer> func() throws Exception {
return new ArrayList<>();
}
}
```
**2. 重载Overload** **2. 重载Overload**
@ -659,6 +700,65 @@ SuperExtendExample.func()
应该注意的是,返回值不同,其它都相同不算是重载。 应该注意的是,返回值不同,其它都相同不算是重载。
**3. 实例**
```java
class A {
public String show(D obj) {
return ("A and D");
}
public String show(A obj) {
return ("A and A");
}
}
class B extends A {
public String show(B obj) {
return ("B and B");
}
public String show(A obj) {
return ("B and A");
}
}
class C extends B {
}
class D extends B {
}
```
```java
public class Test {
public static void main(String[] args) {
A a1 = new A();
A a2 = new B();
B b = new B();
C c = new C();
D d = new D();
System.out.println(a1.show(b)); // A and A
System.out.println(a1.show(c)); // A and A
System.out.println(a1.show(d)); // A and D
System.out.println(a2.show(b)); // B and A
System.out.println(a2.show(c)); // B and A
System.out.println(a2.show(d)); // A and D
System.out.println(b.show(b)); // B and B
System.out.println(b.show(c)); // B and B
System.out.println(b.show(d)); // A and D
}
}
```
涉及到重写时,方法调用的优先级为:
- this.show(O)
- super.show(O)
- this.show((super)O)
- super.show((super)O)
# 五、Object 通用方法 # 五、Object 通用方法
## 概览 ## 概览
@ -1236,7 +1336,7 @@ Throwable 可以用来表示任何可以作为异常抛出的类,分为两种
- **受检异常** :需要用 try...catch... 语句捕获并进行处理,并且可以从异常中恢复; - **受检异常** :需要用 try...catch... 语句捕获并进行处理,并且可以从异常中恢复;
- **非受检异常** :是程序运行时错误,例如除 0 会引发 Arithmetic Exception此时程序崩溃并且无法恢复。 - **非受检异常** :是程序运行时错误,例如除 0 会引发 Arithmetic Exception此时程序崩溃并且无法恢复。
<div align="center"> <img src="pics/PPjwP.png" width="600"/> </div><br> <div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/PPjwP.png" width="600"/> </div><br>
- [Java 入门之异常处理](https://www.tianmaying.com/tutorial/Java-Exception) - [Java 入门之异常处理](https://www.tianmaying.com/tutorial/Java-Exception)
- [Java 异常的面试问题及答案 -Part 1](http://www.importnew.com/7383.html) - [Java 异常的面试问题及答案 -Part 1](http://www.importnew.com/7383.html)
@ -1313,3 +1413,9 @@ Java 注解是附加在代码中的一些元信息,用于一些工具在编译
- Eckel B. Java 编程思想[M]. 机械工业出版社, 2002. - Eckel B. Java 编程思想[M]. 机械工业出版社, 2002.
- Bloch J. Effective java[M]. Addison-Wesley Professional, 2017. - Bloch J. Effective java[M]. Addison-Wesley Professional, 2017.
</br><div align="center">⭐️欢迎关注我的公众号 CyC2018在公众号后台回复关键字 📚 **资料** 可领取复习大纲,这份大纲是我花了一整年时间整理的面试知识点列表,不仅系统整理了面试知识点,而且标注了各个知识点的重要程度,从而帮你理清多而杂的面试知识点。可以说我基本是按照这份大纲来进行复习的,这份大纲对我拿到了 BAT 头条等 Offer 起到很大的帮助。你们完全可以和我一样根据大纲上列的知识点来进行复习,就不用看很多不重要的内容,也可以知道哪些内容很重要从而多安排一些复习时间。</div></br>
<div align="center"><img width="180px" src="https://cyc-1256109796.cos.ap-guangzhou.myqcloud.com/%E5%85%AC%E4%BC%97%E5%8F%B7.jpg"></img></div>

View File

@ -14,18 +14,19 @@
* [ConcurrentHashMap](#concurrenthashmap) * [ConcurrentHashMap](#concurrenthashmap)
* [LinkedHashMap](#linkedhashmap) * [LinkedHashMap](#linkedhashmap)
* [WeakHashMap](#weakhashmap) * [WeakHashMap](#weakhashmap)
* [附录](#附录)
* [参考资料](#参考资料) * [参考资料](#参考资料)
<!-- GFM-TOC --> <!-- GFM-TOC -->
# 一、概览 # 一、概览
容器主要包括 Collection 和 Map 两种Collection 存储着对象的集合,而 Map 存储着键值对(两个对象)的映射表。 容器主要包括 Collection 和 Map 两种Collection 存储着对象的集合,而 Map 存储着键值对(两个对象)的映射表。
## Collection ## Collection
<div align="center"> <img src="pics/VP6n3i8W48Ptde8NQ9_0eSR5eOD6uqx.png"/> </div><br> <div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/6_2001550476096035.png"/> </div><br>
### 1. Set ### 1. Set
@ -51,7 +52,7 @@
## Map ## Map
<div align="center"> <img src="pics/SoWkIImgAStDuUBAp2j9BKfBJ4vLy4q.png"/> </div><br> <div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/2_2001550426232419.png"/> </div><br>
- TreeMap基于红黑树实现。 - TreeMap基于红黑树实现。
@ -66,7 +67,7 @@
## 迭代器模式 ## 迭代器模式
<div align="center"> <img src="pics/SoWkIImgAStDuUBAp2j9BKfBJ4vLy0G.png"/> </div><br> <div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/91aa7c29-438f-4fcc-8c63-2a75899139de.png"/> </div><br>
Collection 继承了 Iterable 接口,其中的 iterator() 方法能够产生一个 Iterator 对象,通过这个对象就可以迭代遍历 Collection 中的元素。 Collection 继承了 Iterable 接口,其中的 iterator() 方法能够产生一个 Iterator 对象,通过这个对象就可以迭代遍历 Collection 中的元素。
@ -111,9 +112,10 @@ List list = Arrays.asList(1, 2, 3);
## ArrayList ## ArrayList
### 1. 概览 ### 1. 概览
实现了 RandomAccess 接口,因此支持随机访问。这是理所当然的,因为 ArrayList 是基于数组实现的 因为 ArrayList 是基于数组实现的所以支持快速随机访问。RandomAccess 接口标识着该类支持快速随机访问
```java ```java
public class ArrayList<E> extends AbstractList<E> public class ArrayList<E> extends AbstractList<E>
@ -126,6 +128,9 @@ public class ArrayList<E> extends AbstractList<E>
private static final int DEFAULT_CAPACITY = 10; private static final int DEFAULT_CAPACITY = 10;
``` ```
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/7935be3d-c2b3-4213-90c9-1e68ec4ac4e7.png"/> </div><br>
### 2. 扩容 ### 2. 扩容
添加元素时使用 ensureCapacityInternal() 方法来保证容量足够,如果不够时,需要使用 grow() 方法进行扩容,新容量的大小为 `oldCapacity + (oldCapacity >> 1)`,也就是旧容量的 1.5 倍。 添加元素时使用 ensureCapacityInternal() 方法来保证容量足够,如果不够时,需要使用 grow() 方法进行扩容,新容量的大小为 `oldCapacity + (oldCapacity >> 1)`,也就是旧容量的 1.5 倍。
@ -387,7 +392,7 @@ transient Node<E> first;
transient Node<E> last; transient Node<E> last;
``` ```
<div align="center"> <img src="pics/49495c95-52e5-4c9a-b27b-92cf235ff5ec.png" width="500"/> </div><br> <div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/09184175-9bf2-40ff-8a68-3b467c77216a.png"/> </div><br>
### 2. 与 ArrayList 的比较 ### 2. 与 ArrayList 的比较
@ -409,7 +414,7 @@ transient Entry[] table;
Entry 存储着键值对。它包含了四个字段,从 next 字段我们可以看出 Entry 是一个链表。即数组中的每个位置被当成一个桶一个桶存放一个链表。HashMap 使用拉链法来解决冲突,同一个链表中存放哈希值相同的 Entry。 Entry 存储着键值对。它包含了四个字段,从 next 字段我们可以看出 Entry 是一个链表。即数组中的每个位置被当成一个桶一个桶存放一个链表。HashMap 使用拉链法来解决冲突,同一个链表中存放哈希值相同的 Entry。
<div align="center"> <img src="pics/8fe838e3-ef77-4f63-bf45-417b6bc5c6bb.png" width="600"/> </div><br> <div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/1d2719d5-8d60-4c9b-a4ad-b2df7c7615af.jpg"/> </div><br>
```java ```java
static class Entry<K,V> implements Map.Entry<K,V> { static class Entry<K,V> implements Map.Entry<K,V> {
@ -485,7 +490,7 @@ map.put("K3", "V3");
- 计算键值对所在的桶; - 计算键值对所在的桶;
- 在链表上顺序查找,时间复杂度显然和链表的长度成正比。 - 在链表上顺序查找,时间复杂度显然和链表的长度成正比。
<div align="center"> <img src="pics/49d6de7b-0d0d-425c-9e49-a1559dc23b10.png" width="600"/> </div><br> <div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/cf779e26-0382-4495-8463-f1e19e2e38a0.jpg"/> </div><br>
### 3. put 操作 ### 3. put 操作
@ -821,7 +826,7 @@ final Segment<K,V>[] segments;
static final int DEFAULT_CONCURRENCY_LEVEL = 16; static final int DEFAULT_CONCURRENCY_LEVEL = 16;
``` ```
<div align="center"> <img src="pics/3fdfc89d-719e-4d93-b518-29fa612b3b18.png"/> </div><br> <div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/deb18bdb-b3b3-4660-b778-b0823a48db12.jpg"/> </div><br>
### 2. size 操作 ### 2. size 操作
@ -1092,90 +1097,6 @@ public final class ConcurrentCache<K, V> {
} }
``` ```
# 附录
Collection 绘图源码:
```
@startuml
interface Collection
interface Set
interface List
interface Queue
interface SortSet
class HashSet
class LinkedHashSet
class TreeSet
class ArrayList
class Vector
class LinkedList
class PriorityQueue
Collection <|-- Set
Collection <|-- List
Collection <|-- Queue
Set <|-- SortSet
Set <|.. HashSet
Set <|.. LinkedHashSet
SortSet <|.. TreeSet
List <|.. ArrayList
List <|.. Vector
List <|.. LinkedList
Queue <|.. LinkedList
Queue <|.. PriorityQueue
@enduml
```
Map 绘图源码
```
@startuml
interface Map
interface SortMap
class HashTable
class LinkedHashMap
class HashMap
class TreeMap
Map <|.. HashTable
Map <|.. LinkedHashMap
Map <|.. HashMap
Map <|-- SortMap
SortMap <|.. TreeMap
@enduml
```
迭代器类图
```
@startuml
interface Iterable
interface Collection
interface List
interface Set
interface Queue
interface Iterator
interface ListIterator
Iterable <|-- Collection
Collection <|.. List
Collection <|.. Set
Collection <|-- Queue
Iterator <-- Iterable
Iterator <|.. ListIterator
ListIterator <-- List
@enduml
```
# 参考资料 # 参考资料
@ -1191,3 +1112,9 @@ ListIterator <-- List
- [Java 集合细节asList 的缺陷](http://wiki.jikexueyuan.com/project/java-enhancement/java-thirtysix.html) - [Java 集合细节asList 的缺陷](http://wiki.jikexueyuan.com/project/java-enhancement/java-thirtysix.html)
- [Java Collection Framework The LinkedList Class](http://javaconceptoftheday.com/java-collection-framework-linkedlist-class/) - [Java Collection Framework The LinkedList Class](http://javaconceptoftheday.com/java-collection-framework-linkedlist-class/)
</br><div align="center">⭐️欢迎关注我的公众号 CyC2018在公众号后台回复关键字 📚 **资料** 可领取复习大纲,这份大纲是我花了一整年时间整理的面试知识点列表,不仅系统整理了面试知识点,而且标注了各个知识点的重要程度,从而帮你理清多而杂的面试知识点。可以说我基本是按照这份大纲来进行复习的,这份大纲对我拿到了 BAT 头条等 Offer 起到很大的帮助。你们完全可以和我一样根据大纲上列的知识点来进行复习,就不用看很多不重要的内容,也可以知道哪些内容很重要从而多安排一些复习时间。</div></br>
<div align="center"><img width="180px" src="https://cyc-1256109796.cos.ap-guangzhou.myqcloud.com/%E5%85%AC%E4%BC%97%E5%8F%B7.jpg"></img></div>

View File

@ -30,7 +30,7 @@
* [wait() notify() notifyAll()](#wait-notify-notifyall) * [wait() notify() notifyAll()](#wait-notify-notifyall)
* [await() signal() signalAll()](#await-signal-signalall) * [await() signal() signalAll()](#await-signal-signalall)
* [七、J.U.C - AQS](#七juc---aqs) * [七、J.U.C - AQS](#七juc---aqs)
* [CountdownLatch](#countdownlatch) * [CountDownLatch](#countdownlatch)
* [CyclicBarrier](#cyclicbarrier) * [CyclicBarrier](#cyclicbarrier)
* [Semaphore](#semaphore) * [Semaphore](#semaphore)
* [八、J.U.C - 其它组件](#八juc---其它组件) * [八、J.U.C - 其它组件](#八juc---其它组件)
@ -61,7 +61,7 @@
# 一、线程状态转换 # 一、线程状态转换
<div align="center"> <img src="pics/ace830df-9919-48ca-91b5-60b193f593d2.png" width=""/> </div><br> <div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/96706658-b3f8-4f32-8eb3-dcb7fc8d5381.jpg"/> </div><br>
## 新建New ## 新建New
@ -73,7 +73,7 @@
包含了操作系统线程状态中的 Running 和 Ready。 包含了操作系统线程状态中的 Running 和 Ready。
## 阻塞Blocking ## 阻塞Blocked
等待获取一个排它锁,如果其线程释放了锁就会结束此状态。 等待获取一个排它锁,如果其线程释放了锁就会结束此状态。
@ -85,7 +85,7 @@
| --- | --- | | --- | --- |
| 没有设置 Timeout 参数的 Object.wait() 方法 | Object.notify() / Object.notifyAll() | | 没有设置 Timeout 参数的 Object.wait() 方法 | Object.notify() / Object.notifyAll() |
| 没有设置 Timeout 参数的 Thread.join() 方法 | 被调用的线程执行完毕 | | 没有设置 Timeout 参数的 Thread.join() 方法 | 被调用的线程执行完毕 |
| LockSupport.park() 方法 | - | | LockSupport.park() 方法 | LockSupport.unpark(Thread) |
## 限期等待Timed Waiting ## 限期等待Timed Waiting
@ -104,8 +104,8 @@
| Thread.sleep() 方法 | 时间结束 | | Thread.sleep() 方法 | 时间结束 |
| 设置了 Timeout 参数的 Object.wait() 方法 | 时间结束 / Object.notify() / Object.notifyAll() | | 设置了 Timeout 参数的 Object.wait() 方法 | 时间结束 / Object.notify() / Object.notifyAll() |
| 设置了 Timeout 参数的 Thread.join() 方法 | 时间结束 / 被调用的线程执行完毕 | | 设置了 Timeout 参数的 Thread.join() 方法 | 时间结束 / 被调用的线程执行完毕 |
| LockSupport.parkNanos() 方法 | - | | LockSupport.parkNanos() 方法 | LockSupport.unpark(Thread) |
| LockSupport.parkUntil() 方法 | - | | LockSupport.parkUntil() 方法 | LockSupport.unpark(Thread) |
## 死亡Terminated ## 死亡Terminated
@ -730,13 +730,13 @@ after
java.util.concurrentJ.U.C大大提高了并发性能AQS 被认为是 J.U.C 的核心。 java.util.concurrentJ.U.C大大提高了并发性能AQS 被认为是 J.U.C 的核心。
## CountdownLatch ## CountDownLatch
用来控制一个线程等待多个线程。 用来控制一个线程等待多个线程。
维护了一个计数器 cnt每次调用 countDown() 方法会让计数器的值减 1减到 0 的时候,那些因为调用 await() 方法而在等待的线程就会被唤醒。 维护了一个计数器 cnt每次调用 countDown() 方法会让计数器的值减 1减到 0 的时候,那些因为调用 await() 方法而在等待的线程就会被唤醒。
<div align="center"> <img src="pics/CountdownLatch.png" width=""/> </div><br> <div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/912a7886-fb1d-4a05-902d-ab17ea17007f.jpg"/> </div><br>
```java ```java
public class CountdownLatchExample { public class CountdownLatchExample {
@ -785,7 +785,7 @@ public CyclicBarrier(int parties) {
} }
``` ```
<div align="center"> <img src="pics/CyclicBarrier.png" width=""/> </div><br> <div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/f944fac3-482b-4ca3-9447-17aec4a3cca0.png"/> </div><br>
```java ```java
public class CyclicBarrierExample { public class CyclicBarrierExample {
@ -818,8 +818,6 @@ before..before..before..before..before..before..before..before..before..before..
Semaphore 类似于操作系统中的信号量,可以控制对互斥资源的访问线程数。 Semaphore 类似于操作系统中的信号量,可以控制对互斥资源的访问线程数。
<div align="center"> <img src="pics/Semaphore.png" width=""/> </div><br>
以下代码模拟了对某个服务的并发请求,每次只能有 3 个客户端同时访问,请求总数为 10。 以下代码模拟了对某个服务的并发请求,每次只能有 3 个客户端同时访问,请求总数为 10。
```java ```java
@ -1024,7 +1022,7 @@ public class ForkJoinPool extends AbstractExecutorService
ForkJoinPool 实现了工作窃取算法来提高 CPU 的利用率。每个线程都维护了一个双端队列用来存储需要执行的任务。工作窃取算法允许空闲的线程从其它线程的双端队列中窃取一个任务来执行。窃取的任务必须是最晚的任务避免和队列所属线程发生竞争。例如下图中Thread2 从 Thread1 的队列中拿出最晚的 Task1 任务Thread1 会拿出 Task2 来执行,这样就避免发生竞争。但是如果队列中只有一个任务时还是会发生竞争。 ForkJoinPool 实现了工作窃取算法来提高 CPU 的利用率。每个线程都维护了一个双端队列用来存储需要执行的任务。工作窃取算法允许空闲的线程从其它线程的双端队列中窃取一个任务来执行。窃取的任务必须是最晚的任务避免和队列所属线程发生竞争。例如下图中Thread2 从 Thread1 的队列中拿出最晚的 Task1 任务Thread1 会拿出 Task2 来执行,这样就避免发生竞争。但是如果队列中只有一个任务时还是会发生竞争。
<div align="center"> <img src="pics/15b45dc6-27aa-4519-9194-f4acfa2b077f.jpg" width=""/> </div><br> <div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/e19452dd-220a-4a6b-bcb0-91ad5e5c4706.png"/> </div><br>
# 九、线程不安全示例 # 九、线程不安全示例
@ -1079,19 +1077,19 @@ Java 内存模型试图屏蔽各种硬件和操作系统的内存访问差异,
加入高速缓存带来了一个新的问题:缓存一致性。如果多个缓存共享同一块主内存区域,那么多个缓存的数据可能会不一致,需要一些协议来解决这个问题。 加入高速缓存带来了一个新的问题:缓存一致性。如果多个缓存共享同一块主内存区域,那么多个缓存的数据可能会不一致,需要一些协议来解决这个问题。
<div align="center"> <img src="pics/68778c1b-15ab-4826-99c0-3b4fd38cb9e9.png" width=""/> </div><br> <div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/d2a12961-2b36-4463-b017-ca46a3308b8e.png"/> </div><br>
所有的变量都存储在主内存中,每个线程还有自己的工作内存,工作内存存储在高速缓存或者寄存器中,保存了该线程使用的变量的主内存副本拷贝。 所有的变量都存储在主内存中,每个线程还有自己的工作内存,工作内存存储在高速缓存或者寄存器中,保存了该线程使用的变量的主内存副本拷贝。
线程只能直接操作工作内存中的变量,不同线程之间的变量值传递需要通过主内存来完成。 线程只能直接操作工作内存中的变量,不同线程之间的变量值传递需要通过主内存来完成。
<div align="center"> <img src="pics/47358f87-bc4c-496f-9a90-8d696de94cee.png" width=""/> </div><br> <div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/8162aebb-8fd2-4620-b771-e65751ba7e41.png"/> </div><br>
## 内存间交互操作 ## 内存间交互操作
Java 内存模型定义了 8 个操作来完成主内存和工作内存的交互操作。 Java 内存模型定义了 8 个操作来完成主内存和工作内存的交互操作。
<div align="center"> <img src="pics/536c6dfd-305a-4b95-b12c-28ca5e8aa043.png" width=""/> </div><br> <div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/b6a7e8af-91bf-44b2-8874-ccc6d9d52afc.jpg"/> </div><br>
- read把一个变量的值从主内存传输到工作内存中 - read把一个变量的值从主内存传输到工作内存中
- load在 read 之后执行,把 read 得到的值放入工作内存的变量副本中 - load在 read 之后执行,把 read 得到的值放入工作内存的变量副本中
@ -1114,11 +1112,11 @@ Java 内存模型保证了 read、load、use、assign、store、write、lock 和
下图演示了两个线程同时对 cnt 进行操作load、assign、store 这一系列操作整体上看不具备原子性,那么在 T1 修改 cnt 并且还没有将修改后的值写入主内存T2 依然可以读入旧值。可以看出,这两个线程虽然执行了两次自增运算,但是主内存中 cnt 的值最后为 1 而不是 2。因此对 int 类型读写操作满足原子性只是说明 load、assign、store 这些单个操作具备原子性。 下图演示了两个线程同时对 cnt 进行操作load、assign、store 这一系列操作整体上看不具备原子性,那么在 T1 修改 cnt 并且还没有将修改后的值写入主内存T2 依然可以读入旧值。可以看出,这两个线程虽然执行了两次自增运算,但是主内存中 cnt 的值最后为 1 而不是 2。因此对 int 类型读写操作满足原子性只是说明 load、assign、store 这些单个操作具备原子性。
<div align="center"> <img src="pics/ef8eab00-1d5e-4d99-a7c2-d6d68ea7fe92.png" width=""/> </div><br> <div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/847b9ba1-b3cd-4e52-aa72-dee0222ae09f.jpg"/> </div><br>
AtomicInteger 能保证多个线程修改的原子性。 AtomicInteger 能保证多个线程修改的原子性。
<div align="center"> <img src="pics/952afa9a-458b-44ce-bba9-463e60162945.png" width=""/> </div><br> <div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/3144015c-dcfb-47ac-94a5-bab3b78b0f14.jpg"/> </div><br>
使用 AtomicInteger 重写之前线程不安全的代码之后得到以下线程安全实现: 使用 AtomicInteger 重写之前线程不安全的代码之后得到以下线程安全实现:
@ -1200,7 +1198,7 @@ public static void main(String[] args) throws InterruptedException {
可见性指当一个线程修改了共享变量的值其它线程能够立即得知这个修改。Java 内存模型是通过在变量修改后将新值同步回主内存,在变量读取前从主内存刷新变量值来实现可见性的。 可见性指当一个线程修改了共享变量的值其它线程能够立即得知这个修改。Java 内存模型是通过在变量修改后将新值同步回主内存,在变量读取前从主内存刷新变量值来实现可见性的。
主要有三种实现可见性的方式: 主要有三种实现可见性的方式:
- volatile - volatile
- synchronized对一个变量执行 unlock 操作之前,必须把变量值同步回主内存。 - synchronized对一个变量执行 unlock 操作之前,必须把变量值同步回主内存。
@ -1226,7 +1224,7 @@ volatile 关键字通过添加内存屏障的方式来禁止指令重排,即
在一个线程内,在程序前面的操作先行发生于后面的操作。 在一个线程内,在程序前面的操作先行发生于后面的操作。
<div align="center"> <img src="pics/single-thread-rule.png" width=""/> </div><br> <div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/94414cd3-5db9-4aca-a2af-539140955c62.jpg"/> </div><br>
### 2. 管程锁定规则 ### 2. 管程锁定规则
@ -1234,7 +1232,7 @@ volatile 关键字通过添加内存屏障的方式来禁止指令重排,即
一个 unlock 操作先行发生于后面对同一个锁的 lock 操作。 一个 unlock 操作先行发生于后面对同一个锁的 lock 操作。
<div align="center"> <img src="pics/monitor-lock-rule.png" width=""/> </div><br> <div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/de9d8133-4c98-4e07-b39c-302e162784ea.jpg"/> </div><br>
### 3. volatile 变量规则 ### 3. volatile 变量规则
@ -1242,7 +1240,7 @@ volatile 关键字通过添加内存屏障的方式来禁止指令重排,即
对一个 volatile 变量的写操作先行发生于后面对这个变量的读操作。 对一个 volatile 变量的写操作先行发生于后面对这个变量的读操作。
<div align="center"> <img src="pics/volatile-variable-rule.png" width=""/> </div><br> <div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/5e6e05d6-1028-4f5c-b9bd-1a40b90d6070.jpg"/> </div><br>
### 4. 线程启动规则 ### 4. 线程启动规则
@ -1250,7 +1248,7 @@ volatile 关键字通过添加内存屏障的方式来禁止指令重排,即
Thread 对象的 start() 方法调用先行发生于此线程的每一个动作。 Thread 对象的 start() 方法调用先行发生于此线程的每一个动作。
<div align="center"> <img src="pics/thread-start-rule.png" width=""/> </div><br> <div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/bc5826f5-014d-47b4-9a76-d86b80968643.jpg"/> </div><br>
### 5. 线程加入规则 ### 5. 线程加入规则
@ -1258,7 +1256,7 @@ Thread 对象的 start() 方法调用先行发生于此线程的每一个动作
Thread 对象的结束先行发生于 join() 方法返回。 Thread 对象的结束先行发生于 join() 方法返回。
<div align="center"> <img src="pics/thread-join-rule.png" width=""/> </div><br> <div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/54e6d499-80df-488e-aa7e-081766c41538.jpg"/> </div><br>
### 6. 线程中断规则 ### 6. 线程中断规则
@ -1476,7 +1474,7 @@ public class ThreadLocalExample1 {
它所对应的底层结构图为: 它所对应的底层结构图为:
<div align="center"> <img src="pics/3646544a-cb57-451d-9e03-d3c4f5e4434a.png" width=""/> </div><br> <div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/066f9c11-0154-42c3-8685-301a70e9bd39.jpg"/> </div><br>
每个 Thread 都有一个 ThreadLocal.ThreadLocalMap 对象。 每个 Thread 都有一个 ThreadLocal.ThreadLocalMap 对象。
@ -1579,17 +1577,17 @@ JDK 1.6 引入了偏向锁和轻量级锁,从而让锁拥有了四个状态:
以下是 HotSpot 虚拟机对象头的内存布局,这些数据被称为 Mark Word。其中 tag bits 对应了五个状态,这些状态在右侧的 state 表格中给出。除了 marked for gc 状态,其它四个状态已经在前面介绍过了。 以下是 HotSpot 虚拟机对象头的内存布局,这些数据被称为 Mark Word。其中 tag bits 对应了五个状态,这些状态在右侧的 state 表格中给出。除了 marked for gc 状态,其它四个状态已经在前面介绍过了。
<div align="center"> <img src="pics/bb6a49be-00f2-4f27-a0ce-4ed764bc605c.png" width="500"/> </div><br> <div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/bb6a49be-00f2-4f27-a0ce-4ed764bc605c.png" width="500"/> </div><br>
下图左侧是一个线程的虚拟机栈,其中有一部分称为 Lock Record 的区域,这是在轻量级锁运行过程创建的,用于存放锁对象的 Mark Word。而右侧就是一个锁对象包含了 Mark Word 和其它信息。 下图左侧是一个线程的虚拟机栈,其中有一部分称为 Lock Record 的区域,这是在轻量级锁运行过程创建的,用于存放锁对象的 Mark Word。而右侧就是一个锁对象包含了 Mark Word 和其它信息。
<div align="center"> <img src="pics/051e436c-0e46-4c59-8f67-52d89d656182.png" width="500"/> </div><br> <div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/051e436c-0e46-4c59-8f67-52d89d656182.png" width="500"/> </div><br>
轻量级锁是相对于传统的重量级锁而言,它使用 CAS 操作来避免重量级锁使用互斥量的开销。对于绝大部分的锁,在整个同步周期内都是不存在竞争的,因此也就不需要都使用互斥量进行同步,可以先采用 CAS 操作进行同步,如果 CAS 失败了再改用互斥量进行同步。 轻量级锁是相对于传统的重量级锁而言,它使用 CAS 操作来避免重量级锁使用互斥量的开销。对于绝大部分的锁,在整个同步周期内都是不存在竞争的,因此也就不需要都使用互斥量进行同步,可以先采用 CAS 操作进行同步,如果 CAS 失败了再改用互斥量进行同步。
当尝试获取一个锁对象时,如果锁对象标记为 0 01说明锁对象的锁未锁定unlocked状态。此时虚拟机在当前线程的虚拟机栈中创建 Lock Record然后使用 CAS 操作将对象的 Mark Word 更新为 Lock Record 指针。如果 CAS 操作成功了,那么线程就获取了该对象上的锁,并且对象的 Mark Word 的锁标记变为 00表示该对象处于轻量级锁状态。 当尝试获取一个锁对象时,如果锁对象标记为 0 01说明锁对象的锁未锁定unlocked状态。此时虚拟机在当前线程的虚拟机栈中创建 Lock Record然后使用 CAS 操作将对象的 Mark Word 更新为 Lock Record 指针。如果 CAS 操作成功了,那么线程就获取了该对象上的锁,并且对象的 Mark Word 的锁标记变为 00表示该对象处于轻量级锁状态。
<div align="center"> <img src="pics/baaa681f-7c52-4198-a5ae-303b9386cf47.png" width="400"/> </div><br> <div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/baaa681f-7c52-4198-a5ae-303b9386cf47.png" width="400"/> </div><br>
如果 CAS 操作失败了,虚拟机首先会检查对象的 Mark Word 是否指向当前线程的虚拟机栈,如果是的话说明当前线程已经拥有了这个锁对象,那就可以直接进入同步块继续执行,否则说明这个锁对象已经被其他线程线程抢占了。如果有两条以上的线程争用同一个锁,那轻量级锁就不再有效,要膨胀为重量级锁。 如果 CAS 操作失败了,虚拟机首先会检查对象的 Mark Word 是否指向当前线程的虚拟机栈,如果是的话说明当前线程已经拥有了这个锁对象,那就可以直接进入同步块继续执行,否则说明这个锁对象已经被其他线程线程抢占了。如果有两条以上的线程争用同一个锁,那轻量级锁就不再有效,要膨胀为重量级锁。
@ -1601,7 +1599,7 @@ JDK 1.6 引入了偏向锁和轻量级锁,从而让锁拥有了四个状态:
当有另外一个线程去尝试获取这个锁对象时偏向状态就宣告结束此时撤销偏向Revoke Bias后恢复到未锁定状态或者轻量级锁状态。 当有另外一个线程去尝试获取这个锁对象时偏向状态就宣告结束此时撤销偏向Revoke Bias后恢复到未锁定状态或者轻量级锁状态。
<div align="center"> <img src="pics/390c913b-5f31-444f-bbdb-2b88b688e7ce.jpg" width="600"/> </div><br> <div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/390c913b-5f31-444f-bbdb-2b88b688e7ce.jpg" width="600"/> </div><br>
# 十三、多线程开发良好的实践 # 十三、多线程开发良好的实践
@ -1636,3 +1634,9 @@ JDK 1.6 引入了偏向锁和轻量级锁,从而让锁拥有了四个状态:
- [JAVA FORK JOIN EXAMPLE](http://www.javacreed.com/java-fork-join-example/ "Java Fork Join Example") - [JAVA FORK JOIN EXAMPLE](http://www.javacreed.com/java-fork-join-example/ "Java Fork Join Example")
- [聊聊并发——Fork/Join 框架介绍](http://ifeve.com/talk-concurrency-forkjoin/) - [聊聊并发——Fork/Join 框架介绍](http://ifeve.com/talk-concurrency-forkjoin/)
- [Eliminating SynchronizationRelated Atomic Operations with Biased Locking and Bulk Rebiasing](http://www.oracle.com/technetwork/java/javase/tech/biasedlocking-oopsla2006-preso-150106.pdf) - [Eliminating SynchronizationRelated Atomic Operations with Biased Locking and Bulk Rebiasing](http://www.oracle.com/technetwork/java/javase/tech/biasedlocking-oopsla2006-preso-150106.pdf)
</br><div align="center">⭐️欢迎关注我的公众号 CyC2018在公众号后台回复关键字 📚 **资料** 可领取复习大纲,这份大纲是我花了一整年时间整理的面试知识点列表,不仅系统整理了面试知识点,而且标注了各个知识点的重要程度,从而帮你理清多而杂的面试知识点。可以说我基本是按照这份大纲来进行复习的,这份大纲对我拿到了 BAT 头条等 Offer 起到很大的帮助。你们完全可以和我一样根据大纲上列的知识点来进行复习,就不用看很多不重要的内容,也可以知道哪些内容很重要从而多安排一些复习时间。</div></br>
<div align="center"><img width="180px" src="https://cyc-1256109796.cos.ap-guangzhou.myqcloud.com/%E5%85%AC%E4%BC%97%E5%8F%B7.jpg"></img></div>

View File

@ -30,7 +30,7 @@
# 一、运行时数据区域 # 一、运行时数据区域
<div align="center"> <img src="pics/85370d54-40d1-4912-bcbe-37a2481c861d.png" width="450"/> </div><br> <div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/83e9c5ed-35a1-41fd-b0dd-ce571969b5f3_200.png" width="500px"> </div><br>
## 程序计数器 ## 程序计数器
@ -40,7 +40,7 @@
每个 Java 方法在执行的同时会创建一个栈帧用于存储局部变量表、操作数栈、常量池引用等信息。从方法调用直至执行完成的过程,就对应着一个栈帧在 Java 虚拟机栈中入栈和出栈的过程。 每个 Java 方法在执行的同时会创建一个栈帧用于存储局部变量表、操作数栈、常量池引用等信息。从方法调用直至执行完成的过程,就对应着一个栈帧在 Java 虚拟机栈中入栈和出栈的过程。
<div align="center"> <img src="pics/28ab96b4-82ea-4d99-99fb-b320f60d0a58.png" width="500"/> </div><br> <div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/ff5b89ac-798e-4fbc-b0ce-da2fc2358570.jpg"/> </div><br>
可以通过 -Xss 这个虚拟机参数来指定每个线程的 Java 虚拟机栈内存大小: 可以通过 -Xss 这个虚拟机参数来指定每个线程的 Java 虚拟机栈内存大小:
@ -59,20 +59,20 @@ java -Xss512M HackTheJava
本地方法一般是用其它语言C、C++ 或汇编语言等)编写的,并且被编译为基于本机硬件和操作系统的程序,对待这些方法需要特别处理。 本地方法一般是用其它语言C、C++ 或汇编语言等)编写的,并且被编译为基于本机硬件和操作系统的程序,对待这些方法需要特别处理。
<div align="center"> <img src="pics/JNI-Java-Native-Interface.jpg" width="350"/> </div><br> <div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/1_2001550547261811.png"/> </div><br>
## 堆 ## 堆
所有对象都在这里分配内存,是垃圾收集的主要区域("GC 堆")。 所有对象都在这里分配内存,是垃圾收集的主要区域("GC 堆")。
现代的垃圾收集器基本都是采用分代收集算法,其主要的思想是针对不同类型的对象采取不同的垃圾回收算法可以将堆分成两块: 现代的垃圾收集器基本都是采用分代收集算法,其主要的思想是针对不同类型的对象采取不同的垃圾回收算法可以将堆分成两块:
- 新生代Young Generation - 新生代Young Generation
- 老年代Old Generation - 老年代Old Generation
堆不需要连续内存,并且可以动态增加其内存,增加失败会抛出 OutOfMemoryError 异常。 堆不需要连续内存,并且可以动态增加其内存,增加失败会抛出 OutOfMemoryError 异常。
可以通过 -Xms 和 -Xmx 两个虚拟机参数来指定一个程序的堆内存大小,第一个参数设置初始值,第二个参数设置最大值。 可以通过 -Xms 和 -Xmx 两个虚拟机参数来指定一个程序的堆内存大小,第一个参数设置初始值,第二个参数设置最大值。
```java ```java
java -Xms1M -Xmx2M HackTheJava java -Xms1M -Xmx2M HackTheJava
@ -86,86 +86,83 @@ java -Xms1M -Xmx2M HackTheJava
对这块区域进行垃圾回收的主要目标是对常量池的回收和对类的卸载,但是一般比较难实现。 对这块区域进行垃圾回收的主要目标是对常量池的回收和对类的卸载,但是一般比较难实现。
HotSpot 虚拟机把它当成永久代来进行垃圾回收。但很难确定永久代的大小,因为它受到很多因素影响,并且每次 Full GC 之后永久代的大小都会改变,所以经常会抛出 OutOfMemoryError 异常。为了更容易管理方法区,从 JDK 1.8 开始,移除永久代,并把方法区移至元空间,它位于本地内存中,而不是虚拟机内存中。 HotSpot 虚拟机把它当成永久代来进行垃圾回收。但很难确定永久代的大小,因为它受到很多因素影响,并且每次 Full GC 之后永久代的大小都会改变,所以经常会抛出 OutOfMemoryError 异常。为了更容易管理方法区,从 JDK 1.8 开始,移除永久代,并把方法区移至元空间,它位于本地内存中,而不是虚拟机内存中。
## 运行时常量池 ## 运行时常量池
运行时常量池是方法区的一部分。 运行时常量池是方法区的一部分。
Class 文件中的常量池(编译器生成的各种字面量和符号引用)会在类加载后被放入这个区域。 Class 文件中的常量池(编译器生成的字面量和符号引用)会在类加载后被放入这个区域。
除了在编译期生成的常量,还允许动态生成,例如 String 类的 intern()。 除了在编译期生成的常量,还允许动态生成,例如 String 类的 intern()。
## 直接内存 ## 直接内存
在 JDK 1.4 中新加入了 NIO 类,它可以使用 Native 函数库直接分配堆外内存Native 堆),然后通过一个存储在 Java 堆里的 DirectByteBuffer 对象作为这块内存的引用进行操作。 在 JDK 1.4 中新引入了 NIO 类,它可以使用 Native 函数库直接分配堆外内存,然后通过 Java 堆里的 DirectByteBuffer 对象作为这块内存的引用进行操作。这样能在一些场景中显著提高性能,因为避免了在堆内存和堆外内存来回拷贝数据。
这样能在一些场景中显著提高性能,因为避免了在 Java 堆和 Native 堆中来回复制数据。
# 二、垃圾收集 # 二、垃圾收集
垃圾收集主要是针对堆和方法区进行。 垃圾收集主要是针对堆和方法区进行。程序计数器、虚拟机栈和本地方法栈这三个区域属于线程私有的,只存在于线程的生命周期内,线程结束之后就会消失,因此不需要对这三个区域进行垃圾回收。
程序计数器、虚拟机栈和本地方法栈这三个区域属于线程私有的,只存在于线程的生命周期内,线程结束之后也会消失,因此不需要对这三个区域进行垃圾回收。
## 判断一个对象是否可被回收 ## 判断一个对象是否可被回收
### 1. 引用计数算法 ### 1. 引用计数算法
对象添加一个引用计数器,当对象增加一个引用时计数器加 1引用失效时计数器减 1。引用计数为 0 的对象可被回收。 对象添加一个引用计数器,当对象增加一个引用时计数器加 1引用失效时计数器减 1。引用计数为 0 的对象可被回收。
两个对象出现循环引用的情况下,此时引用计数器永远不为 0导致无法对它们进行回收。 在两个对象出现循环引用的情况下,此时引用计数器永远不为 0导致无法对它们进行回收。正是因为循环引用的存在因此 Java 虚拟机不使用引用计数算法。
正因为循环引用的存在,因此 Java 虚拟机不使用引用计数算法。
```java ```java
public class ReferenceCountingGC { public class Test {
public Object instance = null; public Object instance = null;
public static void main(String[] args) { public static void main(String[] args) {
ReferenceCountingGC objectA = new ReferenceCountingGC(); Test a = new Test();
ReferenceCountingGC objectB = new ReferenceCountingGC(); Test b = new Test();
objectA.instance = objectB; a.instance = b;
objectB.instance = objectA; b.instance = a;
a = null;
b = null;
doSomething();
} }
} }
``` ```
在上述代码中a 与 b 引用的对象实例互相持有了对象的引用,因此当我们把对 a 对象与 b 对象的引用去除之后,由于两个对象还存在互相之间的引用,导致两个 Test 对象无法被回收。
### 2. 可达性分析算法 ### 2. 可达性分析算法
通过 GC Roots 作为起始点进行搜索,能够到达到的对象都是存活的,不可达的对象可被回收。 以 GC Roots 为起始点进行搜索,可达的对象都是存活的,不可达的对象可被回收。
Java 虚拟机使用该算法来判断对象是否可被回收,在 Java 中 GC Roots 一般包含以下内容: Java 虚拟机使用该算法来判断对象是否可被回收GC Roots 一般包含以下内容:
- 虚拟机栈中局部变量表中引用的对象 - 虚拟机栈中局部变量表中引用的对象
- 本地方法栈中 JNI 中引用的对象 - 本地方法栈中 JNI 中引用的对象
- 方法区中类静态属性引用的对象 - 方法区中类静态属性引用的对象
- 方法区中的常量引用的对象 - 方法区中的常量引用的对象
<div align="center"> <img src="pics/0635cbe8.png" width=""/> </div><br> <div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/6dd28bfc-6ef7-47cb-af50-a681ebc1bbaa.png"/> </div><br>
### 3. 方法区的回收 ### 3. 方法区的回收
因为方法区主要存放永久代对象,而永久代对象的回收率比新生代低很多,因此在方法区上进行回收性价比不高。 因为方法区主要存放永久代对象,而永久代对象的回收率比新生代低很多,所以在方法区上进行回收性价比不高。
主要是对常量池的回收和对类的卸载。 主要是对常量池的回收和对类的卸载。
在大量使用反射、动态代理、CGLib 等 ByteCode 框架、动态生成 JSP 以及 OSGi 这类频繁自定义 ClassLoader 的场景都需要虚拟机具备类卸载功能,以保证不会出现内存溢出 为了避免内存溢出,在大量使用反射和动态代理的场景都需要虚拟机具备类卸载功能
类的卸载条件很多,需要满足以下三个条件,并且满足了也不一定会被卸载: 类的卸载条件很多,需要满足以下三个条件,并且满足了条件也不一定会被卸载:
- 该类所有的实例都已经被回收,也就是堆中不存在该类的任何实例。 - 该类所有的实例都已经被回收,此时堆中不存在该类的任何实例。
- 加载该类的 ClassLoader 已经被回收。 - 加载该类的 ClassLoader 已经被回收。
- 该类对应的 Class 对象没有在任何地方被引用,也就无法在任何地方通过反射访问该类方法。 - 该类对应的 Class 对象没有在任何地方被引用,也就无法在任何地方通过反射访问该类方法。
可以通过 -Xnoclassgc 参数来控制是否对类进行卸载。
### 4. finalize() ### 4. finalize()
finalize() 类似 C++ 的析构函数,用来做关闭外部资源等工作。但是 try-finally 等方式可以做的更好,并且该方法运行代价高昂,不确定性大,无法保证各个对象的调用顺序,因此最好不要使用。 类似 C++ 的析构函数,用于关闭外部资源。但是 try-finally 等方式可以做得更好,并且该方法运行代价很高,不确定性大,无法保证各个对象的调用顺序,因此最好不要使用。
当一个对象可被回收时,如果需要执行该对象的 finalize() 方法,那么就有可能在该方法中让对象重新被引用,从而实现自救。自救只能进行一次,如果回收的对象之前调用了 finalize() 方法自救,后面回收时不会调用 finalize() 方法。 当一个对象可被回收时,如果需要执行该对象的 finalize() 方法,那么就有可能在该方法中让对象重新被引用,从而实现自救。自救只能进行一次,如果回收的对象之前调用了 finalize() 方法自救,后面回收时不会再调用该方法。
## 引用类型 ## 引用类型
@ -199,7 +196,7 @@ obj = null; // 使对象只被软引用关联
被弱引用关联的对象一定会被回收,也就是说它只能存活到下一次垃圾回收发生之前。 被弱引用关联的对象一定会被回收,也就是说它只能存活到下一次垃圾回收发生之前。
使用 WeakReference 类来实现弱引用。 使用 WeakReference 类来创建弱引用。
```java ```java
Object obj = new Object(); Object obj = new Object();
@ -209,15 +206,15 @@ obj = null;
### 4. 虚引用 ### 4. 虚引用
又称为幽灵引用或者幻影引用。一个对象是否有虚引用的存在,完全不会对其生存时间构成影响,也无法通过虚引用取得一个对象。 又称为幽灵引用或者幻影引用,一个对象是否有虚引用的存在,不会对其生存时间造成影响,也无法通过虚引用得到一个对象。
为一个对象设置虚引用关联的唯一目的是能在这个对象被回收时收到一个系统通知。 为一个对象设置虚引用的唯一目的是能在这个对象被回收时收到一个系统通知。
使用 PhantomReference 来实现虚引用。 使用 PhantomReference 来创建虚引用。
```java ```java
Object obj = new Object(); Object obj = new Object();
PhantomReference<Object> pf = new PhantomReference<Object>(obj); PhantomReference<Object> pf = new PhantomReference<Object>(obj, null);
obj = null; obj = null;
``` ```
@ -225,7 +222,8 @@ obj = null;
### 1. 标记 - 清除 ### 1. 标记 - 清除
<div align="center"> <img src="pics/a4248c4b-6c1d-4fb8-a557-86da92d3a294.jpg" width=""/> </div><br> <div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/3_2001550547558008.png"/> </div><br>
标记要回收的对象,然后清除。 标记要回收的对象,然后清除。
@ -236,21 +234,29 @@ obj = null;
### 2. 标记 - 整理 ### 2. 标记 - 整理
<div align="center"> <img src="pics/902b83ab-8054-4bd2-898f-9a4a0fe52830.jpg" width=""/> </div><br> <div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/2_2001550547456403.png"/> </div><br>
让所有存活的对象都向一端移动,然后直接清理掉端边界以外的内存。 让所有存活的对象都向一端移动,然后直接清理掉端边界以外的内存。
优点:
- 不会产生内存碎片
不足:
- 需要移动大量对象,处理效率比较低。
### 3. 复制 ### 3. 复制
<div align="center"> <img src="pics/e6b733ad-606d-4028-b3e8-83c3a73a3797.jpg" width=""/> </div><br> <div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/4_2001550547640585.png"/> </div><br>
将内存划分为大小相等的两块,每次只使用其中一块,当这一块内存用完了就将还存活的对象复制到另一块上面,然后再把使用过的内存空间进行一次清理。 将内存划分为大小相等的两块,每次只使用其中一块,当这一块内存用完了就将还存活的对象复制到另一块上面,然后再把使用过的内存空间进行一次清理。
主要不足是只使用了内存的一半。 主要不足是只使用了内存的一半。
现在的商业虚拟机都采用这种收集算法回收新生代,但是并不是将新生代划分为大小相等的两块,而是分为一块较大的 Eden 空间和两块较小的 Survivor 空间,每次使用 Eden 空间和其中一块 Survivor。在回收时将 Eden 和 Survivor 中还存活着的对象一次性复制到另一块 Survivor 空间上,最后清理 Eden 和使用过的那一块 Survivor。 现在的商业虚拟机都采用这种收集算法回收新生代,但是并不是划分为大小相等的两块,而是一块较大的 Eden 空间和两块较小的 Survivor 空间,每次使用 Eden 和其中一块 Survivor。在回收时将 Eden 和 Survivor 中还存活着的对象全部复制到另一块 Survivor 上,最后清理 Eden 和使用过的那一块 Survivor。
HotSpot 虚拟机的 Eden 和 Survivor 大小比例默认为 8:1保证了内存的利用率达到 90%。如果每次回收有多于 10% 的对象存活,那么一块 Survivor 空间就不够用了,此时需要依赖于老年代进行分配担保,也就是借用老年代的空间存储放不下的对象。 HotSpot 虚拟机的 Eden 和 Survivor 大小比例默认为 8:1保证了内存的利用率达到 90%。如果每次回收有多于 10% 的对象存活,那么一块 Survivor 就不够用了,此时需要依赖于老年代进行空间分配担保,也就是借用老年代的空间存储放不下的对象。
### 4. 分代收集 ### 4. 分代收集
@ -263,40 +269,38 @@ HotSpot 虚拟机的 Eden 和 Survivor 的大小比例默认为 8:1保证了
## 垃圾收集器 ## 垃圾收集器
<div align="center"> <img src="pics/c625baa0-dde6-449e-93df-c3a67f2f430f.jpg" width=""/> </div><br> <div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/c625baa0-dde6-449e-93df-c3a67f2f430f.jpg" width=""/> </div><br>
以上是 HotSpot 虚拟机中的 7 个垃圾收集器,连线表示垃圾收集器可以配合使用。 以上是 HotSpot 虚拟机中的 7 个垃圾收集器,连线表示垃圾收集器可以配合使用。
- 单线程与多线程:单线程指的是垃圾收集器只使用一个线程进行收集,而多线程使用多个线程; - 单线程与多线程:单线程指的是垃圾收集器只使用一个线程,而多线程使用多个线程;
- 串行与并行:串行指的是垃圾收集器与用户程序交替执行,这意味着在执行垃圾收集的时候需要停顿用户程序;并行指的是垃圾收集器和用户程序同时执行。除了 CMS 和 G1 之外,其它垃圾收集器都是以串行的方式执行。 - 串行与并行:串行指的是垃圾收集器与用户程序交替执行,这意味着在执行垃圾收集的时候需要停顿用户程序;并行指的是垃圾收集器和用户程序同时执行。除了 CMS 和 G1 之外,其它垃圾收集器都是以串行的方式执行。
### 1. Serial 收集器 ### 1. Serial 收集器
<div align="center"> <img src="pics/22fda4ae-4dd5-489d-ab10-9ebfdad22ae0.jpg" width=""/> </div><br> <div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/22fda4ae-4dd5-489d-ab10-9ebfdad22ae0.jpg" width=""/> </div><br>
Serial 翻译为串行,也就是说它以串行的方式执行。 Serial 翻译为串行,也就是说它以串行的方式执行。
它是单线程的收集器,只会使用一个线程进行垃圾收集工作。 它是单线程的收集器,只会使用一个线程进行垃圾收集工作。
它的优点是简单高效,对于单个 CPU 环境来说,由于没有线程交互的开销,因此拥有最高的单线程收集效率。 它的优点是简单高效,在单个 CPU 环境下,由于没有线程交互的开销,因此拥有最高的单线程收集效率。
它是 Client 模式下的默认新生代收集器因为在该应用场景下分配给虚拟机管理的内存一般来说不会很大。Serial 收集器收集几十兆甚至一两百兆的新生代停顿时间可以控制在一百多毫秒以内,只要不是太频繁,这点停顿是可以接受的。 它是 Client 场景下的默认新生代收集器,因为在该场景下内存一般来说不会很大。它收集一两百兆垃圾的停顿时间可以控制在一百多毫秒以内,只要不是太频繁,这点停顿时间是可以接受的。
### 2. ParNew 收集器 ### 2. ParNew 收集器
<div align="center"> <img src="pics/81538cd5-1bcf-4e31-86e5-e198df1e013b.jpg" width=""/> </div><br> <div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/81538cd5-1bcf-4e31-86e5-e198df1e013b.jpg" width=""/> </div><br>
它是 Serial 收集器的多线程版本。 它是 Serial 收集器的多线程版本。
是 Server 模式下的虚拟机首选新生代收集器,除了性能原因外,主要是因为除了 Serial 收集器,只有它能与 CMS 收集器配合工作。 它是 Server 场景下默认的新生代收集器,除了性能原因外,主要是因为除了 Serial 收集器,只有它能与 CMS 收集器配合使用。
默认开启的线程数量与 CPU 数量相同,可以使用 -XX:ParallelGCThreads 参数来设置线程数。
### 3. Parallel Scavenge 收集器 ### 3. Parallel Scavenge 收集器
与 ParNew 一样是多线程收集器。 与 ParNew 一样是多线程收集器。
其它收集器关注点是尽可能缩短垃圾收集时用户线程的停顿时间,而它的目标是达到一个可控制的吞吐量,它被称为“吞吐量优先”收集器。这里的吞吐量指 CPU 用于运行用户代码的时间占总时间的比值。 其它收集器目标是尽可能缩短垃圾收集时用户线程的停顿时间,而它的目标是达到一个可控制的吞吐量,因此它被称为“吞吐量优先”收集器。这里的吞吐量指 CPU 用于运行用户程序的时间占总时间的比值。
停顿时间越短就越适合需要与用户交互的程序,良好的响应速度能提升用户体验。而高吞吐量则可以高效率地利用 CPU 时间,尽快完成程序的运算任务,适合在后台运算而不需要太多交互的任务。 停顿时间越短就越适合需要与用户交互的程序,良好的响应速度能提升用户体验。而高吞吐量则可以高效率地利用 CPU 时间,尽快完成程序的运算任务,适合在后台运算而不需要太多交互的任务。
@ -306,16 +310,16 @@ Serial 翻译为串行,也就是说它以串行的方式执行。
### 4. Serial Old 收集器 ### 4. Serial Old 收集器
<div align="center"> <img src="pics/08f32fd3-f736-4a67-81ca-295b2a7972f2.jpg" width=""/> </div><br> <div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/08f32fd3-f736-4a67-81ca-295b2a7972f2.jpg" width=""/> </div><br>
是 Serial 收集器的老年代版本,也是给 Client 模式下的虚拟机使用。如果用在 Server 模式下,它有两大用途: 是 Serial 收集器的老年代版本,也是给 Client 场景下的虚拟机使用。如果用在 Server 场景下,它有两大用途:
- 在 JDK 1.5 以及之前版本Parallel Old 诞生以前)中与 Parallel Scavenge 收集器搭配使用。 - 在 JDK 1.5 以及之前版本Parallel Old 诞生以前)中与 Parallel Scavenge 收集器搭配使用。
- 作为 CMS 收集器的后备预案,在并发收集发生 Concurrent Mode Failure 时使用。 - 作为 CMS 收集器的后备预案,在并发收集发生 Concurrent Mode Failure 时使用。
### 5. Parallel Old 收集器 ### 5. Parallel Old 收集器
<div align="center"> <img src="pics/278fe431-af88-4a95-a895-9c3b80117de3.jpg" width=""/> </div><br> <div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/278fe431-af88-4a95-a895-9c3b80117de3.jpg" width=""/> </div><br>
是 Parallel Scavenge 收集器的老年代版本。 是 Parallel Scavenge 收集器的老年代版本。
@ -323,7 +327,7 @@ Serial 翻译为串行,也就是说它以串行的方式执行。
### 6. CMS 收集器 ### 6. CMS 收集器
<div align="center"> <img src="pics/62e77997-6957-4b68-8d12-bfd609bb2c68.jpg" width=""/> </div><br> <div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/62e77997-6957-4b68-8d12-bfd609bb2c68.jpg" width=""/> </div><br>
CMSConcurrent Mark SweepMark Sweep 指的是标记 - 清除算法。 CMSConcurrent Mark SweepMark Sweep 指的是标记 - 清除算法。
@ -348,17 +352,17 @@ G1Garbage-First它是一款面向服务端应用的垃圾收集器
堆被分为新生代和老年代,其它收集器进行收集的范围都是整个新生代或者老年代,而 G1 可以直接对新生代和老年代一起回收。 堆被分为新生代和老年代,其它收集器进行收集的范围都是整个新生代或者老年代,而 G1 可以直接对新生代和老年代一起回收。
<div align="center"> <img src="pics/4cf711a8-7ab2-4152-b85c-d5c226733807.png" width="600"/> </div><br> <div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/4cf711a8-7ab2-4152-b85c-d5c226733807.png" width="600"/> </div><br>
G1 把堆划分成多个大小相等的独立区域Region新生代和老年代不再物理隔离。 G1 把堆划分成多个大小相等的独立区域Region新生代和老年代不再物理隔离。
<div align="center"> <img src="pics/9bbddeeb-e939-41f0-8e8e-2b1a0aa7e0a7.png" width="600"/> </div><br> <div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/9bbddeeb-e939-41f0-8e8e-2b1a0aa7e0a7.png" width="600"/> </div><br>
通过引入 Region 的概念,从而将原来的一整块内存空间划分成多个的小空间,使得每个小空间可以单独进行垃圾回收。这种划分方法带来了很大的灵活性,使得可预测的停顿时间模型成为可能。通过记录每个 Region 垃圾回收时间以及回收所获得的空间(这两个值是通过过去回收的经验获得),并维护一个优先列表,每次根据允许的收集时间,优先回收价值最大的 Region。 通过引入 Region 的概念,从而将原来的一整块内存空间划分成多个的小空间,使得每个小空间可以单独进行垃圾回收。这种划分方法带来了很大的灵活性,使得可预测的停顿时间模型成为可能。通过记录每个 Region 垃圾回收时间以及回收所获得的空间(这两个值是通过过去回收的经验获得),并维护一个优先列表,每次根据允许的收集时间,优先回收价值最大的 Region。
每个 Region 都有一个 Remembered Set用来记录该 Region 对象的引用对象所在的 Region。通过使用 Remembered Set在做可达性分析的时候就可以避免全堆扫描。 每个 Region 都有一个 Remembered Set用来记录该 Region 对象的引用对象所在的 Region。通过使用 Remembered Set在做可达性分析的时候就可以避免全堆扫描。
<div align="center"> <img src="pics/f99ee771-c56f-47fb-9148-c0036695b5fe.jpg" width=""/> </div><br> <div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/f99ee771-c56f-47fb-9148-c0036695b5fe.jpg" width=""/> </div><br>
如果不计算维护 Remembered Set 的操作G1 收集器的运作大致可划分为以下几个步骤: 如果不计算维护 Remembered Set 的操作G1 收集器的运作大致可划分为以下几个步骤:
@ -376,15 +380,15 @@ G1 把堆划分成多个大小相等的独立区域Region新生代和
## Minor GC 和 Full GC ## Minor GC 和 Full GC
- Minor GC发生在新生代上,因为新生代对象存活时间很短,因此 Minor GC 会频繁执行,执行的速度一般也会比较快。 - Minor GC回收新生代,因为新生代对象存活时间很短,因此 Minor GC 会频繁执行,执行的速度一般也会比较快。
- Full GC发生在老年代上,老年代对象其存活时间长,因此 Full GC 很少执行,执行速度会比 Minor GC 慢很多。 - Full GC回收老年代和新生代,老年代对象其存活时间长,因此 Full GC 很少执行,执行速度会比 Minor GC 慢很多。
## 内存分配策略 ## 内存分配策略
### 1. 对象优先在 Eden 分配 ### 1. 对象优先在 Eden 分配
大多数情况下,对象在新生代 Eden 区分配,当 Eden 区空间不够时,发起 Minor GC。 大多数情况下,对象在新生代 Eden 上分配,当 Eden 空间不够时,发起 Minor GC。
### 2. 大对象直接进入老年代 ### 2. 大对象直接进入老年代
@ -392,7 +396,7 @@ G1 把堆划分成多个大小相等的独立区域Region新生代和
经常出现大对象会提前触发垃圾收集以获取足够的连续空间分配给大对象。 经常出现大对象会提前触发垃圾收集以获取足够的连续空间分配给大对象。
-XX:PretenureSizeThreshold大于此值的对象直接在老年代分配避免在 Eden 和 Survivor 之间的大量内存复制。 -XX:PretenureSizeThreshold大于此值的对象直接在老年代分配避免在 Eden 和 Survivor 之间的大量内存复制。
### 3. 长期存活的对象进入老年代 ### 3. 长期存活的对象进入老年代
@ -402,13 +406,13 @@ G1 把堆划分成多个大小相等的独立区域Region新生代和
### 4. 动态对象年龄判定 ### 4. 动态对象年龄判定
虚拟机并不是永远要求对象的年龄必须达到 MaxTenuringThreshold 才能晋升老年代,如果在 Survivor 中相同年龄所有对象大小的总和大于 Survivor 空间的一半,则年龄大于或等于该年龄的对象可以直接进入老年代,无需等到 MaxTenuringThreshold 中要求的年龄。 虚拟机并不是永远要求对象的年龄必须达到 MaxTenuringThreshold 才能晋升老年代,如果在 Survivor 中相同年龄所有对象大小的总和大于 Survivor 空间的一半,则年龄大于或等于该年龄的对象可以直接进入老年代,无需等到 MaxTenuringThreshold 中要求的年龄。
### 5. 空间分配担保 ### 5. 空间分配担保
在发生 Minor GC 之前,虚拟机先检查老年代最大可用的连续空间是否大于新生代所有对象总空间,如果条件成立的话,那么 Minor GC 可以确认是安全的。 在发生 Minor GC 之前,虚拟机先检查老年代最大可用的连续空间是否大于新生代所有对象总空间,如果条件成立的话,那么 Minor GC 可以确认是安全的。
如果不成立的话虚拟机会查看 HandlePromotionFailure 设置值是否允许担保失败,如果允许那么就会继续检查老年代最大可用的连续空间是否大于历次晋升到老年代对象的平均大小,如果大于,将尝试着进行一次 Minor GC如果小于或者 HandlePromotionFailure 设置不允许冒险,那么就要进行一次 Full GC。 如果不成立的话虚拟机会查看 HandlePromotionFailure 值是否允许担保失败,如果允许那么就会继续检查老年代最大可用的连续空间是否大于历次晋升到老年代对象的平均大小,如果大于,将尝试着进行一次 Minor GC如果小于或者 HandlePromotionFailure 的值不允许冒险,那么就要进行一次 Full GC。
## Full GC 的触发条件 ## Full GC 的触发条件
@ -426,7 +430,7 @@ G1 把堆划分成多个大小相等的独立区域Region新生代和
### 3. 空间分配担保失败 ### 3. 空间分配担保失败
使用复制算法的 Minor GC 需要老年代的内存空间作担保,如果担保失败会执行一次 Full GC。具体内容请参考上面的第小节。 使用复制算法的 Minor GC 需要老年代的内存空间作担保,如果担保失败会执行一次 Full GC。具体内容请参考上面的第 5 小节。
### 4. JDK 1.7 及以前的永久代空间不足 ### 4. JDK 1.7 及以前的永久代空间不足
@ -442,11 +446,11 @@ G1 把堆划分成多个大小相等的独立区域Region新生代和
# 四、类加载机制 # 四、类加载机制
类是在运行期间第一次使用时动态加载的,而不是编译时期一次性加载。因为如果在编译时期一次性加载,那么会占用很多的内存。 类是在运行期间第一次使用时动态加载的,而不是一次性加载所有类。因为如果一次性加载,那么会占用很多的内存。
## 类的生命周期 ## 类的生命周期
<div align="center"> <img src="pics/32b8374a-e822-4720-af0b-c0f485095ea2.jpg" width=""/> </div><br> <div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/303873db-0d11-4683-a43c-f319b7aef2b6.jpg"/> </div><br>
包括以下 7 个阶段: 包括以下 7 个阶段:
@ -468,9 +472,10 @@ G1 把堆划分成多个大小相等的独立区域Region新生代和
加载过程完成以下三件事: 加载过程完成以下三件事:
- 通过一个类的全限定名来获取定义此类的二进制字节流。 - 通过类的完全限定名称获取定义该类的二进制字节流。
- 将这个字节流所代表的静态存储结构转化为方法区的运行时存储结构。 - 将该字节流表示的静态存储结构转换为方法区的运行时存储结构。
- 在内存中生成一个代表这个类的 Class 对象,作为方法区这个类的各种数据的访问入口。 - 在内存中生成一个代表该类的 Class 对象,作为方法区中该类各种数据的访问入口。
其中二进制字节流可以从以下方式中获取: 其中二进制字节流可以从以下方式中获取:
@ -487,9 +492,7 @@ G1 把堆划分成多个大小相等的独立区域Region新生代和
类变量是被 static 修饰的变量,准备阶段为类变量分配内存并设置初始值,使用的是方法区的内存。 类变量是被 static 修饰的变量,准备阶段为类变量分配内存并设置初始值,使用的是方法区的内存。
实例变量不会在这阶段分配内存,它将会在对象实例化时随着对象一起分配在堆中。 实例变量不会在这阶段分配内存,它会在对象实例化时随着对象一起被分配在堆中。应该注意到,实例化不是类加载的一个过程,类加载发生在所有实例化操作之前,并且类加载只进行一次,实例化可以进行多次。
注意,实例化不是类加载的一个过程,类加载发生在所有实例化操作之前,并且类加载只进行一次,实例化可以进行多次。
初始值一般为 0 值,例如下面的类变量 value 被初始化为 0 而不是 123。 初始值一般为 0 值,例如下面的类变量 value 被初始化为 0 而不是 123。
@ -497,7 +500,7 @@ G1 把堆划分成多个大小相等的独立区域Region新生代和
public static int value = 123; public static int value = 123;
``` ```
如果类变量是常量,那么会按照表达式来进行初始化,而不是赋值为 0。 如果类变量是常量,那么它将初始化为表达式所定义的值而不是 0。例如下面的常量 value 被初始化为 123 而不是 0。
```java ```java
public static final int value = 123; public static final int value = 123;
@ -509,15 +512,15 @@ public static final int value = 123;
其中解析过程在某些情况下可以在初始化阶段之后再开始,这是为了支持 Java 的动态绑定。 其中解析过程在某些情况下可以在初始化阶段之后再开始,这是为了支持 Java 的动态绑定。
<div data="补充为什么可以支持动态绑定 --> <--"></div>
### 5. 初始化 ### 5. 初始化
初始化阶段才真正开始执行类中定义的 Java 程序代码。初始化阶段即虚拟机执行类构造器 &lt;clinit>() 方法的过程。 <div data="modify -->"></div>
在准备阶段,类变量已经赋过一次系统要求的初始值,而在初始化阶段,根据程序员通过程序制定的主观计划去初始化类变量和其它资源。 初始化阶段才真正开始执行类中定义的 Java 程序代码。初始化阶段是虚拟机执行类构造器 &lt;clinit>() 方法的过程。在准备阶段,类变量已经赋过一次系统要求的初始值,而在初始化阶段,根据程序员通过程序制定的主观计划去初始化类变量和其它资源。
&lt;clinit>() 方法具有以下特点: &lt;clinit>() 是由编译器自动收集类中所有类变量的赋值动作和静态语句块中的语句合并产生的,编译器收集的顺序由语句在源文件中出现的顺序决定。特别注意的是,静态语句块只能访问到定义在它之前的类变量,定义在它之后的类变量只能赋值,不能访问。例如以下代码:
- 是由编译器自动收集类中所有类变量的赋值动作和静态语句块中的语句合并产生的,编译器收集的顺序由语句在源文件中出现的顺序决定。特别注意的是,静态语句块只能访问到定义在它之前的类变量,定义在它之后的类变量只能赋值,不能访问。例如以下代码:
```java ```java
public class Test { public class Test {
@ -529,9 +532,7 @@ public class Test {
} }
``` ```
- 与类的构造函数(或者说实例构造器 &lt;init>())不同,不需要显式的调用父类的构造器。虚拟机会自动保证在子类的 &lt;clinit>() 方法运行之前,父类的 &lt;clinit>() 方法已经执行结束。因此虚拟机中第一个执行 &lt;clinit>() 方法的类肯定为 java.lang.Object。 由于父类的 &lt;clinit>() 方法先执行,也就意味着父类中定义的静态语句块的执行要优先于子类。例如以下代码:
- 由于父类的 &lt;clinit>() 方法先执行,也就意味着父类中定义的静态语句块的执行要优先于子类。例如以下代码:
```java ```java
static class Parent { static class Parent {
@ -550,11 +551,9 @@ public static void main(String[] args) {
} }
``` ```
- &lt;clinit>() 方法对于类或接口不是必须的,如果一个类中不包含静态语句块,也没有对类变量的赋值操作,编译器可以不为该类生成 &lt;clinit>() 方法。 接口中不可以使用静态语句块,但仍然有类变量初始化的赋值操作,因此接口与类一样都会生成 &lt;clinit>() 方法。但接口与类不同的是,执行接口的 &lt;clinit>() 方法不需要先执行父接口的 &lt;clinit>() 方法。只有当父接口中定义的变量使用时,父接口才会初始化。另外,接口的实现类在初始化时也一样不会执行接口的 &lt;clinit>() 方法。
- 接口中不可以使用静态语句块,但仍然有类变量初始化的赋值操作,因此接口与类一样都会生成 &lt;clinit>() 方法。但接口与类不同的是,执行接口的 &lt;clinit>() 方法不需要先执行父接口的 &lt;clinit>() 方法。只有当父接口中定义的变量使用时,父接口才会初始化。另外,接口的实现类在初始化时也一样不会执行接口的 &lt;clinit>() 方法。 虚拟机会保证一个类的 &lt;clinit>() 方法在多线程环境下被正确的加锁和同步,如果多个线程同时初始化一个类,只会有一个线程执行这个类的 &lt;clinit>() 方法,其它线程都会阻塞等待,直到活动线程执行 &lt;clinit>() 方法完毕。如果在一个类的 &lt;clinit>() 方法中有耗时的操作,就可能造成多个线程阻塞,在实际过程中此种阻塞很隐蔽。
- 虚拟机会保证一个类的 &lt;clinit>() 方法在多线程环境下被正确的加锁和同步,如果多个线程同时初始化一个类,只会有一个线程执行这个类的 &lt;clinit>() 方法,其它线程都会阻塞等待,直到活动线程执行 &lt;clinit>() 方法完毕。如果在一个类的 &lt;clinit>() 方法中有耗时的操作,就可能造成多个线程阻塞,在实际过程中此种阻塞很隐蔽。
## 类初始化时机 ## 类初始化时机
@ -596,7 +595,7 @@ System.out.println(ConstClass.HELLOWORLD);
## 类与类加载器 ## 类与类加载器
两个类相等需要类本身相等,并且使用同一个类加载器进行加载。这是因为每一个类加载器都拥有一个独立的类名称空间。 两个类相等需要类本身相等,并且使用同一个类加载器进行加载。这是因为每一个类加载器都拥有一个独立的类名称空间。
这里的相等,包括类的 Class 对象的 equals() 方法、isAssignableFrom() 方法、isInstance() 方法的返回结果为 true也包括使用 instanceof 关键字做对象所属关系判定结果为 true。 这里的相等,包括类的 Class 对象的 equals() 方法、isAssignableFrom() 方法、isInstance() 方法的返回结果为 true也包括使用 instanceof 关键字做对象所属关系判定结果为 true。
@ -604,9 +603,9 @@ System.out.println(ConstClass.HELLOWORLD);
从 Java 虚拟机的角度来讲,只存在以下两种不同的类加载器: 从 Java 虚拟机的角度来讲,只存在以下两种不同的类加载器:
- 启动类加载器Bootstrap ClassLoader这个类加载器用 C++ 实现,是虚拟机自身的一部分; - 启动类加载器Bootstrap ClassLoader使用 C++ 实现,是虚拟机自身的一部分;
- 所有其他类的加载器,这些类由 Java 实现,独立于虚拟机外部,并且全都继承自抽象类 java.lang.ClassLoader。 - 所有其它类的加载器,使用 Java 实现,独立于虚拟机,继承自抽象类 java.lang.ClassLoader。
从 Java 开发人员的角度看,类加载器可以划分得更细致一些: 从 Java 开发人员的角度看,类加载器可以划分得更细致一些:
@ -616,23 +615,25 @@ System.out.println(ConstClass.HELLOWORLD);
- 应用程序类加载器Application ClassLoader这个类加载器是由 AppClassLoadersun.misc.Launcher$AppClassLoader实现的。由于这个类加载器是 ClassLoader 中的 getSystemClassLoader() 方法的返回值因此一般称为系统类加载器。它负责加载用户类路径ClassPath上所指定的类库开发者可以直接使用这个类加载器如果应用程序中没有自定义过自己的类加载器一般情况下这个就是程序中默认的类加载器。 - 应用程序类加载器Application ClassLoader这个类加载器是由 AppClassLoadersun.misc.Launcher$AppClassLoader实现的。由于这个类加载器是 ClassLoader 中的 getSystemClassLoader() 方法的返回值因此一般称为系统类加载器。它负责加载用户类路径ClassPath上所指定的类库开发者可以直接使用这个类加载器如果应用程序中没有自定义过自己的类加载器一般情况下这个就是程序中默认的类加载器。
<div data="modify <--"></div>
## 双亲委派模型 ## 双亲委派模型
应用程序都是由三种类加载器相互配合进行加载的,如果有必要,还可以加入自己定义的类加载器。 应用程序是由三种类加载器互相配合从而实现类加载,除此之外还可以加入自己定义的类加载器。
下图展示的类加载器之间的层次关系,称为类加载器的双亲委派模型Parents Delegation Model。该模型要求除了顶层的启动类加载器外余的类加载器都应有自己的父类加载器。这里类加载器之间的父子关系一般通过组合Composition关系来实现而不是通过继承Inheritance的关系实现 下图展示了类加载器之间的层次关系,称为双亲委派模型Parents Delegation Model。该模型要求除了顶层的启动类加载器外它的类加载器都要有自己的父类加载器。这里的父子关系一般通过组合关系Composition来实现而不是继承关系Inheritance
<div align="center"> <img src="pics/class_loader_hierarchy.png" width="600"/> </div><br> <div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/805812fa-6ab5-4b8f-a0aa-3bdcadaa829d.png"/> </div><br>
### 1. 工作过程 ### 1. 工作过程
一个类加载器首先将类加载请求传送到父类加载器,只有当父类加载器无法完成类加载请求时才尝试加载。 一个类加载器首先将类加载请求转发到父类加载器,只有当父类加载器无法完成时才尝试自己加载。
### 2. 好处 ### 2. 好处
使得 Java 类随着它的类加载器一起具有一种带有优先级的层次关系,从而使得基础类得到统一。 使得 Java 类随着它的类加载器一起具有一种带有优先级的层次关系,从而使得基础类得到统一。
例如 java.lang.Object 存放在 rt.jar 中,如果编写另外一个 java.lang.Object 的类并放到 ClassPath 中,程序可以编译通过。由于双亲委派模型的存在,所以在 rt.jar 中的 Object 比在 ClassPath 中的 Object 优先级更高,这是因为 rt.jar 中的 Object 使用的是启动类加载器,而 ClassPath 中的 Object 使用的是应用程序类加载器。rt.jar 中的 Object 优先级更高,那么程序中所有的 Object 都是这个 Object。 例如 java.lang.Object 存放在 rt.jar 中,如果编写另外一个 java.lang.Object 并放到 ClassPath 中,程序可以编译通过。由于双亲委派模型的存在,所以在 rt.jar 中的 Object 比在 ClassPath 中的 Object 优先级更高,这是因为 rt.jar 中的 Object 使用的是启动类加载器,而 ClassPath 中的 Object 使用的是应用程序类加载器。rt.jar 中的 Object 优先级更高,那么程序中所有的 Object 都是这个 Object。
### 3. 实现 ### 3. 实现
@ -684,9 +685,9 @@ public abstract class ClassLoader {
## 自定义类加载器实现 ## 自定义类加载器实现
FileSystemClassLoader 是自定义类加载器,继承自 java.lang.ClassLoader用于加载文件系统上的类。它首先根据类的全名在文件系统上查找类的字节代码文件.class 文件),然后读取该文件内容,最后通过 defineClass() 方法来把这些字节代码转换成 java.lang.Class 类的实例。 以下代码中的 FileSystemClassLoader 是自定义类加载器,继承自 java.lang.ClassLoader用于加载文件系统上的类。它首先根据类的全名在文件系统上查找类的字节代码文件.class 文件),然后读取该文件内容,最后通过 defineClass() 方法来把这些字节代码转换成 java.lang.Class 类的实例。
java.lang.ClassLoader 的 loadClass() 实现了双亲委派模型的逻辑,因此自定义类加载器一般不去重写它,但是需要重写 findClass() 方法。 java.lang.ClassLoader 的 loadClass() 实现了双亲委派模型的逻辑,自定义类加载器一般不去重写它,但是需要重写 findClass() 方法。
```java ```java
public class FileSystemClassLoader extends ClassLoader { public class FileSystemClassLoader extends ClassLoader {
@ -747,3 +748,9 @@ public class FileSystemClassLoader extends ClassLoader {
- [深入探讨 Java 类加载器](https://www.ibm.com/developerworks/cn/java/j-lo-classloader/index.html#code6) - [深入探讨 Java 类加载器](https://www.ibm.com/developerworks/cn/java/j-lo-classloader/index.html#code6)
- [Guide to WeakHashMap in Java](http://www.baeldung.com/java-weakhashmap) - [Guide to WeakHashMap in Java](http://www.baeldung.com/java-weakhashmap)
- [Tomcat example source code file (ConcurrentCache.java)](https://alvinalexander.com/java/jwarehouse/apache-tomcat-6.0.16/java/org/apache/el/util/ConcurrentCache.java.shtml) - [Tomcat example source code file (ConcurrentCache.java)](https://alvinalexander.com/java/jwarehouse/apache-tomcat-6.0.16/java/org/apache/el/util/ConcurrentCache.java.shtml)
</br><div align="center">⭐️欢迎关注我的公众号 CyC2018在公众号后台回复关键字 📚 **资料** 可领取复习大纲,这份大纲是我花了一整年时间整理的面试知识点列表,不仅系统整理了面试知识点,而且标注了各个知识点的重要程度,从而帮你理清多而杂的面试知识点。可以说我基本是按照这份大纲来进行复习的,这份大纲对我拿到了 BAT 头条等 Offer 起到很大的帮助。你们完全可以和我一样根据大纲上列的知识点来进行复习,就不用看很多不重要的内容,也可以知道哪些内容很重要从而多安排一些复习时间。</div></br>
<div align="center"><img width="180px" src="https://cyc-1256109796.cos.ap-guangzhou.myqcloud.com/%E5%85%AC%E4%BC%97%E5%8F%B7.jpg"></img></div>

View File

@ -0,0 +1,300 @@
<!-- GFM-TOC -->
* [原理](#原理)
* [1. 正常实现](#1-正常实现)
* [2. 时间复杂度](#2-时间复杂度)
* [3. m 计算](#3-m-计算)
* [4. 返回值](#4-返回值)
* [5. 变种](#5-变种)
* [例题](#例题)
* [1. 求开方](#1-求开方)
* [2. 大于给定元素的最小元素](#2-大于给定元素的最小元素)
* [3. 有序数组的 Single Element](#3-有序数组的-single-element)
* [4. 第一个错误的版本](#4-第一个错误的版本)
* [5. 旋转数组的最小数字](#5-旋转数组的最小数字)
* [6. 查找区间](#6-查找区间)
<!-- GFM-TOC -->
# 原理
## 1. 正常实现
```java
public int binarySearch(int[] nums, int key) {
int l = 0, h = nums.length - 1;
while (l <= h) {
int m = l + (h - l) / 2;
if (nums[m] == key) {
return m;
} else if (nums[m] > key) {
h = m - 1;
} else {
l = m + 1;
}
}
return -1;
}
```
## 2. 时间复杂度
二分查找也称为折半查找,每次都能将查找区间减半,这种折半特性的算法时间复杂度为 O(logN)。
## 3. m 计算
有两种计算中值 m 的方式:
- m = (l + h) / 2
- m = l + (h - l) / 2
l + h 可能出现加法溢出,最好使用第二种方式。
## 4. 返回值
循环退出时如果仍然没有查找到 key那么表示查找失败。可以有两种返回值
- -1以一个错误码表示没有查找到 key
- l将 key 插入到 nums 中的正确位置
## 5. 变种
二分查找可以有很多变种,变种实现要注意边界值的判断。例如在一个有重复元素的数组中查找 key 的最左位置的实现如下:
```java
public int binarySearch(int[] nums, int key) {
int l = 0, h = nums.length - 1;
while (l < h) {
int m = l + (h - l) / 2;
if (nums[m] >= key) {
h = m;
} else {
l = m + 1;
}
}
return l;
}
```
该实现和正常实现有以下不同:
- 循环条件为 l < h
- h 的赋值表达式为 h = m
- 最后返回 l 而不是 -1
在 nums[m] >= key 的情况下,可以推导出最左 key 位于 [l, m] 区间中这是一个闭区间。h 的赋值表达式为 h = m因为 m 位置也可能是解。
在 h 的赋值表达式为 h = mid 的情况下,如果循环条件为 l <= h那么会出现循环无法退出的情况因此循环条件只能是 l < h以下演示了循环条件为 l <= h 时循环无法退出的情况
```text
nums = {0, 1, 2}, key = 1
l m h
0 1 2 nums[m] >= key
0 0 1 nums[m] < key
1 1 1 nums[m] >= key
1 1 1 nums[m] >= key
...
```
当循环体退出时,不表示没有查找到 key因此最后返回的结果不应该为 -1。为了验证有没有查找到需要在调用端判断一下返回位置上的值和 key 是否相等。
# 例题
## 1. 求开方
[69. Sqrt(x) (Easy)](https://leetcode.com/problems/sqrtx/description/)
```html
Input: 4
Output: 2
Input: 8
Output: 2
Explanation: The square root of 8 is 2.82842..., and since we want to return an integer, the decimal part will be truncated.
```
一个数 x 的开方 sqrt 一定在 0 \~ x 之间,并且满足 sqrt == x / sqrt。可以利用二分查找在 0 \~ x 之间查找 sqrt。
对于 x = 8它的开方是 2.82842...,最后应该返回 2 而不是 3。在循环条件为 l <= h 并且循环退出时h 总是比 l 小 1也就是说 h = 2l = 3因此最后的返回值应该为 h 而不是 l。
```java
public int mySqrt(int x) {
if (x <= 1) {
return x;
}
int l = 1, h = x;
while (l <= h) {
int mid = l + (h - l) / 2;
int sqrt = x / mid;
if (sqrt == mid) {
return mid;
} else if (mid > sqrt) {
h = mid - 1;
} else {
l = mid + 1;
}
}
return h;
}
```
## 2. 大于给定元素的最小元素
[744. Find Smallest Letter Greater Than Target (Easy)](https://leetcode.com/problems/find-smallest-letter-greater-than-target/description/)
```html
Input:
letters = ["c", "f", "j"]
target = "d"
Output: "f"
Input:
letters = ["c", "f", "j"]
target = "k"
Output: "c"
```
题目描述:给定一个有序的字符数组 letters 和一个字符 target要求找出 letters 中大于 target 的最小字符,如果找不到就返回第 1 个字符。
```java
public char nextGreatestLetter(char[] letters, char target) {
int n = letters.length;
int l = 0, h = n - 1;
while (l <= h) {
int m = l + (h - l) / 2;
if (letters[m] <= target) {
l = m + 1;
} else {
h = m - 1;
}
}
return l < n ? letters[l] : letters[0];
}
```
## 3. 有序数组的 Single Element
[540. Single Element in a Sorted Array (Medium)](https://leetcode.com/problems/single-element-in-a-sorted-array/description/)
```html
Input: [1, 1, 2, 3, 3, 4, 4, 8, 8]
Output: 2
```
题目描述:一个有序数组只有一个数不出现两次,找出这个数。要求以 O(logN) 时间复杂度进行求解。
令 index 为 Single Element 在数组中的位置。如果 m 为偶数,并且 m + 1 < index那么 nums[m] == nums[m + 1]m + 1 >= index那么 nums[m] != nums[m + 1]。
从上面的规律可以知道,如果 nums[m] == nums[m + 1],那么 index 所在的数组位置为 [m + 2, h],此时令 l = m + 2如果 nums[m] != nums[m + 1],那么 index 所在的数组位置为 [l, m],此时令 h = m。
因为 h 的赋值表达式为 h = m那么循环条件也就只能使用 l < h 这种形式
```java
public int singleNonDuplicate(int[] nums) {
int l = 0, h = nums.length - 1;
while (l < h) {
int m = l + (h - l) / 2;
if (m % 2 == 1) {
m--; // 保证 l/h/m 都在偶数位,使得查找区间大小一直都是奇数
}
if (nums[m] == nums[m + 1]) {
l = m + 2;
} else {
h = m;
}
}
return nums[l];
}
```
## 4. 第一个错误的版本
[278. First Bad Version (Easy)](https://leetcode.com/problems/first-bad-version/description/)
题目描述:给定一个元素 n 代表有 [1, 2, ..., n] 版本,可以调用 isBadVersion(int x) 知道某个版本是否错误,要求找到第一个错误的版本。
如果第 m 个版本出错,则表示第一个错误的版本在 [l, m] 之间,令 h = m否则第一个错误的版本在 [m + 1, h] 之间,令 l = m + 1。
因为 h 的赋值表达式为 h = m因此循环条件为 l < h
```java
public int firstBadVersion(int n) {
int l = 1, h = n;
while (l < h) {
int mid = l + (h - l) / 2;
if (isBadVersion(mid)) {
h = mid;
} else {
l = mid + 1;
}
}
return l;
}
```
## 5. 旋转数组的最小数字
[153. Find Minimum in Rotated Sorted Array (Medium)](https://leetcode.com/problems/find-minimum-in-rotated-sorted-array/description/)
```html
Input: [3,4,5,1,2],
Output: 1
```
```java
public int findMin(int[] nums) {
int l = 0, h = nums.length - 1;
while (l < h) {
int m = l + (h - l) / 2;
if (nums[m] <= nums[h]) {
h = m;
} else {
l = m + 1;
}
}
return nums[l];
}
```
## 6. 查找区间
[34. Search for a Range (Medium)](https://leetcode.com/problems/search-for-a-range/description/)
```html
Input: nums = [5,7,7,8,8,10], target = 8
Output: [3,4]
Input: nums = [5,7,7,8,8,10], target = 6
Output: [-1,-1]
```
```java
public int[] searchRange(int[] nums, int target) {
int first = binarySearch(nums, target);
int last = binarySearch(nums, target + 1) - 1;
if (first == nums.length || nums[first] != target) {
return new int[]{-1, -1};
} else {
return new int[]{first, Math.max(first, last)};
}
}
private int binarySearch(int[] nums, int target) {
int l = 0, h = nums.length; // 注意 h 的初始值
while (l < h) {
int m = l + (h - l) / 2;
if (nums[m] >= target) {
h = m;
} else {
l = m + 1;
}
}
return l;
}
```
</br><div align="center">⭐️欢迎关注我的公众号 CyC2018在公众号后台回复关键字 📚 **资料** 可领取复习大纲,这份大纲是我花了一整年时间整理的面试知识点列表,不仅系统整理了面试知识点,而且标注了各个知识点的重要程度,从而帮你理清多而杂的面试知识点。可以说我基本是按照这份大纲来进行复习的,这份大纲对我拿到了 BAT 头条等 Offer 起到很大的帮助。你们完全可以和我一样根据大纲上列的知识点来进行复习,就不用看很多不重要的内容,也可以知道哪些内容很重要从而多安排一些复习时间。</div></br>
<div align="center"><img width="180px" src="https://cyc-1256109796.cos.ap-guangzhou.myqcloud.com/%E5%85%AC%E4%BC%97%E5%8F%B7.jpg"></img></div>

View File

@ -0,0 +1,433 @@
<!-- GFM-TOC -->
* [原理](#原理)
* [1. 基本原理](#1-基本原理)
* [2. mask 计算](#2-mask-计算)
* [3. Java 中的位操作](#3-java-中的位操作)
* [例题](#例题)
* [统计两个数的二进制表示有多少位不同](#统计两个数的二进制表示有多少位不同)
* [数组中唯一一个不重复的元素](#数组中唯一一个不重复的元素)
* [找出数组中缺失的那个数](#找出数组中缺失的那个数)
* [数组中不重复的两个元素](#数组中不重复的两个元素)
* [翻转一个数的比特位](#翻转一个数的比特位)
* [不用额外变量交换两个整数](#不用额外变量交换两个整数)
* [判断一个数是不是 2 的 n 次方](#判断一个数是不是-2-的-n-次方)
* [判断一个数是不是 4 的 n 次方](#判断一个数是不是-4-的-n-次方)
* [判断一个数的位级表示是否不会出现连续的 0 和 1](#判断一个数的位级表示是否不会出现连续的-0-和-1)
* [求一个数的补码](#求一个数的补码)
* [实现整数的加法](#实现整数的加法)
* [字符串数组最大乘积](#字符串数组最大乘积)
* [统计从 0 \~ n 每个数的二进制表示中 1 的个数](#统计从-0-\~-n-每个数的二进制表示中-1-的个数)
<!-- GFM-TOC -->
# 原理
## 1. 基本原理
0s 表示一串 01s 表示一串 1。
```
x ^ 0s = x x & 0s = 0 x | 0s = x
x ^ 1s = ~x x & 1s = x x | 1s = 1s
x ^ x = 0 x & x = x x | x = x
```
- 利用 x ^ 1s = \~x 的特点,可以将位级表示翻转;利用 x ^ x = 0 的特点,可以将三个数中重复的两个数去除,只留下另一个数。
- 利用 x & 0s = 0 和 x & 1s = x 的特点,可以实现掩码操作。一个数 num 与 mask00111100 进行位与操作,只保留 num 中与 mask 的 1 部分相对应的位。
- 利用 x | 0s = x 和 x | 1s = 1s 的特点,可以实现设值操作。一个数 num 与 mask00111100 进行位或操作,将 num 中与 mask 的 1 部分相对应的位都设置为 1。
位与运算技巧:
- n&(n-1) 去除 n 的位级表示中最低的那一位。例如对于二进制表示 10110100减去 1 得到 10110011这两个数相与得到 10110000。
- n&(-n) 得到 n 的位级表示中最低的那一位。-n 得到 n 的反码加 1对于二进制表示 10110100-n 得到 01001100相与得到 00000100。
- n-n&(\~n+1) 去除 n 的位级表示中最高的那一位。
移位运算:
- \>\> n 为算术右移,相当于除以 2<sup>n</sup>
- \>\>\> n 为无符号右移,左边会补上 0。
- &lt;&lt; n 为算术左移,相当于乘以 2<sup>n</sup>
## 2. mask 计算
要获取 111111111将 0 取反即可,\~0。
要得到只有第 i 位为 1 的 mask将 1 向左移动 i-1 位即可1&lt;&lt;(i-1) 。例如 1&lt;&lt;4 得到只有第 5 位为 1 的 mask 00010000。
要得到 1 到 i 位为 1 的 mask1&lt;&lt;(i+1)-1 即可,例如将 1&lt;&lt;(4+1)-1 = 00010000-1 = 00001111。
要得到 1 到 i 位为 0 的 mask只需将 1 到 i 位为 1 的 mask 取反,即 \~(1&lt;&lt;(i+1)-1)。
## 3. Java 中的位操作
```html
static int Integer.bitCount(); // 统计 1 的数量
static int Integer.highestOneBit(); // 获得最高位
static String toBinaryString(int i); // 转换为二进制表示的字符串
```
# 例题
## 统计两个数的二进制表示有多少位不同
[461. Hamming Distance (Easy)](https://leetcode.com/problems/hamming-distance/)
```html
Input: x = 1, y = 4
Output: 2
Explanation:
1 (0 0 0 1)
4 (0 1 0 0)
↑ ↑
The above arrows point to positions where the corresponding bits are different.
```
对两个数进行异或操作,位级表示不同的那一位为 1统计有多少个 1 即可。
```java
public int hammingDistance(int x, int y) {
int z = x ^ y;
int cnt = 0;
while(z != 0) {
if ((z & 1) == 1) cnt++;
z = z >> 1;
}
return cnt;
}
```
使用 z&(z-1) 去除 z 位级表示最低的那一位。
```java
public int hammingDistance(int x, int y) {
int z = x ^ y;
int cnt = 0;
while (z != 0) {
z &= (z - 1);
cnt++;
}
return cnt;
}
```
可以使用 Integer.bitcount() 来统计 1 个的个数。
```java
public int hammingDistance(int x, int y) {
return Integer.bitCount(x ^ y);
}
```
## 数组中唯一一个不重复的元素
[136. Single Number (Easy)](https://leetcode.com/problems/single-number/description/)
```html
Input: [4,1,2,1,2]
Output: 4
```
两个相同的数异或的结果为 0对所有数进行异或操作最后的结果就是单独出现的那个数。
```java
public int singleNumber(int[] nums) {
int ret = 0;
for (int n : nums) ret = ret ^ n;
return ret;
}
```
## 找出数组中缺失的那个数
[268. Missing Number (Easy)](https://leetcode.com/problems/missing-number/description/)
```html
Input: [3,0,1]
Output: 2
```
题目描述:数组元素在 0-n 之间,但是有一个数是缺失的,要求找到这个缺失的数。
```java
public int missingNumber(int[] nums) {
int ret = 0;
for (int i = 0; i < nums.length; i++) {
ret = ret ^ i ^ nums[i];
}
return ret ^ nums.length;
}
```
## 数组中不重复的两个元素
[260. Single Number III (Medium)](https://leetcode.com/problems/single-number-iii/description/)
两个不相等的元素在位级表示上必定会有一位存在不同。
将数组的所有元素异或得到的结果为不存在重复的两个元素异或的结果。
diff &= -diff 得到出 diff 最右侧不为 0 的位,也就是不存在重复的两个元素在位级表示上最右侧不同的那一位,利用这一位就可以将两个元素区分开来。
```java
public int[] singleNumber(int[] nums) {
int diff = 0;
for (int num : nums) diff ^= num;
diff &= -diff; // 得到最右一位
int[] ret = new int[2];
for (int num : nums) {
if ((num & diff) == 0) ret[0] ^= num;
else ret[1] ^= num;
}
return ret;
}
```
## 翻转一个数的比特位
[190. Reverse Bits (Easy)](https://leetcode.com/problems/reverse-bits/description/)
```java
public int reverseBits(int n) {
int ret = 0;
for (int i = 0; i < 32; i++) {
ret <<= 1;
ret |= (n & 1);
n >>>= 1;
}
return ret;
}
```
如果该函数需要被调用很多次,可以将 int 拆成 4 个 byte然后缓存 byte 对应的比特位翻转,最后再拼接起来。
```java
private static Map<Byte, Integer> cache = new HashMap<>();
public int reverseBits(int n) {
int ret = 0;
for (int i = 0; i < 4; i++) {
ret <<= 8;
ret |= reverseByte((byte) (n & 0b11111111));
n >>= 8;
}
return ret;
}
private int reverseByte(byte b) {
if (cache.containsKey(b)) return cache.get(b);
int ret = 0;
byte t = b;
for (int i = 0; i < 8; i++) {
ret <<= 1;
ret |= t & 1;
t >>= 1;
}
cache.put(b, ret);
return ret;
}
```
## 不用额外变量交换两个整数
[程序员代码面试指南 P317](#)
```java
a = a ^ b;
b = a ^ b;
a = a ^ b;
```
## 判断一个数是不是 2 的 n 次方
[231. Power of Two (Easy)](https://leetcode.com/problems/power-of-two/description/)
二进制表示只有一个 1 存在。
```java
public boolean isPowerOfTwo(int n) {
return n > 0 && Integer.bitCount(n) == 1;
}
```
利用 1000 & 0111 == 0 这种性质,得到以下解法:
```java
public boolean isPowerOfTwo(int n) {
return n > 0 && (n & (n - 1)) == 0;
}
```
## 判断一个数是不是 4 的 n 次方
[342. Power of Four (Easy)](https://leetcode.com/problems/power-of-four/)
这种数在二进制表示中有且只有一个奇数位为 1例如 1610000
```java
public boolean isPowerOfFour(int num) {
return num > 0 && (num & (num - 1)) == 0 && (num & 0b01010101010101010101010101010101) != 0;
}
```
也可以使用正则表达式进行匹配。
```java
public boolean isPowerOfFour(int num) {
return Integer.toString(num, 4).matches("10*");
}
```
## 判断一个数的位级表示是否不会出现连续的 0 和 1
[693. Binary Number with Alternating Bits (Easy)](https://leetcode.com/problems/binary-number-with-alternating-bits/description/)
```html
Input: 10
Output: True
Explanation:
The binary representation of 10 is: 1010.
Input: 11
Output: False
Explanation:
The binary representation of 11 is: 1011.
```
对于 1010 这种位级表示的数,把它向右移动 1 位得到 101这两个数每个位都不同因此异或得到的结果为 1111。
```java
public boolean hasAlternatingBits(int n) {
int a = (n ^ (n >> 1));
return (a & (a + 1)) == 0;
}
```
## 求一个数的补码
[476. Number Complement (Easy)](https://leetcode.com/problems/number-complement/description/)
```html
Input: 5
Output: 2
Explanation: The binary representation of 5 is 101 (no leading zero bits), and its complement is 010. So you need to output 2.
```
题目描述:不考虑二进制表示中的首 0 部分。
对于 00000101要求补码可以将它与 00000111 进行异或操作。那么问题就转换为求掩码 00000111。
```java
public int findComplement(int num) {
if (num == 0) return 1;
int mask = 1 << 30;
while ((num & mask) == 0) mask >>= 1;
mask = (mask << 1) - 1;
return num ^ mask;
}
```
可以利用 Java 的 Integer.highestOneBit() 方法来获得含有首 1 的数。
```java
public int findComplement(int num) {
if (num == 0) return 1;
int mask = Integer.highestOneBit(num);
mask = (mask << 1) - 1;
return num ^ mask;
}
```
对于 10000000 这样的数要扩展成 11111111可以利用以下方法
```html
mask |= mask >> 1 11000000
mask |= mask >> 2 11110000
mask |= mask >> 4 11111111
```
```java
public int findComplement(int num) {
int mask = num;
mask |= mask >> 1;
mask |= mask >> 2;
mask |= mask >> 4;
mask |= mask >> 8;
mask |= mask >> 16;
return (mask ^ num);
}
```
## 实现整数的加法
[371. Sum of Two Integers (Easy)](https://leetcode.com/problems/sum-of-two-integers/description/)
a ^ b 表示没有考虑进位的情况下两数的和,(a & b) << 1 就是进位
递归会终止的原因是 (a & b) << 1 最右边会多一个 0那么继续递归进位最右边的 0 会慢慢增多最后进位会变为 0递归终止
```java
public int getSum(int a, int b) {
return b == 0 ? a : getSum((a ^ b), (a & b) << 1);
}
```
## 字符串数组最大乘积
[318. Maximum Product of Word Lengths (Medium)](https://leetcode.com/problems/maximum-product-of-word-lengths/description/)
```html
Given ["abcw", "baz", "foo", "bar", "xtfn", "abcdef"]
Return 16
The two words can be "abcw", "xtfn".
```
题目描述:字符串数组的字符串只含有小写字符。求解字符串数组中两个字符串长度的最大乘积,要求这两个字符串不能含有相同字符。
本题主要问题是判断两个字符串是否含相同字符,由于字符串只含有小写字符,总共 26 位,因此可以用一个 32 位的整数来存储每个字符是否出现过。
```java
public int maxProduct(String[] words) {
int n = words.length;
int[] val = new int[n];
for (int i = 0; i < n; i++) {
for (char c : words[i].toCharArray()) {
val[i] |= 1 << (c - 'a');
}
}
int ret = 0;
for (int i = 0; i < n; i++) {
for (int j = i + 1; j < n; j++) {
if ((val[i] & val[j]) == 0) {
ret = Math.max(ret, words[i].length() * words[j].length());
}
}
}
return ret;
}
```
## 统计从 0 \~ n 每个数的二进制表示中 1 的个数
[338. Counting Bits (Medium)](https://leetcode.com/problems/counting-bits/description/)
对于数字 6(110),它可以看成是 4(100) 再加一个 2(10),因此 dp[i] = dp[i&(i-1)] + 1;
```java
public int[] countBits(int num) {
int[] ret = new int[num + 1];
for(int i = 1; i <= num; i++){
ret[i] = ret[i&(i-1)] + 1;
}
return ret;
}
```
</br><div align="center">⭐️欢迎关注我的公众号 CyC2018在公众号后台回复关键字 📚 **资料** 可领取复习大纲,这份大纲是我花了一整年时间整理的面试知识点列表,不仅系统整理了面试知识点,而且标注了各个知识点的重要程度,从而帮你理清多而杂的面试知识点。可以说我基本是按照这份大纲来进行复习的,这份大纲对我拿到了 BAT 头条等 Offer 起到很大的帮助。你们完全可以和我一样根据大纲上列的知识点来进行复习,就不用看很多不重要的内容,也可以知道哪些内容很重要从而多安排一些复习时间。</div></br>
<div align="center"><img width="180px" src="https://cyc-1256109796.cos.ap-guangzhou.myqcloud.com/%E5%85%AC%E4%BC%97%E5%8F%B7.jpg"></img></div>

View File

@ -0,0 +1,55 @@
<!-- GFM-TOC -->
* [1. 给表达式加括号](#1-给表达式加括号)
<!-- GFM-TOC -->
# 1. 给表达式加括号
[241. Different Ways to Add Parentheses (Medium)](https://leetcode.com/problems/different-ways-to-add-parentheses/description/)
```html
Input: "2-1-1".
((2-1)-1) = 0
(2-(1-1)) = 2
Output : [0, 2]
```
```java
public List<Integer> diffWaysToCompute(String input) {
List<Integer> ways = new ArrayList<>();
for (int i = 0; i < input.length(); i++) {
char c = input.charAt(i);
if (c == '+' || c == '-' || c == '*') {
List<Integer> left = diffWaysToCompute(input.substring(0, i));
List<Integer> right = diffWaysToCompute(input.substring(i + 1));
for (int l : left) {
for (int r : right) {
switch (c) {
case '+':
ways.add(l + r);
break;
case '-':
ways.add(l - r);
break;
case '*':
ways.add(l * r);
break;
}
}
}
}
}
if (ways.size() == 0) {
ways.add(Integer.valueOf(input));
}
return ways;
}
```
</br><div align="center">⭐️欢迎关注我的公众号 CyC2018在公众号后台回复关键字 📚 **资料** 可领取复习大纲,这份大纲是我花了一整年时间整理的面试知识点列表,不仅系统整理了面试知识点,而且标注了各个知识点的重要程度,从而帮你理清多而杂的面试知识点。可以说我基本是按照这份大纲来进行复习的,这份大纲对我拿到了 BAT 头条等 Offer 起到很大的帮助。你们完全可以和我一样根据大纲上列的知识点来进行复习,就不用看很多不重要的内容,也可以知道哪些内容很重要从而多安排一些复习时间。</div></br>
<div align="center"><img width="180px" src="https://cyc-1256109796.cos.ap-guangzhou.myqcloud.com/%E5%85%AC%E4%BC%97%E5%8F%B7.jpg"></img></div>

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,244 @@
<!-- GFM-TOC -->
* [有序数组的 Two Sum](#有序数组的-two-sum)
* [两数平方和](#两数平方和)
* [反转字符串中的元音字符](#反转字符串中的元音字符)
* [回文字符串](#回文字符串)
* [归并两个有序数组](#归并两个有序数组)
* [判断链表是否存在环](#判断链表是否存在环)
* [最长子序列](#最长子序列)
<!-- GFM-TOC -->
双指针主要用于遍历数组,两个指针指向不同的元素,从而协同完成任务。
# 有序数组的 Two Sum
[Leetcode 167. Two Sum II - Input array is sorted (Easy)](https://leetcode.com/problems/two-sum-ii-input-array-is-sorted/description/)
```html
Input: numbers={2, 7, 11, 15}, target=9
Output: index1=1, index2=2
```
题目描述:在有序数组中找出两个数,使它们的和为 target。
使用双指针,一个指针指向值较小的元素,一个指针指向值较大的元素。指向较小元素的指针从头向尾遍历,指向较大元素的指针从尾向头遍历。
- 如果两个指针指向元素的和 sum == target那么得到要求的结果
- 如果 sum > target移动较大的元素使 sum 变小一些;
- 如果 sum < target移动较小的元素使 sum 变大一些
```java
public int[] twoSum(int[] numbers, int target) {
int i = 0, j = numbers.length - 1;
while (i < j) {
int sum = numbers[i] + numbers[j];
if (sum == target) {
return new int[]{i + 1, j + 1};
} else if (sum < target) {
i++;
} else {
j--;
}
}
return null;
}
```
# 两数平方和
[633. Sum of Square Numbers (Easy)](https://leetcode.com/problems/sum-of-square-numbers/description/)
```html
Input: 5
Output: True
Explanation: 1 * 1 + 2 * 2 = 5
```
题目描述:判断一个数是否为两个数的平方和。
```java
public boolean judgeSquareSum(int c) {
int i = 0, j = (int) Math.sqrt(c);
while (i <= j) {
int powSum = i * i + j * j;
if (powSum == c) {
return true;
} else if (powSum > c) {
j--;
} else {
i++;
}
}
return false;
}
```
# 反转字符串中的元音字符
[345. Reverse Vowels of a String (Easy)](https://leetcode.com/problems/reverse-vowels-of-a-string/description/)
```html
Given s = "leetcode", return "leotcede".
```
使用双指针指向待反转的两个元音字符,一个指针从头向尾遍历,一个指针从尾到头遍历。
```java
private final static HashSet<Character> vowels = new HashSet<>(Arrays.asList('a', 'e', 'i', 'o', 'u', 'A', 'E', 'I', 'O', 'U'));
public String reverseVowels(String s) {
int i = 0, j = s.length() - 1;
char[] result = new char[s.length()];
while (i <= j) {
char ci = s.charAt(i);
char cj = s.charAt(j);
if (!vowels.contains(ci)) {
result[i++] = ci;
} else if (!vowels.contains(cj)) {
result[j--] = cj;
} else {
result[i++] = cj;
result[j--] = ci;
}
}
return new String(result);
}
```
# 回文字符串
[680. Valid Palindrome II (Easy)](https://leetcode.com/problems/valid-palindrome-ii/description/)
```html
Input: "abca"
Output: True
Explanation: You could delete the character 'c'.
```
题目描述:可以删除一个字符,判断是否能构成回文字符串。
```java
public boolean validPalindrome(String s) {
int i = -1, j = s.length();
while (++i < --j) {
if (s.charAt(i) != s.charAt(j)) {
return isPalindrome(s, i, j - 1) || isPalindrome(s, i + 1, j);
}
}
return true;
}
private boolean isPalindrome(String s, int i, int j) {
while (i < j) {
if (s.charAt(i++) != s.charAt(j--)) {
return false;
}
}
return true;
}
```
# 归并两个有序数组
[88. Merge Sorted Array (Easy)](https://leetcode.com/problems/merge-sorted-array/description/)
```html
Input:
nums1 = [1,2,3,0,0,0], m = 3
nums2 = [2,5,6], n = 3
Output: [1,2,2,3,5,6]
```
题目描述:把归并结果存到第一个数组上。
需要从尾开始遍历,否则在 nums1 上归并得到的值会覆盖还未进行归并比较的值。
```java
public void merge(int[] nums1, int m, int[] nums2, int n) {
int index1 = m - 1, index2 = n - 1;
int indexMerge = m + n - 1;
while (index1 >= 0 || index2 >= 0) {
if (index1 < 0) {
nums1[indexMerge--] = nums2[index2--];
} else if (index2 < 0) {
nums1[indexMerge--] = nums1[index1--];
} else if (nums1[index1] > nums2[index2]) {
nums1[indexMerge--] = nums1[index1--];
} else {
nums1[indexMerge--] = nums2[index2--];
}
}
}
```
# 判断链表是否存在环
[141. Linked List Cycle (Easy)](https://leetcode.com/problems/linked-list-cycle/description/)
使用双指针,一个指针每次移动一个节点,一个指针每次移动两个节点,如果存在环,那么这两个指针一定会相遇。
```java
public boolean hasCycle(ListNode head) {
if (head == null) {
return false;
}
ListNode l1 = head, l2 = head.next;
while (l1 != null && l2 != null && l2.next != null) {
if (l1 == l2) {
return true;
}
l1 = l1.next;
l2 = l2.next.next;
}
return false;
}
```
# 最长子序列
[524. Longest Word in Dictionary through Deleting (Medium)](https://leetcode.com/problems/longest-word-in-dictionary-through-deleting/description/)
```
Input:
s = "abpcplea", d = ["ale","apple","monkey","plea"]
Output:
"apple"
```
题目描述:删除 s 中的一些字符,使得它构成字符串列表 d 中的一个字符串,找出能构成的最长字符串。如果有多个相同长度的结果,返回字典序的最小字符串。
```java
public String findLongestWord(String s, List<String> d) {
String longestWord = "";
for (String target : d) {
int l1 = longestWord.length(), l2 = target.length();
if (l1 > l2 || (l1 == l2 && longestWord.compareTo(target) < 0)) {
continue;
}
if (isValid(s, target)) {
longestWord = target;
}
}
return longestWord;
}
private boolean isValid(String s, String target) {
int i = 0, j = 0;
while (i < s.length() && j < target.length()) {
if (s.charAt(i) == target.charAt(j)) {
j++;
}
i++;
}
return j == target.length();
}
```
</br><div align="center">⭐️欢迎关注我的公众号 CyC2018在公众号后台回复关键字 📚 **资料** 可领取复习大纲,这份大纲是我花了一整年时间整理的面试知识点列表,不仅系统整理了面试知识点,而且标注了各个知识点的重要程度,从而帮你理清多而杂的面试知识点。可以说我基本是按照这份大纲来进行复习的,这份大纲对我拿到了 BAT 头条等 Offer 起到很大的帮助。你们完全可以和我一样根据大纲上列的知识点来进行复习,就不用看很多不重要的内容,也可以知道哪些内容很重要从而多安排一些复习时间。</div></br>
<div align="center"><img width="180px" src="https://cyc-1256109796.cos.ap-guangzhou.myqcloud.com/%E5%85%AC%E4%BC%97%E5%8F%B7.jpg"></img></div>

View File

@ -0,0 +1,129 @@
<!-- GFM-TOC -->
* [1. 数组中两个数的和为给定值](#1-数组中两个数的和为给定值)
* [2. 判断数组是否含有重复元素](#2-判断数组是否含有重复元素)
* [3. 最长和谐序列](#3-最长和谐序列)
* [4. 最长连续序列](#4-最长连续序列)
<!-- GFM-TOC -->
哈希表使用 O(N) 空间复杂度存储数据,并且以 O(1) 时间复杂度求解问题。
- Java 中的 **HashSet** 用于存储一个集合,可以查找元素是否在集合中。如果元素有穷,并且范围不大,那么可以用一个布尔数组来存储一个元素是否存在。例如对于只有小写字符的元素,就可以用一个长度为 26 的布尔数组来存储一个字符集合,使得空间复杂度降低为 O(1)。
- Java 中的 **HashMap** 主要用于映射关系从而把两个元素联系起来。HashMap 也可以用来对元素进行计数统计,此时键为元素,值为计数。和 HashSet 类似,如果元素有穷并且范围不大,可以用整型数组来进行统计。在对一个内容进行压缩或者其它转换时,利用 HashMap 可以把原始内容和转换后的内容联系起来。例如在一个简化 url 的系统中 [Leetcdoe : 535. Encode and Decode TinyURL (Medium)](https://leetcode.com/problems/encode-and-decode-tinyurl/description/),利用 HashMap 就可以存储精简后的 url 到原始 url 的映射,使得不仅可以显示简化的 url也可以根据简化的 url 得到原始 url 从而定位到正确的资源。
# 1. 数组中两个数的和为给定值
[1. Two Sum (Easy)](https://leetcode.com/problems/two-sum/description/)
可以先对数组进行排序,然后使用双指针方法或者二分查找方法。这样做的时间复杂度为 O(NlogN),空间复杂度为 O(1)。
用 HashMap 存储数组元素和索引的映射,在访问到 nums[i] 时,判断 HashMap 中是否存在 target - nums[i],如果存在说明 target - nums[i] 所在的索引和 i 就是要找的两个数。该方法的时间复杂度为 O(N),空间复杂度为 O(N),使用空间来换取时间。
```java
public int[] twoSum(int[] nums, int target) {
HashMap<Integer, Integer> indexForNum = new HashMap<>();
for (int i = 0; i < nums.length; i++) {
if (indexForNum.containsKey(target - nums[i])) {
return new int[]{indexForNum.get(target - nums[i]), i};
} else {
indexForNum.put(nums[i], i);
}
}
return null;
}
```
# 2. 判断数组是否含有重复元素
[217. Contains Duplicate (Easy)](https://leetcode.com/problems/contains-duplicate/description/)
```java
public boolean containsDuplicate(int[] nums) {
Set<Integer> set = new HashSet<>();
for (int num : nums) {
set.add(num);
}
return set.size() < nums.length;
}
```
# 3. 最长和谐序列
[594. Longest Harmonious Subsequence (Easy)](https://leetcode.com/problems/longest-harmonious-subsequence/description/)
```html
Input: [1,3,2,2,5,2,3,7]
Output: 5
Explanation: The longest harmonious subsequence is [3,2,2,2,3].
```
和谐序列中最大数和最小数之差正好为 1应该注意的是序列的元素不一定是数组的连续元素。
```java
public int findLHS(int[] nums) {
Map<Integer, Integer> countForNum = new HashMap<>();
for (int num : nums) {
countForNum.put(num, countForNum.getOrDefault(num, 0) + 1);
}
int longest = 0;
for (int num : countForNum.keySet()) {
if (countForNum.containsKey(num + 1)) {
longest = Math.max(longest, countForNum.get(num + 1) + countForNum.get(num));
}
}
return longest;
}
```
# 4. 最长连续序列
[128. Longest Consecutive Sequence (Hard)](https://leetcode.com/problems/longest-consecutive-sequence/description/)
```html
Given [100, 4, 200, 1, 3, 2],
The longest consecutive elements sequence is [1, 2, 3, 4]. Return its length: 4.
```
要求以 O(N) 的时间复杂度求解。
```java
public int longestConsecutive(int[] nums) {
Map<Integer, Integer> countForNum = new HashMap<>();
for (int num : nums) {
countForNum.put(num, 1);
}
for (int num : nums) {
forward(countForNum, num);
}
return maxCount(countForNum);
}
private int forward(Map<Integer, Integer> countForNum, int num) {
if (!countForNum.containsKey(num)) {
return 0;
}
int cnt = countForNum.get(num);
if (cnt > 1) {
return cnt;
}
cnt = forward(countForNum, num + 1) + 1;
countForNum.put(num, cnt);
return cnt;
}
private int maxCount(Map<Integer, Integer> countForNum) {
int max = 0;
for (int num : countForNum.keySet()) {
max = Math.max(max, countForNum.get(num));
}
return max;
}
```
</br><div align="center">⭐️欢迎关注我的公众号 CyC2018在公众号后台回复关键字 📚 **资料** 可领取复习大纲,这份大纲是我花了一整年时间整理的面试知识点列表,不仅系统整理了面试知识点,而且标注了各个知识点的重要程度,从而帮你理清多而杂的面试知识点。可以说我基本是按照这份大纲来进行复习的,这份大纲对我拿到了 BAT 头条等 Offer 起到很大的帮助。你们完全可以和我一样根据大纲上列的知识点来进行复习,就不用看很多不重要的内容,也可以知道哪些内容很重要从而多安排一些复习时间。</div></br>
<div align="center"><img width="180px" src="https://cyc-1256109796.cos.ap-guangzhou.myqcloud.com/%E5%85%AC%E4%BC%97%E5%8F%B7.jpg"></img></div>

View File

@ -0,0 +1,263 @@
<!-- GFM-TOC -->
* [二分图](#二分图)
* [判断是否为二分图](#判断是否为二分图)
* [拓扑排序](#拓扑排序)
* [课程安排的合法性](#课程安排的合法性)
* [课程安排的顺序](#课程安排的顺序)
* [并查集](#并查集)
* [冗余连接](#冗余连接)
<!-- GFM-TOC -->
# 二分图
如果可以用两种颜色对图中的节点进行着色,并且保证相邻的节点颜色不同,那么这个图就是二分图。
## 判断是否为二分图
[785. Is Graph Bipartite? (Medium)](https://leetcode.com/problems/is-graph-bipartite/description/)
```html
Input: [[1,3], [0,2], [1,3], [0,2]]
Output: true
Explanation:
The graph looks like this:
0----1
| |
| |
3----2
We can divide the vertices into two groups: {0, 2} and {1, 3}.
```
```html
Example 2:
Input: [[1,2,3], [0,2], [0,1,3], [0,2]]
Output: false
Explanation:
The graph looks like this:
0----1
| \ |
| \ |
3----2
We cannot find a way to divide the set of nodes into two independent subsets.
```
```java
public boolean isBipartite(int[][] graph) {
int[] colors = new int[graph.length];
Arrays.fill(colors, -1);
for (int i = 0; i < graph.length; i++) { // 处理图不是连通的情况
if (colors[i] == -1 && !isBipartite(i, 0, colors, graph)) {
return false;
}
}
return true;
}
private boolean isBipartite(int curNode, int curColor, int[] colors, int[][] graph) {
if (colors[curNode] != -1) {
return colors[curNode] == curColor;
}
colors[curNode] = curColor;
for (int nextNode : graph[curNode]) {
if (!isBipartite(nextNode, 1 - curColor, colors, graph)) {
return false;
}
}
return true;
}
```
# 拓扑排序
常用于在具有先序关系的任务规划中。
## 课程安排的合法性
[207. Course Schedule (Medium)](https://leetcode.com/problems/course-schedule/description/)
```html
2, [[1,0]]
return true
```
```html
2, [[1,0],[0,1]]
return false
```
题目描述:一个课程可能会先修课程,判断给定的先修课程规定是否合法。
本题不需要使用拓扑排序,只需要检测有向图是否存在环即可。
```java
public boolean canFinish(int numCourses, int[][] prerequisites) {
List<Integer>[] graphic = new List[numCourses];
for (int i = 0; i < numCourses; i++) {
graphic[i] = new ArrayList<>();
}
for (int[] pre : prerequisites) {
graphic[pre[0]].add(pre[1]);
}
boolean[] globalMarked = new boolean[numCourses];
boolean[] localMarked = new boolean[numCourses];
for (int i = 0; i < numCourses; i++) {
if (hasCycle(globalMarked, localMarked, graphic, i)) {
return false;
}
}
return true;
}
private boolean hasCycle(boolean[] globalMarked, boolean[] localMarked,
List<Integer>[] graphic, int curNode) {
if (localMarked[curNode]) {
return true;
}
if (globalMarked[curNode]) {
return false;
}
globalMarked[curNode] = true;
localMarked[curNode] = true;
for (int nextNode : graphic[curNode]) {
if (hasCycle(globalMarked, localMarked, graphic, nextNode)) {
return true;
}
}
localMarked[curNode] = false;
return false;
}
```
## 课程安排的顺序
[210. Course Schedule II (Medium)](https://leetcode.com/problems/course-schedule-ii/description/)
```html
4, [[1,0],[2,0],[3,1],[3,2]]
There are a total of 4 courses to take. To take course 3 you should have finished both courses 1 and 2. Both courses 1 and 2 should be taken after you finished course 0. So one correct course order is [0,1,2,3]. Another correct ordering is[0,2,1,3].
```
使用 DFS 来实现拓扑排序,使用一个栈存储后序遍历结果,这个栈的逆序结果就是拓扑排序结果。
证明对于任何先序关系v->w后序遍历结果可以保证 w 先进入栈中,因此栈的逆序结果中 v 会在 w 之前。
```java
public int[] findOrder(int numCourses, int[][] prerequisites) {
List<Integer>[] graphic = new List[numCourses];
for (int i = 0; i < numCourses; i++) {
graphic[i] = new ArrayList<>();
}
for (int[] pre : prerequisites) {
graphic[pre[0]].add(pre[1]);
}
Stack<Integer> postOrder = new Stack<>();
boolean[] globalMarked = new boolean[numCourses];
boolean[] localMarked = new boolean[numCourses];
for (int i = 0; i < numCourses; i++) {
if (hasCycle(globalMarked, localMarked, graphic, i, postOrder)) {
return new int[0];
}
}
int[] orders = new int[numCourses];
for (int i = numCourses - 1; i >= 0; i--) {
orders[i] = postOrder.pop();
}
return orders;
}
private boolean hasCycle(boolean[] globalMarked, boolean[] localMarked, List<Integer>[] graphic,
int curNode, Stack<Integer> postOrder) {
if (localMarked[curNode]) {
return true;
}
if (globalMarked[curNode]) {
return false;
}
globalMarked[curNode] = true;
localMarked[curNode] = true;
for (int nextNode : graphic[curNode]) {
if (hasCycle(globalMarked, localMarked, graphic, nextNode, postOrder)) {
return true;
}
}
localMarked[curNode] = false;
postOrder.push(curNode);
return false;
}
```
# 并查集
并查集可以动态地连通两个点,并且可以非常快速地判断两个点是否连通。
## 冗余连接
[684. Redundant Connection (Medium)](https://leetcode.com/problems/redundant-connection/description/)
```html
Input: [[1,2], [1,3], [2,3]]
Output: [2,3]
Explanation: The given undirected graph will be like this:
1
/ \
2 - 3
```
题目描述:有一系列的边连成的图,找出一条边,移除它之后该图能够成为一棵树。
```java
public int[] findRedundantConnection(int[][] edges) {
int N = edges.length;
UF uf = new UF(N);
for (int[] e : edges) {
int u = e[0], v = e[1];
if (uf.connect(u, v)) {
return e;
}
uf.union(u, v);
}
return new int[]{-1, -1};
}
private class UF {
private int[] id;
UF(int N) {
id = new int[N + 1];
for (int i = 0; i < id.length; i++) {
id[i] = i;
}
}
void union(int u, int v) {
int uID = find(u);
int vID = find(v);
if (uID == vID) {
return;
}
for (int i = 0; i < id.length; i++) {
if (id[i] == uID) {
id[i] = vID;
}
}
}
int find(int p) {
return id[p];
}
boolean connect(int u, int v) {
return find(u) == find(v);
}
}
```
</br><div align="center">⭐️欢迎关注我的公众号 CyC2018在公众号后台回复关键字 📚 **资料** 可领取复习大纲,这份大纲是我花了一整年时间整理的面试知识点列表,不仅系统整理了面试知识点,而且标注了各个知识点的重要程度,从而帮你理清多而杂的面试知识点。可以说我基本是按照这份大纲来进行复习的,这份大纲对我拿到了 BAT 头条等 Offer 起到很大的帮助。你们完全可以和我一样根据大纲上列的知识点来进行复习,就不用看很多不重要的内容,也可以知道哪些内容很重要从而多安排一些复习时间。</div></br>
<div align="center"><img width="180px" src="https://cyc-1256109796.cos.ap-guangzhou.myqcloud.com/%E5%85%AC%E4%BC%97%E5%8F%B7.jpg"></img></div>

View File

@ -0,0 +1,231 @@
<!-- GFM-TOC -->
* [字符串循环移位包含](#字符串循环移位包含)
* [字符串循环移位](#字符串循环移位)
* [字符串中单词的翻转](#字符串中单词的翻转)
* [两个字符串包含的字符是否完全相同](#两个字符串包含的字符是否完全相同)
* [计算一组字符集合可以组成的回文字符串的最大长度](#计算一组字符集合可以组成的回文字符串的最大长度)
* [字符串同构](#字符串同构)
* [回文子字符串个数](#回文子字符串个数)
* [判断一个整数是否是回文数](#判断一个整数是否是回文数)
* [统计二进制字符串中连续 1 和连续 0 数量相同的子字符串个数](#统计二进制字符串中连续-1-和连续-0-数量相同的子字符串个数)
<!-- GFM-TOC -->
# 字符串循环移位包含
[编程之美 3.1](#)
```html
s1 = AABCD, s2 = CDAA
Return : true
```
给定两个字符串 s1 和 s2要求判定 s2 是否能够被 s1 做循环移位得到的字符串包含。
s1 进行循环移位的结果是 s1s1 的子字符串,因此只要判断 s2 是否是 s1s1 的子字符串即可。
# 字符串循环移位
[编程之美 2.17](#)
```html
s = "abcd123" k = 3
Return "123abcd"
```
将字符串向右循环移动 k 位。
将 abcd123 中的 abcd 和 123 单独翻转,得到 dcba321然后对整个字符串进行翻转得到 123abcd。
# 字符串中单词的翻转
[程序员代码面试指南](#)
```html
s = "I am a student"
Return "student a am I"
```
将每个单词翻转,然后将整个字符串翻转。
# 两个字符串包含的字符是否完全相同
[242. Valid Anagram (Easy)](https://leetcode.com/problems/valid-anagram/description/)
```html
s = "anagram", t = "nagaram", return true.
s = "rat", t = "car", return false.
```
可以用 HashMap 来映射字符与出现次数,然后比较两个字符串出现的字符数量是否相同。
由于本题的字符串只包含 26 个小写字符,因此可以使用长度为 26 的整型数组对字符串出现的字符进行统计,不再使用 HashMap。
```java
public boolean isAnagram(String s, String t) {
int[] cnts = new int[26];
for (char c : s.toCharArray()) {
cnts[c - 'a']++;
}
for (char c : t.toCharArray()) {
cnts[c - 'a']--;
}
for (int cnt : cnts) {
if (cnt != 0) {
return false;
}
}
return true;
}
```
# 计算一组字符集合可以组成的回文字符串的最大长度
[409. Longest Palindrome (Easy)](https://leetcode.com/problems/longest-palindrome/description/)
```html
Input : "abccccdd"
Output : 7
Explanation : One longest palindrome that can be built is "dccaccd", whose length is 7.
```
使用长度为 256 的整型数组来统计每个字符出现的个数,每个字符有偶数个可以用来构成回文字符串。
因为回文字符串最中间的那个字符可以单独出现,所以如果有单独的字符就把它放到最中间。
```java
public int longestPalindrome(String s) {
int[] cnts = new int[256];
for (char c : s.toCharArray()) {
cnts[c]++;
}
int palindrome = 0;
for (int cnt : cnts) {
palindrome += (cnt / 2) * 2;
}
if (palindrome < s.length()) {
palindrome++; // 这个条件下 s 中一定有单个未使用的字符存在,可以把这个字符放到回文的最中间
}
return palindrome;
}
```
# 字符串同构
[205. Isomorphic Strings (Easy)](https://leetcode.com/problems/isomorphic-strings/description/)
```html
Given "egg", "add", return true.
Given "foo", "bar", return false.
Given "paper", "title", return true.
```
记录一个字符上次出现的位置,如果两个字符串中的字符上次出现的位置一样,那么就属于同构。
```java
public boolean isIsomorphic(String s, String t) {
int[] preIndexOfS = new int[256];
int[] preIndexOfT = new int[256];
for (int i = 0; i < s.length(); i++) {
char sc = s.charAt(i), tc = t.charAt(i);
if (preIndexOfS[sc] != preIndexOfT[tc]) {
return false;
}
preIndexOfS[sc] = i + 1;
preIndexOfT[tc] = i + 1;
}
return true;
}
```
# 回文子字符串个数
[647. Palindromic Substrings (Medium)](https://leetcode.com/problems/palindromic-substrings/description/)
```html
Input: "aaa"
Output: 6
Explanation: Six palindromic strings: "a", "a", "a", "aa", "aa", "aaa".
```
从字符串的某一位开始,尝试着去扩展子字符串。
```java
private int cnt = 0;
public int countSubstrings(String s) {
for (int i = 0; i < s.length(); i++) {
extendSubstrings(s, i, i); // 奇数长度
extendSubstrings(s, i, i + 1); // 偶数长度
}
return cnt;
}
private void extendSubstrings(String s, int start, int end) {
while (start >= 0 && end < s.length() && s.charAt(start) == s.charAt(end)) {
start--;
end++;
cnt++;
}
}
```
# 判断一个整数是否是回文数
[9. Palindrome Number (Easy)](https://leetcode.com/problems/palindrome-number/description/)
要求不能使用额外空间,也就不能将整数转换为字符串进行判断。
将整数分成左右两部分,右边那部分需要转置,然后判断这两部分是否相等。
```java
public boolean isPalindrome(int x) {
if (x == 0) {
return true;
}
if (x < 0 || x % 10 == 0) {
return false;
}
int right = 0;
while (x > right) {
right = right * 10 + x % 10;
x /= 10;
}
return x == right || x == right / 10;
}
```
# 统计二进制字符串中连续 1 和连续 0 数量相同的子字符串个数
[696. Count Binary Substrings (Easy)](https://leetcode.com/problems/count-binary-substrings/description/)
```html
Input: "00110011"
Output: 6
Explanation: There are 6 substrings that have equal number of consecutive 1's and 0's: "0011", "01", "1100", "10", "0011", and "01".
```
```java
public int countBinarySubstrings(String s) {
int preLen = 0, curLen = 1, count = 0;
for (int i = 1; i < s.length(); i++) {
if (s.charAt(i) == s.charAt(i - 1)) {
curLen++;
} else {
preLen = curLen;
curLen = 1;
}
if (preLen >= curLen) {
count++;
}
}
return count;
}
```
</br><div align="center">⭐️欢迎关注我的公众号 CyC2018在公众号后台回复关键字 📚 **资料** 可领取复习大纲,这份大纲是我花了一整年时间整理的面试知识点列表,不仅系统整理了面试知识点,而且标注了各个知识点的重要程度,从而帮你理清多而杂的面试知识点。可以说我基本是按照这份大纲来进行复习的,这份大纲对我拿到了 BAT 头条等 Offer 起到很大的帮助。你们完全可以和我一样根据大纲上列的知识点来进行复习,就不用看很多不重要的内容,也可以知道哪些内容很重要从而多安排一些复习时间。</div></br>
<div align="center"><img width="180px" src="https://cyc-1256109796.cos.ap-guangzhou.myqcloud.com/%E5%85%AC%E4%BC%97%E5%8F%B7.jpg"></img></div>

View File

@ -0,0 +1,232 @@
<!-- GFM-TOC -->
* [快速选择](#快速选择)
* [堆排序](#堆排序)
* [Kth Element](#kth-element)
* [桶排序](#桶排序)
* [出现频率最多的 k 个数](#出现频率最多的-k-个数)
* [按照字符出现次数对字符串排序](#按照字符出现次数对字符串排序)
* [荷兰国旗问题](#荷兰国旗问题)
* [按颜色进行排序](#按颜色进行排序)
<!-- GFM-TOC -->
# 快速选择
用于求解 **Kth Element** 问题,使用快速排序的 partition() 进行实现。
需要先打乱数组,否则最坏情况下时间复杂度为 O(N<sup>2</sup>)。
# 堆排序
用于求解 **TopK Elements** 问题,通过维护一个大小为 K 的堆,堆中的元素就是 TopK Elements。
堆排序也可以用于求解 Kth Element 问题,堆顶元素就是 Kth Element。
快速选择也可以求解 TopK Elements 问题,因为找到 Kth Element 之后,再遍历一次数组,所有小于等于 Kth Element 的元素都是 TopK Elements。
可以看到,快速选择和堆排序都可以求解 Kth Element 和 TopK Elements 问题。
## Kth Element
[215. Kth Largest Element in an Array (Medium)](https://leetcode.com/problems/kth-largest-element-in-an-array/description/)
题目描述:找到第 k 大的元素。
**排序** :时间复杂度 O(NlogN),空间复杂度 O(1)
```java
public int findKthLargest(int[] nums, int k) {
Arrays.sort(nums);
return nums[nums.length - k];
}
```
**堆排序** :时间复杂度 O(NlogK),空间复杂度 O(K)。
```java
public int findKthLargest(int[] nums, int k) {
PriorityQueue<Integer> pq = new PriorityQueue<>(); // 小顶堆
for (int val : nums) {
pq.add(val);
if (pq.size() > k) // 维护堆的大小为 K
pq.poll();
}
return pq.peek();
}
```
**快速选择** :时间复杂度 O(N),空间复杂度 O(1)
```java
public int findKthLargest(int[] nums, int k) {
k = nums.length - k;
int l = 0, h = nums.length - 1;
while (l < h) {
int j = partition(nums, l, h);
if (j == k) {
break;
} else if (j < k) {
l = j + 1;
} else {
h = j - 1;
}
}
return nums[k];
}
private int partition(int[] a, int l, int h) {
int i = l, j = h + 1;
while (true) {
while (a[++i] < a[l] && i < h) ;
while (a[--j] > a[l] && j > l) ;
if (i >= j) {
break;
}
swap(a, i, j);
}
swap(a, l, j);
return j;
}
private void swap(int[] a, int i, int j) {
int t = a[i];
a[i] = a[j];
a[j] = t;
}
```
# 桶排序
## 出现频率最多的 k 个数
[347. Top K Frequent Elements (Medium)](https://leetcode.com/problems/top-k-frequent-elements/description/)
```html
Given [1,1,1,2,2,3] and k = 2, return [1,2].
```
设置若干个桶,每个桶存储出现频率相同的数,并且桶的下标代表桶中数出现的频率,即第 i 个桶中存储的数出现的频率为 i。
把数都放到桶之后,从后向前遍历桶,最先得到的 k 个数就是出现频率最多的的 k 个数。
```java
public List<Integer> topKFrequent(int[] nums, int k) {
Map<Integer, Integer> frequencyForNum = new HashMap<>();
for (int num : nums) {
frequencyForNum.put(num, frequencyForNum.getOrDefault(num, 0) + 1);
}
List<Integer>[] buckets = new ArrayList[nums.length + 1];
for (int key : frequencyForNum.keySet()) {
int frequency = frequencyForNum.get(key);
if (buckets[frequency] == null) {
buckets[frequency] = new ArrayList<>();
}
buckets[frequency].add(key);
}
List<Integer> topK = new ArrayList<>();
for (int i = buckets.length - 1; i >= 0 && topK.size() < k; i--) {
if (buckets[i] == null) {
continue;
}
if (buckets[i].size() <= (k - topK.size())) {
topK.addAll(buckets[i]);
} else {
topK.addAll(buckets[i].subList(0, k - topK.size()));
}
}
return topK;
}
```
## 按照字符出现次数对字符串排序
[451. Sort Characters By Frequency (Medium)](https://leetcode.com/problems/sort-characters-by-frequency/description/)
```html
Input:
"tree"
Output:
"eert"
Explanation:
'e' appears twice while 'r' and 't' both appear once.
So 'e' must appear before both 'r' and 't'. Therefore "eetr" is also a valid answer.
```
```java
public String frequencySort(String s) {
Map<Character, Integer> frequencyForNum = new HashMap<>();
for (char c : s.toCharArray())
frequencyForNum.put(c, frequencyForNum.getOrDefault(c, 0) + 1);
List<Character>[] frequencyBucket = new ArrayList[s.length() + 1];
for (char c : frequencyForNum.keySet()) {
int f = frequencyForNum.get(c);
if (frequencyBucket[f] == null) {
frequencyBucket[f] = new ArrayList<>();
}
frequencyBucket[f].add(c);
}
StringBuilder str = new StringBuilder();
for (int i = frequencyBucket.length - 1; i >= 0; i--) {
if (frequencyBucket[i] == null) {
continue;
}
for (char c : frequencyBucket[i]) {
for (int j = 0; j < i; j++) {
str.append(c);
}
}
}
return str.toString();
}
```
# 荷兰国旗问题
荷兰国旗包含三种颜色:红、白、蓝。
有三种颜色的球,算法的目标是将这三种球按颜色顺序正确地排列。
它其实是三向切分快速排序的一种变种,在三向切分快速排序中,每次切分都将数组分成三个区间:小于切分元素、等于切分元素、大于切分元素,而该算法是将数组分成三个区间:等于红色、等于白色、等于蓝色。
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/7a3215ec-6fb7-4935-8b0d-cb408208f7cb.png"/> </div><br>
## 按颜色进行排序
[75. Sort Colors (Medium)](https://leetcode.com/problems/sort-colors/description/)
```html
Input: [2,0,2,1,1,0]
Output: [0,0,1,1,2,2]
```
题目描述:只有 0/1/2 三种颜色。
```java
public void sortColors(int[] nums) {
int zero = -1, one = 0, two = nums.length;
while (one < two) {
if (nums[one] == 0) {
swap(nums, ++zero, one++);
} else if (nums[one] == 2) {
swap(nums, --two, one);
} else {
++one;
}
}
}
private void swap(int[] nums, int i, int j) {
int t = nums[i];
nums[i] = nums[j];
nums[j] = t;
}
```
</br><div align="center">⭐️欢迎关注我的公众号 CyC2018在公众号后台回复关键字 📚 **资料** 可领取复习大纲,这份大纲是我花了一整年时间整理的面试知识点列表,不仅系统整理了面试知识点,而且标注了各个知识点的重要程度,从而帮你理清多而杂的面试知识点。可以说我基本是按照这份大纲来进行复习的,这份大纲对我拿到了 BAT 头条等 Offer 起到很大的帮助。你们完全可以和我一样根据大纲上列的知识点来进行复习,就不用看很多不重要的内容,也可以知道哪些内容很重要从而多安排一些复习时间。</div></br>
<div align="center"><img width="180px" src="https://cyc-1256109796.cos.ap-guangzhou.myqcloud.com/%E5%85%AC%E4%BC%97%E5%8F%B7.jpg"></img></div>

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,515 @@
<!-- GFM-TOC -->
* [素数分解](#素数分解)
* [整除](#整除)
* [最大公约数最小公倍数](#最大公约数最小公倍数)
* [生成素数序列](#生成素数序列)
* [最大公约数](#最大公约数)
* [使用位操作和减法求解最大公约数](#使用位操作和减法求解最大公约数)
* [进制转换](#进制转换)
* [7 进制](#7-进制)
* [16 进制](#16-进制)
* [26 进制](#26-进制)
* [阶乘](#阶乘)
* [统计阶乘尾部有多少个 0](#统计阶乘尾部有多少个-0)
* [字符串加法减法](#字符串加法减法)
* [二进制加法](#二进制加法)
* [字符串加法](#字符串加法)
* [相遇问题](#相遇问题)
* [改变数组元素使所有的数组元素都相等](#改变数组元素使所有的数组元素都相等)
* [解法 1](#解法-1)
* [解法 2](#解法-2)
* [多数投票问题](#多数投票问题)
* [数组中出现次数多于 n / 2 的元素](#数组中出现次数多于-n--2-的元素)
* [其它](#其它)
* [平方数](#平方数)
* [3 的 n 次方](#3-的-n-次方)
* [乘积数组](#乘积数组)
* [找出数组中的乘积最大的三个数](#找出数组中的乘积最大的三个数)
<!-- GFM-TOC -->
# 素数分解
每一个数都可以分解成素数的乘积,例如 84 = 2<sup>2</sup> \* 3<sup>1</sup> \* 5<sup>0</sup> \* 7<sup>1</sup> \* 11<sup>0</sup> \* 13<sup>0</sup> \* 17<sup>0</sup> \* …
# 整除
令 x = 2<sup>m0</sup> \* 3<sup>m1</sup> \* 5<sup>m2</sup> \* 7<sup>m3</sup> \* 11<sup>m4</sup> \* …
令 y = 2<sup>n0</sup> \* 3<sup>n1</sup> \* 5<sup>n2</sup> \* 7<sup>n3</sup> \* 11<sup>n4</sup> \* …
如果 x 整除 yy mod x == 0则对于所有 imi <= ni。
## 最大公约数最小公倍数
x 和 y 的最大公约数为gcd(x,y) = 2<sup>min(m0,n0)</sup> \* 3<sup>min(m1,n1)</sup> \* 5<sup>min(m2,n2)</sup> \* ...
x 和 y 的最小公倍数为lcm(x,y) = 2<sup>max(m0,n0)</sup> \* 3<sup>max(m1,n1)</sup> \* 5<sup>max(m2,n2)</sup> \* ...
## 生成素数序列
[204. Count Primes (Easy)](https://leetcode.com/problems/count-primes/description/)
埃拉托斯特尼筛法在每次找到一个素数时,将能被素数整除的数排除掉。
```java
public int countPrimes(int n) {
boolean[] notPrimes = new boolean[n + 1];
int count = 0;
for (int i = 2; i < n; i++) {
if (notPrimes[i]) {
continue;
}
count++;
// 从 i * i 开始,因为如果 k < i那么 k * i 在之前就已经被去除过了
for (long j = (long) (i) * i; j < n; j += i) {
notPrimes[(int) j] = true;
}
}
return count;
}
```
### 最大公约数
```java
int gcd(int a, int b) {
return b == 0 ? a : gcd(b, a % b);
}
```
最小公倍数为两数的乘积除以最大公约数。
```java
int lcm(int a, int b) {
return a * b / gcd(a, b);
}
```
## 使用位操作和减法求解最大公约数
[编程之美2.7](#)
对于 a 和 b 的最大公约数 f(a, b),有:
- 如果 a 和 b 均为偶数f(a, b) = 2\*f(a/2, b/2);
- 如果 a 是偶数 b 是奇数f(a, b) = f(a/2, b);
- 如果 b 是偶数 a 是奇数f(a, b) = f(a, b/2);
- 如果 a 和 b 均为奇数f(a, b) = f(b, a-b);
乘 2 和除 2 都可以转换为移位操作。
```java
public int gcd(int a, int b) {
if (a < b) {
return gcd(b, a);
}
if (b == 0) {
return a;
}
boolean isAEven = isEven(a), isBEven = isEven(b);
if (isAEven && isBEven) {
return 2 * gcd(a >> 1, b >> 1);
} else if (isAEven && !isBEven) {
return gcd(a >> 1, b);
} else if (!isAEven && isBEven) {
return gcd(a, b >> 1);
} else {
return gcd(b, a - b);
}
}
```
# 进制转换
## 7 进制
[504. Base 7 (Easy)](https://leetcode.com/problems/base-7/description/)
```java
public String convertToBase7(int num) {
if (num == 0) {
return "0";
}
StringBuilder sb = new StringBuilder();
boolean isNegative = num < 0;
if (isNegative) {
num = -num;
}
while (num > 0) {
sb.append(num % 7);
num /= 7;
}
String ret = sb.reverse().toString();
return isNegative ? "-" + ret : ret;
}
```
Java 中 static String toString(int num, int radix) 可以将一个整数转换为 radix 进制表示的字符串。
```java
public String convertToBase7(int num) {
return Integer.toString(num, 7);
}
```
## 16 进制
[405. Convert a Number to Hexadecimal (Easy)](https://leetcode.com/problems/convert-a-number-to-hexadecimal/description/)
```html
Input:
26
Output:
"1a"
Input:
-1
Output:
"ffffffff"
```
负数要用它的补码形式。
```java
public String toHex(int num) {
char[] map = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
if (num == 0) return "0";
StringBuilder sb = new StringBuilder();
while (num != 0) {
sb.append(map[num & 0b1111]);
num >>>= 4; // 因为考虑的是补码形式,因此符号位就不能有特殊的意义,需要使用无符号右移,左边填 0
}
return sb.reverse().toString();
}
```
## 26 进制
[168. Excel Sheet Column Title (Easy)](https://leetcode.com/problems/excel-sheet-column-title/description/)
```html
1 -> A
2 -> B
3 -> C
...
26 -> Z
27 -> AA
28 -> AB
```
因为是从 1 开始计算的,而不是从 0 开始,因此需要对 n 执行 -1 操作。
```java
public String convertToTitle(int n) {
if (n == 0) {
return "";
}
n--;
return convertToTitle(n / 26) + (char) (n % 26 + 'A');
}
```
# 阶乘
## 统计阶乘尾部有多少个 0
[172. Factorial Trailing Zeroes (Easy)](https://leetcode.com/problems/factorial-trailing-zeroes/description/)
尾部的 0 由 2 * 5 得来2 的数量明显多于 5 的数量,因此只要统计有多少个 5 即可。
对于一个数 N它所包含 5 的个数为N/5 + N/5<sup>2</sup> + N/5<sup>3</sup> + ...,其中 N/5 表示不大于 N 的数中 5 的倍数贡献一个 5N/5<sup>2</sup> 表示不大于 N 的数中 5<sup>2</sup> 的倍数再贡献一个 5 ...。
```java
public int trailingZeroes(int n) {
return n == 0 ? 0 : n / 5 + trailingZeroes(n / 5);
}
```
如果统计的是 N! 的二进制表示中最低位 1 的位置,只要统计有多少个 2 即可,该题目出自 [编程之美2.2](#) 。和求解有多少个 5 一样2 的个数为 N/2 + N/2<sup>2</sup> + N/2<sup>3</sup> + ...
# 字符串加法减法
## 二进制加法
[67. Add Binary (Easy)](https://leetcode.com/problems/add-binary/description/)
```html
a = "11"
b = "1"
Return "100".
```
```java
public String addBinary(String a, String b) {
int i = a.length() - 1, j = b.length() - 1, carry = 0;
StringBuilder str = new StringBuilder();
while (carry == 1 || i >= 0 || j >= 0) {
if (i >= 0 && a.charAt(i--) == '1') {
carry++;
}
if (j >= 0 && b.charAt(j--) == '1') {
carry++;
}
str.append(carry % 2);
carry /= 2;
}
return str.reverse().toString();
}
```
## 字符串加法
[415. Add Strings (Easy)](https://leetcode.com/problems/add-strings/description/)
字符串的值为非负整数。
```java
public String addStrings(String num1, String num2) {
StringBuilder str = new StringBuilder();
int carry = 0, i = num1.length() - 1, j = num2.length() - 1;
while (carry == 1 || i >= 0 || j >= 0) {
int x = i < 0 ? 0 : num1.charAt(i--) - '0';
int y = j < 0 ? 0 : num2.charAt(j--) - '0';
str.append((x + y + carry) % 10);
carry = (x + y + carry) / 10;
}
return str.reverse().toString();
}
```
# 相遇问题
## 改变数组元素使所有的数组元素都相等
[462. Minimum Moves to Equal Array Elements II (Medium)](https://leetcode.com/problems/minimum-moves-to-equal-array-elements-ii/description/)
```html
Input:
[1,2,3]
Output:
2
Explanation:
Only two moves are needed (remember each move increments or decrements one element):
[1,2,3] => [2,2,3] => [2,2,2]
```
每次可以对一个数组元素加一或者减一,求最小的改变次数。
这是个典型的相遇问题,移动距离最小的方式是所有元素都移动到中位数。理由如下:
设 m 为中位数。a 和 b 是 m 两边的两个元素,且 b > a。要使 a 和 b 相等,它们总共移动的次数为 b - a这个值等于 (b - m) + (m - a),也就是把这两个数移动到中位数的移动次数。
设数组长度为 N则可以找到 N/2 对 a 和 b 的组合,使它们都移动到 m 的位置。
## 解法 1
先排序时间复杂度O(NlogN)
```java
public int minMoves2(int[] nums) {
Arrays.sort(nums);
int move = 0;
int l = 0, h = nums.length - 1;
while (l <= h) {
move += nums[h] - nums[l];
l++;
h--;
}
return move;
}
```
## 解法 2
使用快速选择找到中位数,时间复杂度 O(N)
```java
public int minMoves2(int[] nums) {
int move = 0;
int median = findKthSmallest(nums, nums.length / 2);
for (int num : nums) {
move += Math.abs(num - median);
}
return move;
}
private int findKthSmallest(int[] nums, int k) {
int l = 0, h = nums.length - 1;
while (l < h) {
int j = partition(nums, l, h);
if (j == k) {
break;
}
if (j < k) {
l = j + 1;
} else {
h = j - 1;
}
}
return nums[k];
}
private int partition(int[] nums, int l, int h) {
int i = l, j = h + 1;
while (true) {
while (nums[++i] < nums[l] && i < h) ;
while (nums[--j] > nums[l] && j > l) ;
if (i >= j) {
break;
}
swap(nums, i, j);
}
swap(nums, l, j);
return j;
}
private void swap(int[] nums, int i, int j) {
int tmp = nums[i];
nums[i] = nums[j];
nums[j] = tmp;
}
```
# 多数投票问题
## 数组中出现次数多于 n / 2 的元素
[169. Majority Element (Easy)](https://leetcode.com/problems/majority-element/description/)
先对数组排序,最中间那个数出现次数一定多于 n / 2。
```java
public int majorityElement(int[] nums) {
Arrays.sort(nums);
return nums[nums.length / 2];
}
```
可以利用 Boyer-Moore Majority Vote Algorithm 来解决这个问题,使得时间复杂度为 O(N)。可以这么理解该算法:使用 cnt 来统计一个元素出现的次数,当遍历到的元素和统计元素不相等时,令 cnt--。如果前面查找了 i 个元素,且 cnt == 0说明前 i 个元素没有 majority或者有 majority但是出现的次数少于 i / 2因为如果多于 i / 2 的话 cnt 就一定不会为 0。此时剩下的 n - i 个元素中majority 的数目依然多于 (n - i) / 2因此继续查找就能找出 majority。
```java
public int majorityElement(int[] nums) {
int cnt = 0, majority = nums[0];
for (int num : nums) {
majority = (cnt == 0) ? num : majority;
cnt = (majority == num) ? cnt + 1 : cnt - 1;
}
return majority;
}
```
# 其它
## 平方数
[367. Valid Perfect Square (Easy)](https://leetcode.com/problems/valid-perfect-square/description/)
```html
Input: 16
Returns: True
```
平方序列1,4,9,16,..
间隔3,5,7,...
间隔为等差数列,使用这个特性可以得到从 1 开始的平方序列。
```java
public boolean isPerfectSquare(int num) {
int subNum = 1;
while (num > 0) {
num -= subNum;
subNum += 2;
}
return num == 0;
}
```
## 3 的 n 次方
[326. Power of Three (Easy)](https://leetcode.com/problems/power-of-three/description/)
```java
public boolean isPowerOfThree(int n) {
return n > 0 && (1162261467 % n == 0);
}
```
## 乘积数组
[238. Product of Array Except Self (Medium)](https://leetcode.com/problems/product-of-array-except-self/description/)
```html
For example, given [1,2,3,4], return [24,12,8,6].
```
给定一个数组,创建一个新数组,新数组的每个元素为原始数组中除了该位置上的元素之外所有元素的乘积。
要求时间复杂度为 O(N),并且不能使用除法。
```java
public int[] productExceptSelf(int[] nums) {
int n = nums.length;
int[] products = new int[n];
Arrays.fill(products, 1);
int left = 1;
for (int i = 1; i < n; i++) {
left *= nums[i - 1];
products[i] *= left;
}
int right = 1;
for (int i = n - 2; i >= 0; i--) {
right *= nums[i + 1];
products[i] *= right;
}
return products;
}
```
## 找出数组中的乘积最大的三个数
[628. Maximum Product of Three Numbers (Easy)](https://leetcode.com/problems/maximum-product-of-three-numbers/description/)
```html
Input: [1,2,3,4]
Output: 24
```
```java
public int maximumProduct(int[] nums) {
int max1 = Integer.MIN_VALUE, max2 = Integer.MIN_VALUE, max3 = Integer.MIN_VALUE, min1 = Integer.MAX_VALUE, min2 = Integer.MAX_VALUE;
for (int n : nums) {
if (n > max1) {
max3 = max2;
max2 = max1;
max1 = n;
} else if (n > max2) {
max3 = max2;
max2 = n;
} else if (n > max3) {
max3 = n;
}
if (n < min1) {
min2 = min1;
min1 = n;
} else if (n < min2) {
min2 = n;
}
}
return Math.max(max1*max2*max3, max1*min1*min2);
}
```
</br><div align="center">⭐️欢迎关注我的公众号 CyC2018在公众号后台回复关键字 📚 **资料** 可领取复习大纲,这份大纲是我花了一整年时间整理的面试知识点列表,不仅系统整理了面试知识点,而且标注了各个知识点的重要程度,从而帮你理清多而杂的面试知识点。可以说我基本是按照这份大纲来进行复习的,这份大纲对我拿到了 BAT 头条等 Offer 起到很大的帮助。你们完全可以和我一样根据大纲上列的知识点来进行复习,就不用看很多不重要的内容,也可以知道哪些内容很重要从而多安排一些复习时间。</div></br>
<div align="center"><img width="180px" src="https://cyc-1256109796.cos.ap-guangzhou.myqcloud.com/%E5%85%AC%E4%BC%97%E5%8F%B7.jpg"></img></div>

View File

@ -0,0 +1,439 @@
<!-- GFM-TOC -->
* [1. 把数组中的 0 移到末尾](#1-把数组中的-0-移到末尾)
* [2. 改变矩阵维度](#2-改变矩阵维度)
* [3. 找出数组中最长的连续 1](#3-找出数组中最长的连续-1)
* [4. 有序矩阵查找](#4-有序矩阵查找)
* [5. 有序矩阵的 Kth Element](#5-有序矩阵的-kth-element)
* [6. 一个数组元素在 [1, n] 之间,其中一个数被替换为另一个数,找出重复的数和丢失的数](#6-一个数组元素在-[1,-n]-之间,其中一个数被替换为另一个数,找出重复的数和丢失的数)
* [7. 找出数组中重复的数,数组值在 [1, n] 之间](#7-找出数组中重复的数,数组值在-[1,-n]-之间)
* [8. 数组相邻差值的个数](#8-数组相邻差值的个数)
* [9. 数组的度](#9-数组的度)
* [10. 对角元素相等的矩阵](#10-对角元素相等的矩阵)
* [11. 嵌套数组](#11-嵌套数组)
* [12. 分隔数组](#12-分隔数组)
<!-- GFM-TOC -->
# 1. 把数组中的 0 移到末尾
[283. Move Zeroes (Easy)](https://leetcode.com/problems/move-zeroes/description/)
```html
For example, given nums = [0, 1, 0, 3, 12], after calling your function, nums should be [1, 3, 12, 0, 0].
```
```java
public void moveZeroes(int[] nums) {
int idx = 0;
for (int num : nums) {
if (num != 0) {
nums[idx++] = num;
}
}
while (idx < nums.length) {
nums[idx++] = 0;
}
}
```
# 2. 改变矩阵维度
[566. Reshape the Matrix (Easy)](https://leetcode.com/problems/reshape-the-matrix/description/)
```html
Input:
nums =
[[1,2],
[3,4]]
r = 1, c = 4
Output:
[[1,2,3,4]]
Explanation:
The row-traversing of nums is [1,2,3,4]. The new reshaped matrix is a 1 * 4 matrix, fill it row by row by using the previous list.
```
```java
public int[][] matrixReshape(int[][] nums, int r, int c) {
int m = nums.length, n = nums[0].length;
if (m * n != r * c) {
return nums;
}
int[][] reshapedNums = new int[r][c];
int index = 0;
for (int i = 0; i < r; i++) {
for (int j = 0; j < c; j++) {
reshapedNums[i][j] = nums[index / n][index % n];
index++;
}
}
return reshapedNums;
}
```
# 3. 找出数组中最长的连续 1
[485. Max Consecutive Ones (Easy)](https://leetcode.com/problems/max-consecutive-ones/description/)
```java
public int findMaxConsecutiveOnes(int[] nums) {
int max = 0, cur = 0;
for (int x : nums) {
cur = x == 0 ? 0 : cur + 1;
max = Math.max(max, cur);
}
return max;
}
```
# 4. 有序矩阵查找
[240. Search a 2D Matrix II (Medium)](https://leetcode.com/problems/search-a-2d-matrix-ii/description/)
```html
[
[ 1, 5, 9],
[10, 11, 13],
[12, 13, 15]
]
```
```java
public boolean searchMatrix(int[][] matrix, int target) {
if (matrix == null || matrix.length == 0 || matrix[0].length == 0) return false;
int m = matrix.length, n = matrix[0].length;
int row = 0, col = n - 1;
while (row < m && col >= 0) {
if (target == matrix[row][col]) return true;
else if (target < matrix[row][col]) col--;
else row++;
}
return false;
}
```
# 5. 有序矩阵的 Kth Element
[378. Kth Smallest Element in a Sorted Matrix ((Medium))](https://leetcode.com/problems/kth-smallest-element-in-a-sorted-matrix/description/)
```html
matrix = [
[ 1, 5, 9],
[10, 11, 13],
[12, 13, 15]
],
k = 8,
return 13.
```
解题参考:[Share my thoughts and Clean Java Code](https://leetcode.com/problems/kth-smallest-element-in-a-sorted-matrix/discuss/85173)
二分查找解法:
```java
public int kthSmallest(int[][] matrix, int k) {
int m = matrix.length, n = matrix[0].length;
int lo = matrix[0][0], hi = matrix[m - 1][n - 1];
while (lo <= hi) {
int mid = lo + (hi - lo) / 2;
int cnt = 0;
for (int i = 0; i < m; i++) {
for (int j = 0; j < n && matrix[i][j] <= mid; j++) {
cnt++;
}
}
if (cnt < k) lo = mid + 1;
else hi = mid - 1;
}
return lo;
}
```
堆解法:
```java
public int kthSmallest(int[][] matrix, int k) {
int m = matrix.length, n = matrix[0].length;
PriorityQueue<Tuple> pq = new PriorityQueue<Tuple>();
for(int j = 0; j < n; j++) pq.offer(new Tuple(0, j, matrix[0][j]));
for(int i = 0; i < k - 1; i++) { // 小根堆去掉 k - 1 个堆顶元素此时堆顶元素就是第 k 的数
Tuple t = pq.poll();
if(t.x == m - 1) continue;
pq.offer(new Tuple(t.x + 1, t.y, matrix[t.x + 1][t.y]));
}
return pq.poll().val;
}
class Tuple implements Comparable<Tuple> {
int x, y, val;
public Tuple(int x, int y, int val) {
this.x = x; this.y = y; this.val = val;
}
@Override
public int compareTo(Tuple that) {
return this.val - that.val;
}
}
```
# 6. 一个数组元素在 [1, n] 之间,其中一个数被替换为另一个数,找出重复的数和丢失的数
[645. Set Mismatch (Easy)](https://leetcode.com/problems/set-mismatch/description/)
```html
Input: nums = [1,2,2,4]
Output: [2,3]
```
```html
Input: nums = [1,2,2,4]
Output: [2,3]
```
最直接的方法是先对数组进行排序,这种方法时间复杂度为 O(NlogN)。本题可以以 O(N) 的时间复杂度、O(1) 空间复杂度来求解。
主要思想是通过交换数组元素,使得数组上的元素在正确的位置上。
```java
public int[] findErrorNums(int[] nums) {
for (int i = 0; i < nums.length; i++) {
while (nums[i] != i + 1 && nums[nums[i] - 1] != nums[i]) {
swap(nums, i, nums[i] - 1);
}
}
for (int i = 0; i < nums.length; i++) {
if (nums[i] != i + 1) {
return new int[]{nums[i], i + 1};
}
}
return null;
}
private void swap(int[] nums, int i, int j) {
int tmp = nums[i];
nums[i] = nums[j];
nums[j] = tmp;
}
```
类似题目:
- [448. Find All Numbers Disappeared in an Array (Easy)](https://leetcode.com/problems/find-all-numbers-disappeared-in-an-array/description/),寻找所有丢失的元素
- [442. Find All Duplicates in an Array (Medium)](https://leetcode.com/problems/find-all-duplicates-in-an-array/description/),寻找所有重复的元素。
# 7. 找出数组中重复的数,数组值在 [1, n] 之间
[287. Find the Duplicate Number (Medium)](https://leetcode.com/problems/find-the-duplicate-number/description/)
要求不能修改数组,也不能使用额外的空间。
二分查找解法:
```java
public int findDuplicate(int[] nums) {
int l = 1, h = nums.length - 1;
while (l <= h) {
int mid = l + (h - l) / 2;
int cnt = 0;
for (int i = 0; i < nums.length; i++) {
if (nums[i] <= mid) cnt++;
}
if (cnt > mid) h = mid - 1;
else l = mid + 1;
}
return l;
}
```
双指针解法,类似于有环链表中找出环的入口:
```java
public int findDuplicate(int[] nums) {
int slow = nums[0], fast = nums[nums[0]];
while (slow != fast) {
slow = nums[slow];
fast = nums[nums[fast]];
}
fast = 0;
while (slow != fast) {
slow = nums[slow];
fast = nums[fast];
}
return slow;
}
```
# 8. 数组相邻差值的个数
[667. Beautiful Arrangement II (Medium)](https://leetcode.com/problems/beautiful-arrangement-ii/description/)
```html
Input: n = 3, k = 2
Output: [1, 3, 2]
Explanation: The [1, 3, 2] has three different positive integers ranging from 1 to 3, and the [2, 1] has exactly 2 distinct integers: 1 and 2.
```
题目描述:数组元素为 1\~n 的整数,要求构建数组,使得相邻元素的差值不相同的个数为 k。
让前 k+1 个元素构建出 k 个不相同的差值序列为1 k+1 2 k 3 k-1 ... k/2 k/2+1.
```java
public int[] constructArray(int n, int k) {
int[] ret = new int[n];
ret[0] = 1;
for (int i = 1, interval = k; i <= k; i++, interval--) {
ret[i] = i % 2 == 1 ? ret[i - 1] + interval : ret[i - 1] - interval;
}
for (int i = k + 1; i < n; i++) {
ret[i] = i + 1;
}
return ret;
}
```
# 9. 数组的度
[697. Degree of an Array (Easy)](https://leetcode.com/problems/degree-of-an-array/description/)
```html
Input: [1,2,2,3,1,4,2]
Output: 6
```
题目描述:数组的度定义为元素出现的最高频率,例如上面的数组度为 3。要求找到一个最小的子数组这个子数组的度和原数组一样。
```java
public int findShortestSubArray(int[] nums) {
Map<Integer, Integer> numsCnt = new HashMap<>();
Map<Integer, Integer> numsLastIndex = new HashMap<>();
Map<Integer, Integer> numsFirstIndex = new HashMap<>();
for (int i = 0; i < nums.length; i++) {
int num = nums[i];
numsCnt.put(num, numsCnt.getOrDefault(num, 0) + 1);
numsLastIndex.put(num, i);
if (!numsFirstIndex.containsKey(num)) {
numsFirstIndex.put(num, i);
}
}
int maxCnt = 0;
for (int num : nums) {
maxCnt = Math.max(maxCnt, numsCnt.get(num));
}
int ret = nums.length;
for (int i = 0; i < nums.length; i++) {
int num = nums[i];
int cnt = numsCnt.get(num);
if (cnt != maxCnt) continue;
ret = Math.min(ret, numsLastIndex.get(num) - numsFirstIndex.get(num) + 1);
}
return ret;
}
```
# 10. 对角元素相等的矩阵
[766. Toeplitz Matrix (Easy)](https://leetcode.com/problems/toeplitz-matrix/description/)
```html
1234
5123
9512
In the above grid, the diagonals are "[9]", "[5, 5]", "[1, 1, 1]", "[2, 2, 2]", "[3, 3]", "[4]", and in each diagonal all elements are the same, so the answer is True.
```
```java
public boolean isToeplitzMatrix(int[][] matrix) {
for (int i = 0; i < matrix[0].length; i++) {
if (!check(matrix, matrix[0][i], 0, i)) {
return false;
}
}
for (int i = 0; i < matrix.length; i++) {
if (!check(matrix, matrix[i][0], i, 0)) {
return false;
}
}
return true;
}
private boolean check(int[][] matrix, int expectValue, int row, int col) {
if (row >= matrix.length || col >= matrix[0].length) {
return true;
}
if (matrix[row][col] != expectValue) {
return false;
}
return check(matrix, expectValue, row + 1, col + 1);
}
```
# 11. 嵌套数组
[565. Array Nesting (Medium)](https://leetcode.com/problems/array-nesting/description/)
```html
Input: A = [5,4,0,3,1,6,2]
Output: 4
Explanation:
A[0] = 5, A[1] = 4, A[2] = 0, A[3] = 3, A[4] = 1, A[5] = 6, A[6] = 2.
One of the longest S[K]:
S[0] = {A[0], A[5], A[6], A[2]} = {5, 6, 2, 0}
```
题目描述S[i] 表示一个集合,集合的第一个元素是 A[i],第二个元素是 A[A[i]],如此嵌套下去。求最大的 S[i]。
```java
public int arrayNesting(int[] nums) {
int max = 0;
for (int i = 0; i < nums.length; i++) {
int cnt = 0;
for (int j = i; nums[j] != -1; ) {
cnt++;
int t = nums[j];
nums[j] = -1; // 标记该位置已经被访问
j = t;
}
max = Math.max(max, cnt);
}
return max;
}
```
# 12. 分隔数组
[769. Max Chunks To Make Sorted (Medium)](https://leetcode.com/problems/max-chunks-to-make-sorted/description/)
```html
Input: arr = [1,0,2,3,4]
Output: 4
Explanation:
We can split into two chunks, such as [1, 0], [2, 3, 4].
However, splitting into [1, 0], [2], [3], [4] is the highest number of chunks possible.
```
题目描述:分隔数组,使得对每部分排序后数组就为有序。
```java
public int maxChunksToSorted(int[] arr) {
if (arr == null) return 0;
int ret = 0;
int right = arr[0];
for (int i = 0; i < arr.length; i++) {
right = Math.max(right, arr[i]);
if (right == i) ret++;
}
return ret;
}
```
</br><div align="center">⭐️欢迎关注我的公众号 CyC2018在公众号后台回复关键字 📚 **资料** 可领取复习大纲,这份大纲是我花了一整年时间整理的面试知识点列表,不仅系统整理了面试知识点,而且标注了各个知识点的重要程度,从而帮你理清多而杂的面试知识点。可以说我基本是按照这份大纲来进行复习的,这份大纲对我拿到了 BAT 头条等 Offer 起到很大的帮助。你们完全可以和我一样根据大纲上列的知识点来进行复习,就不用看很多不重要的内容,也可以知道哪些内容很重要从而多安排一些复习时间。</div></br>
<div align="center"><img width="180px" src="https://cyc-1256109796.cos.ap-guangzhou.myqcloud.com/%E5%85%AC%E4%BC%97%E5%8F%B7.jpg"></img></div>

View File

@ -0,0 +1,226 @@
<!-- GFM-TOC -->
* [用栈实现队列](#用栈实现队列)
* [用队列实现栈](#用队列实现栈)
* [最小值栈](#最小值栈)
* [用栈实现括号匹配](#用栈实现括号匹配)
* [数组中元素与下一个比它大的元素之间的距离](#数组中元素与下一个比它大的元素之间的距离)
* [循环数组中比当前元素大的下一个元素](#循环数组中比当前元素大的下一个元素)
<!-- GFM-TOC -->
# 用栈实现队列
[232. Implement Queue using Stacks (Easy)](https://leetcode.com/problems/implement-queue-using-stacks/description/)
栈的顺序为后进先出,而队列的顺序为先进先出。使用两个栈实现队列,一个元素需要经过两个栈才能出队列,在经过第一个栈时元素顺序被反转,经过第二个栈时再次被反转,此时就是先进先出顺序。
```java
class MyQueue {
private Stack<Integer> in = new Stack<>();
private Stack<Integer> out = new Stack<>();
public void push(int x) {
in.push(x);
}
public int pop() {
in2out();
return out.pop();
}
public int peek() {
in2out();
return out.peek();
}
private void in2out() {
if (out.isEmpty()) {
while (!in.isEmpty()) {
out.push(in.pop());
}
}
}
public boolean empty() {
return in.isEmpty() && out.isEmpty();
}
}
```
# 用队列实现栈
[225. Implement Stack using Queues (Easy)](https://leetcode.com/problems/implement-stack-using-queues/description/)
在将一个元素 x 插入队列时,为了维护原来的后进先出顺序,需要让 x 插入队列首部。而队列的默认插入顺序是队列尾部,因此在将 x 插入队列尾部之后,需要让除了 x 之外的所有元素出队列,再入队列。
```java
class MyStack {
private Queue<Integer> queue;
public MyStack() {
queue = new LinkedList<>();
}
public void push(int x) {
queue.add(x);
int cnt = queue.size();
while (cnt-- > 1) {
queue.add(queue.poll());
}
}
public int pop() {
return queue.remove();
}
public int top() {
return queue.peek();
}
public boolean empty() {
return queue.isEmpty();
}
}
```
# 最小值栈
[155. Min Stack (Easy)](https://leetcode.com/problems/min-stack/description/)
```java
class MinStack {
private Stack<Integer> dataStack;
private Stack<Integer> minStack;
private int min;
public MinStack() {
dataStack = new Stack<>();
minStack = new Stack<>();
min = Integer.MAX_VALUE;
}
public void push(int x) {
dataStack.add(x);
min = Math.min(min, x);
minStack.add(min);
}
public void pop() {
dataStack.pop();
minStack.pop();
min = minStack.isEmpty() ? Integer.MAX_VALUE : minStack.peek();
}
public int top() {
return dataStack.peek();
}
public int getMin() {
return minStack.peek();
}
}
```
对于实现最小值队列问题,可以先将队列使用栈来实现,然后就将问题转换为最小值栈,这个问题出现在 编程之美3.7。
# 用栈实现括号匹配
[20. Valid Parentheses (Easy)](https://leetcode.com/problems/valid-parentheses/description/)
```html
"()[]{}"
Output : true
```
```java
public boolean isValid(String s) {
Stack<Character> stack = new Stack<>();
for (char c : s.toCharArray()) {
if (c == '(' || c == '{' || c == '[') {
stack.push(c);
} else {
if (stack.isEmpty()) {
return false;
}
char cStack = stack.pop();
boolean b1 = c == ')' && cStack != '(';
boolean b2 = c == ']' && cStack != '[';
boolean b3 = c == '}' && cStack != '{';
if (b1 || b2 || b3) {
return false;
}
}
}
return stack.isEmpty();
}
```
# 数组中元素与下一个比它大的元素之间的距离
[739. Daily Temperatures (Medium)](https://leetcode.com/problems/daily-temperatures/description/)
```html
Input: [73, 74, 75, 71, 69, 72, 76, 73]
Output: [1, 1, 4, 2, 1, 1, 0, 0]
```
在遍历数组时用栈把数组中的数存起来,如果当前遍历的数比栈顶元素来的大,说明栈顶元素的下一个比它大的数就是当前元素。
```java
public int[] dailyTemperatures(int[] temperatures) {
int n = temperatures.length;
int[] dist = new int[n];
Stack<Integer> indexs = new Stack<>();
for (int curIndex = 0; curIndex < n; curIndex++) {
while (!indexs.isEmpty() && temperatures[curIndex] > temperatures[indexs.peek()]) {
int preIndex = indexs.pop();
dist[preIndex] = curIndex - preIndex;
}
indexs.add(curIndex);
}
return dist;
}
```
# 循环数组中比当前元素大的下一个元素
[503. Next Greater Element II (Medium)](https://leetcode.com/problems/next-greater-element-ii/description/)
```text
Input: [1,2,1]
Output: [2,-1,2]
Explanation: The first 1's next greater number is 2;
The number 2 can't find next greater number;
The second 1's next greater number needs to search circularly, which is also 2.
```
与 739. Daily Temperatures (Medium) 不同的是,数组是循环数组,并且最后要求的不是距离而是下一个元素。
```java
public int[] nextGreaterElements(int[] nums) {
int n = nums.length;
int[] next = new int[n];
Arrays.fill(next, -1);
Stack<Integer> pre = new Stack<>();
for (int i = 0; i < n * 2; i++) {
int num = nums[i % n];
while (!pre.isEmpty() && nums[pre.peek()] < num) {
next[pre.pop()] = num;
}
if (i < n){
pre.push(i);
}
}
return next;
}
```
</br><div align="center">⭐️欢迎关注我的公众号 CyC2018在公众号后台回复关键字 📚 **资料** 可领取复习大纲,这份大纲是我花了一整年时间整理的面试知识点列表,不仅系统整理了面试知识点,而且标注了各个知识点的重要程度,从而帮你理清多而杂的面试知识点。可以说我基本是按照这份大纲来进行复习的,这份大纲对我拿到了 BAT 头条等 Offer 起到很大的帮助。你们完全可以和我一样根据大纲上列的知识点来进行复习,就不用看很多不重要的内容,也可以知道哪些内容很重要从而多安排一些复习时间。</div></br>
<div align="center"><img width="180px" src="https://cyc-1256109796.cos.ap-guangzhou.myqcloud.com/%E5%85%AC%E4%BC%97%E5%8F%B7.jpg"></img></div>

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,44 @@
<!-- GFM-TOC -->
* [算法思想](#算法思想)
* [数据结构相关](#数据结构相关)
* [参考资料](#参考资料)
<!-- GFM-TOC -->
# 算法思想
- [双指针](Leetcode%20题解%20-%20双指针.md)
- [排序](Leetcode%20题解%20-%20排序.md)
- [贪心思想](Leetcode%20题解%20-%20贪心思想.md)
- [二分查找](Leetcode%20题解%20-%20二分查找.md)
- [分治](Leetcode%20题解%20-%20分治.md)
- [搜索](Leetcode%20题解%20-%20搜索.md)
- [动态规划](Leetcode%20题解%20-%20动态规划.md)
- [数学](Leetcode%20题解%20-%20数学.md)
# 数据结构相关
- [链表](Leetcode%20题解%20-%20链表.md)
- [](Leetcode%20题解%20-%20树.md)
- [栈和队列](Leetcode%20题解%20-%20栈和队列.md)
- [哈希表](Leetcode%20题解%20-%20哈希表.md)
- [字符串](Leetcode%20题解%20-%20字符串.md)
- [数组与矩阵](Leetcode%20题解%20-%20数组与矩阵.md)
- [](Leetcode%20题解%20-%20图.md)
- [位运算](Leetcode%20题解%20-%20位运算.md)
# 参考资料
- Leetcode
- Weiss M A, 冯舜玺. 数据结构与算法分析——C 语言描述[J]. 2004.
- Sedgewick R. Algorithms[M]. Pearson Education India, 1988.
- 何海涛, 软件工程师. 剑指 Offer: 名企面试官精讲典型编程题[M]. 电子工业出版社, 2014.
- 《编程之美》小组. 编程之美[M]. 电子工业出版社, 2008.
- 左程云. 程序员代码面试指南[M]. 电子工业出版社, 2015.
</br><div align="center">⭐️欢迎关注我的公众号 CyC2018在公众号后台回复关键字 📚 **资料** 可领取复习大纲,这份大纲是我花了一整年时间整理的面试知识点列表,不仅系统整理了面试知识点,而且标注了各个知识点的重要程度,从而帮你理清多而杂的面试知识点。可以说我基本是按照这份大纲来进行复习的,这份大纲对我拿到了 BAT 头条等 Offer 起到很大的帮助。你们完全可以和我一样根据大纲上列的知识点来进行复习,就不用看很多不重要的内容,也可以知道哪些内容很重要从而多安排一些复习时间。</div></br>
<div align="center"><img width="180px" src="https://cyc-1256109796.cos.ap-guangzhou.myqcloud.com/%E5%85%AC%E4%BC%97%E5%8F%B7.jpg"></img></div>

View File

@ -0,0 +1,44 @@
<!-- GFM-TOC -->
* [算法思想](#算法思想)
* [数据结构相关](#数据结构相关)
* [参考资料](#参考资料)
<!-- GFM-TOC -->
# 算法思想
- [双指针](notes/Leetcode%20题解%20-%20双指针.md)
- [排序](notes/Leetcode%20题解%20-%20排序.md)
- [贪心思想](notes/Leetcode%20题解%20-%20贪心思想.md)
- [二分查找](notes/Leetcode%20题解%20-%20二分查找.md)
- [分治](notes/Leetcode%20题解%20-%20分治.md)
- [搜索](notes/Leetcode%20题解%20-%20搜索.md)
- [动态规划](notes/Leetcode%20题解%20-%20动态规划.md)
- [数学](notes/Leetcode%20题解%20-%20数学.md)
# 数据结构相关
- [链表](notes/Leetcode%20题解%20-%20链表.md)
- [](notes/Leetcode%20题解%20-%20树.md)
- [栈和队列](notes/Leetcode%20题解%20-%20栈和队列.md)
- [哈希表](notes/Leetcode%20题解%20-%20哈希表.md)
- [字符串](notes/Leetcode%20题解%20-%20字符串.md)
- [数组与矩阵](notes/Leetcode%20题解%20-%20数组与矩阵.md)
- [](notes/Leetcode%20题解%20-%20图.md)
- [位运算](notes/Leetcode%20题解%20-%20位运算.md)
# 参考资料
- Leetcode
- Weiss M A, 冯舜玺. 数据结构与算法分析——C 语言描述[J]. 2004.
- Sedgewick R. Algorithms[M]. Pearson Education India, 1988.
- 何海涛, 软件工程师. 剑指 Offer: 名企面试官精讲典型编程题[M]. 电子工业出版社, 2014.
- 《编程之美》小组. 编程之美[M]. 电子工业出版社, 2008.
- 左程云. 程序员代码面试指南[M]. 电子工业出版社, 2015.
</br><div align="center">⭐️欢迎关注我的公众号 CyC2018在公众号后台回复关键字 📚 **资料** 可领取复习大纲,这份大纲是我花了一整年时间整理的面试知识点列表,不仅系统整理了面试知识点,而且标注了各个知识点的重要程度,从而帮你理清多而杂的面试知识点。可以说我基本是按照这份大纲来进行复习的,这份大纲对我拿到了 BAT 头条等 Offer 起到很大的帮助。你们完全可以和我一样根据大纲上列的知识点来进行复习,就不用看很多不重要的内容,也可以知道哪些内容很重要从而多安排一些复习时间。</div></br>
<div align="center"><img width="180px" src="https://cyc-1256109796.cos.ap-guangzhou.myqcloud.com/%E5%85%AC%E4%BC%97%E5%8F%B7.jpg"></img></div>

View File

@ -0,0 +1,372 @@
<!-- GFM-TOC -->
* [分配饼干](#分配饼干)
* [不重叠的区间个数](#不重叠的区间个数)
* [投飞镖刺破气球](#投飞镖刺破气球)
* [根据身高和序号重组队列](#根据身高和序号重组队列)
* [分隔字符串使同种字符出现在一起](#分隔字符串使同种字符出现在一起)
* [种植花朵](#种植花朵)
* [判断是否为子序列](#判断是否为子序列)
* [修改一个数成为非递减数组](#修改一个数成为非递减数组)
* [股票的最大收益](#股票的最大收益)
* [子数组最大的和](#子数组最大的和)
* [买入和售出股票最大的收益](#买入和售出股票最大的收益)
<!-- GFM-TOC -->
保证每次操作都是局部最优的,并且最后得到的结果是全局最优的。
# 分配饼干
[455. Assign Cookies (Easy)](https://leetcode.com/problems/assign-cookies/description/)
```html
Input: [1,2], [1,2,3]
Output: 2
Explanation: You have 2 children and 3 cookies. The greed factors of 2 children are 1, 2.
You have 3 cookies and their sizes are big enough to gratify all of the children,
You need to output 2.
```
题目描述:每个孩子都有一个满足度,每个饼干都有一个大小,只有饼干的大小大于等于一个孩子的满足度,该孩子才会获得满足。求解最多可以获得满足的孩子数量。
给一个孩子的饼干应当尽量小又能满足该孩子,这样大饼干就能拿来给满足度比较大的孩子。因为最小的孩子最容易得到满足,所以先满足最小的孩子。
证明:假设在某次选择中,贪心策略选择给当前满足度最小的孩子分配第 m 个饼干,第 m 个饼干为可以满足该孩子的最小饼干。假设存在一种最优策略,给该孩子分配第 n 个饼干,并且 m < n我们可以发现经过这一轮分配贪心策略分配后剩下的饼干一定有一个比最优策略来得大因此在后续的分配中贪心策略一定能满足更多的孩子也就是说不存在比贪心策略更优的策略即贪心策略就是最优策略
```java
public int findContentChildren(int[] g, int[] s) {
Arrays.sort(g);
Arrays.sort(s);
int gi = 0, si = 0;
while (gi < g.length && si < s.length) {
if (g[gi] <= s[si]) {
gi++;
}
si++;
}
return gi;
}
```
# 不重叠的区间个数
[435. Non-overlapping Intervals (Medium)](https://leetcode.com/problems/non-overlapping-intervals/description/)
```html
Input: [ [1,2], [1,2], [1,2] ]
Output: 2
Explanation: You need to remove two [1,2] to make the rest of intervals non-overlapping.
```
```html
Input: [ [1,2], [2,3] ]
Output: 0
Explanation: You don't need to remove any of the intervals since they're already non-overlapping.
```
题目描述:计算让一组区间不重叠所需要移除的区间个数。
先计算最多能组成的不重叠区间个数,然后用区间总个数减去不重叠区间的个数。
在每次选择中,区间的结尾最为重要,选择的区间结尾越小,留给后面的区间的空间越大,那么后面能够选择的区间个数也就越大。
按区间的结尾进行排序,每次选择结尾最小,并且和前一个区间不重叠的区间。
```java
public int eraseOverlapIntervals(Interval[] intervals) {
if (intervals.length == 0) {
return 0;
}
Arrays.sort(intervals, Comparator.comparingInt(o -> o.end));
int cnt = 1;
int end = intervals[0].end;
for (int i = 1; i < intervals.length; i++) {
if (intervals[i].start < end) {
continue;
}
end = intervals[i].end;
cnt++;
}
return intervals.length - cnt;
}
```
使用 lambda 表示式创建 Comparator 会导致算法运行时间过长,如果注重运行时间,可以修改为普通创建 Comparator 语句:
```java
Arrays.sort(intervals, new Comparator<Interval>() {
@Override
public int compare(Interval o1, Interval o2) {
return o1.end - o2.end;
}
});
```
# 投飞镖刺破气球
[452. Minimum Number of Arrows to Burst Balloons (Medium)](https://leetcode.com/problems/minimum-number-of-arrows-to-burst-balloons/description/)
```
Input:
[[10,16], [2,8], [1,6], [7,12]]
Output:
2
```
题目描述:气球在一个水平数轴上摆放,可以重叠,飞镖垂直投向坐标轴,使得路径上的气球都会刺破。求解最小的投飞镖次数使所有气球都被刺破。
也是计算不重叠的区间个数,不过和 Non-overlapping Intervals 的区别在于,[1, 2] 和 [2, 3] 在本题中算是重叠区间。
```java
public int findMinArrowShots(int[][] points) {
if (points.length == 0) {
return 0;
}
Arrays.sort(points, Comparator.comparingInt(o -> o[1]));
int cnt = 1, end = points[0][1];
for (int i = 1; i < points.length; i++) {
if (points[i][0] <= end) {
continue;
}
cnt++;
end = points[i][1];
}
return cnt;
}
```
# 根据身高和序号重组队列
[406. Queue Reconstruction by Height(Medium)](https://leetcode.com/problems/queue-reconstruction-by-height/description/)
```html
Input:
[[7,0], [4,4], [7,1], [5,0], [6,1], [5,2]]
Output:
[[5,0], [7,0], [5,2], [6,1], [4,4], [7,1]]
```
题目描述:一个学生用两个分量 (h, k) 描述h 表示身高k 表示排在前面的有 k 个学生的身高比他高或者和他一样高。
为了使插入操作不影响后续的操作,身高较高的学生应该先做插入操作,否则身高较小的学生原先正确插入的第 k 个位置可能会变成第 k+1 个位置。
身高降序、k 值升序,然后按排好序的顺序插入队列的第 k 个位置中。
```java
public int[][] reconstructQueue(int[][] people) {
if (people == null || people.length == 0 || people[0].length == 0) {
return new int[0][0];
}
Arrays.sort(people, (a, b) -> (a[0] == b[0] ? a[1] - b[1] : b[0] - a[0]));
List<int[]> queue = new ArrayList<>();
for (int[] p : people) {
queue.add(p[1], p);
}
return queue.toArray(new int[queue.size()][]);
}
```
# 分隔字符串使同种字符出现在一起
[763. Partition Labels (Medium)](https://leetcode.com/problems/partition-labels/description/)
```html
Input: S = "ababcbacadefegdehijhklij"
Output: [9,7,8]
Explanation:
The partition is "ababcbaca", "defegde", "hijhklij".
This is a partition so that each letter appears in at most one part.
A partition like "ababcbacadefegde", "hijhklij" is incorrect, because it splits S into less parts.
```
```java
public List<Integer> partitionLabels(String S) {
int[] lastIndexsOfChar = new int[26];
for (int i = 0; i < S.length(); i++) {
lastIndexsOfChar[char2Index(S.charAt(i))] = i;
}
List<Integer> partitions = new ArrayList<>();
int firstIndex = 0;
while (firstIndex < S.length()) {
int lastIndex = firstIndex;
for (int i = firstIndex; i < S.length() && i <= lastIndex; i++) {
int index = lastIndexsOfChar[char2Index(S.charAt(i))];
if (index > lastIndex) {
lastIndex = index;
}
}
partitions.add(lastIndex - firstIndex + 1);
firstIndex = lastIndex + 1;
}
return partitions;
}
private int char2Index(char c) {
return c - 'a';
}
```
# 种植花朵
[605. Can Place Flowers (Easy)](https://leetcode.com/problems/can-place-flowers/description/)
```html
Input: flowerbed = [1,0,0,0,1], n = 1
Output: True
```
题目描述:花朵之间至少需要一个单位的间隔,求解是否能种下 n 朵花。
```java
public boolean canPlaceFlowers(int[] flowerbed, int n) {
int len = flowerbed.length;
int cnt = 0;
for (int i = 0; i < len && cnt < n; i++) {
if (flowerbed[i] == 1) {
continue;
}
int pre = i == 0 ? 0 : flowerbed[i - 1];
int next = i == len - 1 ? 0 : flowerbed[i + 1];
if (pre == 0 && next == 0) {
cnt++;
flowerbed[i] = 1;
}
}
return cnt >= n;
}
```
# 判断是否为子序列
[392. Is Subsequence (Medium)](https://leetcode.com/problems/is-subsequence/description/)
```html
s = "abc", t = "ahbgdc"
Return true.
```
```java
public boolean isSubsequence(String s, String t) {
int index = -1;
for (char c : s.toCharArray()) {
index = t.indexOf(c, index + 1);
if (index == -1) {
return false;
}
}
return true;
}
```
# 修改一个数成为非递减数组
[665. Non-decreasing Array (Easy)](https://leetcode.com/problems/non-decreasing-array/description/)
```html
Input: [4,2,3]
Output: True
Explanation: You could modify the first 4 to 1 to get a non-decreasing array.
```
题目描述:判断一个数组能不能只修改一个数就成为非递减数组。
在出现 nums[i] < nums[i - 1] 需要考虑的是应该修改数组的哪个数使得本次修改能使 i 之前的数组成为非递减数组并且 **不影响后续的操作** 优先考虑令 nums[i - 1] = nums[i]因为如果修改 nums[i] = nums[i - 1] 的话那么 nums[i] 这个数会变大就有可能比 nums[i + 1] 从而影响了后续操作还有一个比较特别的情况就是 nums[i] < nums[i - 2]只修改 nums[i - 1] = nums[i] 不能使数组成为非递减数组只能修改 nums[i] = nums[i - 1]。
```java
public boolean checkPossibility(int[] nums) {
int cnt = 0;
for (int i = 1; i < nums.length && cnt < 2; i++) {
if (nums[i] >= nums[i - 1]) {
continue;
}
cnt++;
if (i - 2 >= 0 && nums[i - 2] > nums[i]) {
nums[i] = nums[i - 1];
} else {
nums[i - 1] = nums[i];
}
}
return cnt <= 1;
}
```
# 股票的最大收益
[122. Best Time to Buy and Sell Stock II (Easy)](https://leetcode.com/problems/best-time-to-buy-and-sell-stock-ii/description/)
题目描述:一次股票交易包含买入和卖出,多个交易之间不能交叉进行。
对于 [a, b, c, d],如果有 a <= b <= c <= d ,那么最大收益为 d - a。而 d - a = (d - c) + (c - b) + (b - a) ,因此当访问到一个 prices[i] 且 prices[i] - prices[i-1] > 0那么就把 prices[i] - prices[i-1] 添加到收益中,从而在局部最优的情况下也保证全局最优。
```java
public int maxProfit(int[] prices) {
int profit = 0;
for (int i = 1; i < prices.length; i++) {
if (prices[i] > prices[i - 1]) {
profit += (prices[i] - prices[i - 1]);
}
}
return profit;
}
```
# 子数组最大的和
[53. Maximum Subarray (Easy)](https://leetcode.com/problems/maximum-subarray/description/)
```html
For example, given the array [-2,1,-3,4,-1,2,1,-5,4],
the contiguous subarray [4,-1,2,1] has the largest sum = 6.
```
```java
public int maxSubArray(int[] nums) {
if (nums == null || nums.length == 0) {
return 0;
}
int preSum = nums[0];
int maxSum = preSum;
for (int i = 1; i < nums.length; i++) {
preSum = preSum > 0 ? preSum + nums[i] : nums[i];
maxSum = Math.max(maxSum, preSum);
}
return maxSum;
}
```
# 买入和售出股票最大的收益
[121. Best Time to Buy and Sell Stock (Easy)](https://leetcode.com/problems/best-time-to-buy-and-sell-stock/description/)
题目描述:只进行一次交易。
只要记录前面的最小价格,将这个最小价格作为买入价格,然后将当前的价格作为售出价格,查看当前收益是不是最大收益。
```java
public int maxProfit(int[] prices) {
int n = prices.length;
if (n == 0) return 0;
int soFarMin = prices[0];
int max = 0;
for (int i = 1; i < n; i++) {
if (soFarMin > prices[i]) soFarMin = prices[i];
else max = Math.max(max, prices[i] - soFarMin);
}
return max;
}
```
</br><div align="center">⭐️欢迎关注我的公众号 CyC2018在公众号后台回复关键字 📚 **资料** 可领取复习大纲,这份大纲是我花了一整年时间整理的面试知识点列表,不仅系统整理了面试知识点,而且标注了各个知识点的重要程度,从而帮你理清多而杂的面试知识点。可以说我基本是按照这份大纲来进行复习的,这份大纲对我拿到了 BAT 头条等 Offer 起到很大的帮助。你们完全可以和我一样根据大纲上列的知识点来进行复习,就不用看很多不重要的内容,也可以知道哪些内容很重要从而多安排一些复习时间。</div></br>
<div align="center"><img width="180px" src="https://cyc-1256109796.cos.ap-guangzhou.myqcloud.com/%E5%85%AC%E4%BC%97%E5%8F%B7.jpg"></img></div>

View File

@ -0,0 +1,333 @@
<!-- GFM-TOC -->
* [找出两个链表的交点](#找出两个链表的交点)
* [链表反转](#链表反转)
* [归并两个有序的链表](#归并两个有序的链表)
* [从有序链表中删除重复节点](#从有序链表中删除重复节点)
* [删除链表的倒数第 n 个节点](#删除链表的倒数第-n-个节点)
* [交换链表中的相邻结点](#交换链表中的相邻结点)
* [链表求和](#链表求和)
* [回文链表](#回文链表)
* [分隔链表](#分隔链表)
* [链表元素按奇偶聚集](#链表元素按奇偶聚集)
<!-- GFM-TOC -->
链表是空节点,或者有一个值和一个指向下一个链表的指针,因此很多链表问题可以用递归来处理。
# 找出两个链表的交点
[160. Intersection of Two Linked Lists (Easy)](https://leetcode.com/problems/intersection-of-two-linked-lists/description/)
```html
A: a1 → a2
c1 → c2 → c3
B: b1 → b2 → b3
```
要求:时间复杂度为 O(N),空间复杂度为 O(1)
设 A 的长度为 a + cB 的长度为 b + c其中 c 为尾部公共部分长度,可知 a + c + b = b + c + a。
当访问 A 链表的指针访问到链表尾部时,令它从链表 B 的头部开始访问链表 B同样地当访问 B 链表的指针访问到链表尾部时,令它从链表 A 的头部开始访问链表 A。这样就能控制访问 A 和 B 两个链表的指针能同时访问到交点。
```java
public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
ListNode l1 = headA, l2 = headB;
while (l1 != l2) {
l1 = (l1 == null) ? headB : l1.next;
l2 = (l2 == null) ? headA : l2.next;
}
return l1;
}
```
如果只是判断是否存在交点,那么就是另一个问题,即 [编程之美 3.6]() 的问题。有两种解法:
- 把第一个链表的结尾连接到第二个链表的开头,看第二个链表是否存在环;
- 或者直接比较两个链表的最后一个节点是否相同。
# 链表反转
[206. Reverse Linked List (Easy)](https://leetcode.com/problems/reverse-linked-list/description/)
递归
```java
public ListNode reverseList(ListNode head) {
if (head == null || head.next == null) {
return head;
}
ListNode next = head.next;
ListNode newHead = reverseList(next);
next.next = head;
head.next = null;
return newHead;
}
```
头插法
```java
public ListNode reverseList(ListNode head) {
ListNode newHead = new ListNode(-1);
while (head != null) {
ListNode next = head.next;
head.next = newHead.next;
newHead.next = head;
head = next;
}
return newHead.next;
}
```
# 归并两个有序的链表
[21. Merge Two Sorted Lists (Easy)](https://leetcode.com/problems/merge-two-sorted-lists/description/)
```java
public ListNode mergeTwoLists(ListNode l1, ListNode l2) {
if (l1 == null) return l2;
if (l2 == null) return l1;
if (l1.val < l2.val) {
l1.next = mergeTwoLists(l1.next, l2);
return l1;
} else {
l2.next = mergeTwoLists(l1, l2.next);
return l2;
}
}
```
# 从有序链表中删除重复节点
[83. Remove Duplicates from Sorted List (Easy)](https://leetcode.com/problems/remove-duplicates-from-sorted-list/description/)
```html
Given 1->1->2, return 1->2.
Given 1->1->2->3->3, return 1->2->3.
```
```java
public ListNode deleteDuplicates(ListNode head) {
if (head == null || head.next == null) return head;
head.next = deleteDuplicates(head.next);
return head.val == head.next.val ? head.next : head;
}
```
# 删除链表的倒数第 n 个节点
[19. Remove Nth Node From End of List (Medium)](https://leetcode.com/problems/remove-nth-node-from-end-of-list/description/)
```html
Given linked list: 1->2->3->4->5, and n = 2.
After removing the second node from the end, the linked list becomes 1->2->3->5.
```
```java
public ListNode removeNthFromEnd(ListNode head, int n) {
ListNode fast = head;
while (n-- > 0) {
fast = fast.next;
}
if (fast == null) return head.next;
ListNode slow = head;
while (fast.next != null) {
fast = fast.next;
slow = slow.next;
}
slow.next = slow.next.next;
return head;
}
```
# 交换链表中的相邻结点
[24. Swap Nodes in Pairs (Medium)](https://leetcode.com/problems/swap-nodes-in-pairs/description/)
```html
Given 1->2->3->4, you should return the list as 2->1->4->3.
```
题目要求:不能修改结点的 val 值O(1) 空间复杂度。
```java
public ListNode swapPairs(ListNode head) {
ListNode node = new ListNode(-1);
node.next = head;
ListNode pre = node;
while (pre.next != null && pre.next.next != null) {
ListNode l1 = pre.next, l2 = pre.next.next;
ListNode next = l2.next;
l1.next = next;
l2.next = l1;
pre.next = l2;
pre = l1;
}
return node.next;
}
```
# 链表求和
[445. Add Two Numbers II (Medium)](https://leetcode.com/problems/add-two-numbers-ii/description/)
```html
Input: (7 -> 2 -> 4 -> 3) + (5 -> 6 -> 4)
Output: 7 -> 8 -> 0 -> 7
```
题目要求:不能修改原始链表。
```java
public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
Stack<Integer> l1Stack = buildStack(l1);
Stack<Integer> l2Stack = buildStack(l2);
ListNode head = new ListNode(-1);
int carry = 0;
while (!l1Stack.isEmpty() || !l2Stack.isEmpty() || carry != 0) {
int x = l1Stack.isEmpty() ? 0 : l1Stack.pop();
int y = l2Stack.isEmpty() ? 0 : l2Stack.pop();
int sum = x + y + carry;
ListNode node = new ListNode(sum % 10);
node.next = head.next;
head.next = node;
carry = sum / 10;
}
return head.next;
}
private Stack<Integer> buildStack(ListNode l) {
Stack<Integer> stack = new Stack<>();
while (l != null) {
stack.push(l.val);
l = l.next;
}
return stack;
}
```
# 回文链表
[234. Palindrome Linked List (Easy)](https://leetcode.com/problems/palindrome-linked-list/description/)
题目要求:以 O(1) 的空间复杂度来求解。
切成两半,把后半段反转,然后比较两半是否相等。
```java
public boolean isPalindrome(ListNode head) {
if (head == null || head.next == null) return true;
ListNode slow = head, fast = head.next;
while (fast != null && fast.next != null) {
slow = slow.next;
fast = fast.next.next;
}
if (fast != null) slow = slow.next; // 偶数节点,让 slow 指向下一个节点
cut(head, slow); // 切成两个链表
return isEqual(head, reverse(slow));
}
private void cut(ListNode head, ListNode cutNode) {
while (head.next != cutNode) {
head = head.next;
}
head.next = null;
}
private ListNode reverse(ListNode head) {
ListNode newHead = null;
while (head != null) {
ListNode nextNode = head.next;
head.next = newHead;
newHead = head;
head = nextNode;
}
return newHead;
}
private boolean isEqual(ListNode l1, ListNode l2) {
while (l1 != null && l2 != null) {
if (l1.val != l2.val) return false;
l1 = l1.next;
l2 = l2.next;
}
return true;
}
```
# 分隔链表
[725. Split Linked List in Parts(Medium)](https://leetcode.com/problems/split-linked-list-in-parts/description/)
```html
Input:
root = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10], k = 3
Output: [[1, 2, 3, 4], [5, 6, 7], [8, 9, 10]]
Explanation:
The input has been split into consecutive parts with size difference at most 1, and earlier parts are a larger size than the later parts.
```
题目描述:把链表分隔成 k 部分,每部分的长度都应该尽可能相同,排在前面的长度应该大于等于后面的。
```java
public ListNode[] splitListToParts(ListNode root, int k) {
int N = 0;
ListNode cur = root;
while (cur != null) {
N++;
cur = cur.next;
}
int mod = N % k;
int size = N / k;
ListNode[] ret = new ListNode[k];
cur = root;
for (int i = 0; cur != null && i < k; i++) {
ret[i] = cur;
int curSize = size + (mod-- > 0 ? 1 : 0);
for (int j = 0; j < curSize - 1; j++) {
cur = cur.next;
}
ListNode next = cur.next;
cur.next = null;
cur = next;
}
return ret;
}
```
# 链表元素按奇偶聚集
[328. Odd Even Linked List (Medium)](https://leetcode.com/problems/odd-even-linked-list/description/)
```html
Example:
Given 1->2->3->4->5->NULL,
return 1->3->5->2->4->NULL.
```
```java
public ListNode oddEvenList(ListNode head) {
if (head == null) {
return head;
}
ListNode odd = head, even = head.next, evenHead = even;
while (even != null && even.next != null) {
odd.next = odd.next.next;
odd = odd.next;
even.next = even.next.next;
even = even.next;
}
odd.next = evenHead;
return head;
}
```
</br><div align="center">⭐️欢迎关注我的公众号 CyC2018在公众号后台回复关键字 📚 **资料** 可领取复习大纲,这份大纲是我花了一整年时间整理的面试知识点列表,不仅系统整理了面试知识点,而且标注了各个知识点的重要程度,从而帮你理清多而杂的面试知识点。可以说我基本是按照这份大纲来进行复习的,这份大纲对我拿到了 BAT 头条等 Offer 起到很大的帮助。你们完全可以和我一样根据大纲上列的知识点来进行复习,就不用看很多不重要的内容,也可以知道哪些内容很重要从而多安排一些复习时间。</div></br>
<div align="center"><img width="180px" src="https://cyc-1256109796.cos.ap-guangzhou.myqcloud.com/%E5%85%AC%E4%BC%97%E5%8F%B7.jpg"></img></div>

File diff suppressed because it is too large Load Diff

View File

@ -496,7 +496,7 @@ https://leetcode.com/problems/customers-who-never-order/description/
## Description ## Description
Curstomers 表: Customers 表:
```html ```html
+----+-------+ +----+-------+
@ -948,3 +948,9 @@ WHERE
ORDER BY ORDER BY
id; id;
``` ```
</br><div align="center">⭐️欢迎关注我的公众号 CyC2018在公众号后台回复关键字 📚 **资料** 可领取复习大纲,这份大纲是我花了一整年时间整理的面试知识点列表,不仅系统整理了面试知识点,而且标注了各个知识点的重要程度,从而帮你理清多而杂的面试知识点。可以说我基本是按照这份大纲来进行复习的,这份大纲对我拿到了 BAT 头条等 Offer 起到很大的帮助。你们完全可以和我一样根据大纲上列的知识点来进行复习,就不用看很多不重要的内容,也可以知道哪些内容很重要从而多安排一些复习时间。</div></br>
<div align="center"><img width="180px" src="https://cyc-1256109796.cos.ap-guangzhou.myqcloud.com/%E5%85%AC%E4%BC%97%E5%8F%B7.jpg"></img></div>

View File

@ -157,7 +157,7 @@ Linux 发行版是 Linux 内核及各种应用软件的集成版本。
- 编辑模式Insert mode按下 "i" 等按键之后进入,可以对文本进行编辑; - 编辑模式Insert mode按下 "i" 等按键之后进入,可以对文本进行编辑;
- 指令列模式Bottom-line mode按下 ":" 按键之后进入,用于保存退出等操作。 - 指令列模式Bottom-line mode按下 ":" 按键之后进入,用于保存退出等操作。
<div align="center"> <img src="pics/5942debd-fc00-477a-b390-7c5692cc8070.jpg" width="400"/> </div><br> <div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/5942debd-fc00-477a-b390-7c5692cc8070.jpg" width="400"/> </div><br>
在指令列模式下,有以下命令用于离开或者保存文件。 在指令列模式下,有以下命令用于离开或者保存文件。
@ -191,25 +191,25 @@ GNU 计划,译为革奴计划,它的目标是创建一套完全自由的操
IDEATA全称 Advanced Technology Attachment接口速度最大为 133MB/s因为并口线的抗干扰性太差且排线占用空间较大不利电脑内部散热已逐渐被 SATA 所取代。 IDEATA全称 Advanced Technology Attachment接口速度最大为 133MB/s因为并口线的抗干扰性太差且排线占用空间较大不利电脑内部散热已逐渐被 SATA 所取代。
<div align="center"> <img src="pics/924914c0-660c-4e4a-bbc0-1df1146e7516.jpg" width="400"/> </div><br> <div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/924914c0-660c-4e4a-bbc0-1df1146e7516.jpg" width="400"/> </div><br>
### 2. SATA ### 2. SATA
SATA 全称 Serial ATA也就是使用串口的 ATA 接口,抗干扰性强,且对数据线的长度要求比 ATA 低很多支持热插拔等功能。SATA-II 的接口速度为 300MiB/s而新的 SATA-III 标准可达到 600MiB/s 的传输速度。SATA 的数据线也比 ATA 的细得多,有利于机箱内的空气流通,整理线材也比较方便。 SATA 全称 Serial ATA也就是使用串口的 ATA 接口,抗干扰性强,且对数据线的长度要求比 ATA 低很多支持热插拔等功能。SATA-II 的接口速度为 300MiB/s而新的 SATA-III 标准可达到 600MiB/s 的传输速度。SATA 的数据线也比 ATA 的细得多,有利于机箱内的空气流通,整理线材也比较方便。
<div align="center"> <img src="pics/f9f2a16b-4843-44d1-9759-c745772e9bcf.jpg" width=""/> </div><br> <div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/f9f2a16b-4843-44d1-9759-c745772e9bcf.jpg" width=""/> </div><br>
### 3. SCSI ### 3. SCSI
SCSI 全称是 Small Computer System Interface小型机系统接口经历多代的发展从早期的 SCSI-II 到目前的 Ultra320 SCSI 以及 Fiber-Channel光纤通道接口型式也多种多样。SCSI 硬盘广为工作站级个人电脑以及服务器所使用,因此会使用较为先进的技术,如碟片转速 15000rpm 的高转速,且传输时 CPU 占用率较低,但是单价也比相同容量的 ATA 及 SATA 硬盘更加昂贵。 SCSI 全称是 Small Computer System Interface小型机系统接口经历多代的发展从早期的 SCSI-II 到目前的 Ultra320 SCSI 以及 Fiber-Channel光纤通道接口型式也多种多样。SCSI 硬盘广为工作站级个人电脑以及服务器所使用,因此会使用较为先进的技术,如碟片转速 15000rpm 的高转速,且传输时 CPU 占用率较低,但是单价也比相同容量的 ATA 及 SATA 硬盘更加昂贵。
<div align="center"> <img src="pics/f0574025-c514-49f5-a591-6d6a71f271f7.jpg" width=""/> </div><br> <div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/f0574025-c514-49f5-a591-6d6a71f271f7.jpg" width=""/> </div><br>
### 4. SAS ### 4. SAS
SASSerial Attached SCSI是新一代的 SCSI 技术,和 SATA 硬盘相同,都是采取序列式技术以获得更高的传输速度,可达到 6Gb/s。此外也透过缩小连接线改善系统内部空间等。 SASSerial Attached SCSI是新一代的 SCSI 技术,和 SATA 硬盘相同,都是采取序列式技术以获得更高的传输速度,可达到 6Gb/s。此外也透过缩小连接线改善系统内部空间等。
<div align="center"> <img src="pics/6729baa0-57d7-4817-b3aa-518cbccf824c.jpg" width=""/> </div><br> <div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/6729baa0-57d7-4817-b3aa-518cbccf824c.jpg" width=""/> </div><br>
## 磁盘的文件名 ## 磁盘的文件名
@ -244,7 +244,7 @@ GPT 没有扩展分区概念,都是主分区,每个 LAB 可以分 4 个分
MBR 不支持 2.2 TB 以上的硬盘GPT 则最多支持到 2<sup>33</sup> TB = 8 ZB。 MBR 不支持 2.2 TB 以上的硬盘GPT 则最多支持到 2<sup>33</sup> TB = 8 ZB。
<div align="center"> <img src="pics/GUID_Partition_Table_Scheme.svg.png" width="400"/> </div><br> <div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/GUID_Partition_Table_Scheme.svg.png" width="400"/> </div><br>
## 开机检测程序 ## 开机检测程序
@ -252,7 +252,7 @@ MBR 不支持 2.2 TB 以上的硬盘GPT 则最多支持到 2<sup>33</sup> TB
BIOSBasic Input/Output System基本输入输出系统它是一个固件嵌入在硬件中的软件BIOS 程序存放在断电后内容不会丢失的只读内存中。 BIOSBasic Input/Output System基本输入输出系统它是一个固件嵌入在硬件中的软件BIOS 程序存放在断电后内容不会丢失的只读内存中。
<div align="center"> <img src="pics/50831a6f-2777-46ea-a571-29f23c85cc21.jpg"/> </div><br> <div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/50831a6f-2777-46ea-a571-29f23c85cc21.jpg"/> </div><br>
BIOS 是开机的时候计算机执行的第一个程序这个程序知道可以开机的磁盘并读取磁盘第一个扇区的主要开机记录MBR由主要开机记录MBR执行其中的开机管理程序这个开机管理程序会加载操作系统的核心文件。 BIOS 是开机的时候计算机执行的第一个程序这个程序知道可以开机的磁盘并读取磁盘第一个扇区的主要开机记录MBR由主要开机记录MBR执行其中的开机管理程序这个开机管理程序会加载操作系统的核心文件。
@ -260,7 +260,7 @@ BIOS 是开机的时候计算机执行的第一个程序,这个程序知道可
下图中第一扇区的主要开机记录MBR中的开机管理程序提供了两个选单M1、M2M1 指向了 Windows 操作系统,而 M2 指向其它分区的启动扇区,里面包含了另外一个开机管理程序,提供了一个指向 Linux 的选单。 下图中第一扇区的主要开机记录MBR中的开机管理程序提供了两个选单M1、M2M1 指向了 Windows 操作系统,而 M2 指向其它分区的启动扇区,里面包含了另外一个开机管理程序,提供了一个指向 Linux 的选单。
<div align="center"> <img src="pics/f900f266-a323-42b2-bc43-218fdb8811a8.jpg" width="600"/> </div><br> <div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/f900f266-a323-42b2-bc43-218fdb8811a8.jpg" width="600"/> </div><br>
安装多重引导,最好先安装 Windows 再安装 Linux。因为安装 Windows 时会覆盖掉主要开机记录MBR而 Linux 可以选择将开机管理程序安装在主要开机记录MBR或者其它分区的启动扇区并且可以设置开机管理程序的选单。 安装多重引导,最好先安装 Windows 再安装 Linux。因为安装 Windows 时会覆盖掉主要开机记录MBR而 Linux 可以选择将开机管理程序安装在主要开机记录MBR或者其它分区的启动扇区并且可以设置开机管理程序的选单。
@ -286,17 +286,17 @@ BIOS 不可以读取 GPT 分区表,而 UEFI 可以。
- superblock记录文件系统的整体信息包括 inode 和 block 的总量、使用量、剩余量,以及文件系统的格式与相关信息等; - superblock记录文件系统的整体信息包括 inode 和 block 的总量、使用量、剩余量,以及文件系统的格式与相关信息等;
- block bitmap记录 block 是否被使用的位域。 - block bitmap记录 block 是否被使用的位域。
<div align="center"> <img src="pics/BSD_disk.png" width="800"/> </div><br> <div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/BSD_disk.png" width="800"/> </div><br>
## 文件读取 ## 文件读取
对于 Ext2 文件系统,当要读取一个文件的内容时,先在 inode 中去查找文件内容所在的所有 block然后把所有 block 的内容读出来。 对于 Ext2 文件系统,当要读取一个文件的内容时,先在 inode 中去查找文件内容所在的所有 block然后把所有 block 的内容读出来。
<div align="center"> <img src="pics/83185315-793a-453a-a927-5e8d92b5c0ef.jpg"/> </div><br> <div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/83185315-793a-453a-a927-5e8d92b5c0ef.jpg"/> </div><br>
而对于 FAT 文件系统,它没有 inode每个 block 中存储着下一个 block 的编号。 而对于 FAT 文件系统,它没有 inode每个 block 中存储着下一个 block 的编号。
<div align="center"> <img src="pics/075e1977-7846-4928-96c8-bb5b0268693c.jpg"/> </div><br> <div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/075e1977-7846-4928-96c8-bb5b0268693c.jpg"/> </div><br>
## 磁盘碎片 ## 磁盘碎片
@ -333,7 +333,7 @@ inode 具有以下特点:
inode 中记录了文件内容所在的 block 编号,但是每个 block 非常小,一个大文件随便都需要几十万的 block。而一个 inode 大小有限,无法直接引用这么多 block 编号。因此引入了间接、双间接、三间接引用。间接引用是指,让 inode 记录的引用 block 块记录引用信息。 inode 中记录了文件内容所在的 block 编号,但是每个 block 非常小,一个大文件随便都需要几十万的 block。而一个 inode 大小有限,无法直接引用这么多 block 编号。因此引入了间接、双间接、三间接引用。间接引用是指,让 inode 记录的引用 block 块记录引用信息。
<div align="center"> <img src="pics/inode_with_signatures.jpg" width="600"/> </div><br> <div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/inode_with_signatures.jpg" width="600"/> </div><br>
## 目录 ## 目录
@ -359,7 +359,7 @@ ext3/ext4 文件系统引入了日志功能,可以利用日志来修复文件
- /usr (unix software resource):所有系统默认软件都会安装到这个目录; - /usr (unix software resource):所有系统默认软件都会安装到这个目录;
- /var (variable):存放系统或程序运行过程中的数据文件。 - /var (variable):存放系统或程序运行过程中的数据文件。
<div align="center"> <img src="pics/linux-filesystem.png" width=""/> </div><br> <div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/linux-filesystem.png" width=""/> </div><br>
# 五、文件 # 五、文件
@ -534,7 +534,7 @@ cp [-adfilprsu] source destination
-f :如果目标文件存在时,先删除目标文件 -f :如果目标文件存在时,先删除目标文件
``` ```
<div align="center"> <img src="pics/b8081c84-62c4-4019-b3ee-4bd0e443d647.jpg"/> </div><br> <div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/b8081c84-62c4-4019-b3ee-4bd0e443d647.jpg" width="400px"> </div><br>
### 1. 实体链接 ### 1. 实体链接
@ -655,7 +655,7 @@ example: find . -name "shadow*"
+4、4 和 -4 的指示的时间范围如下: +4、4 和 -4 的指示的时间范围如下:
<div align="center"> <img src="pics/658fc5e7-79c0-4247-9445-d69bf194c539.png" width=""/> </div><br> <div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/658fc5e7-79c0-4247-9445-d69bf194c539.png" width=""/> </div><br>
**② 与文件拥有者和所属群组有关的选项** **② 与文件拥有者和所属群组有关的选项**
@ -1168,7 +1168,7 @@ dmtsai lines: 5 columns: 9
| Z | zombie (terminated but not reaped by its parent) | | Z | zombie (terminated but not reaped by its parent) |
| T | stopped (either by a job control signal or because it is being traced) | | T | stopped (either by a job control signal or because it is being traced) |
<br> <br>
<div align="center"> <img src="pics/76a49594323247f21c9b3a69945445ee.png" width=""/> </div><br> <div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/76a49594323247f21c9b3a69945445ee.png" width=""/> </div><br>
## SIGCHLD ## SIGCHLD
@ -1181,7 +1181,7 @@ dmtsai lines: 5 columns: 9
在子进程退出时,它的进程描述符不会立即释放,这是为了让父进程得到子进程信息,父进程通过 wait() 和 waitpid() 来获得一个已经退出的子进程的信息。 在子进程退出时,它的进程描述符不会立即释放,这是为了让父进程得到子进程信息,父进程通过 wait() 和 waitpid() 来获得一个已经退出的子进程的信息。
<div align="center"> <img src="pics/flow.png" width=""/> </div><br> <div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/flow.png" width=""/> </div><br>
## wait() ## wait()
@ -1245,3 +1245,9 @@ options 参数主要有 WNOHANG 和 WUNTRACED 两个选项WNOHANG 可以使 w
- [File system design case studies](https://www.cs.rutgers.edu/\~pxk/416/notes/13-fs-studies.html) - [File system design case studies](https://www.cs.rutgers.edu/\~pxk/416/notes/13-fs-studies.html)
- [Programming Project #4](https://classes.soe.ucsc.edu/cmps111/Fall08/proj4.shtml) - [Programming Project #4](https://classes.soe.ucsc.edu/cmps111/Fall08/proj4.shtml)
- [FILE SYSTEM DESIGN](http://web.cs.ucla.edu/classes/fall14/cs111/scribe/11a/index.html) - [FILE SYSTEM DESIGN](http://web.cs.ucla.edu/classes/fall14/cs111/scribe/11a/index.html)
</br><div align="center">⭐️欢迎关注我的公众号 CyC2018在公众号后台回复关键字 📚 **资料** 可领取复习大纲,这份大纲是我花了一整年时间整理的面试知识点列表,不仅系统整理了面试知识点,而且标注了各个知识点的重要程度,从而帮你理清多而杂的面试知识点。可以说我基本是按照这份大纲来进行复习的,这份大纲对我拿到了 BAT 头条等 Offer 起到很大的帮助。你们完全可以和我一样根据大纲上列的知识点来进行复习,就不用看很多不重要的内容,也可以知道哪些内容很重要从而多安排一些复习时间。</div></br>
<div align="center"><img width="180px" src="https://cyc-1256109796.cos.ap-guangzhou.myqcloud.com/%E5%85%AC%E4%BC%97%E5%8F%B7.jpg"></img></div>

View File

@ -42,7 +42,7 @@ B+ Tree 是基于 B Tree 和叶子节点顺序访问指针进行实现,它具
在 B+ Tree 中,一个节点中的 key 从左到右非递减排列,如果某个指针的左右相邻 key 分别是 key<sub>i</sub> 和 key<sub>i+1</sub>,且不为 null则该指针指向节点的所有 key 大于等于 key<sub>i</sub> 且小于等于 key<sub>i+1</sub> 在 B+ Tree 中,一个节点中的 key 从左到右非递减排列,如果某个指针的左右相邻 key 分别是 key<sub>i</sub> 和 key<sub>i+1</sub>,且不为 null则该指针指向节点的所有 key 大于等于 key<sub>i</sub> 且小于等于 key<sub>i+1</sub>
<div align="center"> <img src="pics/061c88c1-572f-424f-b580-9cbce903a3fe.png"/> </div><br> <div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/10a6d3ee-04b2-46b4-b171-d596e5ab0f84.jpg"/> </div><br>
### 2. 操作 ### 2. 操作
@ -56,15 +56,15 @@ B+ Tree 是基于 B Tree 和叶子节点顺序访问指针进行实现,它具
(一)更少的查找次数 (一)更少的查找次数
平衡树查找操作的时间复杂度等于树高 h而树高大致为 O(h)=O(log<sub>d</sub>N),其中 d 为每个节点的出度。 平衡树查找操作的时间复杂度和树高 h 相关,O(h)=O(log<sub>d</sub>N),其中 d 为每个节点的出度。
红黑树的出度为 2而 B+ Tree 的出度一般都非常大,所以红黑树的树高 h 很明显比 B+ Tree 大非常多,查找的次数也就更多。 红黑树的出度为 2而 B+ Tree 的出度一般都非常大,所以红黑树的树高 h 很明显比 B+ Tree 大非常多,查找的次数也就更多。
(二)利用磁盘预读特性 (二)利用磁盘预读特性
为了减少磁盘 I/O磁盘往往不是严格按需读取而是每次都会预读。预读过程中磁盘进行顺序读取顺序读取不需要进行磁盘寻道并且只需要很短的旋转时间速度会非常快。 为了减少磁盘 I/O 操作,磁盘往往不是严格按需读取,而是每次都会预读。预读过程中,磁盘进行顺序读取,顺序读取不需要进行磁盘寻道,并且只需要很短的旋转时间,速度会非常快。
操作系统一般将内存和磁盘分割成固大小的块,每一块称为一页,内存与磁盘以页为单位交换数据。数据库系统将索引的一个节点的大小设置为页的大小,使得一次 I/O 就能完全载入一个节点。并且可以利用预读特性,相邻的节点也能够被预先载入。 操作系统一般将内存和磁盘分割成固大小的块,每一块称为一页,内存与磁盘以页为单位交换数据。数据库系统将索引的一个节点的大小设置为页的大小,使得一次 I/O 就能完全载入一个节点。并且可以利用预读特性,相邻的节点也能够被预先载入。
## MySQL 索引 ## MySQL 索引
@ -84,11 +84,11 @@ B+ Tree 是基于 B Tree 和叶子节点顺序访问指针进行实现,它具
InnoDB 的 B+Tree 索引分为主索引和辅助索引。主索引的叶子节点 data 域记录着完整的数据记录,这种索引方式被称为聚簇索引。因为无法把数据行存放在两个不同的地方,所以一个表只能有一个聚簇索引。 InnoDB 的 B+Tree 索引分为主索引和辅助索引。主索引的叶子节点 data 域记录着完整的数据记录,这种索引方式被称为聚簇索引。因为无法把数据行存放在两个不同的地方,所以一个表只能有一个聚簇索引。
<div align="center"> <img src="pics/c28c6fbc-2bc1-47d9-9b2e-cf3d4034f877.jpg"/> </div><br> <div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/4f151e62-6160-47f1-9eff-47b1f4dea4e9.jpg"/> </div><br>
辅助索引的叶子节点的 data 域记录着主键的值,因此在使用辅助索引进行查找时,需要先查找到主键值,然后再到主索引中进行查找。 辅助索引的叶子节点的 data 域记录着主键的值,因此在使用辅助索引进行查找时,需要先查找到主键值,然后再到主索引中进行查找。
<div align="center"> <img src="pics/7ab8ca28-2a41-4adf-9502-cc0a21e63b51.jpg"/> </div><br> <div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/40f29839-fd56-4ed0-9353-39dfe6f0bba5.jpg"/> </div><br>
### 2. 哈希索引 ### 2. 哈希索引
@ -350,7 +350,7 @@ MySQL 提供了 FROM_UNIXTIME() 函数把 UNIX 时间戳转换为日期,并提
当一个表的数据不断增多时Sharding 是必然的选择,它可以将数据分布到集群的不同节点上,从而缓存单个数据库的压力。 当一个表的数据不断增多时Sharding 是必然的选择,它可以将数据分布到集群的不同节点上,从而缓存单个数据库的压力。
<div align="center"> <img src="pics/63c2909f-0c5f-496f-9fe5-ee9176b31aba.jpg"/> </div><br> <div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/63c2909f-0c5f-496f-9fe5-ee9176b31aba.jpg"/> </div><br>
## 垂直切分 ## 垂直切分
@ -358,7 +358,7 @@ MySQL 提供了 FROM_UNIXTIME() 函数把 UNIX 时间戳转换为日期,并提
在数据库的层面使用垂直切分将按数据库中表的密集程度部署到不同的库中,例如将原来的电商数据库垂直切分成商品数据库、用户数据库等。 在数据库的层面使用垂直切分将按数据库中表的密集程度部署到不同的库中,例如将原来的电商数据库垂直切分成商品数据库、用户数据库等。
<div align="center"> <img src="pics/e130e5b8-b19a-4f1e-b860-223040525cf6.jpg"/> </div><br> <div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/e130e5b8-b19a-4f1e-b860-223040525cf6.jpg"/> </div><br>
## Sharding 策略 ## Sharding 策略
@ -389,10 +389,10 @@ MySQL 提供了 FROM_UNIXTIME() 函数把 UNIX 时间戳转换为日期,并提
主要涉及三个线程binlog 线程、I/O 线程和 SQL 线程。 主要涉及三个线程binlog 线程、I/O 线程和 SQL 线程。
- **binlog 线程** 负责将主服务器上的数据更改写入二进制日志Binary log中。 - **binlog 线程** 负责将主服务器上的数据更改写入二进制日志Binary log中。
- **I/O 线程** :负责从主服务器上读取二进制日志,并写入从服务器的重放日志Replay log - **I/O 线程** :负责从主服务器上读取二进制日志,并写入从服务器的中继日志Relay log
- **SQL 线程** :负责读取重放日志并重放其中的 SQL 语句 - **SQL 线程** :负责读取中继日志,解析出主服务器已经执行的数据更改并在从服务器中执行
<div align="center"> <img src="pics/master-slave.png"/> </div><br> <div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/master-slave.png"/> </div><br>
## 读写分离 ## 读写分离
@ -406,7 +406,7 @@ MySQL 提供了 FROM_UNIXTIME() 函数把 UNIX 时间戳转换为日期,并提
读写分离常用代理方式来实现,代理服务器接收应用层传来的读写请求,然后决定转发到哪个服务器。 读写分离常用代理方式来实现,代理服务器接收应用层传来的读写请求,然后决定转发到哪个服务器。
<div align="center"> <img src="pics/master-slave-proxy.png"/> </div><br> <div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/master-slave-proxy.png"/> </div><br>
# 参考资料 # 参考资料
@ -420,3 +420,10 @@ MySQL 提供了 FROM_UNIXTIME() 函数把 UNIX 时间戳转换为日期,并提
- [MySQL 性能优化神器 Explain 使用分析](https://segmentfault.com/a/1190000008131735) - [MySQL 性能优化神器 Explain 使用分析](https://segmentfault.com/a/1190000008131735)
- [How Sharding Works](https://medium.com/@jeeyoungk/how-sharding-works-b4dec46b3f6) - [How Sharding Works](https://medium.com/@jeeyoungk/how-sharding-works-b4dec46b3f6)
- [大众点评订单系统分库分表实践](https://tech.meituan.com/dianping_order_db_sharding.html) - [大众点评订单系统分库分表实践](https://tech.meituan.com/dianping_order_db_sharding.html)
- [B + 树](https://zh.wikipedia.org/wiki/B%2B%E6%A0%91)
</br><div align="center">⭐️欢迎关注我的公众号 CyC2018在公众号后台回复关键字 📚 **资料** 可领取复习大纲,这份大纲是我花了一整年时间整理的面试知识点列表,不仅系统整理了面试知识点,而且标注了各个知识点的重要程度,从而帮你理清多而杂的面试知识点。可以说我基本是按照这份大纲来进行复习的,这份大纲对我拿到了 BAT 头条等 Offer 起到很大的帮助。你们完全可以和我一样根据大纲上列的知识点来进行复习,就不用看很多不重要的内容,也可以知道哪些内容很重要从而多安排一些复习时间。</div></br>
<div align="center"><img width="180px" src="https://cyc-1256109796.cos.ap-guangzhou.myqcloud.com/%E5%85%AC%E4%BC%97%E5%8F%B7.jpg"></img></div>

View File

@ -67,7 +67,7 @@ Redis 支持很多特性,例如将内存中的数据持久化到硬盘中,
## STRING ## STRING
<div align="center"> <img src="pics/6019b2db-bc3e-4408-b6d8-96025f4481d6.png" width="400"/> </div><br> <div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/6019b2db-bc3e-4408-b6d8-96025f4481d6.png" width="400"/> </div><br>
```html ```html
> set hello world > set hello world
@ -82,7 +82,7 @@ OK
## LIST ## LIST
<div align="center"> <img src="pics/fb327611-7e2b-4f2f-9f5b-38592d408f07.png" width="400"/> </div><br> <div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/fb327611-7e2b-4f2f-9f5b-38592d408f07.png" width="400"/> </div><br>
```html ```html
> rpush list-key item > rpush list-key item
@ -110,7 +110,7 @@ OK
## SET ## SET
<div align="center"> <img src="pics/cd5fbcff-3f35-43a6-8ffa-082a93ce0f0e.png" width="400"/> </div><br> <div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/cd5fbcff-3f35-43a6-8ffa-082a93ce0f0e.png" width="400"/> </div><br>
```html ```html
> sadd set-key item > sadd set-key item
@ -144,7 +144,7 @@ OK
## HASH ## HASH
<div align="center"> <img src="pics/7bd202a7-93d4-4f3a-a878-af68ae25539a.png" width="400"/> </div><br> <div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/7bd202a7-93d4-4f3a-a878-af68ae25539a.png" width="400"/> </div><br>
```html ```html
> hset hash-key sub-key1 value1 > hset hash-key sub-key1 value1
@ -175,7 +175,7 @@ OK
## ZSET ## ZSET
<div align="center"> <img src="pics/1202b2d6-9469-4251-bd47-ca6034fb6116.png" width="400"/> </div><br> <div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/1202b2d6-9469-4251-bd47-ca6034fb6116.png" width="400"/> </div><br>
```html ```html
> zadd zset-key 728 member1 > zadd zset-key 728 member1
@ -317,11 +317,11 @@ int dictRehash(dict *d, int n) {
跳跃表是基于多指针有序链表实现的,可以看成多个有序链表。 跳跃表是基于多指针有序链表实现的,可以看成多个有序链表。
<div align="center"> <img src="pics/beba612e-dc5b-4fc2-869d-0b23408ac90a.png"/> </div><br> <div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/beba612e-dc5b-4fc2-869d-0b23408ac90a.png" width="600px"/> </div><br>
在查找时,从上层指针开始查找,找到对应的区间之后再到下一层去查找。下图演示了查找 22 的过程。 在查找时,从上层指针开始查找,找到对应的区间之后再到下一层去查找。下图演示了查找 22 的过程。
<div align="center"> <img src="pics/0ea37ee2-c224-4c79-b895-e131c6805c40.png"/> </div><br> <div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/0ea37ee2-c224-4c79-b895-e131c6805c40.png" width="600px"/> </div><br>
与红黑树等平衡树相比,跳跃表具有以下优点: 与红黑树等平衡树相比,跳跃表具有以下优点:
@ -349,7 +349,7 @@ Redis 这种内存型数据库的读写性能非常高,很适合存储频繁
## 消息队列 ## 消息队列
List 是一个双向链表,可以通过 lpop 和 lpush 写入和读取消息。 List 是一个双向链表,可以通过 lpush 和 rpop 写入和读取消息。
不过最好使用 Kafka、RabbitMQ 等消息中间件。 不过最好使用 Kafka、RabbitMQ 等消息中间件。
@ -363,7 +363,7 @@ List 是一个双向链表,可以通过 lpop 和 lpush 写入和读取消息
在分布式场景下,无法使用单机环境下的锁来对多个节点上的进程进行同步。 在分布式场景下,无法使用单机环境下的锁来对多个节点上的进程进行同步。
可以使用 Reids 自带的 SETNX 命令实现分布式锁,除此之外,还可以使用官方提供的 RedLock 分布式锁实现。 可以使用 Redis 自带的 SETNX 命令实现分布式锁,除此之外,还可以使用官方提供的 RedLock 分布式锁实现。
## 其它 ## 其它
@ -405,7 +405,7 @@ Redis 可以为每个键设置过期时间,当键过期时,会自动删除
可以设置内存最大使用量,当内存使用量超出时,会施行数据淘汰策略。 可以设置内存最大使用量,当内存使用量超出时,会施行数据淘汰策略。
Reids 具体有 6 种淘汰策略: Redis 具体有 6 种淘汰策略:
| 策略 | 描述 | | 策略 | 描述 |
| :--: | :--: | | :--: | :--: |
@ -472,7 +472,7 @@ Redis 服务器是一个事件驱动程序。
Redis 基于 Reactor 模式开发了自己的网络事件处理器,使用 I/O 多路复用程序来同时监听多个套接字,并将到达的事件传送给文件事件分派器,分派器会根据套接字产生的事件类型调用相应的事件处理器。 Redis 基于 Reactor 模式开发了自己的网络事件处理器,使用 I/O 多路复用程序来同时监听多个套接字,并将到达的事件传送给文件事件分派器,分派器会根据套接字产生的事件类型调用相应的事件处理器。
<div align="center"> <img src="pics/9ea86eb5-000a-4281-b948-7b567bd6f1d8.png"/> </div><br> <div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/9ea86eb5-000a-4281-b948-7b567bd6f1d8.png" width=""/> </div><br>
## 时间事件 ## 时间事件
@ -525,7 +525,7 @@ def main():
从事件处理的角度来看,服务器运行流程如下: 从事件处理的角度来看,服务器运行流程如下:
<div align="center"> <img src="pics/c0a9fa91-da2e-4892-8c9f-80206a6f7047.png" width="400"/> </div><br> <div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/c0a9fa91-da2e-4892-8c9f-80206a6f7047.png" width="350"/> </div><br>
# 十一、复制 # 十一、复制
@ -545,7 +545,7 @@ def main():
随着负载不断上升,主服务器可能无法很快地更新所有从服务器,或者重新连接和重新同步从服务器将导致系统超载。为了解决这个问题,可以创建一个中间层来分担主服务器的复制工作。中间层的服务器是最上层服务器的从服务器,又是最下层服务器的主服务器。 随着负载不断上升,主服务器可能无法很快地更新所有从服务器,或者重新连接和重新同步从服务器将导致系统超载。为了解决这个问题,可以创建一个中间层来分担主服务器的复制工作。中间层的服务器是最上层服务器的从服务器,又是最下层服务器的主服务器。
<div align="center"> <img src="pics/395a9e83-b1a1-4a1d-b170-d081e7bb5bab.png" width="600"/> </div><br> <div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/395a9e83-b1a1-4a1d-b170-d081e7bb5bab.png" width="600"/> </div><br>
# 十二、Sentinel # 十二、Sentinel
@ -555,7 +555,7 @@ Sentinel哨兵可以监听集群中的服务器并在主服务器进入
分片是将数据划分为多个部分的方法,可以将数据存储到多台机器里面,这种方法在解决某些问题时可以获得线性级别的性能提升。 分片是将数据划分为多个部分的方法,可以将数据存储到多台机器里面,这种方法在解决某些问题时可以获得线性级别的性能提升。
假设有 4 个 Reids 实例 R0R1R2R3还有很多表示用户的键 user:1user:2... ,有不同的方式来选择一个指定的键存储在哪个实例中。 假设有 4 个 Redis 实例 R0R1R2R3还有很多表示用户的键 user:1user:2... ,有不同的方式来选择一个指定的键存储在哪个实例中。
- 最简单的方式是范围分片,例如用户 id 从 0\~1000 的存储到实例 R0 中,用户 id 从 1001\~2000 的存储到实例 R1 中,等等。但是这样需要维护一张映射范围表,维护操作代价很高。 - 最简单的方式是范围分片,例如用户 id 从 0\~1000 的存储到实例 R0 中,用户 id 从 1001\~2000 的存储到实例 R1 中,等等。但是这样需要维护一张映射范围表,维护操作代价很高。
- 还有一种方式是哈希分片,使用 CRC32 哈希函数将键转换为一个数字,再对实例数量求模就能知道应该存储的实例。 - 还有一种方式是哈希分片,使用 CRC32 哈希函数将键转换为一个数字,再对实例数量求模就能知道应该存储的实例。
@ -580,7 +580,7 @@ Sentinel哨兵可以监听集群中的服务器并在主服务器进入
Redis 没有关系型数据库中的表这一概念来将同种类型的数据存放在一起,而是使用命名空间的方式来实现这一功能。键名的前面部分存储命名空间,后面部分的内容存储 ID通常使用 : 来进行分隔。例如下面的 HASH 的键名为 article:92617其中 article 为命名空间ID 为 92617。 Redis 没有关系型数据库中的表这一概念来将同种类型的数据存放在一起,而是使用命名空间的方式来实现这一功能。键名的前面部分存储命名空间,后面部分的内容存储 ID通常使用 : 来进行分隔。例如下面的 HASH 的键名为 article:92617其中 article 为命名空间ID 为 92617。
<div align="center"> <img src="pics/7c54de21-e2ff-402e-bc42-4037de1c1592.png" width="400"/> </div><br> <div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/7c54de21-e2ff-402e-bc42-4037de1c1592.png" width="400"/> </div><br>
## 点赞功能 ## 点赞功能
@ -588,13 +588,13 @@ Redis 没有关系型数据库中的表这一概念来将同种类型的数据
为了节约内存,规定一篇文章发布满一周之后,就不能再对它进行投票,而文章的已投票集合也会被删除,可以为文章的已投票集合设置一个一周的过期时间就能实现这个规定。 为了节约内存,规定一篇文章发布满一周之后,就不能再对它进行投票,而文章的已投票集合也会被删除,可以为文章的已投票集合设置一个一周的过期时间就能实现这个规定。
<div align="center"> <img src="pics/485fdf34-ccf8-4185-97c6-17374ee719a0.png" width="400"/> </div><br> <div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/485fdf34-ccf8-4185-97c6-17374ee719a0.png" width="400"/> </div><br>
## 对文章进行排序 ## 对文章进行排序
为了按发布时间和点赞数进行排序,可以建立一个文章发布时间的有序集合和一个文章点赞数的有序集合。(下图中的 score 就是这里所说的点赞数;下面所示的有序集合分值并不直接是时间和点赞数,而是根据时间和点赞数间接计算出来的) 为了按发布时间和点赞数进行排序,可以建立一个文章发布时间的有序集合和一个文章点赞数的有序集合。(下图中的 score 就是这里所说的点赞数;下面所示的有序集合分值并不直接是时间和点赞数,而是根据时间和点赞数间接计算出来的)
<div align="center"> <img src="pics/f7d170a3-e446-4a64-ac2d-cb95028f81a8.png" width="800"/> </div><br> <div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/f7d170a3-e446-4a64-ac2d-cb95028f81a8.png" width="800"/> </div><br>
# 参考资料 # 参考资料
@ -606,3 +606,9 @@ Redis 没有关系型数据库中的表这一概念来将同种类型的数据
- [Redis 3.0 中文版- 分片](http://wiki.jikexueyuan.com/project/redis-guide) - [Redis 3.0 中文版- 分片](http://wiki.jikexueyuan.com/project/redis-guide)
- [Redis 应用场景](http://www.scienjus.com/redis-use-case/) - [Redis 应用场景](http://www.scienjus.com/redis-use-case/)
- [Using Redis as an LRU cache](https://redis.io/topics/lru-cache) - [Using Redis as an LRU cache](https://redis.io/topics/lru-cache)
</br><div align="center">⭐️欢迎关注我的公众号 CyC2018在公众号后台回复关键字 📚 **资料** 可领取复习大纲,这份大纲是我花了一整年时间整理的面试知识点列表,不仅系统整理了面试知识点,而且标注了各个知识点的重要程度,从而帮你理清多而杂的面试知识点。可以说我基本是按照这份大纲来进行复习的,这份大纲对我拿到了 BAT 头条等 Offer 起到很大的帮助。你们完全可以和我一样根据大纲上列的知识点来进行复习,就不用看很多不重要的内容,也可以知道哪些内容很重要从而多安排一些复习时间。</div></br>
<div align="center"><img width="180px" src="https://cyc-1256109796.cos.ap-guangzhou.myqcloud.com/%E5%85%AC%E4%BC%97%E5%8F%B7.jpg"></img></div>

View File

@ -765,3 +765,9 @@ SET PASSWROD FOR myuser = Password('new_password');
# 参考资料 # 参考资料
- BenForta. SQL 必知必会 [M]. 人民邮电出版社, 2013. - BenForta. SQL 必知必会 [M]. 人民邮电出版社, 2013.
</br><div align="center">⭐️欢迎关注我的公众号 CyC2018在公众号后台回复关键字 📚 **资料** 可领取复习大纲,这份大纲是我花了一整年时间整理的面试知识点列表,不仅系统整理了面试知识点,而且标注了各个知识点的重要程度,从而帮你理清多而杂的面试知识点。可以说我基本是按照这份大纲来进行复习的,这份大纲对我拿到了 BAT 头条等 Offer 起到很大的帮助。你们完全可以和我一样根据大纲上列的知识点来进行复习,就不用看很多不重要的内容,也可以知道哪些内容很重要从而多安排一些复习时间。</div></br>
<div align="center"><img width="180px" src="https://cyc-1256109796.cos.ap-guangzhou.myqcloud.com/%E5%85%AC%E4%BC%97%E5%8F%B7.jpg"></img></div>

View File

@ -36,25 +36,25 @@ Unix 有五种 I/O 模型:
## 阻塞式 I/O ## 阻塞式 I/O
应用进程被阻塞,直到数据复制到应用进程缓冲区中才返回。 应用进程被阻塞,直到数据从内核缓冲区复制到应用进程缓冲区中才返回。
应该注意到,在阻塞的过程中,其它程还可以执行,因此阻塞不意味着整个操作系统都被阻塞。因为其他程序还可以执行,所以不消耗 CPU 时间,这种模型的 CPU 利用率效率会比较高。 应该注意到,在阻塞的过程中,其它应用进程还可以执行,因此阻塞不意味着整个操作系统都被阻塞。因为其它应用进程还可以执行,所以不消耗 CPU 时间,这种模型的 CPU 利用率效率会比较高。
下图中recvfrom 用于接收 Socket 传来的数据,并复制到应用进程的缓冲区 buf 中。这里把 recvfrom() 当成系统调用。 下图中recvfrom() 用于接收 Socket 传来的数据,并复制到应用进程的缓冲区 buf 中。这里把 recvfrom() 当成系统调用。
```c ```c
ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags, struct sockaddr *src_addr, socklen_t *addrlen); ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags, struct sockaddr *src_addr, socklen_t *addrlen);
``` ```
<div align="center"> <img src="pics/1492928416812_4.png"/> </div><br> <div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/1492928416812_4.png"/> </div><br>
## 非阻塞式 I/O ## 非阻塞式 I/O
应用进程执行系统调用之后,内核返回一个错误码。应用进程可以继续执行,但是需要不断的执行系统调用来获知 I/O 是否完成这种方式称为轮询polling 应用进程执行系统调用之后,内核返回一个错误码。应用进程可以继续执行,但是需要不断的执行系统调用来获知 I/O 是否完成这种方式称为轮询polling
由于 CPU 要处理更多的系统调用,因此这种模型的 CPU 利用率比较低 由于 CPU 要处理更多的系统调用,因此这种模型的 CPU 利用率比较低。
<div align="center"> <img src="pics/1492929000361_5.png"/> </div><br> <div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/1492929000361_5.png"/> </div><br>
## I/O 复用 ## I/O 复用
@ -64,7 +64,7 @@ ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags, struct sockaddr *
如果一个 Web 服务器没有 I/O 复用,那么每一个 Socket 连接都需要创建一个线程去处理。如果同时有几万个连接那么就需要创建相同数量的线程。相比于多进程和多线程技术I/O 复用不需要进程线程创建和切换的开销,系统开销更小。 如果一个 Web 服务器没有 I/O 复用,那么每一个 Socket 连接都需要创建一个线程去处理。如果同时有几万个连接那么就需要创建相同数量的线程。相比于多进程和多线程技术I/O 复用不需要进程线程创建和切换的开销,系统开销更小。
<div align="center"> <img src="pics/1492929444818_6.png"/> </div><br> <div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/1492929444818_6.png"/> </div><br>
## 信号驱动 I/O ## 信号驱动 I/O
@ -72,7 +72,7 @@ ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags, struct sockaddr *
相比于非阻塞式 I/O 的轮询方式,信号驱动 I/O 的 CPU 利用率更高。 相比于非阻塞式 I/O 的轮询方式,信号驱动 I/O 的 CPU 利用率更高。
<div align="center"> <img src="pics/1492929553651_7.png"/> </div><br> <div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/1492929553651_7.png"/> </div><br>
## 异步 I/O ## 异步 I/O
@ -80,7 +80,7 @@ ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags, struct sockaddr *
异步 I/O 与信号驱动 I/O 的区别在于,异步 I/O 的信号是通知应用进程 I/O 完成,而信号驱动 I/O 的信号是通知应用进程可以开始 I/O。 异步 I/O 与信号驱动 I/O 的区别在于,异步 I/O 的信号是通知应用进程 I/O 完成,而信号驱动 I/O 的信号是通知应用进程可以开始 I/O。
<div align="center"> <img src="pics/1492930243286_8.png"/> </div><br> <div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/1492930243286_8.png"/> </div><br>
## 五大 I/O 模型比较 ## 五大 I/O 模型比较
@ -91,7 +91,7 @@ ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags, struct sockaddr *
非阻塞式 I/O 、信号驱动 I/O 和异步 I/O 在第一阶段不会阻塞。 非阻塞式 I/O 、信号驱动 I/O 和异步 I/O 在第一阶段不会阻塞。
<div align="center"> <img src="pics/1492928105791_3.png"/> </div><br> <div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/1492928105791_3.png"/> </div><br>
# 二、I/O 复用 # 二、I/O 复用
@ -321,3 +321,9 @@ poll 没有最大描述符数量的限制,如果平台支持并且对实时性
- [poll vs select vs event-based](https://daniel.haxx.se/docs/poll-vs-select.html) - [poll vs select vs event-based](https://daniel.haxx.se/docs/poll-vs-select.html)
- [select / poll / epoll: practical difference for system architects](http://www.ulduzsoft.com/2014/01/select-poll-epoll-practical-difference-for-system-architects/) - [select / poll / epoll: practical difference for system architects](http://www.ulduzsoft.com/2014/01/select-poll-epoll-practical-difference-for-system-architects/)
- [Browse the source code of userspace/glibc/sysdeps/unix/sysv/linux/ online](https://code.woboq.org/userspace/glibc/sysdeps/unix/sysv/linux/) - [Browse the source code of userspace/glibc/sysdeps/unix/sysv/linux/ online](https://code.woboq.org/userspace/glibc/sysdeps/unix/sysv/linux/)
</br><div align="center">⭐️欢迎关注我的公众号 CyC2018在公众号后台回复关键字 📚 **资料** 可领取复习大纲,这份大纲是我花了一整年时间整理的面试知识点列表,不仅系统整理了面试知识点,而且标注了各个知识点的重要程度,从而帮你理清多而杂的面试知识点。可以说我基本是按照这份大纲来进行复习的,这份大纲对我拿到了 BAT 头条等 Offer 起到很大的帮助。你们完全可以和我一样根据大纲上列的知识点来进行复习,就不用看很多不重要的内容,也可以知道哪些内容很重要从而多安排一些复习时间。</div></br>
<div align="center"><img width="180px" src="https://cyc-1256109796.cos.ap-guangzhou.myqcloud.com/%E5%85%AC%E4%BC%97%E5%8F%B7.jpg"></img></div>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 409 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 37 KiB

Some files were not shown because too many files have changed in this diff Show More