diff --git a/notes/2016 校招真题题解.md b/notes/2016 校招真题题解.md index 0285debe..da6709ab 100644 --- a/notes/2016 校招真题题解.md +++ b/notes/2016 校招真题题解.md @@ -1,33 +1,34 @@ -* [ǰÑÔ](#ǰÑÔ) -* [1. СÃ×-СÃ×Git](#1-СÃ×-СÃ×git) -* [2. СÃ×-¶®¶þ½øÖÆ](#2-СÃ×-¶®¶þ½øÖÆ) -* [3. СÃ×-ÖйúÅ£ÊÐ](#3-СÃ×-ÖйúÅ£ÊÐ) -* [4. ΢Èí-LUCKY STRING](#4-΢Èí-lucky-string) -* [5. ΢Èí-Numeric Keypad](#5-΢Èí-numeric-keypad) -* [6. ΢Èí-Spring Outing](#6-΢Èí-spring-outing) -* [7. ΢Èí-S-expression](#7-΢Èí-s-expression) -* [8. »ªÎª-×î¸ß·ÖÊǶàÉÙ](#8-»ªÎª-×î¸ß·ÖÊǶàÉÙ) -* [9. »ªÎª-¼òµ¥´íÎó¼Ç¼](#9-»ªÎª-¼òµ¥´íÎó¼Ç¼) -* [10. »ªÎª-ÆË¿ËÅÆ´óС](#10-»ªÎª-ÆË¿ËÅÆ´óС) -* [11. È¥ÄĶù-¶þ·Ö²éÕÒ](#11-È¥ÄĶù-¶þ·Ö²éÕÒ) -* [12. È¥ÄĶù-Ê׸öÖØ¸´×Ö·û](#12-È¥ÄĶù-Ê׸öÖØ¸´×Ö·û) -* [13. È¥ÄĶù-ѰÕÒCoder](#13-È¥ÄĶù-ѰÕÒcoder) -* [14. ÃÀÍÅ-×î´ó²îÖµ](#14-ÃÀÍÅ-×î´ó²îÖµ) -* [15. ÃÀÍÅ-Æå×Ó·­×ª](#15-ÃÀÍÅ-Æå×Ó·­×ª) -* [16. ÃÀÍÅ-°Ý·Ã](#16-ÃÀÍÅ-°Ý·Ã) -* [17. ÃÀÍÅ-Ö±·½Í¼ÄÚ×î´ó¾ØÐÎ](#17-ÃÀÍÅ-Ö±·½Í¼ÄÚ×î´ó¾ØÐÎ) -* [18. ÃÀÍÅ-×Ö·û´®¼ÆÊý](#18-ÃÀÍÅ-×Ö·û´®¼ÆÊý) -* [19. ÃÀÍÅ-ƽ¾ùÄêÁä](#19-ÃÀÍÅ-ƽ¾ùÄêÁä) -* [20. °Ù¶È-×ï·¸×ªÒÆ](#20-°Ù¶È-×ï·¸×ªÒÆ) -* [22. °Ù¶È-²Ã¼õÍø¸ñÖ½](#22-°Ù¶È-²Ã¼õÍø¸ñÖ½) -* [23. °Ù¶È-µöÓã±ÈÈü](#23-°Ù¶È-µöÓã±ÈÈü) -* [24. °Ù¶È-Ä¢¹½Õó](#24-°Ù¶È-Ä¢¹½Õó) +* [å‰�言](#å‰�言) +* [1. å°�ç±³-å°�ç±³Git](#1-å°�ç±³-å°�ç±³git) +* [2. å°�ç±³-懂二进制](#2-å°�ç±³-懂二进制) +* [3. å°�ç±³-中国牛市](#3-å°�ç±³-中国牛市) +* [4. 微软-LUCKY STRING](#4-微软-lucky-string) +* [5. 微软-Numeric Keypad](#5-微软-numeric-keypad) +* [6. 微软-Spring Outing](#6-微软-spring-outing) +* [7. 微软-S-expression](#7-微软-s-expression) +* [8. å�Žä¸º-最高分是多少](#8-å�Žä¸º-最高分是多少) +* [9. å�Žä¸º-简å�•错误记录](#9-å�Žä¸º-简å�•错误记录) +* [10. å�Žä¸º-扑克牌大å°�](#10-å�Žä¸º-扑克牌大å°�) +* [11. 去哪儿-二分查找](#11-去哪儿-二分查找) +* [12. 去哪儿-首个é‡�å¤�字符](#12-去哪儿-首个é‡�å¤�字符) +* [13. 去哪儿-寻找Coder](#13-去哪儿-寻找coder) +* [14. 美团-最大差值](#14-美团-最大差值) +* [15. 美团-棋å­�翻转](#15-美团-棋å­�翻转) +* [16. 美团-拜访](#16-美团-拜访) +* [17. 美团-直方图内最大矩形](#17-美团-直方图内最大矩形) +* [18. 美团-字符串计数](#18-美团-字符串计数) +* [19. 美团-å¹³å�‡å¹´é¾„](#19-美团-å¹³å�‡å¹´é¾„) +* [20. 百度-罪犯转移](#20-百度-罪犯转移) +* [22. 百度-è£�å‡�网格纸](#22-百度-è£�å‡�网格纸) +* [23. 百度-钓鱼比赛](#23-百度-钓鱼比赛) +* [24. 百度-蘑è�‡é˜µ](#24-百度-蘑è�‡é˜µ) -# ǰÑÔ -Ê¡ÂԵĴúÂ룺 +# å‰�言 + +çœ�略的代ç �: ```java import java.util.*; @@ -48,10 +49,10 @@ public class Main { } ``` -# 1. СÃ×-СÃ×Git +# 1. å°�ç±³-å°�ç±³Git -- ÖØ½¨¶à²æÊ÷ -- ʹÓà LCA +- é‡�建多å�‰æ ‘ +- 使用 LCA ```java private class TreeNode { @@ -65,7 +66,7 @@ private class TreeNode { public int getSplitNode(String[] matrix, int indexA, int indexB) { int n = matrix.length; - boolean[][] linked = new boolean[n][n]; // ÖØ½¨ÁÚ½Ó¾ØÕó + boolean[][] linked = new boolean[n][n]; // é‡�建邻接矩阵 for (int i = 0; i < n; i++) { for (int j = 0; j < n; j++) { linked[i][j] = matrix[i].charAt(j) == '1'; @@ -80,7 +81,7 @@ private TreeNode constructTree(boolean[][] linked, int root) { TreeNode tree = new TreeNode(root); for (int i = 0; i < linked[root].length; i++) { if (linked[root][i]) { - linked[i][root] = false; // ÒòΪÌâÄ¿¸øµÄÁÚ½Ó¾ØÕóÊÇË«ÏòµÄ£¬ÔÚÕâÀïÐèÒª°ÑËüתΪµ¥ÏòµÄ + linked[i][root] = false; // 因为题目给的邻接矩阵是å�Œå�‘的,在这里需è¦�把它转为å�•å�‘çš„ tree.childs.add(constructTree(links, i)); } } @@ -102,9 +103,9 @@ private TreeNode LCA(TreeNode root, TreeNode p, TreeNode q) { } ``` -# 2. СÃ×-¶®¶þ½øÖÆ +# 2. å°�ç±³-懂二进制 -¶ÔÁ½¸öÊý½øÐÐÒì»ò£¬½á¹ûµÄ¶þ½øÖƱíʾΪ 1 µÄÄÇһλ¾ÍÊÇÁ½¸öÊý²»Í¬µÄλ¡£ +对两个数进行异或,结果的二进制表示为 1 的那一ä½�就是两个数ä¸�å�Œçš„ä½�。 ```java public int countBitDiff(int m, int n) { @@ -112,11 +113,11 @@ public int countBitDiff(int m, int n) { } ``` -# 3. СÃ×-ÖйúÅ£ÊÐ +# 3. å°�ç±³-中国牛市 -±³°üÎÊÌ⣬¿ÉÒÔÉèÒ»¸ö´óСΪ 2 µÄ±³°ü¡£ +背包问题,å�¯ä»¥è®¾ä¸€ä¸ªå¤§å°�为 2 的背包。 -×´Ì¬×ªÒÆ·½³ÌÈçÏ£º +状æ€�转移方程如下: ```html dp[i, j] = max(dp[i, j-1], prices[j] - prices[jj] + dp[i-1, jj]) { jj in range of [0, j-1] } = max(dp[i, j-1], prices[j] + max(dp[i-1, jj] - prices[jj])) @@ -137,10 +138,10 @@ public int calculateMax(int[] prices) { } ``` -# 4. ΢Èí-LUCKY STRING +# 4. 微软-LUCKY STRING -- ì³²¨ÄÇÆõÊýÁпÉÒÔÔ¤¼ÆË㣻 -- ´ÓÍ·µ½Î²±éÀú×Ö·û´®µÄ¹ý³Ì£¬Ã¿Ò»ÂÖÑ­»·¶¼Ê¹ÓÃÒ»¸ö Set À´±£´æ´Ó i µ½ j ³öÏÖµÄ×Ö·û£¬²¢ÇÒ Set ±£Ö¤ÁË×Ö·û¶¼²»Í¬£¬Òò´Ë Set µÄ´óС¾ÍÊDz»Í¬×Ö·ûµÄ¸öÊý¡£ +- æ–�波那契数列å�¯ä»¥é¢„计算; +- 从头到尾é��历字符串的过程,æ¯�一轮循环都使用一个 Set æ�¥ä¿�存从 i 到 j 出现的字符,并且 Set ä¿�è¯�了字符都ä¸�å�Œï¼Œå› æ­¤ Set 的大å°�就是ä¸�å�Œå­—符的个数。 ```java Set fibSet = new HashSet<>(Arrays.asList(1, 2, 3, 5, 8, 13, 21, 34, 55, 89)); @@ -165,7 +166,7 @@ for (String s : arr) { } ``` -# 5. ΢Èí-Numeric Keypad +# 5. 微软-Numeric Keypad ```java private static int[][] canReach = { @@ -209,17 +210,17 @@ public static void main(String[] args) { } ``` -# 6. ΢Èí-Spring Outing +# 6. 微软-Spring Outing -ÏÂÃæÒÔ N = 3£¬K = 4 À´½øÐÐÌÖÂÛ¡£ +下é�¢ä»¥ N = 3,K = 4 æ�¥è¿›è¡Œè®¨è®ºã€‚ -³õʼʱ£¬ÁîµÚ 0 ¸öµØ·½³ÉΪ´ý¶¨µØµã£¬Ò²¾ÍÊÇ´ôÔÚ¼ÒÀï¡£ +åˆ�始时,令第 0 个地方æˆ�为待定地点,也就是呆在家里。 -´ÓµÚ 4 ¸öµØµã¿ªÊ¼Í¶Æ±£¬Ã¿¸öÈËÖ»ÐèÒª±È½ÏµÚ 4 ¸öµØ·½ºÍµÚ 0 ¸öµØ·½µÄÓÅÏȼ¶£¬ÀÈç¹û³¬¹ý°ëÊýµÄÈËÑ¡ÔñÁËµÚ 4 ¸öµØ·½£¬ÄÇô¸üÐÂµÚ 4 ¸öµØ·½³ÉΪ´ý¶¨µØµã¡£ +从第 4 个地点开始投票,æ¯�个人å�ªéœ€è¦�比较第 4 个地方和第 0 个地方的优先级,里,如果超过å�Šæ•°çš„人选择了第 4 个地方,那么更新第 4 个地方æˆ�为待定地点。 -´ÓºóÍùǰ²»¶ÏÖØ¸´ÒÔÉϲ½Ö裬²»¶Ï¸üдý¶¨µØµã£¬Ö±µ½ËùÓеط½¶¼ÒѾ­Í¶Æ±¡£ +从å�Žå¾€å‰�ä¸�æ–­é‡�å¤�以上步骤,ä¸�断更新待定地点,直到所有地方都已ç»�投票。 -ÉÏÃæµÄÌÖÂÛÖУ¬ÏÈÁîµÚ 0 ¸öµØµã³ÉΪ´ý¶¨µØµã£¬ÊÇÒòΪÕâÑùµÄ»°µÚ 4 ¸öµØµã¾ÍÖ»ÐèÒªºÍÕâ¸öµØµã½øÐбȽϣ¬¶ø²»Óÿ¼ÂÇÆäËüÇé¿ö¡£Èç¹û×ʼÏÈÁîµÚ 1 ¸öµØµã³ÉΪ´ý¶¨µØµã£¬ÄÇôÔÚ¶ÔµÚ 2 ¸öµØµã½øÐÐͶƱʱ£¬Ã¿¸öÈ˲»½öÒª¿¼ÂÇµÚ 2 ¸öµØµãÓëµÚ 1 ¸öµØµãµÄÓÅÏȼ¶£¬Ò²Òª¿¼ÂÇÓëÆäºóͶƱµØµãµÄÓÅÏȼ¶¡£ +上é�¢çš„讨论中,先令第 0 个地点æˆ�为待定地点,是因为这样的è¯�第 4 个地点就å�ªéœ€è¦�和这个地点进行比较,而ä¸�用考虑其它情况。如果最开始先令第 1 个地点æˆ�为待定地点,那么在对第 2 个地点进行投票时,æ¯�个人ä¸�ä»…è¦�考虑第 2 个地点与第 1 个地点的优先级,也è¦�考虑与其å�ŽæŠ•ç¥¨åœ°ç‚¹çš„ä¼˜å…ˆçº§ã€‚ ```java int N = in.nextInt(); @@ -246,9 +247,9 @@ for (int place = K; place > 0; place--) { System.out.println(ret == 0 ? "otaku" : ret); ``` -# 7. ΢Èí-S-expression +# 7. 微软-S-expression -# 8. »ªÎª-×î¸ß·ÖÊǶàÉÙ +# 8. å�Žä¸º-最高分是多少 ```java int N = in.nextInt(); @@ -280,7 +281,7 @@ for (int i = 0; i < M; i++) { } ``` -# 9. »ªÎª-¼òµ¥´íÎó¼Ç¼ +# 9. å�Žä¸º-简å�•错误记录 ```java HashMap map = new LinkedHashMap<>(); @@ -300,7 +301,7 @@ for (int i = 0; i < 8 && i < list.size(); i++) { } ``` -# 10. »ªÎª-ÆË¿ËÅÆ´óС +# 10. å�Žä¸º-扑克牌大å°� ```java public class Main { @@ -391,12 +392,12 @@ public class Main { } ``` -# 11. È¥ÄĶù-¶þ·Ö²éÕÒ +# 11. 去哪儿-二分查找 -¶ÔÓÚÓÐÖØ¸´ÔªËصÄÓÐÐòÊý×飬¶þ·Ö²éÕÒÐèҪעÒâÒÔÏÂÒªµã£º +对于有é‡�å¤�元素的有åº�数组,二分查找需è¦�注æ„�以下è¦�点: - if (val <= A[m]) h = m; -- ÒòΪ h µÄ¸³ÖµÎª m ¶ø²»ÊÇ m - 1£¬Òò´Ë while Ñ­»·µÄÌõ¼þÒ²¾ÍΪ l < h¡££¨Èç¹ûÊÇ m - 1 Ñ­»·Ìõ¼þΪ l <= h£© +- 因为 h 的赋值为 m 而ä¸�是 m - 1,因此 while 循环的æ�¡ä»¶ä¹Ÿå°±ä¸º l < h。(如果是 m - 1 循环æ�¡ä»¶ä¸º l <= h) ```java public int getPos(int[] A, int n, int val) { @@ -410,7 +411,7 @@ public int getPos(int[] A, int n, int val) { } ``` -# 12. È¥ÄĶù-Ê׸öÖØ¸´×Ö·û +# 12. 去哪儿-首个é‡�å¤�字符 ```java public char findFirstRepeat(String A, int n) { @@ -424,7 +425,7 @@ public char findFirstRepeat(String A, int n) { } ``` -# 13. È¥ÄĶù-ѰÕÒCoder +# 13. 去哪儿-寻找Coder ```java public String[] findCoder(String[] A, int n) { @@ -450,7 +451,7 @@ public String[] findCoder(String[] A, int n) { return ret; } -// Å£¿ÍÍøÎÞ·¨µ¼Èë javafx.util.Pair£¬ÕâÀï¾Í×Ô¼ºÊµÏÖһϠPair Àà +// 牛客网无法导入 javafx.util.Pair,这里就自己实现一下 Pair ç±» private class Pair { T t; K k; @@ -470,9 +471,9 @@ private class Pair { } ``` -# 14. ÃÀÍÅ-×î´ó²îÖµ +# 14. 美团-最大差值 -̰ÐIJßÂÔ¡£ +贪心策略。 ```java public int getDis(int[] A, int n) { @@ -486,7 +487,7 @@ public int getDis(int[] A, int n) { } ``` -# 15. ÃÀÍÅ-Æå×Ó·­×ª +# 15. 美团-棋å­�翻转 ```java public int[][] flipChess(int[][] A, int[][] f) { @@ -502,7 +503,7 @@ public int[][] flipChess(int[][] A, int[][] f) { } ``` -# 16. ÃÀÍÅ-°Ý·Ã +# 16. 美团-拜访 ```java private Set paths; @@ -554,7 +555,7 @@ private void backtracking(int[][] map, int n, int m, int r, int c, int[][] direc } ``` -# 17. ÃÀÍÅ-Ö±·½Í¼ÄÚ×î´ó¾ØÐÎ +# 17. 美团-直方图内最大矩形 ```java public int countArea(int[] A, int n) { @@ -570,15 +571,15 @@ public int countArea(int[] A, int n) { } ``` -# 18. ÃÀÍÅ-×Ö·û´®¼ÆÊý +# 18. 美团-字符串计数 -×Ö·û´®¶¼ÊÇСд×Ö·û£¬¿ÉÒÔ°Ñ×Ö·û´®µ±³ÉÊÇ 26 ½øÖÆ¡£µ«ÊÇ×ÖµäÐòµÄ±È½ÏºÍÆÕͨµÄÕûÊý±È½Ï²»Í¬£¬ÊÇ´Ó×óÍùÓÒ½øÐбȽϣ¬ÀýÈç "ac" ºÍ "abc"£¬×ÖµäÐòµÄ±È½Ï½á¹ûΪ "ac" > "abc"£¬Èç¹û°´ÕÕÕûÊý·½·¨±È½Ï£¬ÒòΪ "abc" ÊÇÈýλÊý£¬ÏÔÈ»¸ü´ó¡£ +字符串都是å°�写字符,å�¯ä»¥æŠŠå­—符串当æˆ�是 26 进制。但是字典åº�的比较和普通的整数比较ä¸�å�Œï¼Œæ˜¯ä»Žå·¦å¾€å�³è¿›è¡Œæ¯”较,例如 "ac" å’Œ "abc",字典åº�的比较结果为 "ac" > "abc",如果按照整数方法比较,因为 "abc" 是三ä½�数,显然更大。 -ÓÉÓÚÁ½¸ö×Ö·û´®µÄ³¤¶È¿ÉÄܲ»ÏëµÈ£¬ÔÚ s1 ¿Õ°×²¿·ÖºÍ s2 ¶ÔÓ¦²¿·Ö½øÐбȽÏʱ£¬Ó¦¸Ã°Ñ s1 µÄ¿Õ°×²¿·Ö¿´³ÉÊÇ 'a' ×Ö·û½øÐÐÌî³äµÄ¡£ +由于两个字符串的长度å�¯èƒ½ä¸�想等,在 s1 空白部分和 s2 对应部分进行比较时,应该把 s1 的空白部分看æˆ�是 'a' 字符进行填充的。 -»¹ÓÐÒ»µãҪעÒâµÄÊÇ£¬s1 µ½ s2 ³¤¶ÈΪ leni µÄ×Ö·û´®¸öÊýÖ»±È½ÏÇ°Ãæ i ¸ö×Ö·û¡£ÀýÈç 'aaa' ºÍ 'bbb' £¬³¤¶ÈΪ 2 µÄ¸öÊýΪ 'aa' µ½ 'bb' µÄ×Ö·û´®¸öÊý£¬²»ÐèÒª¿¼ÂǺóÃæ²¿·ÖµÄ×Ö·û¡£ +还有一点è¦�注æ„�的是,s1 到 s2 长度为 leni 的字符串个数å�ªæ¯”较å‰�é�¢ i 个字符。例如 'aaa' å’Œ 'bbb' ,长度为 2 的个数为 'aa' 到 'bb' 的字符串个数,ä¸�需è¦�考虑å�Žé�¢éƒ¨åˆ†çš„字符。 -ÔÚͳ¼Æ¸öÊýʱ£¬´Ó len1 ¿ªÊ¼Ò»Ö±±éÀúµ½×î´óºÏ·¨³¤¶È£¬Ã¿´ÎÑ­»·¶¼Í³¼Æ³¤¶ÈΪ i µÄ×Ó×Ö·û´®¸öÊý¡£ +在统计个数时,从 len1 开始一直é��历到最大å�ˆæ³•长度,æ¯�次循环都统计长度为 i çš„å­�字符串个数。 ```java String s1 = in.next(); @@ -601,7 +602,7 @@ for (int i = len1; i <= len; i++) { System.out.println(ret - 1); ``` -# 19. ÃÀÍÅ-ƽ¾ùÄêÁä +# 19. 美团-å¹³å�‡å¹´é¾„ ```java int W = in.nextInt(); @@ -609,15 +610,15 @@ double Y = in.nextDouble(); double x = in.nextDouble(); int N = in.nextInt(); while (N-- > 0) { - Y++; // ÀÏÔ±¹¤Ã¿ÄêÄêÁä¶¼Òª¼Ó 1 + Y++; // è€�员工æ¯�年年龄都è¦�加 1 Y += (21 - Y) * x; } System.out.println((int) Math.ceil(Y)); ``` -# 20. °Ù¶È-×ï·¸×ªÒÆ +# 20. 百度-罪犯转移 -²¿·ÖºÍÎÊÌ⣬½«Ã¿´ÎÇóµÄ²¿·ÖºÍ»º´æÆðÀ´¡£ +部分和问题,将æ¯�次求的部分和缓存起æ�¥ã€‚ ```java int n = in.nextInt(); @@ -640,7 +641,7 @@ for (int s = 0, e = c - 1; e < n; s++, e++) { System.out.println(cnt); ``` -# 22. °Ù¶È-²Ã¼õÍø¸ñÖ½ +# 22. 百度-è£�å‡�网格纸 ```java int n = in.nextInt(); @@ -658,11 +659,11 @@ for (int i = 0; i < n; i++) { System.out.println((int) Math.pow(Math.max(maxX - minX, maxY - minY), 2)); ``` -# 23. °Ù¶È-µöÓã±ÈÈü +# 23. 百度-钓鱼比赛 -P ( ÖÁÉÙµöÒ»ÌõÓã ) = 1 - P ( Ò»ÌõÒ²µö²»µ½ ) +P ( 至少钓一æ�¡é±¼ ) = 1 - P ( 一æ�¡ä¹Ÿé’“ä¸�到 ) -¿Ó£º¶ÁÈ¡¸ÅÂʾØÕóµÄʱºò£¬ÐèÒªÒ»ÐÐÒ»ÐнøÐжÁÈ¡£¬¶ø²»ÄÜÖ±½ÓÓà in.nextDouble()¡£ +å�‘:读å�–概率矩阵的时候,需è¦�一行一行进行读å�–,而ä¸�能直接用 in.nextDouble()。 ```java public static void main(String[] args) { @@ -673,11 +674,11 @@ public static void main(String[] args) { int x = in.nextInt(); int y = in.nextInt(); int t = in.nextInt(); - in.nextLine(); // ¿Ó + in.nextLine(); // å�‘ double pcc = 0.0; double sum = 0.0; for (int i = 1; i <= n; i++) { - String[] token = in.nextLine().split(" "); // ¿Ó + String[] token = in.nextLine().split(" "); // å�‘ for (int j = 1; j <= m; j++) { double p = Double.parseDouble(token[j - 1]); // double p = in.nextDouble(); @@ -701,13 +702,13 @@ private static double computePOfIRT(double p, int t) { } ``` -# 24. °Ù¶È-Ä¢¹½Õó +# 24. 百度-蘑è�‡é˜µ -ÕâÌâÓûØËݻᳬʱ£¬ÐèÒªÓà DP¡£ +这题用回溯会超时,需è¦�用 DP。 -dp[i][j] ±íʾµ½´ï (i,j) λÖò»»á´¥ÅöÄ¢¹½µÄ¸ÅÂÊ¡£¶ÔÓÚ N\*M ¾ØÕó£¬Èç¹û i == N || j == M£¬ÄÇô (i,j) Ö»ÄÜÓÐÒ»¸öÒÆ¶¯·½Ïò£»ÆäËüÇé¿öÏÂÄÜÓÐÁ½¸öÒÆ¶¯·½Ïò¡£ +dp[i][j] 表示到达 (i,j) ä½�ç½®ä¸�会触碰蘑è�‡çš„æ¦‚率。对于 N\*M 矩阵,如果 i == N || j == M,那么 (i,j) å�ªèƒ½æœ‰ä¸€ä¸ªç§»åŠ¨æ–¹å�‘;其它情况下能有两个移动方å�‘。 -¿¼ÂÇÒÔϾØÕ󣬯äÖÐµÚ 3 ÐÐºÍµÚ 3 ÁÐÖ»ÄÜÍùÒ»¸ö·½ÏòÒÆ¶¯£¬¶øÆäËüλÖÿÉÒÔÓÐÁ½¸ö·½ÏòÒÆ¶¯¡£ +考虑以下矩阵,其中第 3 行和第 3 列å�ªèƒ½å¾€ä¸€ä¸ªæ–¹å�‘移动,而其它ä½�ç½®å�¯ä»¥æœ‰ä¸¤ä¸ªæ–¹å�‘移动。 ```java diff --git a/notes/HTTP.md b/notes/HTTP.md index 02c65e9b..c2afd12a 100644 --- a/notes/HTTP.md +++ b/notes/HTTP.md @@ -1,84 +1,85 @@ -* [»ù´¡¸ÅÄî](#»ù´¡¸ÅÄî) - * [Web »ù´¡](#web-»ù´¡) +* [基础概念](#基础概念) + * [Web 基础](#web-基础) * [URL](#url) - * [ÇëÇóºÍÏìÓ¦±¨ÎÄ](#ÇëÇóºÍÏìÓ¦±¨ÎÄ) -* [HTTP ·½·¨](#http-·½·¨) - * [GET£º»ñÈ¡×ÊÔ´](#get»ñÈ¡×ÊÔ´) - * [POST£º´«ÊäʵÌåÖ÷Ìå](#post´«ÊäʵÌåÖ÷Ìå) - * [HEAD£º»ñÈ¡±¨ÎÄÊײ¿](#head»ñÈ¡±¨ÎÄÊײ¿) - * [PUT£ºÉÏ´«Îļþ](#putÉÏ´«Îļþ) - * [DELETE£ºÉ¾³ýÎļþ](#deleteɾ³ýÎļþ) - * [OPTIONS£º²éѯ֧³ÖµÄ·½·¨](#options²éѯ֧³ÖµÄ·½·¨) - * [TRACE£º×·×Ù·¾¶](#trace×·×Ù·¾¶) - * [CONNECT£ºÒªÇóÓÃËíµÀЭÒéÁ¬½Ó´úÀí](#connectÒªÇóÓÃËíµÀЭÒéÁ¬½Ó´úÀí) -* [HTTP ״̬Âë](#http-״̬Âë) - * [2XX ³É¹¦](#2xx-³É¹¦) - * [3XX ÖØ¶¨Ïò](#3xx-ÖØ¶¨Ïò) - * [4XX ¿Í»§¶Ë´íÎó](#4xx-¿Í»§¶Ë´íÎó) - * [5XX ·þÎñÆ÷´íÎó](#5xx-·þÎñÆ÷´íÎó) -* [HTTP Êײ¿](#http-Êײ¿) - * [ͨÓÃÊײ¿×Ö¶Î](#ͨÓÃÊײ¿×Ö¶Î) - * [ÇëÇóÊײ¿×Ö¶Î](#ÇëÇóÊײ¿×Ö¶Î) - * [ÏìÓ¦Êײ¿×Ö¶Î](#ÏìÓ¦Êײ¿×Ö¶Î) - * [ʵÌåÊײ¿×Ö¶Î](#ʵÌåÊײ¿×Ö¶Î) -* [¾ßÌåÓ¦ÓÃ](#¾ßÌåÓ¦ÓÃ) + * [请求和å“�应报文](#请求和å“�应报文) +* [HTTP 方法](#http-方法) + * [GET:获å�–资æº�](#get获å�–资æº�) + * [POST:传输实体主体](#post传输实体主体) + * [HEAD:获å�–报文首部](#head获å�–报文首部) + * [PUT:上传文件](#put上传文件) + * [DELETE:删除文件](#delete删除文件) + * [OPTIONS:查询支æŒ�的方法](#options查询支æŒ�的方法) + * [TRACE:追踪路径](#trace追踪路径) + * [CONNECT:è¦�求用隧é�“å��议连接代ç�†](#connectè¦�求用隧é�“å��议连接代ç�†) +* [HTTP 状æ€�ç �](#http-状æ€�ç �) + * [2XX æˆ�功](#2xx-æˆ�功) + * [3XX é‡�定å�‘](#3xx-é‡�定å�‘) + * [4XX 客户端错误](#4xx-客户端错误) + * [5XX æœ�务器错误](#5xx-æœ�务器错误) +* [HTTP 首部](#http-首部) + * [通用首部字段](#通用首部字段) + * [请求首部字段](#请求首部字段) + * [å“�应首部字段](#å“�应首部字段) + * [实体首部字段](#实体首部字段) +* [具体应用](#具体应用) * [Cookie](#cookie) - * [»º´æ](#»º´æ) - * [³Ö¾ÃÁ¬½Ó](#³Ö¾ÃÁ¬½Ó) - * [±àÂë](#±àÂë) - * [·Ö¿é´«Êä](#·Ö¿é´«Êä) - * [¶à²¿·Ö¶ÔÏ󼯺Ï](#¶à²¿·Ö¶ÔÏ󼯺Ï) - * [·¶Î§ÇëÇó](#·¶Î§ÇëÇó) - * [ÄÚÈÝЭÉÌ](#ÄÚÈÝЭÉÌ) - * [ÐéÄâÖ÷»ú](#ÐéÄâÖ÷»ú) - * [ͨÐÅÊý¾Ýת·¢](#ͨÐÅÊý¾Ýת·¢) + * [缓存](#缓存) + * [æŒ�久连接](#æŒ�久连接) + * [ç¼–ç �](#ç¼–ç �) + * [分å�—传输](#分å�—传输) + * [多部分对象集å�ˆ](#多部分对象集å�ˆ) + * [范围请求](#范围请求) + * [内容å��商](#内容å��商) + * [虚拟主机](#虚拟主机) + * [通信数æ�®è½¬å�‘](#通信数æ�®è½¬å�‘) * [HTTPs](#https) - * [¼ÓÃÜ](#¼ÓÃÜ) - * [ÈÏÖ¤](#ÈÏÖ¤) - * [ÍêÕûÐÔ](#ÍêÕûÐÔ) -* [HTTP/1.0 Óë HTTP/1.1 µÄÇø±ð](#http10-Óë-http11-µÄÇø±ð) + * [加密](#加密) + * [认è¯�](#认è¯�) + * [完整性](#完整性) +* [HTTP/1.0 与 HTTP/1.1 的区别](#http10-与-http11-的区别) -# »ù´¡¸ÅÄî -## Web »ù´¡ +# 基础概念 -- HTTP£¨HyperText Transfer Protocol£¬³¬Îª±¾´«ÊäЭÒ飩¡£ -- WWW£¨Word Wide Web£©µÄÈýÖÖ¼¼Êõ£ºHTML¡¢HTTP¡¢URL¡£ -- RFC£¨Request for Comments£¬Õ÷ÇóÐÞÕýÒâ¼ûÊ飩£¬»¥ÁªÍøµÄÉè¼ÆÎĵµ¡£ +## Web 基础 + +- HTTP(HyperText Transfer Protocol,超为本传输å��议)。 +- WWW(Word Wide Web)的三ç§�技术:HTMLã€�HTTPã€�URL。 +- RFC(Request for Comments,å¾�求修正æ„�è§�书),互è�”网的设计文档。 ## URL -- URI£¨Uniform Resource Indentifier£¬Í³Ò»×ÊÔ´±êʶ·û£© -- URL£¨Uniform Resource Locator£¬Í³Ò»×ÊÔ´¶¨Î»·û£© -- URN£¨Uniform Resource Name£¬Í³Ò»×ÊÔ´Ãû³Æ£©£¬ÀýÈç urn:isbn:0-486-27557-4 ¡£ +- URI(Uniform Resource Indentifier,统一资æº�标识符) +- URL(Uniform Resource Locator,统一资æº�定ä½�符) +- URN(Uniform Resource Name,统一资æº�å��称),例如 urn:isbn:0-486-27557-4 。 -URI °üº¬ URL ºÍ URN£¬Ä¿Ç° WEB Ö»ÓÐ URL ±È½ÏÁ÷ÐУ¬ËùÒÔ¼ûµ½µÄ»ù±¾¶¼ÊÇ URL¡£ +URI 包å�« URL å’Œ URN,目å‰� WEB å�ªæœ‰ URL 比较æµ�行,所以è§�到的基本都是 URL。 -![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/4102b7d0-39b9-48d8-82ae-ac4addb7ebfb.jpg) +![](https://github.com/CyC2018/InterviewNotes/blob/master/pics//4102b7d0-39b9-48d8-82ae-ac4addb7ebfb.jpg) -## ÇëÇóºÍÏìÓ¦±¨ÎÄ +## 请求和å“�应报文 -**ÇëÇó±¨ÎÄ** +**请求报文** -![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/9dbb5fc2-936b-4c6d-b3a7-9617aae45080.jpg) +![](https://github.com/CyC2018/InterviewNotes/blob/master/pics//9dbb5fc2-936b-4c6d-b3a7-9617aae45080.jpg) -**ÏìÓ¦±¨ÎÄ** +**å“�应报文** -![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/c634b5ed-a14b-4302-b40e-3ee387dd3c8a.jpg) +![](https://github.com/CyC2018/InterviewNotes/blob/master/pics//c634b5ed-a14b-4302-b40e-3ee387dd3c8a.jpg) -# HTTP ·½·¨ +# HTTP 方法 -¿Í»§¶Ë·¢Ë͵ÄÇëÇó±¨ÎĵÚÒ»ÐÐΪÇëÇóÐУ¬°üº¬ÁË·½·¨×ֶΡ£ +客户端å�‘é€�的请求报文第一行为请求行,包å�«äº†æ–¹æ³•字段。 -## GET£º»ñÈ¡×ÊÔ´ +## GET:获å�–资æº� -## POST£º´«ÊäʵÌåÖ÷Ìå +## POST:传输实体主体 -POST Ö÷ҪĿµÄ²»ÊÇ»ñÈ¡×ÊÔ´£¬¶øÊÇ´«ÊäʵÌåÖ÷ÌåÊý¾Ý¡£ +POST 主è¦�目的ä¸�是获å�–资æº�,而是传输实体主体数æ�®ã€‚ -GET ºÍ POST µÄÇëÇó¶¼ÄÜʹÓöîÍâµÄ²ÎÊý£¬µ«ÊÇ GET µÄ²ÎÊýÊÇÒÔ²éѯ×Ö·û´®³öÏÖÔÚ URLÖУ¬¶ø POST µÄ²ÎÊý´æ´¢ÔÚʵÌåÖ÷Ì岿·Ö¡£ +GET å’Œ POST 的请求都能使用é¢�外的å�‚数,但是 GET çš„å�‚数是以查询字符串出现在 URL中,而 POST çš„å�‚数存储在实体主体部分。 ``` GET /test/demo_form.asp?name1=value1&name2=value2 HTTP/1.1 @@ -89,318 +90,318 @@ Host: w3schools.com name1=value1&name2=value2 ``` -GET µÄ´«²Î·½Ê½Ïà±ÈÓÚ POST °²È«ÐԽϲÒòΪ GET ´«µÄ²ÎÊýÔÚ URL ÊǿɼûµÄ£¬¿ÉÄÜ»áй¶˽ÃÜÐÅÏ¢¡£²¢ÇÒ GET Ö»Ö§³Ö ASCII ×Ö·û£¬Èç¹û²ÎÊýΪÖÐÎÄÔò¿ÉÄÜ»á³öÏÖÂÒÂ룬¶ø POST Ö§³Ö±ê×¼×Ö·û¼¯¡£ +GET 的传å�‚æ–¹å¼�相比于 POST 安全性较差,因为 GET ä¼ çš„å�‚数在 URL 是å�¯è§�的,å�¯èƒ½ä¼šæ³„露ç§�密信æ�¯ã€‚并且 GET å�ªæ”¯æŒ� ASCII 字符,如果å�‚数为中文则å�¯èƒ½ä¼šå‡ºçް乱ç �,而 POST 支æŒ�标准字符集。 -## HEAD£º»ñÈ¡±¨ÎÄÊײ¿ +## HEAD:获å�–报文首部 -ºÍ GET ·½·¨Ò»Ñù£¬µ«ÊDz»·µ»Ø±¨ÎÄʵÌåÖ÷Ì岿·Ö¡£ +å’Œ GET 方法一样,但是ä¸�返回报文实体主体部分。 -Ö÷ÒªÓÃÓÚÈ·ÈÏ URL µÄÓÐЧÐÔÒÔ¼°×ÊÔ´¸üеÄÈÕÆÚʱ¼äµÈ¡£ +主è¦�用于确认 URL 的有效性以å�Šèµ„æº�更新的日期时间等。 -## PUT£ºÉÏ´«Îļþ +## PUT:上传文件 -ÓÉÓÚ×ÔÉí²»´øÑéÖ¤»úÖÆ£¬ÈκÎÈ˶¼¿ÉÒÔÉÏ´«Îļþ£¬Òò´Ë´æÔÚ°²È«ÐÔÎÊÌ⣬һ°ã WEB ÍøÕ¾²»Ê¹Óø÷½·¨¡£ +由于自身ä¸�带验è¯�机制,任何人都å�¯ä»¥ä¸Šä¼ æ–‡ä»¶ï¼Œå› æ­¤å­˜åœ¨å®‰å…¨æ€§é—®é¢˜ï¼Œä¸€èˆ¬ WEB 网站ä¸�使用该方法。 -## DELETE£ºÉ¾³ýÎļþ +## DELETE:删除文件 -Óë PUT ¹¦ÄÜÏà·´£¬²¢ÇÒͬÑù²»´øÑéÖ¤»úÖÆ¡£ +与 PUT 功能相å��,并且å�Œæ ·ä¸�带验è¯�机制。 -## OPTIONS£º²éѯ֧³ÖµÄ·½·¨ +## OPTIONS:查询支æŒ�的方法 -²éѯָ¶¨µÄ URL Äܹ»Ö§³ÖµÄ·½·¨¡£ +查询指定的 URL 能够支æŒ�的方法。 -»á·µ»Ø Allow: GET, POST, HEAD, OPTIONS ÕâÑùµÄÄÚÈÝ¡£ +会返回 Allow: GET, POST, HEAD, OPTIONS 这样的内容。 -## TRACE£º×·×Ù·¾¶ +## TRACE:追踪路径 -·þÎñÆ÷»á½«Í¨ÐÅ·¾¶·µ»Ø¸ø¿Í»§¶Ë¡£ +æœ�务器会将通信路径返回给客户端。 -·¢ËÍÇëÇóʱ£¬ÔÚ Max-Forwards Êײ¿×Ö¶ÎÖÐÌîÈëÊýÖµ£¬Ã¿¾­¹ýÒ»¸ö·þÎñÆ÷¾Í»á¼õ 1£¬µ±ÊýֵΪ 0 ʱ¾ÍÍ£Ö¹´«Êä¡£ +å�‘é€�请求时,在 Max-Forwards 首部字段中填入数值,æ¯�ç»�过一个æœ�务器就会å‡� 1,当数值为 0 æ—¶å°±å�œæ­¢ä¼ è¾“。 -TRACE Ò»°ã²»»áʹÓ㬲¢ÇÒËüÈÝÒ×Êܵ½ XST ¹¥»÷£¨Cross-Site Tracing£¬¿çÕ¾×·×Ù£©£¬Òò´Ë¸ü²»»áȥʹÓÃËü¡£ +TRACE 一般ä¸�会使用,并且它容易å�—到 XST 攻击(Cross-Site Tracing,跨站追踪),因此更ä¸�会去使用它。 -![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/ca711108-e937-4d7d-99aa-61b325c61f1a.jpg) +![](https://github.com/CyC2018/InterviewNotes/blob/master/pics//ca711108-e937-4d7d-99aa-61b325c61f1a.jpg) -## CONNECT£ºÒªÇóÓÃËíµÀЭÒéÁ¬½Ó´úÀí +## CONNECT:è¦�求用隧é�“å��议连接代ç�† -Ö÷ҪʹÓà SSL£¨Secure Sokets Layer£¬°²È«Ì×½Ó×Ö£©ºÍ TLS£¨Transport Layer Security£¬´«Êä²ã°²È«£©Ð­Òé°ÑͨÐÅÄÚÈݼÓÃܺó¾­ÍøÂçËíµÀ´«Êä¡£ +主è¦�使用 SSL(Secure Sokets Layer,安全套接字)和 TLS(Transport Layer Security,传输层安全)å��议把通信内容加密å�Žç»�网络隧é�“传输。 -![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/d8355d56-aa2b-4452-8001-8475cc095af1.jpg) +![](https://github.com/CyC2018/InterviewNotes/blob/master/pics//d8355d56-aa2b-4452-8001-8475cc095af1.jpg) -# HTTP ״̬Âë +# HTTP 状æ€�ç � -·þÎñÆ÷·µ»ØµÄÏìÓ¦±¨ÎÄÖеÚÒ»ÐÐΪ״̬ÐУ¬°üº¬ÁË״̬ÂëÒÔ¼°Ô­Òò¶ÌÓÀ´¸æÖª¿Í»§¶ËÇëÇóµÄ½á¹û¡£ +æœ�务器返回的å“�应报文中第一行为状æ€�行,包å�«äº†çжæ€�ç �以å�ŠåŽŸå› çŸ­è¯­ï¼Œæ�¥å‘ŠçŸ¥å®¢æˆ·ç«¯è¯·æ±‚的结果。 -| ״̬Âë | Àà±ð | Ô­Òò¶ÌÓï | +| 状æ€�ç � | 类别 | 原因短语 | | --- | --- | --- | -| 1XX | Informational£¨ÐÅÏ¢ÐÔ״̬Â룩 | ½ÓÊÕµÄÇëÇóÕýÔÚ´¦Àí | -| 2XX | Success£¨³É¹¦×´Ì¬Â룩 | ÇëÇóÕý³£´¦ÀíÍê±Ï | -| 3XX | Redirection£¨Öض¨Ïò״̬Â룩 | ÐèÒª½øÐи½¼Ó²Ù×÷ÒÔÍê³ÉÇëÇó | -| 4XX | Client Error£¨¿Í»§¶Ë´íÎó״̬Â룩 | ·þÎñÆ÷ÎÞ·¨´¦ÀíÇëÇó | -| 5XX | Server Error£¨·þÎñÆ÷´íÎó״̬Â룩 | ·þÎñÆ÷´¦ÀíÇëÇó³ö´í | +| 1XX | Informational(信æ�¯æ€§çжæ€�ç �) | 接收的请求正在处ç�† | +| 2XX | Success(æˆ�功状æ€�ç �) | 请求正常处ç�†å®Œæ¯• | +| 3XX | Redirection(é‡�定å�‘状æ€�ç �) | 需è¦�进行附加æ“�作以完æˆ�请求 | +| 4XX | Client Error(客户端错误状æ€�ç �) | æœ�务器无法处ç�†è¯·æ±‚ | +| 5XX | Server Error(æœ�务器错误状æ€�ç �) | æœ�务器处ç�†è¯·æ±‚出错 | -## 2XX ³É¹¦ +## 2XX æˆ�功 - **200 OK** -- **204 No Content**£ºÇëÇóÒѾ­³É¹¦´¦Àí£¬µ«ÊÇ·µ»ØµÄÏìÓ¦±¨ÎIJ»°üº¬ÊµÌåµÄÖ÷Ì岿·Ö¡£Ò»°ãÔÚÖ»ÐèÒª´Ó¿Í»§¶ËÍù·þÎñÆ÷·¢ËÍÐÅÏ¢£¬¶ø²»ÐèÒª·µ»ØÊý¾ÝʱʹÓᣠ+- **204 No Content**:请求已ç»�æˆ�功处ç�†ï¼Œä½†æ˜¯è¿”回的å“�应报文ä¸�包å�«å®žä½“的主体部分。一般在å�ªéœ€è¦�从客户端往æœ�务器å�‘é€�ä¿¡æ�¯ï¼Œè€Œä¸�需è¦�返回数æ�®æ—¶ä½¿ç”¨ã€‚ - **206 Partial Content** -## 3XX ÖØ¶¨Ïò +## 3XX é‡�定å�‘ -- **301 Moved Permanently**£ºÓÀ¾ÃÐÔÖØ¶¨Ïò +- **301 Moved Permanently**:永久性é‡�定å�‘ -- **302 Found**£ºÁÙʱÐÔÖØ¶¨Ïò +- **302 Found**:临时性é‡�定å�‘ - **303 See Other** -- ×¢£ºËäÈ» HTTP ЭÒ鹿¶¨ 301¡¢302 ״̬ÏÂÖØ¶¨Ïòʱ²»ÔÊÐí°Ñ POST ·½·¨¸Ä³É GET ·½·¨£¬µ«ÊÇ´ó¶àÊýä¯ÀÀÆ÷¶¼»á ÔÚ 301¡¢302 ºÍ 303 ״̬ϵÄÖØ¶¨Ïò°Ñ POST ·½·¨¸Ä³É GET ·½·¨¡£ +- 注:虽然 HTTP å��议规定 301ã€�302 状æ€�下é‡�定å�‘æ—¶ä¸�å…�许把 POST 方法改æˆ� GET 方法,但是大多数æµ�览器都会 在 301ã€�302 å’Œ 303 状æ€�下的é‡�定å�‘把 POST 方法改æˆ� GET 方法。 -- **304 Not Modified**£ºÈç¹ûÇëÇó±¨ÎÄÊײ¿°üº¬Ò»Ð©Ìõ¼þ£¬ÀýÈ磺If-Match£¬If-ModifiedSince£¬If-None-Match£¬If-Range£¬If-Unmodified-Since£¬µ«ÊDz»Âú×ãÌõ¼þ£¬Ôò·þÎñÆ÷»á·µ»Ø 304 ״̬Âë¡£ +- **304 Not Modified**:如果请求报文首部包å�«ä¸€äº›æ�¡ä»¶ï¼Œä¾‹å¦‚:If-Match,If-ModifiedSince,If-None-Match,If-Range,If-Unmodified-Since,但是ä¸�满足æ�¡ä»¶ï¼Œåˆ™æœ�务器会返回 304 状æ€�ç �。 -- **307 Temporary Redirect**£ºÁÙÊ±ÖØ¶¨Ïò£¬Óë 302 µÄº¬ÒåÀàËÆ£¬µ«ÊÇ 307 ÒªÇóä¯ÀÀÆ÷²»»á°ÑÖØ¶¨ÏòÇëÇóµÄ POST ·½·¨¸Ä³É GET ·½·¨¡£ +- **307 Temporary Redirect**:临时é‡�定å�‘,与 302 çš„å�«ä¹‰ç±»ä¼¼ï¼Œä½†æ˜¯ 307 è¦�求æµ�览器ä¸�会把é‡�定å�‘请求的 POST 方法改æˆ� GET 方法。 -## 4XX ¿Í»§¶Ë´íÎó +## 4XX 客户端错误 -- **400 Bad Request**£ºÇëÇó±¨ÎÄÖдæÔÚÓï·¨´íÎó +- **400 Bad Request**:请求报文中存在语法错误 -- **401 Unauthorized**£º¸Ã״̬Âë±íʾ·¢Ë͵ÄÇëÇóÐèÒªÓÐͨ¹ý HTTP ÈÏÖ¤£¨BASIC ÈÏÖ¤¡¢DIGEST ÈÏÖ¤£©µÄÈÏÖ¤ÐÅÏ¢¡£Èç¹û֮ǰÒѽøÐйýÒ»´ÎÇëÇó£¬Ôò±íʾÓû§ÈÏ֤ʧ°Ü¡£ +- **401 Unauthorized**:该状æ€�ç �表示å�‘é€�的请求需è¦�有通过 HTTP 认è¯�(BASIC 认è¯�ã€�DIGEST 认è¯�)的认è¯�ä¿¡æ�¯ã€‚如果之å‰�已进行过一次请求,则表示用户认è¯�失败。 -![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/b1b4cf7d-c54a-4ff1-9741-cd2eea331123.jpg) +![](https://github.com/CyC2018/InterviewNotes/blob/master/pics//b1b4cf7d-c54a-4ff1-9741-cd2eea331123.jpg) -- **403 Forbidden**£ºÇëÇ󱻾ܾø£¬·þÎñÆ÷¶ËûÓбØÒª¸ø³ö¾Ü¾øµÄÏêϸÀíÓÉ¡£ +- **403 Forbidden**:请求被拒ç»�,æœ�务器端没有必è¦�给出拒ç»�的详细ç�†ç”±ã€‚ - **404 Not Found** -## 5XX ·þÎñÆ÷´íÎó +## 5XX æœ�务器错误 -- **500 Internal Server Error**£º·þÎñÆ÷ÕýÔÚÖ´ÐÐÇëÇóʱ·¢Éú´íÎó +- **500 Internal Server Error**:æœ�务器正在执行请求时å�‘生错误 -- **503 Service Unavilable**£º¸Ã״̬Âë±íÃ÷·þÎñÆ÷ÔÝʱ´¦ÓÚ³¬¸ºÔØ»òÕýÔÚ½øÐÐÍ£»úά»¤£¬ÏÖÔÚÎÞ·¨´¦ÀíÇëÇó¡£ +- **503 Service Unavilable**:该状æ€�ç �表明æœ�务器暂时处于超负载或正在进行å�œæœºç»´æŠ¤ï¼ŒçŽ°åœ¨æ— æ³•å¤„ç�†è¯·æ±‚。 -# HTTP Êײ¿ +# HTTP 首部 -ÓÐ 4 ÖÖÀàÐ͵ÄÊײ¿×ֶΣºÍ¨ÓÃÊײ¿×ֶΡ¢ÇëÇóÊײ¿×ֶΡ¢ÏìÓ¦Êײ¿×ֶκÍʵÌåÊײ¿×ֶΡ£ +有 4 ç§�类型的首部字段:通用首部字段ã€�请求首部字段ã€�å“�应首部字段和实体首部字段。 -¸÷ÖÖÊײ¿×ֶμ°Æäº¬ÒåÈçÏ£¨²»ÐèҪȫ¼Ç£¬½ö¹©²éÔÄ£©£º +å�„ç§�首部字段å�Šå…¶å�«ä¹‰å¦‚下(ä¸�需è¦�全记,仅供查阅): -## ͨÓÃÊײ¿×Ö¶Î +## 通用首部字段 -| Êײ¿×Ö¶ÎÃû | ˵Ã÷ | +| 首部字段å�� | 说明 | | -- | -- | -| Cache-Control | ¿ØÖÆ»º´æµÄÐÐΪ | -| Connection | ÖðÌøÊײ¿¡¢ Á¬½ÓµÄ¹ÜÀí | -| Date | ´´½¨±¨ÎĵÄÈÕÆÚʱ¼ä | -| Pragma | ±¨ÎÄÖ¸Áî | -| Trailer | ±¨ÎÄÄ©¶ËµÄÊײ¿Ò»ÀÀ | -| Transfer-Encoding | Ö¸¶¨±¨ÎÄÖ÷ÌåµÄ´«Êä±àÂ뷽ʽ | -| Upgrade | Éý¼¶ÎªÆäËûЭÒé | -| Via | ´úÀí·þÎñÆ÷µÄÏà¹ØÐÅÏ¢ | -| Warning | ´íÎó֪ͨ | +| Cache-Control | 控制缓存的行为 | +| Connection | é€�跳首部ã€� 连接的管ç�† | +| Date | 创建报文的日期时间 | +| Pragma | 报文指令 | +| Trailer | 报文末端的首部一览 | +| Transfer-Encoding | 指定报文主体的传输编ç �æ–¹å¼� | +| Upgrade | å�‡çº§ä¸ºå…¶ä»–å��è®® | +| Via | 代ç�†æœ�务器的相关信æ�¯ | +| Warning | 错误通知 | -## ÇëÇóÊײ¿×Ö¶Î +## 请求首部字段 -| Êײ¿×Ö¶ÎÃû | ˵Ã÷ | +| 首部字段å�� | 说明 | | -- | -- | -| Accept | Óû§´úÀí¿É´¦ÀíµÄýÌåÀàÐÍ | -| Accept-Charset | ÓÅÏȵÄ×Ö·û¼¯ | -| Accept-Encoding | ÓÅÏȵÄÄÚÈݱàÂë | -| Accept-Language | ÓÅÏȵÄÓïÑÔ£¨×ÔÈ»ÓïÑÔ£© | -| Authorization | WebÈÏÖ¤ÐÅÏ¢ | -| Expect | ÆÚ´ý·þÎñÆ÷µÄÌØ¶¨ÐÐΪ | -| From | Óû§µÄµç×ÓÓÊÏ䵨ַ | -| Host | ÇëÇó×ÊÔ´ËùÔÚ·þÎñÆ÷ | -| If-Match | ±È½ÏʵÌå±ê¼Ç£¨ETag£© | -| If-Modified-Since | ±È½Ï×ÊÔ´µÄ¸üÐÂʱ¼ä | -| If-None-Match | ±È½ÏʵÌå±ê¼Ç£¨Óë If-Match Ïà·´£© | -| If-Range | ×ÊԴδ¸üÐÂʱ·¢ËÍʵÌå Byte µÄ·¶Î§ÇëÇó | -| If-Unmodified-Since | ±È½Ï×ÊÔ´µÄ¸üÐÂʱ¼ä£¨ÓëIf-Modified-SinceÏà·´£© | -| Max-Forwards | ×î´ó´«ÊäÖðÌøÊý | -| Proxy-Authorization | ´úÀí·þÎñÆ÷ÒªÇó¿Í»§¶ËµÄÈÏÖ¤ÐÅÏ¢ | -| Range | ʵÌåµÄ×Ö½Ú·¶Î§ÇëÇó | -| Referer | ¶ÔÇëÇóÖÐ URI µÄԭʼ»ñÈ¡·½ | -| TE | ´«Êä±àÂëµÄÓÅÏȼ¶ | -| User-Agent | HTTP ¿Í»§¶Ë³ÌÐòµÄÐÅÏ¢ | +| Accept | 用户代ç�†å�¯å¤„ç�†çš„媒体类型 | +| Accept-Charset | 优先的字符集 | +| Accept-Encoding | 优先的内容编ç � | +| Accept-Language | 优先的语言(自然语言) | +| Authorization | Web认è¯�ä¿¡æ�¯ | +| Expect | 期待æœ�务器的特定行为 | +| From | 用户的电å­�邮箱地å�€ | +| Host | 请求资æº�所在æœ�务器 | +| If-Match | 比较实体标记(ETag) | +| If-Modified-Since | 比较资æº�的更新时间 | +| If-None-Match | 比较实体标记(与 If-Match 相å��) | +| If-Range | 资æº�未更新时å�‘é€�实体 Byte 的范围请求 | +| If-Unmodified-Since | 比较资æº�的更新时间(与If-Modified-Since相å��) | +| Max-Forwards | 最大传输é€�跳数 | +| Proxy-Authorization | 代ç�†æœ�务器è¦�求客户端的认è¯�ä¿¡æ�¯ | +| Range | 实体的字节范围请求 | +| Referer | 对请求中 URI 的原始获å�–æ–¹ | +| TE | 传输编ç �的优先级 | +| User-Agent | HTTP 客户端程åº�的信æ�¯ | -## ÏìÓ¦Êײ¿×Ö¶Î +## å“�应首部字段 -| Êײ¿×Ö¶ÎÃû | ˵Ã÷ | +| 首部字段å�� | 说明 | | -- | -- | -| Accept-Ranges | ÊÇ·ñ½ÓÊÜ×Ö½Ú·¶Î§ÇëÇó | -| Age | ÍÆËã×ÊÔ´´´½¨¾­¹ýʱ¼ä | -| ETag | ×ÊÔ´µÄÆ¥ÅäÐÅÏ¢ | -| Location | Áî¿Í»§¶ËÖØ¶¨ÏòÖÁÖ¸¶¨URI | -| Proxy-Authenticate | ´úÀí·þÎñÆ÷¶Ô¿Í»§¶ËµÄÈÏÖ¤ÐÅÏ¢ | -| Retry-After | ¶ÔÔٴη¢ÆðÇëÇóµÄʱ»úÒªÇó | -| Server | HTTP·þÎñÆ÷µÄ°²×°ÐÅÏ¢ | -| Vary | ´úÀí·þÎñÆ÷»º´æµÄ¹ÜÀíÐÅÏ¢ | -| WWW-Authenticate | ·þÎñÆ÷¶Ô¿Í»§¶ËµÄÈÏÖ¤ÐÅÏ¢ | +| Accept-Ranges | 是å�¦æŽ¥å�—字节范围请求 | +| Age | 推算资æº�创建ç»�过时间 | +| ETag | 资æº�的匹é…�ä¿¡æ�¯ | +| Location | 令客户端é‡�定å�‘至指定URI | +| Proxy-Authenticate | 代ç�†æœ�务器对客户端的认è¯�ä¿¡æ�¯ | +| Retry-After | 对å†�次å�‘起请求的时机è¦�求 | +| Server | HTTPæœ�务器的安装信æ�¯ | +| Vary | 代ç�†æœ�务器缓存的管ç�†ä¿¡æ�¯ | +| WWW-Authenticate | æœ�务器对客户端的认è¯�ä¿¡æ�¯ | -## ʵÌåÊײ¿×Ö¶Î +## 实体首部字段 -| Êײ¿×Ö¶ÎÃû | ˵Ã÷ | +| 首部字段å�� | 说明 | | -- | -- | -| Allow | ×ÊÔ´¿ÉÖ§³ÖµÄHTTP·½·¨ | -| Content-Encoding | ʵÌåÖ÷ÌåÊÊÓõıàÂ뷽ʽ | -| Content-Language | ʵÌåÖ÷ÌåµÄ×ÔÈ»ÓïÑÔ | -| Content-Length | ʵÌåÖ÷ÌåµÄ´óС£¨µ¥Î»£º ×Ö½Ú£© | -| Content-Location | Ìæ´ú¶ÔÓ¦×ÊÔ´µÄURI | -| Content-MD5 | ʵÌåÖ÷ÌåµÄ±¨ÎÄÕªÒª | -| Content-Range | ʵÌåÖ÷ÌåµÄλÖ÷¶Î§ | -| Content-Type | ʵÌåÖ÷ÌåµÄýÌåÀàÐÍ | -| Expires | ʵÌåÖ÷Ìå¹ýÆÚµÄÈÕÆÚʱ¼ä | -| Last-Modified | ×ÊÔ´µÄ×îºóÐÞ¸ÄÈÕÆÚʱ¼ä | +| Allow | 资æº�å�¯æ”¯æŒ�çš„HTTP方法 | +| Content-Encoding | 实体主体适用的编ç �æ–¹å¼� | +| Content-Language | 实体主体的自然语言 | +| Content-Length | 实体主体的大å°�(å�•ä½�: 字节) | +| Content-Location | 替代对应资æº�çš„URI | +| Content-MD5 | 实体主体的报文摘è¦� | +| Content-Range | 实体主体的ä½�置范围 | +| Content-Type | 实体主体的媒体类型 | +| Expires | 实体主体过期的日期时间 | +| Last-Modified | 资æº�的最å�Žä¿®æ”¹æ—¥æœŸæ—¶é—´ | -# ¾ßÌåÓ¦Óà +# 具体应用 ## Cookie -HTTP ЭÒéÊÇÎÞ״̬µÄ£¬Ö÷ÒªÊÇΪÁËÈà HTTP ЭÒ龡¿ÉÄܼòµ¥£¬Ê¹µÃËüÄܹ»´¦Àí´óÁ¿ÊÂÎñ¡£HTTP/1.1 ÒýÈë Cookie À´±£´æ×´Ì¬ÐÅÏ¢¡£ +HTTP å��议是无状æ€�的,主è¦�是为了让 HTTP å��议尽å�¯èƒ½ç®€å�•,使得它能够处ç�†å¤§é‡�事务。HTTP/1.1 引入 Cookie æ�¥ä¿�存状æ€�ä¿¡æ�¯ã€‚ -·þÎñÆ÷·¢Ë͵ÄÏìÓ¦±¨Îİüº¬ Set-Cookie ×ֶΣ¬¿Í»§¶ËµÃµ½ÏìÓ¦±¨Îĺó°Ñ Cookie ÄÚÈݱ£´æµ½ä¯ÀÀÆ÷ÖС£Ï´ÎÔÙ·¢ËÍÇëÇóʱ£¬´Óä¯ÀÀÆ÷ÖжÁ³ö Cookie Öµ£¬ÔÚÇëÇó±¨ÎÄÖаüº¬ Cookie ×ֶΣ¬ÕâÑù·þÎñÆ÷¾ÍÖªµÀ¿Í»§¶ËµÄ״̬ÐÅÏ¢ÁË¡£Cookie ״̬ÐÅÏ¢±£´æÔÚ¿Í»§¶Ëä¯ÀÀÆ÷ÖУ¬¶ø²»ÊÇ·þÎñÆ÷ÉÏ¡£ +æœ�务器å�‘é€�çš„å“�应报文包å�« Set-Cookie 字段,客户端得到å“�应报文å�ŽæŠŠ Cookie 内容ä¿�存到æµ�览器中。下次å†�å�‘é€�请求时,从æµ�览器中读出 Cookie 值,在请求报文中包å�« Cookie 字段,这样æœ�务器就知é�“客户端的状æ€�ä¿¡æ�¯äº†ã€‚Cookie 状æ€�ä¿¡æ�¯ä¿�存在客户端æµ�览器中,而ä¸�是æœ�务器上。 -![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/ff17c103-750a-4bb8-9afa-576327023af9.png) +![](https://github.com/CyC2018/InterviewNotes/blob/master/pics//ff17c103-750a-4bb8-9afa-576327023af9.png) -Set-Cookie ×Ö¶ÎÓÐÒÔÏÂÊôÐÔ£º +Set-Cookie 字段有以下属性: -| ÊôÐÔ | ˵Ã÷ | +| 属性 | 说明 | | -- | -- | -| NAME=VALUE | ¸³Óè Cookie µÄÃû³ÆºÍÆäÖµ£¨±ØÐèÏ | -| expires=DATE | Cookie µÄÓÐЧÆÚ£¨Èô²»Ã÷È·Ö¸¶¨ÔòĬÈÏΪä¯ÀÀÆ÷¹Ø±ÕǰΪֹ£© | -| path=PATH | ½«·þÎñÆ÷ÉϵÄÎļþĿ¼×÷Ϊ Cookie µÄÊÊÓöÔÏó£¨Èô²»Ö¸¶¨ÔòĬÈÏΪÎĵµËùÔÚµÄÎļþĿ¼£© | -| domain=ÓòÃû | ×÷Ϊ Cookie ÊÊÓöÔÏóµÄÓòÃû£¨Èô²»Ö¸¶¨ÔòĬÈÏΪ´´½¨ Cookie µÄ·þÎñÆ÷µÄÓòÃû£© | -| Secure | ½öÔÚ HTTPS °²È«Í¨ÐÅʱ²Å»á·¢ËÍ Cookie | -| HttpOnly | ¼ÓÒÔÏÞÖÆ£¬Ê¹ Cookie ²»Äܱ» JavaScript ½Å±¾·ÃÎÊ | +| NAME=VALUE | 赋予 Cookie çš„å��称和其值(必需项) | +| expires=DATE | Cookie 的有效期(若ä¸�明确指定则默认为æµ�览器关闭å‰�为止) | +| path=PATH | å°†æœ�务器上的文件目录作为 Cookie 的适用对象(若ä¸�指定则默认为文档所在的文件目录) | +| domain=域å�� | 作为 Cookie 适用对象的域å��(若ä¸�指定则默认为创建 Cookie çš„æœ�务器的域å��) | +| Secure | 仅在 HTTPS 安全通信时æ‰�会å�‘é€� Cookie | +| HttpOnly | 加以é™�制,使 Cookie ä¸�能被 JavaScript 脚本访问 | -**Session ºÍ Cookie Çø±ð** +**Session å’Œ Cookie 区别** -Session ÊÇ·þÎñÆ÷ÓÃÀ´¸ú×ÙÓû§µÄÒ»ÖÖÊֶΣ¬Ã¿¸ö Session ¶¼ÓÐÒ»¸öΨһ±êʶ£ºSession ID¡£µ±·þÎñÆ÷´´½¨ÁËÒ»¸ö Session ʱ£¬¸ø¿Í»§¶Ë·¢Ë͵ÄÏìÓ¦±¨ÎľͰüº¬ÁË Set-Cookie ×ֶΣ¬ÆäÖÐÓÐÒ»¸öÃûΪ sid µÄ¼üÖµ¶Ô£¬Õâ¸ö¼üÖµ¶Ô¾ÍÊÇ Session ID¡£¿Í»§¶ËÊÕµ½ºó¾Í°Ñ Cookie ±£´æÔÚä¯ÀÀÆ÷ÖУ¬²¢ÇÒÖ®ºó·¢Ë͵ÄÇëÇó±¨Îͼ°üº¬ Session ID¡£HTTP ¾ÍÊÇͨ¹ý Session ºÍ Cookie ÕâÁ½ÖÖ·½Ê½Ò»ÆðºÏ×÷À´ÊµÏÖ¸ú×ÙÓû§×´Ì¬µÄ£¬Session ÓÃÓÚ·þÎñÆ÷¶Ë£¬Cookie ÓÃÓÚ¿Í»§¶Ë¡£ +Session 是æœ�务器用æ�¥è·Ÿè¸ªç”¨æˆ·çš„一ç§�手段,æ¯�个 Session 都有一个唯一标识:Session ID。当æœ�务器创建了一个 Session 时,给客户端å�‘é€�çš„å“�应报文就包å�«äº† Set-Cookie 字段,其中有一个å��为 sid 的键值对,这个键值对就是 Session ID。客户端收到å�Žå°±æŠŠ Cookie ä¿�存在æµ�览器中,并且之å�Žå�‘é€�的请求报文都包å�« Session ID。HTTP 就是通过 Session å’Œ Cookie 这两ç§�æ–¹å¼�一起å�ˆä½œæ�¥å®žçŽ°è·Ÿè¸ªç”¨æˆ·çŠ¶æ€�的,Session 用于æœ�务器端,Cookie 用于客户端。 -**ä¯ÀÀÆ÷½ûÓà Cookie µÄÇé¿ö** +**æµ�览器ç¦�用 Cookie 的情况** -»áʹÓà URL ÖØÐ´¼¼Êõ£¬ÔÚ URL ºóÃæ¼ÓÉÏ sid=xxx ¡£ +会使用 URL é‡�写技术,在 URL å�Žé�¢åŠ ä¸Š sid=xxx 。 -**ʹÓà Cookie ʵÏÖÓû§ÃûºÍÃÜÂëµÄ×Ô¶¯Ìîд** +**使用 Cookie 实现用户å��和密ç �的自动填写** -ÍøÕ¾½Å±¾»á×Ô¶¯´Ó Cookie ÖжÁÈ¡Óû§ÃûºÍÃÜÂ룬´Ó¶øÊµÏÖ×Ô¶¯Ìîд¡£ +网站脚本会自动从 Cookie 中读å�–用户å��和密ç �,从而实现自动填写。 -## »º´æ +## 缓存 -ÓÐÁ½ÖÖ»º´æ·½·¨£ºÈôúÀí·þÎñÆ÷½øÐлº´æºÍÈÿͻ§¶Ëä¯ÀÀÆ÷½øÐлº´æ¡£ +有两ç§�缓存方法:让代ç�†æœ�务器进行缓存和让客户端æµ�览器进行缓存。 -Cache-Control ÓÃÓÚ¿ØÖÆ»º´æµÄÐÐΪ¡£ +Cache-Control 用于控制缓存的行为。 -Cache-Control: no-cache ÓÐÁ½ÖÖº¬Ò壬Èç¹ûÊǿͻ§¶ËÏò»º´æ·þÎñÆ÷·¢Ë͵ÄÇëÇó±¨ÎÄÖк¬ÓиÃÖ¸Á±íʾ¿Í»§¶Ë²»ÏëÒª»º´æµÄ×ÊÔ´£»Èç¹ûÊÇÔ´·þÎñÆ÷Ïò»º´æ·þÎñÆ÷·¢Ë͵ÄÏìÓ¦±¨ÎÄÖк¬ÓиÃÖ¸Á±íʾ»º´æ·þÎñÆ÷²»ÄܶÔ×ÊÔ´½øÐлº´æ¡£ +Cache-Control: no-cache 有两ç§�å�«ä¹‰ï¼Œå¦‚果是客户端å�‘缓存æœ�务器å�‘é€�的请求报文中å�«æœ‰è¯¥æŒ‡ä»¤ï¼Œè¡¨ç¤ºå®¢æˆ·ç«¯ä¸�想è¦�缓存的资æº�;如果是æº�æœ�务器å�‘缓存æœ�务器å�‘é€�çš„å“�应报文中å�«æœ‰è¯¥æŒ‡ä»¤ï¼Œè¡¨ç¤ºç¼“å­˜æœ�务器ä¸�能对资æº�进行缓存。 -Expires ×ֶοÉÒÔÓÃÓÚ¸æÖª»º´æ·þÎñÆ÷¸Ã×ÊԴʲôʱºò»á¹ýÆÚ¡£µ±Êײ¿×Ö¶Î Cache-Control ÓÐÖ¸¶¨ max-age Ö¸Áîʱ£¬±ÈÆðÊײ¿×Ö¶Î Expires£¬»áÓÅÏÈ´¦Àí max-age Ö¸Áî¡£ +Expires 字段å�¯ä»¥ç”¨äºŽå‘ŠçŸ¥ç¼“å­˜æœ�务器该资æº�什么时候会过期。当首部字段 Cache-Control 有指定 max-age 指令时,比起首部字段 Expires,会优先处ç�† max-age 指令。 -## ³Ö¾ÃÁ¬½Ó +## æŒ�久连接 -µ±ä¯ÀÀÆ÷·ÃÎÊÒ»¸ö°üº¬¶àÕÅͼƬµÄ HTML Ò³ÃæÊ±£¬³ýÁËÇëÇó·ÃÎÊ HTML Ò³Ãæ×ÊÔ´£¬»¹»áÇëÇóͼƬ×ÊÔ´£¬Èç¹ûÿ½øÐÐÒ»´Î HTTP ͨОÍÒª¶Ï¿ªÒ»´Î TCP Á¬½Ó£¬Á¬½Ó½¨Á¢ºÍ¶Ï¿ªµÄ¿ªÏú»áºÜ´ó¡£**³Ö¾ÃÁ¬½Ó** Ö»ÐèÒª½øÐÐÒ»´Î TCP Á¬½Ó¾ÍÄܽøÐжà´Î HTTP ͨÐÅ¡£HTTP/1.1 ¿ªÊ¼£¬ËùÓеÄÁ¬½ÓĬÈ϶¼Êdz־ÃÁ¬½Ó¡£ +当æµ�览器访问一个包å�«å¤šå¼ å›¾ç‰‡çš„ HTML 页é�¢æ—¶ï¼Œé™¤äº†è¯·æ±‚访问 HTML 页é�¢èµ„æº�,还会请求图片资æº�,如果æ¯�进行一次 HTTP 通信就è¦�断开一次 TCP 连接,连接建立和断开的开销会很大。**æŒ�久连接** å�ªéœ€è¦�进行一次 TCP 连接就能进行多次 HTTP 通信。HTTP/1.1 开始,所有的连接默认都是æŒ�久连接。 -![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/c73a0b78-5f46-4d2d-a009-dab2a999b5d8.jpg) +![](https://github.com/CyC2018/InterviewNotes/blob/master/pics//c73a0b78-5f46-4d2d-a009-dab2a999b5d8.jpg) -³Ö¾ÃÁ¬½ÓÐèҪʹÓà Connection Êײ¿×ֶνøÐйÜÀí¡£HTTP/1.1 ¿ªÊ¼ HTTP ĬÈÏÊdz־û¯Á¬½ÓµÄ£¬Èç¹ûÒª¶Ï¿ª TCP Á¬½Ó£¬ÐèÒªÓɿͻ§¶Ë»òÕß·þÎñÆ÷¶ËÌá³ö¶Ï¿ª£¬Ê¹Óà Connection: close£»¶øÔÚ HTTP/1.1 ֮ǰĬÈÏÊǷdz־û¯Á¬½ÓµÄ£¬Èç¹ûҪά³Ö³ÖÐøÁ¬½Ó£¬ÐèҪʹÓà Keep-Alive¡£ +æŒ�久连接需è¦�使用 Connection 首部字段进行管ç�†ã€‚HTTP/1.1 开始 HTTP 默认是æŒ�久化连接的,如果è¦�æ–­å¼€ TCP 连接,需è¦�由客户端或者æœ�务器端æ��出断开,使用 Connection: close;而在 HTTP/1.1 之å‰�默认是é�žæŒ�久化连接的,如果è¦�ç»´æŒ�æŒ�续连接,需è¦�使用 Keep-Alive。 -¹ÜÏß»¯·½Ê½¿ÉÒÔͬʱ·¢ËͶà¸öÇëÇóºÍÏìÓ¦£¬¶ø²»ÐèÒª·¢ËÍÒ»¸öÇëÇóÈ»ºóµÈ´ýÏìÓ¦Ö®ºóÔÙ·¢ÏÂÒ»¸öÇëÇó¡£ +管线化方å¼�å�¯ä»¥å�Œæ—¶å�‘é€�多个请求和å“�应,而ä¸�需è¦�å�‘é€�一个请求然å�Žç­‰å¾…å“�应之å�Žå†�å�‘下一个请求。 -![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/6943e2af-5a70-4004-8bee-b33d60f39da3.jpg) +![](https://github.com/CyC2018/InterviewNotes/blob/master/pics//6943e2af-5a70-4004-8bee-b33d60f39da3.jpg) -## ±àÂë +## ç¼–ç � -±àÂ루Encoding£©Ö÷ÒªÊÇΪÁ˶ÔʵÌå½øÐÐѹËõ¡£³£ÓõıàÂëÓУºgzip¡¢compress¡¢deflate¡¢identity£¬ÆäÖÐ identity ±íʾ²»Ö´ÐÐѹËõµÄ±àÂë¸ñʽ¡£ +ç¼–ç �(Encoding)主è¦�是为了对实体进行压缩。常用的编ç �有:gzipã€�compressã€�deflateã€�identity,其中 identity 表示ä¸�执行压缩的编ç �æ ¼å¼�。 -## ·Ö¿é´«Êä +## 分å�—传输 -·Ö¿é´«Ê䣨Chunked Transfer Coding£©¿ÉÒÔ°ÑÊý¾Ý·Ö¸î³É¶à¿é£¬ÈÃä¯ÀÀÆ÷Öð²½ÏÔÊ¾Ò³Ãæ¡£ +分å�—传输(Chunked Transfer Coding)å�¯ä»¥æŠŠæ•°æ�®åˆ†å‰²æˆ�多å�—,让æµ�览器é€�步显示页é�¢ã€‚ -## ¶à²¿·Ö¶ÔÏó¼¯ºÏ +## 多部分对象集å�ˆ -Ò»·Ý±¨ÎÄÖ÷ÌåÄڿɺ¬ÓжàÀàÐ͵ÄʵÌåͬʱ·¢ËÍ£¬Ã¿¸ö²¿·ÖÖ®¼äÓà boundary ×ֶζ¨ÒåµÄ·Ö¸ô·û½øÐзָô£»Ã¿¸ö²¿·Ö¶¼¿ÉÒÔÓÐÊײ¿×ֶΡ£ +一份报文主体内å�¯å�«æœ‰å¤šç±»åž‹çš„实体å�Œæ—¶å�‘é€�,æ¯�个部分之间用 boundary 字段定义的分隔符进行分隔;æ¯�个部分都å�¯ä»¥æœ‰é¦–部字段。 -ÀýÈ磬ÉÏ´«¶à¸ö±íµ¥Ê±¿ÉÒÔʹÓÃÈçÏ·½Ê½£º +例如,上传多个表å�•æ—¶å�¯ä»¥ä½¿ç”¨å¦‚下方å¼�: -![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/decb0936-e83c-4a55-840a-fe8aa101ac61.png) +![](https://github.com/CyC2018/InterviewNotes/blob/master/pics//decb0936-e83c-4a55-840a-fe8aa101ac61.png) -## ·¶Î§ÇëÇó +## 范围请求 -Èç¹ûÍøÂç³öÏÖÖжϣ¬·þÎñÆ÷Ö»·¢ËÍÁËÒ»²¿·ÖÊý¾Ý£¬·¶Î§ÇëÇóʹµÃ¿Í»§¶ËÄܹ»Ö»ÇëÇóδ·¢Ë͵ÄÄDz¿·ÖÊý¾Ý£¬´Ó¶ø±ÜÃâ·þÎñÆ÷¶ËÖØÐ·¢ËÍËùÓÐÊý¾Ý¡£ +如果网络出现中断,æœ�务器å�ªå�‘é€�了一部分数æ�®ï¼ŒèŒƒå›´è¯·æ±‚使得客户端能够å�ªè¯·æ±‚未å�‘é€�的那部分数æ�®ï¼Œä»Žè€Œé�¿å…�æœ�务器端é‡�æ–°å�‘é€�所有数æ�®ã€‚ -ÔÚÇëÇó±¨ÎÄÊײ¿ÖÐÌí¼Ó Range ×ֶΣ¬È»ºóÖ¸¶¨ÇëÇóµÄ·¶Î§£¬ÀýÈç Range : bytes = 5001-10000¡£ÇëÇó³É¹¦µÄ»°·þÎñÆ÷·¢ËÍ 206 Partial Content ״̬¡£ +在请求报文首部中添加 Range 字段,然å�ŽæŒ‡å®šè¯·æ±‚的范围,例如 Range : bytes = 5001-10000。请求æˆ�功的è¯�æœ�务器å�‘é€� 206 Partial Content 状æ€�。 -## ÄÚÈÝЭÉÌ +## 内容å��商 -ͨ¹ýÄÚÈÝЭÉÌ·µ»Ø×îºÏÊʵÄÄÚÈÝ£¬ÀýÈç¸ù¾Ýä¯ÀÀÆ÷µÄĬÈÏÓïÑÔÑ¡Ôñ·µ»ØÖÐÎĽçÃæ»¹ÊÇÓ¢ÎĽçÃæ¡£ +通过内容å��商返回最å�ˆé€‚的内容,例如根æ�®æµ�览器的默认语言选择返回中文界é�¢è¿˜æ˜¯è‹±æ–‡ç•Œé�¢ã€‚ -Éæ¼°ÒÔÏÂÊײ¿×ֶΣºAccept¡¢Accept-Charset¡¢Accept-Encoding¡¢Accept-Language¡¢Content-Language¡£ +涉å�Šä»¥ä¸‹é¦–部字段:Acceptã€�Accept-Charsetã€�Accept-Encodingã€�Accept-Languageã€�Content-Language。 -## ÐéÄâÖ÷»ú +## 虚拟主机 -ʹÓÃÐéÄâÖ÷»ú¼¼Êõ£¬Ê¹µÃһ̨·þÎñÆ÷ÓµÓжà¸öÓòÃû£¬²¢ÇÒÔÚÂß¼­ÉÏ¿ÉÒÔ¿´³É¶à¸ö·þÎñÆ÷¡£ +使用虚拟主机技术,使得一å�°æœ�务器拥有多个域å��,并且在逻辑上å�¯ä»¥çœ‹æˆ�多个æœ�务器。 -## ͨÐÅÊý¾Ýת·¢ +## 通信数æ�®è½¬å�‘ -**´úÀí** +**代ç�†** -´úÀí·þÎñÆ÷½ÓÊܿͻ§¶ËµÄÇëÇ󣬲¢ÇÒת·¢¸øÆäËü·þÎñÆ÷¡£´úÀí·þÎñÆ÷Ò»°ãÊÇ͸Ã÷µÄ£¬²»»á¸Ä±ä URL¡£ +代ç�†æœ�务器接å�—客户端的请求,并且转å�‘给其它æœ�务器。代ç�†æœ�务器一般是é€�明的,ä¸�会改å�˜ URL。 -ʹÓôúÀíµÄÖ÷ҪĿµÄÊÇ£º»º´æ¡¢ÍøÂç·ÃÎÊ¿ØÖÆÒÔ¼°¼Ç¼·ÃÎÊÈÕÖ¾¡£ +使用代ç�†çš„主è¦�目的是:缓存ã€�网络访问控制以å�Šè®°å½•访问日志。 -![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/c07035c3-a9ba-4508-8e3c-d8ae4c6ee9ee.jpg) +![](https://github.com/CyC2018/InterviewNotes/blob/master/pics//c07035c3-a9ba-4508-8e3c-d8ae4c6ee9ee.jpg) -**Íø¹Ø** +**网关** -Óë´úÀí·þÎñÆ÷²»Í¬µÄÊÇ£¬Íø¹Ø·þÎñÆ÷»á½« HTTP ת»¯ÎªÆäËüЭÒé½øÐÐͨÐÅ£¬´Ó¶øÇëÇóÆäËü·Ç HTTP ·þÎñÆ÷µÄ·þÎñ¡£ +与代ç�†æœ�务器ä¸�å�Œçš„æ˜¯ï¼Œç½‘å…³æœ�务器会将 HTTP 转化为其它å��议进行通信,从而请求其它é�ž HTTP æœ�务器的æœ�务。 -![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/81375888-6be1-476f-9521-42eea3e3154f.jpg) +![](https://github.com/CyC2018/InterviewNotes/blob/master/pics//81375888-6be1-476f-9521-42eea3e3154f.jpg) -**ËíµÀ** +**éš§é�“** -ʹÓà SSL µÈ¼ÓÃÜÊֶΣ¬Îª¿Í»§¶ËºÍ·þÎñÆ÷Ö®¼ä½¨Á¢Ò»Ìõ°²È«µÄͨÐÅÏß·¡£ +使用 SSL 等加密手段,为客户端和æœ�务器之间建立一æ�¡å®‰å…¨çš„通信线路。 -![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/64b95403-d976-421a-8b45-bac89c0b5185.jpg) +![](https://github.com/CyC2018/InterviewNotes/blob/master/pics//64b95403-d976-421a-8b45-bac89c0b5185.jpg) # HTTPs -HTTP ÓÐÒÔϰ²È«ÐÔÎÊÌ⣺ +HTTP 有以下安全性问题: -1. ͨÐÅʹÓÃÃ÷ÎÄ£¬ÄÚÈÝ¿ÉÄܻᱻÇÔÌý£» -2. ²»Ñé֤ͨÐÅ·½µÄÉí·Ý£¬Òò´ËÓпÉÄÜÔâÓöαװ£» -3. ÎÞ·¨Ö¤Ã÷±¨ÎĵÄÍêÕûÐÔ£¬ËùÒÔÓпÉÄÜÒÑÔâ´Û¸Ä¡£ +1. 通信使用明文,内容å�¯èƒ½ä¼šè¢«çªƒå�¬ï¼› +2. ä¸�验è¯�通信方的身份,因此有å�¯èƒ½é�­é�‡ä¼ªè£…ï¼› +3. 无法è¯�明报文的完整性,所以有å�¯èƒ½å·²é�­ç¯¡æ”¹ã€‚ -HTTPs ²¢²»ÊÇÐÂЭÒ飬¶øÊÇ HTTP ÏÈºÍ SSL£¨Secure Socket Layer£©Í¨ÐÅ£¬ÔÙÓÉ SSL ºÍ TCP ͨÐÅ¡£Í¨¹ýʹÓà SSL£¬HTTPs ÌṩÁ˼ÓÃÜ¡¢ÈÏÖ¤ºÍÍêÕûÐÔ±£»¤¡£ +HTTPs å¹¶ä¸�是新å��议,而是 HTTP 先和 SSL(Secure Socket Layer)通信,å†�ç”± SSL å’Œ TCP 通信。通过使用 SSL,HTTPs æ��供了加密ã€�认è¯�和完整性ä¿�护。 -## ¼ÓÃÜ +## 加密 -ÓÐÁ½ÖÖ¼ÓÃÜ·½Ê½£º¶Ô³ÆÃÜÔ¿¼ÓÃܺ͹«¿ªÃÜÔ¿¼ÓÃÜ¡£¶Ô³ÆÃÜÔ¿¼ÓÃܵļÓÃܺͽâÃÜʹÓÃͬһÃÜÔ¿£¬¶ø¹«¿ªÃÜÔ¿¼ÓÃÜʹÓÃÒ»¶ÔÃÜÔ¿ÓÃÓÚ¼ÓÃܺͽâÃÜ£¬·Ö±ðΪ¹«¿ªÃÜÔ¿ºÍ˽ÓÐÃÜÔ¿¡£¹«¿ªÃÜÔ¿ËùÓÐÈ˶¼¿ÉÒÔ»ñµÃ£¬Í¨ÐÅ·¢ËÍ·½»ñµÃ½ÓÊÕ·½µÄ¹«¿ªÃÜÔ¿Ö®ºó£¬¾Í¿ÉÒÔʹÓù«¿ªÃÜÔ¿½øÐмÓÃÜ£¬½ÓÊÕ·½ÊÕµ½Í¨ÐÅÄÚÈݺóʹÓÃ˽ÓÐÃÜÔ¿½âÃÜ¡£ +有两ç§�加密方å¼�:对称密钥加密和公开密钥加密。对称密钥加密的加密和解密使用å�Œä¸€å¯†é’¥ï¼Œè€Œå…¬å¼€å¯†é’¥åŠ å¯†ä½¿ç”¨ä¸€å¯¹å¯†é’¥ç”¨äºŽåŠ å¯†å’Œè§£å¯†ï¼Œåˆ†åˆ«ä¸ºå…¬å¼€å¯†é’¥å’Œç§�有密钥。公开密钥所有人都å�¯ä»¥èŽ·å¾—ï¼Œé€šä¿¡å�‘é€�方获得接收方的公开密钥之å�Žï¼Œå°±å�¯ä»¥ä½¿ç”¨å…¬å¼€å¯†é’¥è¿›è¡ŒåŠ å¯†ï¼ŒæŽ¥æ”¶æ–¹æ”¶åˆ°é€šä¿¡å†…å®¹å�Žä½¿ç”¨ç§�有密钥解密。 -¶Ô³ÆÃÜÔ¿¼ÓÃܵÄȱµã£ºÎÞ·¨°²È«´«ÊäÃÜÔ¿£»¹«¿ªÃÜÔ¿¼ÓÃܵÄȱµã£ºÏà¶ÔÀ´Ëµ¸üºÄʱ¡£ +对称密钥加密的缺点:无法安全传输密钥;公开密钥加密的缺点:相对æ�¥è¯´æ›´è€—时。 -HTTPs ²ÉÓà **»ìºÏµÄ¼ÓÃÜ»úÖÆ**£¬Ê¹Óù«¿ªÃÜÔ¿¼ÓÃÜÓÃÓÚ´«Êä¶Ô³ÆÃÜÔ¿£¬Ö®ºóʹÓöԳÆÃÜÔ¿¼ÓÃܽøÐÐͨÐÅ¡££¨ÏÂͼÖУ¬¹²ÏíÃÜÔ¿¼´¶Ô³ÆÃÜÔ¿£© +HTTPs 采用 **æ··å�ˆçš„加密机制**,使用公开密钥加密用于传输对称密钥,之å�Žä½¿ç”¨å¯¹ç§°å¯†é’¥åŠ å¯†è¿›è¡Œé€šä¿¡ã€‚ï¼ˆä¸‹å›¾ä¸­ï¼Œå…±äº«å¯†é’¥å�³å¯¹ç§°å¯†é’¥ï¼‰ -![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/110b1a9b-87cd-45c3-a21d-824623715b33.jpg) +![](https://github.com/CyC2018/InterviewNotes/blob/master/pics//110b1a9b-87cd-45c3-a21d-824623715b33.jpg) -## ÈÏÖ¤ +## 认è¯� -ͨ¹ýʹÓà **Ö¤Êé** À´¶ÔͨÐÅ·½½øÐÐÈÏÖ¤¡£Ö¤ÊéÖÐÓй«¿ªÃÜÔ¿Êý¾Ý£¬Èç¹û¿ÉÒÔÑéÖ¤¹«¿ªÃÜÔ¿µÄÈ·ÊôÓÚͨÐÅ·½µÄ£¬ÄÇô¾Í¿ÉÒÔÈ·¶¨Í¨ÐÅ·½Êǿɿ¿µÄ¡£ +通过使用 **è¯�书** æ�¥å¯¹é€šä¿¡æ–¹è¿›è¡Œè®¤è¯�。è¯�书中有公开密钥数æ�®ï¼Œå¦‚æžœå�¯ä»¥éªŒè¯�公开密钥的确属于通信方的,那么就å�¯ä»¥ç¡®å®šé€šä¿¡æ–¹æ˜¯å�¯é� çš„。 -Êý×ÖÖ¤ÊéÈÏÖ¤»ú¹¹£¨CA£¬Certificate Authority£©°ä·¢µÄ¹«¿ªÃÜÔ¿Ö¤Ê飬¿ÉÒÔͨ¹ý CA ¶ÔÆä½øÐÐÑéÖ¤¡£ +æ•°å­—è¯�书认è¯�机构(CA,Certificate Authority)é¢�å�‘的公开密钥è¯�书,å�¯ä»¥é€šè¿‡ CA 对其进行验è¯�。 -½øÐÐ HTTPs ͨÐÅʱ£¬·þÎñÆ÷»á°ÑÖ¤Êé·¢Ë͸ø¿Í»§¶Ë£¬¿Í»§¶ËÈ¡µÃÆäÖеĹ«¿ªÃÜÔ¿Ö®ºó£¬¾Í¿ÉÒÔ¿ªÊ¼¼ÓÃܹý³Ì¡£ +进行 HTTPs 通信时,æœ�务器会把è¯�书å�‘é€�给客户端,客户端å�–得其中的公开密钥之å�Žï¼Œå°±å�¯ä»¥å¼€å§‹åŠ å¯†è¿‡ç¨‹ã€‚ -ʹÓà OpenSSL ÕâÌ׿ªÔ´³ÌÐò£¬Ã¿¸öÈ˶¼¿ÉÒÔ¹¹½¨Ò»Ì×ÊôÓÚ×Ô¼ºµÄÈÏÖ¤»ú¹¹£¬´Ó¶ø×Ô¼º¸ø×Ô¼º°ä·¢·þÎñÆ÷Ö¤Êé¡£ä¯ÀÀÆ÷ÔÚ·ÃÎʸ÷þÎñÆ÷ʱ£¬»áÏÔʾ¡°ÎÞ·¨È·ÈÏÁ¬½Ó°²È«ÐÔ¡±»ò¡°¸ÃÍøÕ¾µÄ°²È«Ö¤Êé´æÔÚÎÊÌ⡱µÈ¾¯¸æÏûÏ¢¡£ +使用 OpenSSL 这套开æº�程åº�,æ¯�个人都å�¯ä»¥æž„建一套属于自己的认è¯�机构,从而自己给自己é¢�å�‘æœ�务器è¯�书。æµ�览器在访问该æœ�务器时,会显示“无法确认连接安全性â€�或“该网站的安全è¯�书存在问题â€�等警告消æ�¯ã€‚ -¿Í»§¶ËÖ¤ÊéÐèÒªÓû§×ÔÐа²×°£¬Ö»ÓÐÔÚÒµÎñÐèÒª·Ç³£¸ßµÄ°²È«ÐÔʱ²ÅʹÓÿͻ§¶ËÖ¤Ê飬ÀýÈçÍøÉÏÒøÐС£ +客户端è¯�书需è¦�用户自行安装,å�ªæœ‰åœ¨ä¸šåŠ¡éœ€è¦�é�žå¸¸é«˜çš„安全性时æ‰�使用客户端è¯�书,例如网上银行。 -## ÍêÕûÐÔ +## 完整性 -SSL ÌṩժҪ¹¦ÄÜÀ´ÑéÖ¤ÍêÕûÐÔ¡£ +SSL æ��供摘è¦�功能æ�¥éªŒè¯�完整性。 -# HTTP/1.0 Óë HTTP/1.1 µÄÇø±ð +# HTTP/1.0 与 HTTP/1.1 的区别 -- HTTP/1.1 ĬÈÏÊdz¤Á¬½Ó£» -- HTTP/1.1 ÌṩÁË·¶Î§ÇëÇó¹¦ÄÜ£» -- HTTP/1.1 ÌṩÁËÐéÄâÖ÷»úµÄ¹¦ÄÜ£» -- HTTP/1.1 ¶àÁËһЩ»º´æ´¦Àí×ֶΣ» -- HTTP/1.1 ¶àÁËһЩ״̬Â룻 +- HTTP/1.1 默认是长连接; +- HTTP/1.1 æ��供了范围请求功能; +- HTTP/1.1 æ��供了虚拟主机的功能; +- HTTP/1.1 多了一些缓存处ç�†å­—段; +- HTTP/1.1 多了一些状æ€�ç �ï¼› diff --git a/notes/JVM.md b/notes/JVM.md index 597eda7c..cb7ced4e 100644 --- a/notes/JVM.md +++ b/notes/JVM.md @@ -1,166 +1,167 @@ -* [ÄÚ´æÄ£ÐÍ](#ÄÚ´æÄ£ÐÍ) - * [1. ³ÌÐò¼ÆÊýÆ÷](#1-³ÌÐò¼ÆÊýÆ÷) - * [2. Java ÐéÄâ»úÕ»](#2-java-ÐéÄâ»úÕ») - * [3. ±¾µØ·½·¨Õ»](#3-±¾µØ·½·¨Õ») - * [4. Java ¶Ñ](#4-java-¶Ñ) - * [5. ·½·¨Çø](#5-·½·¨Çø) - * [6. ÔËÐÐʱ³£Á¿³Ø](#6-ÔËÐÐʱ³£Á¿³Ø) - * [7. Ö±½ÓÄÚ´æ](#7-Ö±½ÓÄÚ´æ) -* [À¬»øÊÕ¼¯](#À¬»øÊÕ¼¯) - * [1. ÅжÏÒ»¸ö¶ÔÏóÊÇ·ñ¿É»ØÊÕ](#1-ÅжÏÒ»¸ö¶ÔÏóÊÇ·ñ¿É»ØÊÕ) - * [1.1 ÒýÓüÆÊý](#11-ÒýÓüÆÊý) - * [1.2 ¿É´ïÐÔ](#12-¿É´ïÐÔ) - * [1.3 ÒýÓÃÀàÐÍ](#13-ÒýÓÃÀàÐÍ) - * [1.3.1 Ç¿ÒýÓÃ](#131-Ç¿ÒýÓÃ) - * [1.3.2 ÈíÒýÓÃ](#132-ÈíÒýÓÃ) - * [1.3.3 ÈõÒýÓÃ](#133-ÈõÒýÓÃ) - * [1.3.4 ÐéÒýÓÃ](#134-ÐéÒýÓÃ) - * [1.3 ·½·¨ÇøµÄ»ØÊÕ](#13-·½·¨ÇøµÄ»ØÊÕ) +* [内存模型](#内存模型) + * [1. 程åº�计数器](#1-程åº�计数器) + * [2. Java 虚拟机栈](#2-java-虚拟机栈) + * [3. 本地方法栈](#3-本地方法栈) + * [4. Java å †](#4-java-å †) + * [5. 方法区](#5-方法区) + * [6. è¿�行时常é‡�æ± ](#6-è¿�行时常é‡�æ± ) + * [7. 直接内存](#7-直接内存) +* [垃圾收集](#垃圾收集) + * [1. 判断一个对象是å�¦å�¯å›žæ”¶](#1-判断一个对象是å�¦å�¯å›žæ”¶) + * [1.1 引用计数](#11-引用计数) + * [1.2 å�¯è¾¾æ€§](#12-å�¯è¾¾æ€§) + * [1.3 引用类型](#13-引用类型) + * [1.3.1 强引用](#131-强引用) + * [1.3.2 软引用](#132-软引用) + * [1.3.3 弱引用](#133-弱引用) + * [1.3.4 虚引用](#134-虚引用) + * [1.3 方法区的回收](#13-方法区的回收) * [1.4 finalize()](#14-finalize) - * [2. À¬»øÊÕ¼¯Ëã·¨](#2-À¬»øÊÕ¼¯Ëã·¨) - * [2.1 ±ê¼Ç - Çå³ýËã·¨](#21-±ê¼Ç---Çå³ýËã·¨) - * [2.2 ¸´ÖÆËã·¨](#22-¸´ÖÆËã·¨) - * [2.3 ±ê¼Ç - ÕûÀíËã·¨](#23-±ê¼Ç---ÕûÀíËã·¨) - * [2.4 ·Ö´úÊÕ¼¯Ëã·¨](#24-·Ö´úÊÕ¼¯Ëã·¨) - * [3. À¬»øÊÕ¼¯Æ÷](#3-À¬»øÊÕ¼¯Æ÷) - * [3.1 Serial ÊÕ¼¯Æ÷](#31-serial-ÊÕ¼¯Æ÷) - * [3.2 ParNew ÊÕ¼¯Æ÷](#32-parnew-ÊÕ¼¯Æ÷) - * [3.3 Parallel Scavenge ÊÕ¼¯Æ÷](#33-parallel-scavenge-ÊÕ¼¯Æ÷) - * [3.4 Serial Old ÊÕ¼¯Æ÷](#34-serial-old-ÊÕ¼¯Æ÷) - * [3.5 Parallel Old ÊÕ¼¯Æ÷](#35-parallel-old-ÊÕ¼¯Æ÷) - * [3.6 CMS ÊÕ¼¯Æ÷](#36-cms-ÊÕ¼¯Æ÷) - * [3.7 G1 ÊÕ¼¯Æ÷](#37-g1-ÊÕ¼¯Æ÷) - * [3.8 ÆßÖÖÀ¬»øÊÕ¼¯Æ÷µÄ±È½Ï](#38-ÆßÖÖÀ¬»øÊÕ¼¯Æ÷µÄ±È½Ï) - * [4. ÄÚ´æ·ÖÅäÓë»ØÊÕ²ßÂÔ](#4-ÄÚ´æ·ÖÅäÓë»ØÊÕ²ßÂÔ) - * [4.1 ÓÅÏÈÔÚ Eden ·ÖÅä](#41-ÓÅÏÈÔÚ-eden-·ÖÅä) - * [4.2 ´ó¶ÔÏóÖ±½Ó½øÈëÀÏÄê´ú](#42-´ó¶ÔÏóÖ±½Ó½øÈëÀÏÄê´ú) - * [4.3 ³¤ÆÚ´æ»îµÄ¶ÔÏó½øÈëÀÏÄê´ú](#43-³¤ÆÚ´æ»îµÄ¶ÔÏó½øÈëÀÏÄê´ú) - * [4.4 ¶¯Ì¬¶ÔÏóÄêÁäÅж¨](#44-¶¯Ì¬¶ÔÏóÄêÁäÅж¨) - * [4.5 ¿Õ¼ä·ÖÅäµ£±£](#45-¿Õ¼ä·ÖÅäµ£±£) - * [4.6 Full GC µÄ´¥·¢Ìõ¼þ](#46-full-gc-µÄ´¥·¢Ìõ¼þ) - * [4.6.1 µ÷Óà System.gc()](#461-µ÷ÓÃ-systemgc) - * [4.6.2 ÀÏÄê´ú¿Õ¼ä²»×ã](#462-ÀÏÄê´ú¿Õ¼ä²»×ã) - * [4.6.3 ¿Õ¼ä·ÖÅäµ£±£Ê§°Ü](#463-¿Õ¼ä·ÖÅäµ£±£Ê§°Ü) - * [4.6.4 JDK 1.7 ¼°ÒÔǰµÄÓÀ¾Ã´ú¿Õ¼ä²»×ã](#464-jdk-17-¼°ÒÔǰµÄÓÀ¾Ã´ú¿Õ¼ä²»×ã) + * [2. 垃圾收集算法](#2-垃圾收集算法) + * [2.1 标记 - 清除算法](#21-标记---清除算法) + * [2.2 å¤�制算法](#22-å¤�制算法) + * [2.3 标记 - æ•´ç�†ç®—法](#23-标记---æ•´ç�†ç®—法) + * [2.4 分代收集算法](#24-分代收集算法) + * [3. 垃圾收集器](#3-垃圾收集器) + * [3.1 Serial 收集器](#31-serial-收集器) + * [3.2 ParNew 收集器](#32-parnew-收集器) + * [3.3 Parallel Scavenge 收集器](#33-parallel-scavenge-收集器) + * [3.4 Serial Old 收集器](#34-serial-old-收集器) + * [3.5 Parallel Old 收集器](#35-parallel-old-收集器) + * [3.6 CMS 收集器](#36-cms-收集器) + * [3.7 G1 收集器](#37-g1-收集器) + * [3.8 七ç§�垃圾收集器的比较](#38-七ç§�垃圾收集器的比较) + * [4. 内存分é…�与回收策略](#4-内存分é…�与回收策略) + * [4.1 优先在 Eden 分é…�](#41-优先在-eden-分é…�) + * [4.2 大对象直接进入è€�年代](#42-大对象直接进入è€�年代) + * [4.3 长期存活的对象进入è€�年代](#43-长期存活的对象进入è€�年代) + * [4.4 动æ€�对象年龄判定](#44-动æ€�对象年龄判定) + * [4.5 空间分é…�æ‹…ä¿�](#45-空间分é…�æ‹…ä¿�) + * [4.6 Full GC 的触å�‘æ�¡ä»¶](#46-full-gc-的触å�‘æ�¡ä»¶) + * [4.6.1 调用 System.gc()](#461-调用-systemgc) + * [4.6.2 è€�年代空间ä¸�è¶³](#462-è€�年代空间ä¸�è¶³) + * [4.6.3 空间分é…�æ‹…ä¿�失败](#463-空间分é…�æ‹…ä¿�失败) + * [4.6.4 JDK 1.7 å�Šä»¥å‰�的永久代空间ä¸�è¶³](#464-jdk-17-å�Šä»¥å‰�的永久代空间ä¸�è¶³) * [4.6.5 Concurrent Mode Failure](#465-concurrent-mode-failure) -* [Àà¼ÓÔØ»úÖÆ](#Àà¼ÓÔØ»úÖÆ) - * [1 ÀàµÄÉúÃüÖÜÆÚ](#1-ÀàµÄÉúÃüÖÜÆÚ) - * [2. Àà³õʼ»¯Ê±»ú](#2-Àà³õʼ»¯Ê±»ú) - * [3. Àà¼ÓÔØ¹ý³Ì](#3-Àà¼ÓÔØ¹ý³Ì) - * [3.1 ¼ÓÔØ](#31-¼ÓÔØ) - * [3.2 ÑéÖ¤](#32-ÑéÖ¤) - * [3.3 ×¼±¸](#33-×¼±¸) - * [3.4 ½âÎö](#34-½âÎö) - * [3.5 ³õʼ»¯](#35-³õʼ»¯) - * [4. Àà¼ÓÔØÆ÷](#4-Àà¼ÓÔØÆ÷) - * [4.1 ÀàÓëÀà¼ÓÔØÆ÷](#41-ÀàÓëÀà¼ÓÔØÆ÷) - * [4.2 Àà¼ÓÔØÆ÷·ÖÀà](#42-Àà¼ÓÔØÆ÷·ÖÀà) - * [4.3 Ë«Ç×ίÅÉÄ£ÐÍ](#43-Ë«Ç×ίÅÉÄ£ÐÍ) -* [JVM ²ÎÊý](#jvm-²ÎÊý) - * [GC ÓÅ»¯ÅäÖÃ](#gc-ÓÅ»¯ÅäÖÃ) - * [GC ÀàÐÍÉèÖÃ](#gc-ÀàÐÍÉèÖÃ) +* [类加载机制](#类加载机制) + * [1 类的生命周期](#1-类的生命周期) + * [2. ç±»åˆ�始化时机](#2-ç±»åˆ�始化时机) + * [3. 类加载过程](#3-类加载过程) + * [3.1 加载](#31-加载) + * [3.2 验è¯�](#32-验è¯�) + * [3.3 准备](#33-准备) + * [3.4 è§£æž�](#34-è§£æž�) + * [3.5 åˆ�始化](#35-åˆ�始化) + * [4. 类加载器](#4-类加载器) + * [4.1 类与类加载器](#41-类与类加载器) + * [4.2 类加载器分类](#42-类加载器分类) + * [4.3 å�Œäº²å§”派模型](#43-å�Œäº²å§”派模型) +* [JVM å�‚æ•°](#jvm-å�‚æ•°) + * [GC 优化é…�ç½®](#gc-优化é…�ç½®) + * [GC 类型设置](#gc-类型设置) -# ÄÚ´æÄ£ÐÍ -![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/dc695f48-4189-4fc7-b950-ed25f6c80f82.jpg) +# 内存模型 -×¢£º°×É«ÇøÓòΪÏß³Ì˽Óеģ¬À¶É«ÇøÓòΪÏ̹߳²ÏíµÄ¡£ +![](https://github.com/CyC2018/InterviewNotes/blob/master/pics//dc695f48-4189-4fc7-b950-ed25f6c80f82.jpg) -## 1. ³ÌÐò¼ÆÊýÆ÷ +注:白色区域为线程ç§�有的,è“�色区域为线程共享的。 -¼Ç¼ÕýÔÚÖ´ÐеÄÐéÄâ»ú×Ö½ÚÂëÖ¸ÁîµÄµØÖ·£¨Èç¹ûÕýÔÚÖ´ÐеÄÊÇ Native ·½·¨ÔòΪ¿Õ£©¡£ +## 1. 程åº�计数器 -## 2. Java ÐéÄâ»úÕ» +记录正在执行的虚拟机字节ç �指令的地å�€ï¼ˆå¦‚果正在执行的是 Native 方法则为空)。 -ÿ¸ö Java ·½·¨ÔÚÖ´ÐеÄͬʱ»á´´½¨Ò»¸öÕ»Ö¡ÓÃÓÚ´æ´¢¾Ö²¿±äÁ¿±í¡¢²Ù×÷ÊýÕ»¡¢¶¯Ì¬Á´½Ó¡¢·½·¨³ö¿ÚµÈÐÅÏ¢¡£Ã¿Ò»¸ö·½·¨´Óµ÷ÓÃÖ±ÖÁÖ´ÐÐÍê³ÉµÄ¹ý³Ì£¬¾Í¶ÔÓ¦×ÅÒ»¸öÕ»Ö¡ÔÚ Java ÐéÄâ»úÕ»ÖÐÈëÕ»ºÍ³öÕ»µÄ¹ý³Ì¡£ +## 2. Java 虚拟机栈 -¸ÃÇøÓò¿ÉÄÜÅ׳öÒÔÏÂÒì³££º +æ¯�个 Java 方法在执行的å�Œæ—¶ä¼šåˆ›å»ºä¸€ä¸ªæ ˆå¸§ç”¨äºŽå­˜å‚¨å±€éƒ¨å�˜é‡�表ã€�æ“�作数栈ã€�动æ€�链接ã€�方法出å�£ç­‰ä¿¡æ�¯ã€‚æ¯�一个方法从调用直至执行完æˆ�的过程,就对应ç�€ä¸€ä¸ªæ ˆå¸§åœ¨ Java 虚拟机栈中入栈和出栈的过程。 -1. µ±Ïß³ÌÇëÇóµÄÕ»Éî¶È³¬¹ý×î´óÖµ£¬»áÅ׳ö StackOverflowError Òì³££» -2. Õ»½øÐж¯Ì¬À©Õ¹Ê±Èç¹ûÎÞ·¨ÉêÇëµ¼×ã¹»Äڴ棬»áÅ׳ö OutOfMemoryError Òì³£¡£ +该区域å�¯èƒ½æŠ›å‡ºä»¥ä¸‹å¼‚常: -## 3. ±¾µØ·½·¨Õ» +1. 当线程请求的栈深度超过最大值,会抛出 StackOverflowError 异常; +2. 栈进行动æ€�扩展时如果无法申请导足够内存,会抛出 OutOfMemoryError 异常。 -Óë Java ÐéÄâ»úÕ»ÀàËÆ£¬ËüÃÇÖ®¼äµÄÇø±ðÖ»²»¹ýÊDZ¾µØ·½·¨Õ»Îª±¾µØ·½·¨·þÎñ¡£ +## 3. 本地方法栈 -## 4. Java ¶Ñ +与 Java 虚拟机栈类似,它们之间的区别å�ªä¸�过是本地方法栈为本地方法æœ�务。 -ËùÓжÔÏóʵÀý¶¼ÔÚÕâÀï·ÖÅäÄÚ´æ¡£ +## 4. Java å † -Õâ¿éÇøÓòÊÇÀ¬»øÊÕ¼¯Æ÷¹ÜÀíµÄÖ÷񻂿Óò£¨"GC ¶Ñ "£©¡£ÏÖÔÚÊÕ¼¯Æ÷»ù±¾¶¼ÊDzÉÓ÷ִúÊÕ¼¯Ëã·¨£¬Java ¶Ñ»¹¿ÉÒԷֳɣºÐÂÉú´úºÍÀÏÄê´ú£¨ÐÂÉú´ú»¹¿ÉÒÔ·Ö³É Eden ¿Õ¼ä¡¢From Survivor ¿Õ¼ä¡¢To Survivor ¿Õ¼äµÈ£©¡£ +所有对象实例都在这里分é…�内存。 -²»ÐèÒªÁ¬ÐøÄڴ棬¿ÉÒÔͨ¹ý -Xmx ºÍ -Xms À´¿ØÖƶ¯Ì¬À©Õ¹ÄÚ´æ´óС£¬Èç¹û¶¯Ì¬À©Õ¹Ê§°Ü»áÅ׳ö OutOfMemoryError Òì³£¡£ +è¿™å�—区域是垃圾收集器管ç�†çš„主è¦�区域("GC å † ")。现在收集器基本都是采用分代收集算法,Java 堆还å�¯ä»¥åˆ†æˆ�:新生代和è€�年代(新生代还å�¯ä»¥åˆ†æˆ� Eden 空间ã€�From Survivor 空间ã€�To Survivor 空间等)。 -## 5. ·½·¨Çø +ä¸�需è¦�连续内存,å�¯ä»¥é€šè¿‡ -Xmx å’Œ -Xms æ�¥æŽ§åˆ¶åЍæ€�扩展内存大å°�,如果动æ€�扩展失败会抛出 OutOfMemoryError 异常。 -ÓÃÓÚ´æ·ÅÒѱ»ÐéÄâ»ú¼ÓÔØµÄÀàÐÅÏ¢¡¢³£Á¿¡¢¾²Ì¬±äÁ¿¡¢¼´Ê±±àÒëÆ÷±àÒëºóµÄ´úÂëµÈÊý¾Ý¡£ +## 5. 方法区 -ºÍ Java ¶ÑÒ»Ñù²»ÐèÒªÁ¬ÐøµÄÄڴ棬²¢ÇÒ¿ÉÒÔ¶¯Ì¬À©Õ¹£¬¶¯Ì¬À©Õ¹Ê§°ÜÒ»Ñù»áÅ׳ö OutOfMemoryError Òì³£¡£ +用于存放已被虚拟机加载的类信æ�¯ã€�常é‡�ã€�é�™æ€�å�˜é‡�ã€�å�³æ—¶ç¼–译器编译å�Žçš„代ç �等数æ�®ã€‚ -¶ÔÕâ¿éÇøÓò½øÐÐÀ¬»ø»ØÊÕµÄÖ÷ҪĿ±êÊǶԳ£Á¿³ØµÄ»ØÊպͶÔÀàµÄÐ¶ÔØ£¬µ«ÊÇÒ»°ã±È½ÏÄÑʵÏÖ£¬HotSpot ÐéÄâ»ú°ÑËüµ±³ÉÓÀ¾Ã´úÀ´½øÐÐÀ¬»ø»ØÊÕ¡£ +å’Œ Java 堆一样ä¸�需è¦�连续的内存,并且å�¯ä»¥åЍæ€�扩展,动æ€�扩展失败一样会抛出 OutOfMemoryError 异常。 -## 6. ÔËÐÐʱ³£Á¿³Ø +对这å�—区域进行垃圾回收的主è¦�目标是对常é‡�池的回收和对类的å�¸è½½ï¼Œä½†æ˜¯ä¸€èˆ¬æ¯”较难实现,HotSpot 虚拟机把它当æˆ�永久代æ�¥è¿›è¡Œåžƒåœ¾å›žæ”¶ã€‚ -ÔËÐÐʱ³£Á¿³ØÊÇ·½·¨ÇøµÄÒ»²¿·Ö¡£ +## 6. è¿�行时常é‡�æ±  -Àà¼ÓÔØºó£¬Class ÎļþÖеij£Á¿³Ø£¨ÓÃÓÚ´æ·Å±àÒëÆÚÉú³ÉµÄ¸÷ÖÖ×ÖÃæÁ¿ºÍ·ûºÅÒýÓ㩾ͻᱻ·Åµ½Õâ¸öÇøÓò¡£ +è¿�行时常é‡�池是方法区的一部分。 -ÔÚÔËÐÐÆÚ¼äÒ²¿ÉÒÔÓùý String ÀàµÄ intern() ·½·¨½«Ðµij£Á¿·ÅÈë¸ÃÇøÓò¡£ +类加载å�Žï¼ŒClass 文件中的常é‡�池(用于存放编译期生æˆ�çš„å�„ç§�å­—é�¢é‡�和符å�·å¼•用)就会被放到这个区域。 -## 7. Ö±½ÓÄÚ´æ +在è¿�行期间也å�¯ä»¥ç”¨è¿‡ String 类的 intern() 方法将新的常é‡�放入该区域。 -ÔÚ JDK 1.4 ÖÐмÓÈëÁË NIO À࣬ÒýÈëÁËÒ»ÖÖ»ùÓÚͨµÀ£¨Channel£©Ó뻺³åÇø£¨Buffer£©µÄ I/O ·½Ê½£¬Ëü¿ÉÒÔʹÓà Native º¯Êý¿âÖ±½Ó·ÖÅä¶ÑÍâÄڴ棬Ȼºóͨ¹ýÒ»¸ö´æ´¢ÔÚ Java ¶ÑÀïµÄ DirectByteBuffer ¶ÔÏó×÷ΪÕâ¿éÄÚ´æµÄÒýÓýøÐвÙ×÷¡£ÕâÑùÄÜÔÚһЩ³¡¾°ÖÐÏÔÖøÌá¸ßÐÔÄÜ£¬ÒòΪ±ÜÃâÁËÔÚ Java ¶ÑºÍ Native ¶ÑÖÐÀ´»Ø¸´ÖÆÊý¾Ý¡£ +## 7. 直接内存 -# À¬»øÊÕ¼¯ +在 JDK 1.4 中新加入了 NIO 类,引入了一ç§�基于通é�“(Channel)与缓冲区(Buffer)的 I/O æ–¹å¼�,它å�¯ä»¥ä½¿ç”¨ Native 函数库直接分é…�堆外内存,然å�Žé€šè¿‡ä¸€ä¸ªå­˜å‚¨åœ¨ Java 堆里的 DirectByteBuffer 对象作为这å�—内存的引用进行æ“�作。这样能在一些场景中显著æ��高性能,因为é�¿å…�了在 Java 堆和 Native 堆中æ�¥å›žå¤�制数æ�®ã€‚ -³ÌÐò¼ÆÊýÆ÷¡¢ÐéÄâ»úÕ»ºÍ±¾µØ·½·¨Õ»ÕâÈý¸öÇøÓòÊôÓÚÏß³Ì˽Óеģ¬Ö»´æÔÚÓÚÏ̵߳ÄÉúÃüÖÜÆÚÄÚ£¬Ï߳̽áÊøÖ®ºóÒ²»áÏûʧ£¬Òò´Ë²»ÐèÒª¶ÔÕâÈý¸öÇøÓò½øÐÐÀ¬»ø»ØÊÕ¡£ +# 垃圾收集 -À¬»ø»ØÊÕÖ÷ÒªÊÇÕë¶Ô Java ¶ÑºÍ·½·¨Çø½øÐС£ +程åº�计数器ã€�虚拟机栈和本地方法栈这三个区域属于线程ç§�有的,å�ªå­˜åœ¨äºŽçº¿ç¨‹çš„生命周期内,线程结æ�Ÿä¹‹å�Žä¹Ÿä¼šæ¶ˆå¤±ï¼Œå› æ­¤ä¸�需è¦�对这三个区域进行垃圾回收。 -## 1. ÅжÏÒ»¸ö¶ÔÏóÊÇ·ñ¿É»ØÊÕ +垃圾回收主è¦�是针对 Java 堆和方法区进行。 -### 1.1 ÒýÓüÆÊý +## 1. 判断一个对象是å�¦å�¯å›žæ”¶ -¸ø¶ÔÏóÌí¼ÓÒ»¸öÒýÓüÆÊýÆ÷£¬µ±¶ÔÏóÔö¼ÓÒ»¸öÒýÓÃʱ¼ÆÊýÆ÷¼Ó 1£¬ÒýÓÃʧЧʱ¼ÆÊýÆ÷¼õ 1¡£ +### 1.1 引用计数 -ÒýÓüÆÊýΪ 0 µÄ¶ÔÏó¿É±»»ØÊÕ¡£ +给对象添加一个引用计数器,当对象增加一个引用时计数器加 1,引用失效时计数器å‡� 1。 -Á½¸ö¶ÔÏó»á³öÏÖÑ­»·ÒýÓÃÎÊÌ⣬´ËʱÒýÓüÆÊýÆ÷ÓÀÔ¶²»Îª 0£¬µ¼Ö GC ÊÕ¼¯Æ÷ÎÞ·¨»ØÊÕ¡£ +引用计数为 0 的对象å�¯è¢«å›žæ”¶ã€‚ + +两个对象会出现循环引用问题,此时引用计数器永远ä¸�为 0,导致 GC 收集器无法回收。 ```java objA.instance = objB; objB.instance = objA; ``` -### 1.2 ¿É´ïÐÔ +### 1.2 å�¯è¾¾æ€§ -ͨ¹ý GC Roots ×÷ΪÆðʼµã½øÐÐËÑË÷£¬Äܹ»µ½´ïµ½µÄ¶ÔÏó¶¼ÊǶ¼ÊÇ¿ÉÓõ쬲»¿É´ïµÄ¶ÔÏó¿É±»»ØÊÕ¡£ +通过 GC Roots 作为起始点进行æ�œç´¢ï¼Œèƒ½å¤Ÿåˆ°è¾¾åˆ°çš„对象都是都是å�¯ç”¨çš„,ä¸�å�¯è¾¾çš„对象å�¯è¢«å›žæ”¶ã€‚ -GC Roots Ò»°ã°üº¬ÒÔÏÂÄÚÈÝ£º +GC Roots 一般包å�«ä»¥ä¸‹å†…容: -1. ÐéÄâ»úÕ»ÖÐÒýÓõĶÔÏó -2. ·½·¨ÇøÖÐÀྲ̬ÊôÐÔÒýÓõĶÔÏó -3. ·½·¨ÇøÖеij£Á¿ÒýÓõĶÔÏó -4. ±¾µØ·½·¨Õ»ÖÐÒýÓõĶÔÏó +1. 虚拟机栈中引用的对象 +2. 方法区中类é�™æ€�属性引用的对象 +3. 方法区中的常é‡�引用的对象 +4. 本地方法栈中引用的对象 -### 1.3 ÒýÓÃÀàÐÍ +### 1.3 引用类型 -ÎÞÂÛÊÇͨ¹ýÒýÓüÆËãËã·¨Åж϶ÔÏóµÄÒýÓÃÊýÁ¿£¬»¹ÊÇͨ¹ý¿É´ïÐÔ·ÖÎöËã·¨Åж϶ÔÏóµÄÒýÓÃÁ´ÊÇ·ñ¿É´ï£¬Åж¨¶ÀÏíÊÇ·ñ´æ»î¶¼Óë¡°ÒýÓá±Óйء£ +无论是通过引用计算算法判断对象的引用数é‡�,还是通过å�¯è¾¾æ€§åˆ†æž�算法判断对象的引用链是å�¦å�¯è¾¾ï¼Œåˆ¤å®šç‹¬äº«æ˜¯å�¦å­˜æ´»éƒ½ä¸Žâ€œå¼•用â€�有关。 -#### 1.3.1 Ç¿ÒýÓà +#### 1.3.1 强引用 -ֻҪǿÒýÓôæÔÚ£¬À¬»ø»ØÊÕÆ÷ÓÀÔ¶²»»á»ØÊÕµ÷µô±»ÒýÓõĶÔÏó¡£ +å�ªè¦�强引用存在,垃圾回收器永远ä¸�会回收调掉被引用的对象。 ```java Object obj = new Object(); ``` -#### 1.3.2 ÈíÒýÓà +#### 1.3.2 软引用 -·Ç±ØÐëÒýÓã¬ÄÚ´æÒç³ö֮ǰ½øÐлØÊÕ¡£ +é�žå¿…须引用,内存溢出之å‰�进行回收。 ```java Object obj = new Object(); @@ -169,14 +170,14 @@ obj = null; sf.get(); ``` -sf ÊÇ¶Ô obj µÄÒ»¸öÈíÒýÓã¬Í¨¹ý sf.get() ·½·¨¿ÉÒÔÈ¡µ½Õâ¸ö¶ÔÏ󣬵±È»£¬µ±Õâ¸ö¶ÔÏó±»±ê¼ÇΪÐèÒª»ØÊյĶÔÏóʱ£¬Ôò·µ»Ø null£» +sf 是对 obj 的一个软引用,通过 sf.get() 方法å�¯ä»¥å�–到这个对象,当然,当这个对象被标记为需è¦�回收的对象时,则返回 nullï¼› -ÈíÒýÓÃÖ÷ÒªÓû§ÊµÏÖÀàËÆ»º´æµÄ¹¦ÄÜ£¬ÔÚÄÚ´æ×ã¹»µÄÇé¿öÏÂÖ±½Óͨ¹ýÈíÒýÓÃȡֵ£¬ÎÞÐè´Ó·±Ã¦µÄÕæÊµÀ´Ô´²éѯÊý¾Ý£¬ÌáÉýËÙ¶È£»µ±ÄÚ´æ²»×ãʱ£¬×Ô¶¯É¾³ýÕⲿ·Ö»º´æÊý¾Ý£¬´ÓÕæÕýµÄÀ´Ô´²éѯÕâЩÊý¾Ý¡£ +软引用主è¦�用户实现类似缓存的功能,在内存足够的情况下直接通过软引用å�–值,无需从ç¹�忙的真实æ�¥æº�查询数æ�®ï¼Œæ��å�‡é€Ÿåº¦ï¼›å½“内存ä¸�足时,自动删除这部分缓存数æ�®ï¼Œä»ŽçœŸæ­£çš„æ�¥æº�查询这些数æ�®ã€‚ -#### 1.3.3 ÈõÒýÓà +#### 1.3.3 弱引用 -Ö»ÄÜÉú´æµ½ÏÂÒ»´ÎÀ¬»øÊÕ¼¯·¢Éú֮ǰ£¬µ±À¬»øÊÕ¼¯Æ÷¹¤×÷ʱ£¬ÎÞÂÛµ±Ç°ÄÚ´æÊÇ·ñ×ã¹»£¬¶¼»á±»»ØÊÕ¡£ +å�ªèƒ½ç”Ÿå­˜åˆ°ä¸‹ä¸€æ¬¡åžƒåœ¾æ”¶é›†å�‘生之å‰�,当垃圾收集器工作时,无论当å‰�内存是å�¦è¶³å¤Ÿï¼Œéƒ½ä¼šè¢«å›žæ”¶ã€‚ ```java Object obj = new Object(); @@ -186,9 +187,9 @@ wf.get(); wf.isEnQueued(); ``` -#### 1.3.4 ÐéÒýÓà +#### 1.3.4 虚引用 -ÓÖ³ÆÎªÓÄÁéÒýÓûòÕß»ÃÓ°ÒýÓã¬Ò»¸ö¶ÔÏóÊÇ·ñÓÐÐéÒýÓõĴæÔÚ£¬ÍêÈ«²»»á¶ÔÆäÉú´æÊ±¼ä¹¹³ÉÓ°Ï죬ҲÎÞ·¨Í¨¹ýÐéÒýÓÃÈ¡µÃÒ»¸ö¶ÔÏóʵÀý¡£ÎªÒ»¸ö¶ÔÏóÉèÖÃÐéÒýÓùØÁªµÄΨһĿµÄ¾ÍÊÇÄÜÔÚÕâ¸ö¶ÔÏó±»ÊÕ¼¯Æ÷»ØÊÕʱÊÕµ½Ò»¸öϵͳ֪ͨ¡£ +å�ˆç§°ä¸ºå¹½ç�µå¼•用或者幻影引用,一个对象是å�¦æœ‰è™šå¼•用的存在,完全ä¸�会对其生存时间构æˆ�å½±å“�,也无法通过虚引用å�–得一个对象实例。为一个对象设置虚引用关è�”的唯一目的就是能在这个对象被收集器回收时收到一个系统通知。 ```java Object obj = new Object(); @@ -198,367 +199,367 @@ pf.get(); pf.isEnQueued(); ``` -### 1.3 ·½·¨ÇøµÄ»ØÊÕ +### 1.3 方法区的回收 -ÔÚ·½·¨ÇøÖ÷ÒªÊǶԳ£Á¿³ØµÄ»ØÊպͶÔÀàµÄÐ¶ÔØ¡£ +在方法区主è¦�是对常é‡�池的回收和对类的å�¸è½½ã€‚ -³£Á¿³ØµÄ»ØÊպͶÑÖжÔÏó»ØÊÕÀàËÆ¡£ +常é‡�池的回收和堆中对象回收类似。 -ÀàµÄÐ¶ÔØÌõ¼þºÜ¶à£¬ÐèÒªÂú×ãÒÔÏÂÈý¸öÌõ¼þ£¬²¢ÇÒÂú×ãÁËÒ²²»Ò»¶¨»á±»Ð¶ÔØ£º +类的å�¸è½½æ�¡ä»¶å¾ˆå¤šï¼Œéœ€è¦�满足以下三个æ�¡ä»¶ï¼Œå¹¶ä¸”满足了也ä¸�一定会被å�¸è½½ï¼š -1. ¸ÃÀàËùÓеÄʵÀý¶¼ÒѾ­±»»ØÊÕ£¬Ò²¾ÍÊÇ Java ¶ÑÖв»´æÔÚ¸ÃÀàµÄÈκÎʵÀý¡£ -2. ¼ÓÔØ¸ÃÀàµÄ ClassLoader ÒѾ­±»»ØÊÕ¡£ -3. ¸ÃÀà¶ÔÓ¦µÄ java.lang.Class ¶ÔÏóûÓÐÔÚÈκεط½±»ÒýÓã¬Ò²¾ÍÎÞ·¨ÔÚÈκεط½Í¨¹ý·´Éä·ÃÎʸÃÀà·½·¨¡£ +1. 该类所有的实例都已ç»�被回收,也就是 Java 堆中ä¸�存在该类的任何实例。 +2. 加载该类的 ClassLoader å·²ç»�被回收。 +3. 该类对应的 java.lang.Class 对象没有在任何地方被引用,也就无法在任何地方通过å��射访问该类方法。 -¿ÉÒÔͨ¹ý -Xnoclassgc ²ÎÊýÀ´¿ØÖÆÊÇ·ñ¶ÔÀà½øÐÐÐ¶ÔØ¡£ +å�¯ä»¥é€šè¿‡ -Xnoclassgc å�‚æ•°æ�¥æŽ§åˆ¶æ˜¯å�¦å¯¹ç±»è¿›è¡Œå�¸è½½ã€‚ -ÔÚ´óÁ¿Ê¹Ó÷´Éä¡¢¶¯Ì¬´úÀí¡¢CGLib µÈ ByteCode ¿ò¼Ü¡¢¶¯Ì¬Éú³É JSP ÒÔ¼° OSGo ÕâÀàÆµ·±×Ô¶¨Òå ClassLoader µÄ³¡¾°¶¼ÐèÒªÐéÄâ»ú¾ß±¸ÀàÐ¶ÔØ¹¦ÄÜ£¬ÒÔ±£Ö¤²»»á³öÏÖÄÚ´æÒç³ö¡£ +在大é‡�使用å��å°„ã€�动æ€�代ç�†ã€�CGLib ç­‰ ByteCode 框架ã€�动æ€�生æˆ� JSP 以å�Š OSGo 这类频ç¹�自定义 ClassLoader 的场景都需è¦�虚拟机具备类å�¸è½½åŠŸèƒ½ï¼Œä»¥ä¿�è¯�ä¸�会出现内存溢出。 ### 1.4 finalize() -µ±Ò»¸ö¶ÔÏó¿É±»»ØÊÕʱ£¬Èç¹û¸Ã¶ÔÏóÓбØÒªÖ´ÐÐ finalize() ·½·¨£¬ÄÇô¾ÍÓпÉÄÜ¿ÉÄÜͨ¹ýÔڸ÷½·¨ÖÐÈöÔÏóÖØÐ±»ÒýÓ㬴ӶøÊµÏÖ×Ծȡ£ +当一个对象å�¯è¢«å›žæ”¶æ—¶ï¼Œå¦‚果该对象有必è¦�执行 finalize() 方法,那么就有å�¯èƒ½å�¯èƒ½é€šè¿‡åœ¨è¯¥æ–¹æ³•中让对象é‡�新被引用,从而实现自救。 -finalize() ÀàËÆ C++ µÄÐé¹¹º¯Êý£¬ÓÃÀ´×ö¹Ø±ÕÍⲿ×ÊÔ´µÈ¹¤×÷¡£µ«ÊÇ try-finally µÈ·½Ê½¿ÉÒÔ×öµÄ¸üºÃ£¬²¢ÇҸ÷½·¨ÔËÐдú¼Û¸ß°º£¬²»È·¶¨ÐÔ´ó£¬ÎÞ·¨±£Ö¤¸÷¸ö¶ÔÏóµÄµ÷ÓÃ˳Ðò£¬Òò´Ë×îºÃ²»ÒªÊ¹Óᣠ+finalize() 类似 C++ 的虚构函数,用æ�¥å�šå…³é—­å¤–部资æº�等工作。但是 try-finally 等方å¼�å�¯ä»¥å�šçš„æ›´å¥½ï¼Œå¹¶ä¸”该方法è¿�行代价高昂,ä¸�确定性大,无法ä¿�è¯�å�„个对象的调用顺åº�,因此最好ä¸�è¦�使用。 -## 2. À¬»øÊÕ¼¯Ëã·¨ +## 2. 垃圾收集算法 -### 2.1 ±ê¼Ç - Çå³ýËã·¨ +### 2.1 标记 - 清除算法 -![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/a4248c4b-6c1d-4fb8-a557-86da92d3a294.jpg) +![](https://github.com/CyC2018/InterviewNotes/blob/master/pics//a4248c4b-6c1d-4fb8-a557-86da92d3a294.jpg) -½«ÐèÒª»ØÊյĶÔÏó½øÐбê¼Ç£¬È»ºóÇå³ý¡£ +将需è¦�回收的对象进行标记,然å�Žæ¸…除。 -²»×㣺 +ä¸�足: -1. ±ê¼ÇºÍÇå³ý¹ý³ÌЧÂʶ¼²»¸ß -2. »á²úÉú´óÁ¿Ë鯬 +1. 标记和清除过程效率都ä¸�高 +2. 会产生大é‡�碎片 -Ö®ºóµÄËã·¨¶¼ÊÇ»ùÓÚ¸ÃËã·¨½øÐиĽø¡£ +之å�Žçš„算法都是基于该算法进行改进。 -### 2.2 ¸´ÖÆËã·¨ +### 2.2 å¤�制算法 -![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/e6b733ad-606d-4028-b3e8-83c3a73a3797.jpg) +![](https://github.com/CyC2018/InterviewNotes/blob/master/pics//e6b733ad-606d-4028-b3e8-83c3a73a3797.jpg) -½«ÄÚ´æ»®·ÖΪ´óСÏàµÈµÄÁ½¿é£¬Ã¿´ÎֻʹÓÃÆäÖÐÒ»¿é£¬µ±ÕâÒ»¿éÄÚ´æÓÃÍêÁ˾ͽ«»¹´æ»îµÄ¶ÔÏó¸´ÖƵ½ÁíÒ»¿éÉÏÃæ£¬È»ºóÔÙ°ÑʹÓùýµÄÄÚ´æ¿Õ¼ä½øÐÐÒ»´ÎÇåÀí¡£ +将内存划分为大å°�相等的两å�—,æ¯�次å�ªä½¿ç”¨å…¶ä¸­ä¸€å�—,当这一å�—内存用完了就将还存活的对象å¤�制到å�¦ä¸€å�—上é�¢ï¼Œç„¶å�Žå†�把使用过的内存空间进行一次清ç�†ã€‚ -Ö÷Òª²»×ãÊÇֻʹÓÃÁËÄÚ´æµÄÒ»°ë¡£ +主è¦�ä¸�足是å�ªä½¿ç”¨äº†å†…存的一å�Šã€‚ -ÏÖÔÚµÄÉÌÒµÐéÄâ»ú¶¼²ÉÓÃÕâÖÖÊÕ¼¯Ëã·¨À´»ØÊÕÐÂÉú´ú£¬µ«ÊDz¢²»Êǽ«ÄÚ´æ»®·ÖΪ´óСÏàµÈµÄÁ½¿é£¬¶øÊÇ·ÖΪһ¿é½Ï´óµÄ Eden ¿Õ¼äºÍÁ½¿é½ÏСµÄ Survior ¿Õ¼ä£¬Ã¿´ÎʹÓà Eden ¿Õ¼äºÍÆäÖÐÒ»¿é Survivor¡£ÔÚ»ØÊÕʱ£¬½« Eden ºÍ Survivor Öл¹´æ»î×ŵĶÔÏóÒ»´ÎÐÔ¸´ÖƵ½ÁíÒ»¿é Survivor ¿Õ¼äÉÏ£¬×îºóÇåÀí Eden ºÍ Survivor¡£HotSpot ÐéÄâ»úµÄ Eden ºÍ Survivor µÄ´óС±ÈÀýĬÈÏΪ 8:1£¬±£Ö¤ÁËÄÚ´æµÄÀûÓÃÂÊ´ïµ½ 90 %¡£Èç¹ûÿ´Î»ØÊÕÓжàÓÚ 10% µÄ¶ÔÏó´æ»î£¬ÄÇôһ¿é Survivor ¿Õ¼ä¾Í²»¹»ÓÃÁË£¬ÐèÒªÒÀÀµÓÚÀÏÄê´ú½øÐзÖÅäµ£±££¬Ò²¾ÍÊǽèÓÃÀÏÄê´úµÄ¿Õ¼ä¡£ +现在的商业虚拟机都采用这ç§�收集算法æ�¥å›žæ”¶æ–°ç”Ÿä»£ï¼Œä½†æ˜¯å¹¶ä¸�是将内存划分为大å°�相等的两å�—,而是分为一å�—较大的 Eden 空间和两å�—较å°�çš„ Survior 空间,æ¯�次使用 Eden 空间和其中一å�— Survivor。在回收时,将 Eden å’Œ Survivor 中还存活ç�€çš„对象一次性å¤�制到å�¦ä¸€å�— Survivor 空间上,最å�Žæ¸…ç�† Eden å’Œ Survivor。HotSpot 虚拟机的 Eden å’Œ Survivor 的大å°�比例默认为 8:1,ä¿�è¯�了内存的利用率达到 90 %。如果æ¯�次回收有多于 10% 的对象存活,那么一å�— Survivor 空间就ä¸�够用了,需è¦�ä¾�赖于è€�年代进行分é…�æ‹…ä¿�,也就是借用è€�年代的空间。 -### 2.3 ±ê¼Ç - ÕûÀíËã·¨ +### 2.3 标记 - æ•´ç�†ç®—法 -![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/902b83ab-8054-4bd2-898f-9a4a0fe52830.jpg) +![](https://github.com/CyC2018/InterviewNotes/blob/master/pics//902b83ab-8054-4bd2-898f-9a4a0fe52830.jpg) -ÈÃËùÓдæ»îµÄ¶ÔÏó¶¼ÏòÒ»¶ÎÒÆ¶¯£¬È»ºóÖ±½ÓÇåÀíµô¶Ë±ß½çÒÔÍâµÄÄÚ´æ¡£ +让所有存活的对象都å�‘一段移动,然å�Žç›´æŽ¥æ¸…ç�†æŽ‰ç«¯è¾¹ç•Œä»¥å¤–的内存。 -### 2.4 ·Ö´úÊÕ¼¯Ëã·¨ +### 2.4 分代收集算法 -ÏÖÔÚµÄÉÌÒµÐéÄâ»ú²ÉÓ÷ִúÊÕ¼¯Ëã·¨£¬ËüʹÓÃÁËÇ°Ãæ½éÉܵļ¸ÖÖÊÕ¼¯Ëã·¨£¬¸ù¾Ý¶ÔÏó´æ»îÖÜÆÚ½«ÄÚ´æ»®·ÖΪ¼¸¿é£¬²»Í¬¿é²ÉÓÃÊʵ±µÄÊÕ¼¯Ëã·¨¡£ +现在的商业虚拟机采用分代收集算法,它使用了å‰�é�¢ä»‹ç»�的几ç§�收集算法,根æ�®å¯¹è±¡å­˜æ´»å‘¨æœŸå°†å†…存划分为几å�—,ä¸�å�Œå�—采用适当的收集算法。 -Ò»°ã½« Java ¶Ñ·ÖΪÐÂÉú´úºÍÀÏÄê´ú¡£ +一般将 Java 堆分为新生代和è€�年代。 -1. ÐÂÉú´úʹÓ㺸´ÖÆËã·¨ -2. ÀÏÄê´úʹÓ㺱ê¼Ç - ÇåÀí »òÕß ±ê¼Ç - ÕûÀí Ëã·¨¡£ +1. 新生代使用:å¤�制算法 +2. è€�年代使用:标记 - 清ç�† 或者 标记 - æ•´ç�† 算法。 -## 3. À¬»øÊÕ¼¯Æ÷ +## 3. 垃圾收集器 -![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/c625baa0-dde6-449e-93df-c3a67f2f430f.jpg) +![](https://github.com/CyC2018/InterviewNotes/blob/master/pics//c625baa0-dde6-449e-93df-c3a67f2f430f.jpg) -ÒÔÉÏÊÇ HotSpot ÐéÄâ»úÖÐµÄ 7 ¸öÀ¬»øÊÕ¼¯Æ÷£¬Á¬Ïß±íʾÀ¬»øÊÕ¼¯Æ÷¿ÉÒÔÅäºÏʹÓᣠ+以上是 HotSpot 虚拟机中的 7 个垃圾收集器,连线表示垃圾收集器å�¯ä»¥é…�å�ˆä½¿ç”¨ã€‚ -### 3.1 Serial ÊÕ¼¯Æ÷ +### 3.1 Serial 收集器 -![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/22fda4ae-4dd5-489d-ab10-9ebfdad22ae0.jpg) +![](https://github.com/CyC2018/InterviewNotes/blob/master/pics//22fda4ae-4dd5-489d-ab10-9ebfdad22ae0.jpg) -ËüÊǵ¥Ï̵߳ÄÊÕ¼¯Æ÷£¬²»½öÒâζ×ÅÖ»»áʹÓÃÒ»¸öÏ߳̽øÐÐÀ¬»øÊÕ¼¯¹¤×÷£¬¸üÖØÒªµÄÊÇËüÔÚ½øÐÐÀ¬»øÊÕ¼¯Ê±£¬±ØÐëÔÝÍ£ËùÓÐÆäËû¹¤×÷Ị̈߳¬ÍùÍùÔì³É¹ý³¤µÄµÈ´ýʱ¼ä¡£ +它是å�•线程的收集器,ä¸�ä»…æ„�味ç�€å�ªä¼šä½¿ç”¨ä¸€ä¸ªçº¿ç¨‹è¿›è¡Œåžƒåœ¾æ”¶é›†å·¥ä½œï¼Œæ›´é‡�è¦�的是它在进行垃圾收集时,必须暂å�œæ‰€æœ‰å…¶ä»–工作线程,往往造æˆ�过长的等待时间。 -ËüµÄÓŵãÊǼòµ¥¸ßЧ£¬¶ÔÓÚµ¥¸ö CPU »·¾³À´Ëµ£¬ÓÉÓÚûÓÐÏ߳̽»»¥µÄ¿ªÏú£¬Òò´ËÓµÓÐ×î¸ßµÄµ¥Ïß³ÌÊÕ¼¯Ð§ÂÊ¡£ +它的优点是简å�•高效,对于å�•个 CPU 环境æ�¥è¯´ï¼Œç”±äºŽæ²¡æœ‰çº¿ç¨‹äº¤äº’的开销,因此拥有最高的å�•线程收集效率。 -ÔÚ Client Ó¦Óó¡¾°ÖУ¬·ÖÅ䏸ÐéÄâ»ú¹ÜÀíµÄÄÚ´æÒ»°ãÀ´Ëµ²»»áºÜ´ó£¬¸ÃÊÕ¼¯Æ÷ÊÕ¼¯¼¸Ê®Õ×ÉõÖÁÒ»Á½°ÙÕ×µÄÐÂÉú´úÍ£¶Ùʱ¼ä¿ÉÒÔ¿ØÖÆÔÚÒ»°Ù¶àºÁÃëÒÔÄÚ£¬Ö»Òª²»ÊÇ̫Ƶ·±£¬ÕâµãÍ£¶ÙÊÇ¿ÉÒÔ½ÓÊܵġ£ +在 Client 应用场景中,分é…�给虚拟机管ç�†çš„内存一般æ�¥è¯´ä¸�会很大,该收集器收集几å��兆甚至一两百兆的新生代å�œé¡¿æ—¶é—´å�¯ä»¥æŽ§åˆ¶åœ¨ä¸€ç™¾å¤šæ¯«ç§’以内,å�ªè¦�ä¸�是太频ç¹�,这点å�œé¡¿æ˜¯å�¯ä»¥æŽ¥å�—的。 -### 3.2 ParNew ÊÕ¼¯Æ÷ +### 3.2 ParNew 收集器 -![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/81538cd5-1bcf-4e31-86e5-e198df1e013b.jpg) +![](https://github.com/CyC2018/InterviewNotes/blob/master/pics//81538cd5-1bcf-4e31-86e5-e198df1e013b.jpg) -ËüÊÇ Serial ÊÕ¼¯Æ÷µÄ¶àḬ̈߳汾¡£ +它是 Serial 收集器的多线程版本。 -ÊÇ Server ģʽϵÄÐéÄâ»úÊ×Ñ¡ÐÂÉú´úÊÕ¼¯Æ÷£¬³ýÁËÐÔÄÜÔ­ÒòÍ⣬Ö÷ÒªÊÇÒòΪ³ýÁË Serial ÊÕ¼¯Æ÷£¬Ö»ÓÐËüÄÜÓë CMS ÊÕ¼¯Æ÷ÅäºÏ¹¤×÷¡£ +是 Server 模å¼�下的虚拟机首选新生代收集器,除了性能原因外,主è¦�是因为除了 Serial 收集器,å�ªæœ‰å®ƒèƒ½ä¸Ž CMS 收集器é…�å�ˆå·¥ä½œã€‚ -ĬÈÏ¿ªÊ¼µÄÏß³ÌÊýÁ¿Óë CPU ÊýÁ¿Ïàͬ£¬¿ÉÒÔʹÓà -XX:ParallelGCThreads ²ÎÊýÀ´ÉèÖÃÏß³ÌÊý¡£ +默认开始的线程数é‡�与 CPU æ•°é‡�相å�Œï¼Œå�¯ä»¥ä½¿ç”¨ -XX:ParallelGCThreads å�‚æ•°æ�¥è®¾ç½®çº¿ç¨‹æ•°ã€‚ -### 3.3 Parallel Scavenge ÊÕ¼¯Æ÷ +### 3.3 Parallel Scavenge 收集器 -ÊDz¢ÐеĶàÏß³ÌÊÕ¼¯Æ÷¡£ +是并行的多线程收集器。 -ÆäËüÊÕ¼¯Æ÷¹Ø×¢µãÊǾ¡¿ÉÄÜËõ¶ÌÀ¬»øÊÕ¼¯Ê±Óû§Ï̵߳ÄÍ£¶Ùʱ¼ä£¬¶øËüµÄÄ¿±êÊÇ´ïµ½Ò»¸ö¿É¿ØÖƵÄÍÌÍÂÁ¿£¬Ëü±»³ÆÎª¡°ÍÌÍÂÁ¿ÓÅÏÈ¡±ÊÕ¼¯Æ÷¡£ÕâÀïµÄÍÌÍÂÁ¿Ö¸ CPU ÓÃÓÚÔËÐÐÓû§´úÂëµÄʱ¼äÕ¼×Üʱ¼äµÄ±ÈÖµ¡£ +其它收集器关注点是尽å�¯èƒ½ç¼©çŸ­åžƒåœ¾æ”¶é›†æ—¶ç”¨æˆ·çº¿ç¨‹çš„å�œé¡¿æ—¶é—´ï¼Œè€Œå®ƒçš„目标是达到一个å�¯æŽ§åˆ¶çš„å�žå��é‡�,它被称为“å�žå��é‡�优先â€�收集器。这里的å�žå��é‡�指 CPU 用于è¿�行用户代ç �的时间å� æ€»æ—¶é—´çš„æ¯”值。 -Í£¶Ùʱ¼äÔ½¶Ì¾ÍÔ½ÊʺÏÐèÒªÓëÓû§½»»¥µÄ³ÌÐò£¬Á¼ºÃµÄÏìÓ¦ËÙ¶ÈÄÜÌáÉýÓû§ÌåÑé¡£¶ø¸ßÍÌÍÂÁ¿Ôò¿ÉÒÔ¸ßЧÂʵØÀûÓà CPU ʱ¼ä£¬¾¡¿ìÍê³É³ÌÐòµÄÔËËãÈÎÎñ£¬Ö÷ÒªÊʺÏÔÚºǫ́ÔËËã¶ø²»ÐèҪ̫¶à½»»¥µÄÈÎÎñ¡£ +å�œé¡¿æ—¶é—´è¶ŠçŸ­å°±è¶Šé€‚å�ˆéœ€è¦�与用户交互的程åº�,良好的å“�应速度能æ��å�‡ç”¨æˆ·ä½“验。而高å�žå��é‡�则å�¯ä»¥é«˜æ•ˆçŽ‡åœ°åˆ©ç”¨ CPU 时间,尽快完æˆ�程åº�çš„è¿�算任务,主è¦�适å�ˆåœ¨å�Žå�°è¿�算而ä¸�需è¦�太多交互的任务。 -ÌṩÁËÁ½¸ö²ÎÊýÓÃÓÚ¾«È·¿ØÖÆÍÌÍÂÁ¿£¬·Ö±ðÊÇ¿ØÖÆ×î´óÀ¬»øÊÕ¼¯Í£¶Ùʱ¼ä -XX:MaxGCPauseMillis ²ÎÊýÒÔ¼°Ö±½ÓÉèÖÃÍÌÍÂÁ¿´óСµÄ -XX:GCTimeRatio ²ÎÊý£¨ÖµÎª´óÓÚ 0 ÇÒСÓÚ 100 µÄÕûÊý£©¡£Ëõ¶ÌÍ£¶Ùʱ¼äÊÇÒÔÎþÉüÍÌÍÂÁ¿ºÍÐÂÉú´ú¿Õ¼äÀ´»»È¡µÄ£ºÐÂÉú´ú¿Õ¼ä±äС£¬À¬»ø»ØÊÕ±äµÃƵ·±£¬µ¼ÖÂÍÌÍÂÁ¿Ï½µ¡£ +æ��供了两个å�‚数用于精确控制å�žå��é‡�,分别是控制最大垃圾收集å�œé¡¿æ—¶é—´ -XX:MaxGCPauseMillis å�‚数以å�Šç›´æŽ¥è®¾ç½®å�žå��é‡�大å°�çš„ -XX:GCTimeRatio å�‚数(值为大于 0 且å°�于 100 的整数)。缩短å�œé¡¿æ—¶é—´æ˜¯ä»¥ç‰ºç‰²å�žå��é‡�和新生代空间æ�¥æ�¢å�–的:新生代空间å�˜å°�,垃圾回收å�˜å¾—频ç¹�,导致å�žå��é‡�下é™�。 -»¹ÌṩÁËÒ»¸ö²ÎÊý -XX:+UseAdaptiveSizePolicy£¬ÕâÊÇÒ»¸ö¿ª¹Ø²ÎÊý£¬´ò¿ª²ÎÊýºó£¬¾Í²»ÐèÒªÊÖ¹¤Ö¸¶¨ÐÂÉú´úµÄ´óС£¨-Xmn£©¡¢Eden ºÍ Survivor ÇøµÄ±ÈÀý£¨-XX:SurvivorRatio£©¡¢½úÉýÀÏÄê´ú¶ÔÏóÄêÁ䣨-XX:PretenureSizeThreshold£©µÈϸ½Ú²ÎÊýÁË£¬ÐéÄâ»ú»á¸ù¾Ýµ±Ç°ÏµÍ³µÄÔËÐÐÇé¿öÊÕ¼¯ÐÔÄÜ¼à¿ØÐÅÏ¢£¬¶¯Ì¬µ÷ÕûÕâЩ²ÎÊýÒÔÌṩ×îºÏÊʵÄÍ£¶Ùʱ¼ä»òÕß×î´óµÄÍÌÍÂÁ¿£¬ÕâÖÖ·½Ê½³ÆÎª GC ×ÔÊÊÓ¦µÄµ÷½Ú²ßÂÔ£¨GC Ergonomics£©¡£×ÔÊÊÓ¦µ÷½Ú²ßÂÔÒ²ÊÇËüÓë ParNew ÊÕ¼¯Æ÷µÄÒ»¸öÖØÒªÇø±ð¡£ +还æ��供了一个å�‚æ•° -XX:+UseAdaptiveSizePolicy,这是一个开关å�‚数,打开å�‚æ•°å�Žï¼Œå°±ä¸�需è¦�手工指定新生代的大å°�(-Xmn)ã€�Eden å’Œ Survivor 区的比例(-XX:SurvivorRatio)ã€�晋å�‡è€�年代对象年龄(-XX:PretenureSizeThreshold)等细节å�‚数了,虚拟机会根æ�®å½“å‰�系统的è¿�行情况收集性能监控信æ�¯ï¼ŒåЍæ€�调整这些å�‚数以æ��供最å�ˆé€‚çš„å�œé¡¿æ—¶é—´æˆ–者最大的å�žå��é‡�,这ç§�æ–¹å¼�称为 GC 自适应的调节策略(GC Ergonomics)。自适应调节策略也是它与 ParNew 收集器的一个é‡�è¦�区别。 -### 3.4 Serial Old ÊÕ¼¯Æ÷ +### 3.4 Serial Old 收集器 -![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/08f32fd3-f736-4a67-81ca-295b2a7972f2.jpg) +![](https://github.com/CyC2018/InterviewNotes/blob/master/pics//08f32fd3-f736-4a67-81ca-295b2a7972f2.jpg) -Serial Old ÊÇ Serial ÊÕ¼¯Æ÷µÄÀÏÄê´ú°æ±¾£¬Ò²ÊǸø Client ģʽϵÄÐéÄâ»úʹÓá£Èç¹ûÓÃÔÚ Server ģʽÏ£¬ËüÓÐÁ½´óÓÃ;£º +Serial Old 是 Serial 收集器的è€�年代版本,也是给 Client 模å¼�下的虚拟机使用。如果用在 Server 模å¼�下,它有两大用途: -1. ÔÚ JDK 1.5 ÒÔ¼°Ö®Ç°°æ±¾£¨Parallel Old µ®ÉúÒÔǰ£©ÖÐÓë Parallel Scavenge ÊÕ¼¯Æ÷´îÅäʹÓᣠ-2. ×÷Ϊ CMS ÊÕ¼¯Æ÷µÄºó±¸Ô¤°¸£¬ÔÚ²¢·¢ÊÕ¼¯·¢Éú Concurrent Mode Failure ʱʹÓᣠ+1. 在 JDK 1.5 以å�Šä¹‹å‰�版本(Parallel Old 诞生以å‰�)中与 Parallel Scavenge 收集器æ�­é…�使用。 +2. 作为 CMS 收集器的å�Žå¤‡é¢„案,在并å�‘收集å�‘生 Concurrent Mode Failure 时使用。 -### 3.5 Parallel Old ÊÕ¼¯Æ÷ +### 3.5 Parallel Old 收集器 -![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/278fe431-af88-4a95-a895-9c3b80117de3.jpg) +![](https://github.com/CyC2018/InterviewNotes/blob/master/pics//278fe431-af88-4a95-a895-9c3b80117de3.jpg) -ÊÇ Parallel Scavenge ÊÕ¼¯Æ÷µÄÀÏÄê´ú°æ±¾¡£ +是 Parallel Scavenge 收集器的è€�年代版本。 -ÔÚ×¢ÖØÍÌÍÂÁ¿ÒÔ¼° CPU ×ÊÔ´Ãô¸ÐµÄ³¡ºÏ£¬¶¼¿ÉÒÔÓÅÏÈ¿¼ÂÇ Parallel Scavenge ¼Ó Parallel Old ÊÕ¼¯Æ÷¡£ +在注é‡�å�žå��é‡�以å�Š CPU 资æº�æ•�感的场å�ˆï¼Œéƒ½å�¯ä»¥ä¼˜å…ˆè€ƒè™‘ Parallel Scavenge 加 Parallel Old 收集器。 -### 3.6 CMS ÊÕ¼¯Æ÷ +### 3.6 CMS 收集器 -![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/62e77997-6957-4b68-8d12-bfd609bb2c68.jpg) +![](https://github.com/CyC2018/InterviewNotes/blob/master/pics//62e77997-6957-4b68-8d12-bfd609bb2c68.jpg) -CMS£¨Concurrent Mark Sweep£©£¬´Ó Mark Sweep ¿ÉÒÔÖªµÀËüÊÇ»ùÓÚ ±ê¼Ç - Çå³ý Ë㷨ʵÏֵġ£ +CMS(Concurrent Mark Sweep),从 Mark Sweep å�¯ä»¥çŸ¥é�“它是基于 标记 - 清除 算法实现的。 -ÌØµã£º²¢·¢ÊÕ¼¯¡¢µÍÍ£¶Ù¡£ +特点:并å�‘收集ã€�低å�œé¡¿ã€‚ -·ÖΪÒÔÏÂËĸöÁ÷³Ì£º +分为以下四个æµ�程: -1. ³õʼ±ê¼Ç£º½ö½öÖ»ÊDZê¼ÇһϠGC Roots ÄÜÖ±½Ó¹ØÁªµ½µÄ¶ÔÏó£¬ËٶȺܿ죬ÐèҪͣ¶Ù¡£ -2. ²¢·¢±ê¼Ç£º½øÐÐ GC Roots Tracing µÄ¹ý³Ì£¬ËüÔÚÕû¸ö»ØÊÕ¹ý³ÌÖкÄʱ×£¬²»ÐèҪͣ¶Ù¡£ -3. ÖØÐ±ê¼Ç£ºÎªÁËÐÞÕý²¢·¢±ê¼ÇÆÚ¼äÒòÓû§³ÌÐò¼ÌÐøÔË×÷¶øµ¼Ö±ê¼Ç²úÉú±ä¶¯µÄÄÇÒ»²¿·Ö¶ÔÏóµÄ±ê¼Ç¼Ç¼£¬ÐèҪͣ¶Ù¡£ -4. ²¢·¢Çå³ý£º²»ÐèҪͣ¶Ù¡£ +1. åˆ�始标记:仅仅å�ªæ˜¯æ ‡è®°ä¸€ä¸‹ GC Roots 能直接关è�”到的对象,速度很快,需è¦�å�œé¡¿ã€‚ +2. å¹¶å�‘标记:进行 GC Roots Tracing 的过程,它在整个回收过程中耗时最长,ä¸�需è¦�å�œé¡¿ã€‚ +3. é‡�新标记:为了修正并å�‘标记期间因用户程åº�ç»§ç»­è¿�作而导致标记产生å�˜åŠ¨çš„é‚£ä¸€éƒ¨åˆ†å¯¹è±¡çš„æ ‡è®°è®°å½•ï¼Œéœ€è¦�å�œé¡¿ã€‚ +4. å¹¶å�‘清除:ä¸�需è¦�å�œé¡¿ã€‚ -ÔÚÕû¸ö¹ý³ÌÖкÄʱ×µÄ²¢·¢±ê¼ÇºÍ²¢·¢Çå³ý¹ý³ÌÖУ¬ÊÕ¼¯Æ÷Ï̶߳¼¿ÉÒÔÓëÓû§Ïß³ÌÒ»Æð¹¤×÷£¬²»ÐèÒª½øÐÐÍ£¶Ù¡£ +在整个过程中耗时最长的并å�‘标记和并å�‘清除过程中,收集器线程都å�¯ä»¥ä¸Žç”¨æˆ·çº¿ç¨‹ä¸€èµ·å·¥ä½œï¼Œä¸�需è¦�进行å�œé¡¿ã€‚ -¾ßÓÐÒÔÏÂȱµã£º +具有以下缺点: -1. ¶Ô CPU ×ÊÔ´Ãô¸Ð¡£CMS ĬÈÏÆô¶¯µÄ»ØÊÕÏß³ÌÊýÊÇ (CPU ÊýÁ¿ + 3) / 4£¬µ± CPU ²»×ã 4 ¸öʱ£¬CMS ¶ÔÓû§³ÌÐòµÄÓ°Ïì¾Í¿ÉÄܱäµÃºÜ´ó£¬Èç¹û±¾À´ CPU ¸ºÔؾͱȽϴ󣬻¹Òª·Ö³öÒ»°ëµÄÔËËãÄÜÁ¦È¥Ö´ÐÐÊÕ¼¯Æ÷Ị̈߳¬¾Í¿ÉÄܵ¼ÖÂÓû§³ÌÐòµÄÖ´ÐÐËٶȺöÈ»½µµÍÁË 50%£¬ÆäʵҲÈÃÈËÎÞ·¨½ÓÊÜ¡£²¢ÇÒµÍÍ£¶Ùʱ¼äÊÇÒÔÎþÉüÍÌÍÂÁ¿Îª´ú¼ÛµÄ£¬µ¼Ö CPU ÀûÓÃÂʱäµÍ¡£ +1. 对 CPU 资æº�æ•�感。CMS 默认å�¯åŠ¨çš„å›žæ”¶çº¿ç¨‹æ•°æ˜¯ (CPU æ•°é‡� + 3) / 4,当 CPU ä¸�è¶³ 4 个时,CMS 对用户程åº�的影å“�å°±å�¯èƒ½å�˜å¾—很大,如果本æ�¥ CPU 负载就比较大,还è¦�分出一å�Šçš„è¿�算能力去执行收集器线程,就å�¯èƒ½å¯¼è‡´ç”¨æˆ·ç¨‹åº�的执行速度忽然é™�低了 50%,其实也让人无法接å�—。并且低å�œé¡¿æ—¶é—´æ˜¯ä»¥ç‰ºç‰²å�žå��é‡�为代价的,导致 CPU 利用率å�˜ä½Žã€‚ -2. ÎÞ·¨´¦Àí¸¡¶¯À¬»ø¡£ÓÉÓÚ²¢·¢ÇåÀí½×¶ÎÓû§Ï̻߳¹ÔÚÔËÐÐ×Å£¬°éËæ³ÌÐòÔËÐÐ×ÔÈ»¾Í»¹»áÓÐеÄÀ¬»ø²»¶Ï²úÉú¡£ÕâÒ»²¿·ÖÀ¬»ø³öÏÖÔÚ±ê¼Ç¹ý³ÌÖ®ºó£¬CMS ÎÞ·¨ÔÚµ±´ÎÊÕ¼¯Öд¦ÀíµôËüÃÇ£¬Ö»ºÃÁôµ½ÏÂÒ»´Î GC ʱÔÙÇåÀíµô£¬ÕâÒ»²¿·ÖÀ¬»ø¾Í±»³ÆÎª¡°¸¡¶¯À¬»ø¡±¡£Ò²ÊÇÓÉÓÚÔÚÀ¬»øÊÕ¼¯½×¶ÎÓû§Ï̻߳¹ÐèÒªÔËÐУ¬ÄÇÒ²¾Í»¹ÐèÒªÔ¤ÁôÓÐ×ã¹»µÄÄÚ´æ¿Õ¼ä¸øÓû§Ïß³ÌʹÓã¬Òò´ËËü²»ÄÜÏñÆäËûÊÕ¼¯Æ÷ÄÇÑùµÈµ½ÀÏÄê´ú¼¸ºõÍêÈ«±»ÌîÂúÁËÔÙ½øÐÐÊÕ¼¯£¬ÐèÒªÔ¤ÁôÒ»²¿·Ö¿Õ¼äÌṩ²¢·¢ÊÕ¼¯Ê±µÄ³ÌÐòÔË×÷ʹÓ᣿ÉÒÔʹÓà -XX:CMSInitiatingOccupancyFraction µÄÖµÀ´¸Ä±ä´¥·¢ÊÕ¼¯Æ÷¹¤×÷µÄÄÚ´æÕ¼Óðٷֱȣ¬JDK 1.5 ĬÈÏÉèÖÃϸÃֵΪ 68£¬Ò²¾ÍÊǵ±ÀÏÄê´úʹÓÃÁË 68% µÄ¿Õ¼äÖ®ºó»á´¥·¢ÊÕ¼¯Æ÷¹¤×÷¡£Èç¹û¸ÃÖµÉèÖõÄÌ«¸ß£¬µ¼Ö¸¡¶¯À¬»øÎÞ·¨±£´æ£¬ÄÇô¾Í»á³öÏÖ Concurrent Mode Failure£¬´ËʱÐéÄâ»ú½«Æô¶¯ºó±¸Ô¤°¸£ºÁÙʱÆôÓà Serial Old ÊÕ¼¯Æ÷À´ÖØÐ½øÐÐÀÏÄê´úµÄÀ¬»øÊÕ¼¯¡£ +2. 无法处ç�†æµ®åŠ¨åžƒåœ¾ã€‚ç”±äºŽå¹¶å�‘清ç�†é˜¶æ®µç”¨æˆ·çº¿ç¨‹è¿˜åœ¨è¿�行ç�€ï¼Œä¼´éš�程åº�è¿�行自然就还会有新的垃圾ä¸�断产生。这一部分垃圾出现在标记过程之å�Žï¼ŒCMS 无法在当次收集中处ç�†æŽ‰å®ƒä»¬ï¼Œå�ªå¥½ç•™åˆ°ä¸‹ä¸€æ¬¡ GC æ—¶å†�清ç�†æŽ‰ï¼Œè¿™ä¸€éƒ¨åˆ†åžƒåœ¾å°±è¢«ç§°ä¸ºâ€œæµ®åŠ¨åžƒåœ¾â€�。也是由于在垃圾收集阶段用户线程还需è¦�è¿�行,那也就还需è¦�预留有足够的内存空间给用户线程使用,因此它ä¸�能åƒ�其他收集器那样等到è€�年代几乎完全被填满了å†�进行收集,需è¦�预留一部分空间æ��供并å�‘收集时的程åº�è¿�作使用。å�¯ä»¥ä½¿ç”¨ -XX:CMSInitiatingOccupancyFraction 的值æ�¥æ”¹å�˜è§¦å�‘收集器工作的内存å� ç”¨ç™¾åˆ†æ¯”,JDK 1.5 默认设置下该值为 68,也就是当è€�年代使用了 68% 的空间之å�Žä¼šè§¦å�‘收集器工作。如果该值设置的太高,导致浮动垃圾无法ä¿�存,那么就会出现 Concurrent Mode Failure,此时虚拟机将å�¯åЍå�Žå¤‡é¢„案:临时å�¯ç”¨ Serial Old 收集器æ�¥é‡�新进行è€�年代的垃圾收集。 -3. ±ê¼Ç - Çå³ýËã·¨µ¼ÖµĿռäË鯬£¬¸ø´ó¶ÔÏó·ÖÅä´øÀ´ºÜ´óÂé·³£¬ÍùÍù³öÏÖÀÏÄê´ú¿Õ¼äÊ£Ó࣬µ«ÎÞ·¨ÕÒµ½×ã¹»´óÁ¬Ðø¿Õ¼äÀ´·ÖÅ䵱ǰ¶ÔÏ󣬲»µÃ²»Ìáǰ³ö·¢Ò»´Î Full GC¡£ +3. 标记 - 清除算法导致的空间碎片,给大对象分é…�带æ�¥å¾ˆå¤§éº»çƒ¦ï¼Œå¾€å¾€å‡ºçްè€�年代空间剩余,但无法找到足够大连续空间æ�¥åˆ†é…�当å‰�对象,ä¸�å¾—ä¸�æ��å‰�出å�‘一次 Full GC。 -### 3.7 G1 ÊÕ¼¯Æ÷ +### 3.7 G1 收集器 -![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/f99ee771-c56f-47fb-9148-c0036695b5fe.jpg) +![](https://github.com/CyC2018/InterviewNotes/blob/master/pics//f99ee771-c56f-47fb-9148-c0036695b5fe.jpg) -G1£¨Garbage-First£©ÊÕ¼¯Æ÷Êǵ±½ñÊÕ¼¯Æ÷¼¼Êõ·¢Õ¹×îÇ°ÑØµÄ³É¹ûÖ®Ò»£¬ËüÊÇÒ»¿îÃæÏò·þÎñ¶ËÓ¦ÓõÄÀ¬»øÊÕ¼¯Æ÷£¬HotSpot ¿ª·¢ÍŶӸ³ÓèËüµÄʹÃüÊÇ£¨ÔڱȽϳ¤ÆÚµÄ£©Î´À´¿ÉÒÔÌæ»»µô JDK 1.5 Öз¢²¼µÄ CMS ÊÕ¼¯Æ÷¡£ +G1(Garbage-First)收集器是当今收集器技术å�‘展最å‰�沿的æˆ�果之一,它是一款é�¢å�‘æœ�务端应用的垃圾收集器,HotSpot å¼€å�‘团队赋予它的使命是(在比较长期的)未æ�¥å�¯ä»¥æ›¿æ�¢æŽ‰ JDK 1.5 中å�‘布的 CMS 收集器。 -¾ß±¸ÈçÏÂÌØµã£º +具备如下特点: -- ²¢ÐÐÓë²¢·¢£ºÄܳä·ÖÀûÓöà CPU »·¾³ÏµÄÓ²¼þÓÅÊÆ£¬Ê¹Óöà¸ö CPU À´Ëõ¶ÌÍ£¶Ùʱ¼ä£» -- ·Ö´úÊÕ¼¯£º·Ö´ú¸ÅÄîÒÀÈ»µÃÒÔ±£Áô£¬ËäÈ»Ëü²»ÐèÒªÆäËüÊÕ¼¯Æ÷ÅäºÏ¾ÍÄܶÀÁ¢¹ÜÀíÕû¸ö GC ¶Ñ£¬µ«ËüÄܹ»²ÉÓò»Í¬·½Ê½È¥´¦Àíд´½¨µÄ¶ÔÏóºÍÒÑ´æ»îÒ»¶Îʱ¼ä¡¢°¾¹ý¶à´Î GC µÄ¾É¶ÔÏóÀ´»ñÈ¡¸üºÃµÄÊÕ¼¯Ð§¹û¡£ -- ¿Õ¼äÕûºÏ£ºÕûÌåÀ´¿´ÊÇ»ùÓÚ¡°±ê¼Ç - ÕûÀí¡±Ë㷨ʵÏÖµÄÊÕ¼¯Æ÷£¬´Ó¾Ö²¿£¨Á½¸ö Region Ö®¼ä£©ÉÏÀ´¿´ÊÇ»ùÓÚ¡°¸´ÖÆ¡±Ë㷨ʵÏֵģ¬ÕâÒâζ×ÅÔËÐÐÆÚ¼ä²»»á²úÉúÄÚ´æ¿Õ¼äË鯬¡£ -- ¿ÉÔ¤²âµÄÍ£¶Ù£ºÕâÊÇËüÏà¶Ô CMS µÄÒ»´óÓÅÊÆ£¬½µµÍÍ£¶Ùʱ¼äÊÇ G1 ºÍ CMS ¹²Í¬µÄ¹Ø×¢µã£¬µ« G1 ³ýÁ˽µµÍÍ£¶ÙÍ⣬»¹Äܽ¨Á¢¿ÉÔ¤²âµÄÍ£¶Ùʱ¼äÄ£ÐÍ£¬ÄÜÈÃʹÓÃÕßÃ÷È·Ö¸¶¨ÔÚÒ»¸ö³¤¶ÈΪ M ºÁÃëµÄʱ¼äƬ¶ÎÄÚ£¬ÏûºÄÔÚ GC ÉϵÄʱ¼ä²»µÃ³¬¹ý N ºÁÃ룬Õ⼸ºõÒѾ­ÊÇʵʱ Java£¨RTSJ£©µÄÀ¬»øÊÕ¼¯Æ÷µÄÌØÕ÷ÁË¡£ +- 并行与并å�‘:能充分利用多 CPU 环境下的硬件优势,使用多个 CPU æ�¥ç¼©çŸ­å�œé¡¿æ—¶é—´ï¼› +- 分代收集:分代概念ä¾�然得以ä¿�留,虽然它ä¸�需è¦�其它收集器é…�å�ˆå°±èƒ½ç‹¬ç«‹ç®¡ç�†æ•´ä¸ª GC 堆,但它能够采用ä¸�å�Œæ–¹å¼�去处ç�†æ–°åˆ›å»ºçš„对象和已存活一段时间ã€�熬过多次 GC 的旧对象æ�¥èŽ·å�–更好的收集效果。 +- 空间整å�ˆï¼šæ•´ä½“æ�¥çœ‹æ˜¯åŸºäºŽâ€œæ ‡è®° - æ•´ç�†â€�算法实现的收集器,从局部(两个 Region 之间)上æ�¥çœ‹æ˜¯åŸºäºŽâ€œå¤�制â€�算法实现的,这æ„�味ç�€è¿�行期间ä¸�会产生内存空间碎片。 +- å�¯é¢„测的å�œé¡¿ï¼šè¿™æ˜¯å®ƒç›¸å¯¹ CMS 的一大优势,é™�低å�œé¡¿æ—¶é—´æ˜¯ G1 å’Œ CMS å…±å�Œçš„关注点,但 G1 除了é™�低å�œé¡¿å¤–,还能建立å�¯é¢„测的å�œé¡¿æ—¶é—´æ¨¡åž‹ï¼Œèƒ½è®©ä½¿ç”¨è€…明确指定在一个长度为 M 毫秒的时间片段内,消耗在 GC 上的时间ä¸�得超过 N 毫秒,这几乎已ç»�是实时 Java(RTSJ)的垃圾收集器的特å¾�了。 -ÔÚ G1 ֮ǰµÄÆäËûÊÕ¼¯Æ÷½øÐÐÊÕ¼¯µÄ·¶Î§¶¼ÊÇÕû¸öÐÂÉú´ú»òÕßÀÏÉú´ú£¬¶ø G1 ²»ÔÙÊÇÕâÑù£¬Java ¶ÑµÄÄÚ´æ²¼¾ÖÓëÆäËûÊÕ¼¯Æ÷ÓкܴóÇø±ð£¬½«Õû¸ö Java ¶Ñ»®·ÖΪ¶à¸ö´óСÏàµÈµÄ¶ÀÁ¢ÇøÓò£¨Region£©¡£ËäÈ»»¹±£ÁôÐÂÉú´úºÍÀÏÄê´úµÄ¸ÅÄµ«ÐÂÉú´úºÍÀÏÄê´ú²»ÔÙÊÇÎïÀí¸ôÀëµÄÁË£¬¶ø¶¼ÊÇÒ»²¿·Ö Region£¨²»ÐèÒªÁ¬Ðø£©µÄ¼¯ºÏ¡£ +在 G1 之å‰�的其他收集器进行收集的范围都是整个新生代或者è€�生代,而 G1 ä¸�å†�是这样,Java 堆的内存布局与其他收集器有很大区别,将整个 Java 堆划分为多个大å°�相等的独立区域(Region)。虽然还ä¿�留新生代和è€�年代的概念,但新生代和è€�年代ä¸�å†�是物ç�†éš”离的了,而都是一部分 Region(ä¸�需è¦�连续)的集å�ˆã€‚ -Ö®ËùÒÔÄܽ¨Á¢¿ÉÔ¤²âµÄÍ£¶Ùʱ¼äÄ£ÐÍ£¬ÊÇÒòΪËü¿ÉÒÔÓмƻ®µØ±ÜÃâÔÚÕû¸ö Java ¶ÑÖнøÐÐÈ«ÇøÓòµÄÀ¬»øÊÕ¼¯¡£Ëü¸ú×Ù¸÷¸ö Region ÀïÃæµÄÀ¬»ø¶Ñ»ýµÄ¼ÛÖµ´óС£¨»ØÊÕËù»ñµÃµÄ¿Õ¼ä´óСÒÔ¼°»ØÊÕËùÐèʱ¼äµÄ¾­ÑéÖµ£©£¬ÔÚºǫ́ά»¤Ò»¸öÓÅÏÈÁÐ±í£¬Ã¿´Î¸ù¾ÝÔÊÐíµÄÊÕ¼¯Ê±¼ä£¬ÓÅÏÈ»ØÊÕ¼ÛÖµ×î´óµÄ Region£¨ÕâÒ²¾ÍÊÇ Garbage-First Ãû³ÆµÄÀ´ÓÉ£©¡£ÕâÖÖʹÓà Region »®·ÖÄÚ´æ¿Õ¼äÒÔ¼°ÓÐÓÅÏȼ¶µÄÇøÓò»ØÊÕ·½Ê½£¬±£Ö¤ÁËËüÔÚÓÐÏÞµÄʱ¼äÄÚ¿ÉÒÔ»ñÈ¡¾¡¿ÉÄܸߵÄÊÕ¼¯Ð§ÂÊ¡£ +之所以能建立å�¯é¢„测的å�œé¡¿æ—¶é—´æ¨¡åž‹ï¼Œæ˜¯å› ä¸ºå®ƒå�¯ä»¥æœ‰è®¡åˆ’地é�¿å…�在整个 Java 堆中进行全区域的垃圾收集。它跟踪å�„个 Region 里é�¢çš„垃圾堆积的价值大å°�(回收所获得的空间大å°�以å�Šå›žæ”¶æ‰€éœ€æ—¶é—´çš„ç»�验值),在å�Žå�°ç»´æŠ¤ä¸€ä¸ªä¼˜å…ˆåˆ—表,æ¯�次根æ�®å…�许的收集时间,优先回收价值最大的 Region(这也就是 Garbage-First å��ç§°çš„æ�¥ç”±ï¼‰ã€‚è¿™ç§�使用 Region 划分内存空间以å�Šæœ‰ä¼˜å…ˆçº§çš„区域回收方å¼�,ä¿�è¯�了它在有é™�的时间内å�¯ä»¥èŽ·å�–å°½å�¯èƒ½é«˜çš„æ”¶é›†æ•ˆçŽ‡ã€‚ -Region ²»¿ÉÄÜÊǹÂÁ¢µÄ£¬Ò»¸ö¶ÔÏó·ÖÅäÔÚij¸ö Region ÖУ¬¿ÉÒÔÓëÕû¸ö Java ¶ÑÈÎÒâµÄ¶ÔÏó·¢ÉúÒýÓùØÏµ¡£ÔÚ×ö¿É´ïÐÔ·ÖÎöÈ·¶¨¶ÔÏóÊÇ·ñ´æ»îµÄʱºò£¬ÐèҪɨÃèÕû¸ö Java ¶Ñ²ÅÄܱ£Ö¤×¼È·ÐÔ£¬ÕâÏÔÈ»ÊÇ¶Ô GC ЧÂʵļ«´óÉ˺¦¡£ÎªÁ˱ÜÃâÈ«¶ÑɨÃèµÄ·¢Éú£¬Ã¿¸ö Region ¶¼Î¬»¤ÁËÒ»¸öÓëÖ®¶ÔÓ¦µÄ Remembered Set¡£ÐéÄâ»ú·¢ÏÖ³ÌÐòÔÚ¶Ô Reference ÀàÐ͵ÄÊý¾Ý½øÐÐд²Ù×÷ʱ£¬»á²úÉúÒ»¸ö Write Barrier ÔÝʱÖжÏд²Ù×÷£¬¼ì²é Reference ÒýÓõĶÔÏóÊÇ·ñ´¦ÓÚ²»Í¬µÄ Region Ö®ÖУ¬Èç¹ûÊÇ£¬±ãͨ¹ý CardTable °ÑÏà¹ØÒýÓÃÐÅÏ¢¼Ç¼µ½±»ÒýÓöÔÏóËùÊôµÄ Region µÄ Remembered Set Ö®ÖС£µ±½øÐÐÄÚ´æ»ØÊÕʱ£¬ÔÚ GC ¸ù½ÚµãµÄö¾Ù·¶Î§ÖмÓÈë Remembered Set ¼´¿É±£Ö¤²»¶ÔÈ«¶ÑɨÃèÒ²²»»áÓÐÒÅ©¡£ +Region ä¸�å�¯èƒ½æ˜¯å­¤ç«‹çš„,一个对象分é…�在æŸ�个 Region 中,å�¯ä»¥ä¸Žæ•´ä¸ª Java 堆任æ„�的对象å�‘生引用关系。在å�šå�¯è¾¾æ€§åˆ†æž�确定对象是å�¦å­˜æ´»çš„æ—¶å€™ï¼Œéœ€è¦�扫æ��整个 Java å †æ‰�能ä¿�è¯�准确性,这显然是对 GC 效率的æž�大伤害。为了é�¿å…�全堆扫æ��çš„å�‘生,æ¯�个 Region 都维护了一个与之对应的 Remembered Set。虚拟机å�‘现程åº�在对 Reference 类型的数æ�®è¿›è¡Œå†™æ“�作时,会产生一个 Write Barrier 暂时中断写æ“�作,检查 Reference 引用的对象是å�¦å¤„于ä¸�å�Œçš„ Region 之中,如果是,便通过 CardTable 把相关引用信æ�¯è®°å½•到被引用对象所属的 Region çš„ Remembered Set 之中。当进行内存回收时,在 GC 根节点的枚举范围中加入 Remembered Set å�³å�¯ä¿�è¯�ä¸�对全堆扫æ��也ä¸�会有é�—æ¼�。 -Èç¹û²»¼ÆËãά»¤ Remembered Set µÄ²Ù×÷£¬G1 ÊÕ¼¯Æ÷µÄÔË×÷´óÖ¿ɻ®·ÖΪÒÔϼ¸¸ö²½Ö裺 +如果ä¸�计算维护 Remembered Set çš„æ“�作,G1 收集器的è¿�作大致å�¯åˆ’分为以下几个步骤: -1. ³õʼ±ê¼Ç -2. ²¢·¢±ê¼Ç -3. ×îÖÕ±ê¼Ç£ºÎªÁËÐÞÕýÔÚ²¢·¢±ê¼ÇÆÚ¼äÒòÓû§³ÌÐò¼ÌÐøÔË×÷¶øµ¼Ö±ê¼Ç²úÉú±ä¶¯µÄÄÇÒ»²¿·Ö±ê¼Ç¼Ç¼£¬ÐéÄâ»ú½«Õâ¶Îʱ¼ä¶ÔÏó±ä»¯¼Ç¼ÔÚÏß³ÌµÄ Remembered Set Logs ÀïÃæ£¬×îÖÕ±ê¼Ç½×¶ÎÐèÒª°Ñ Remembered Set Logs µÄÊý¾ÝºÏ²¢µ½ Remembered Set ÖС£Õâ½×¶ÎÐèҪͣ¶ÙỊ̈߳¬µ«Êǿɲ¢ÐÐÖ´ÐС£ -4. ɸѡ»ØÊÕ£ºÊ×ÏȶԸ÷¸ö Region ÖеĻØÊÕ¼ÛÖµºÍ³É±¾½øÐÐÅÅÐò£¬¸ù¾ÝÓû§ËùÆÚÍûµÄ GC Í£¶ÙÊÇʱ¼äÀ´Öƶ¨»ØÊռƻ®¡£´Ë½×¶ÎÆäʵҲ¿ÉÒÔ×öµ½ÓëÓû§³ÌÐòÒ»Æð²¢·¢Ö´ÐУ¬µ«ÊÇÒòΪֻ»ØÊÕÒ»²¿·Ö Region£¬Ê±¼äÊÇÓû§¿É¿ØÖƵ쬶øÇÒÍ£¶ÙÓû§Ï߳̽«´ó·ù¶ÈÌá¸ßÊÕ¼¯Ð§ÂÊ¡£ +1. åˆ�始标记 +2. å¹¶å�‘标记 +3. 最终标记:为了修正在并å�‘标记期间因用户程åº�ç»§ç»­è¿�作而导致标记产生å�˜åŠ¨çš„é‚£ä¸€éƒ¨åˆ†æ ‡è®°è®°å½•ï¼Œè™šæ‹Ÿæœºå°†è¿™æ®µæ—¶é—´å¯¹è±¡å�˜åŒ–记录在线程的 Remembered Set Logs 里é�¢ï¼Œæœ€ç»ˆæ ‡è®°é˜¶æ®µéœ€è¦�把 Remembered Set Logs 的数æ�®å�ˆå¹¶åˆ° Remembered Set 中。这阶段需è¦�å�œé¡¿çº¿ç¨‹ï¼Œä½†æ˜¯å�¯å¹¶è¡Œæ‰§è¡Œã€‚ +4. 筛选回收:首先对å�„个 Region 中的回收价值和æˆ�本进行排åº�,根æ�®ç”¨æˆ·æ‰€æœŸæœ›çš„ GC å�œé¡¿æ˜¯æ—¶é—´æ�¥åˆ¶å®šå›žæ”¶è®¡åˆ’。此阶段其实也å�¯ä»¥å�šåˆ°ä¸Žç”¨æˆ·ç¨‹åº�一起并å�‘执行,但是因为å�ªå›žæ”¶ä¸€éƒ¨åˆ† Region,时间是用户å�¯æŽ§åˆ¶çš„,而且å�œé¡¿ç”¨æˆ·çº¿ç¨‹å°†å¤§å¹…度æ��高收集效率。 -### 3.8 ÆßÖÖÀ¬»øÊÕ¼¯Æ÷µÄ±È½Ï +### 3.8 七ç§�垃圾收集器的比较 -| ÊÕ¼¯Æ÷ | ´®ÐС¢²¢ÐÐ or ²¢·¢ | ÐÂÉú´ú / ÀÏÄê´ú | Ëã·¨ | Ä¿±ê | ÊÊÓó¡¾° | +| 收集器 | 串行ã€�并行 or å¹¶å�‘ | 新生代 / è€�年代 | 算法 | 目标 | 适用场景 | | --- | --- | --- | --- | --- | --- | -| **Serial** | ´®ÐÐ | ÐÂÉú´ú | ¸´ÖÆËã·¨ | ÏìÓ¦ËÙ¶ÈÓÅÏÈ | µ¥ CPU »·¾³Ï嵀 Client ģʽ | -| **Serial Old** | ´®ÐÐ | ÀÏÄê´ú | ±ê¼Ç - ÕûÀí | ÏìÓ¦ËÙ¶ÈÓÅÏÈ | µ¥ CPU »·¾³Ï嵀 Client ģʽ¡¢CMS µÄºó±¸Ô¤°¸ | -| **ParNew** | ²¢ÐÐ | ÐÂÉú´ú | ¸´ÖÆËã·¨ | ÏìÓ¦ËÙ¶ÈÓÅÏÈ | ¶à CPU »·¾³Ê±ÔÚ Server ģʽÏÂÓë CMS ÅäºÏ | -| **Parallel Scavenge** | ²¢ÐÐ | ÐÂÉú´ú | ¸´ÖÆËã·¨ | ÍÌÍÂÁ¿ÓÅÏÈ | ÔÚºǫ́ÔËËã¶ø²»ÐèҪ̫¶à½»»¥µÄÈÎÎñ | -| **Parallel Old** | ²¢ÐÐ | ÀÏÄê´ú | ±ê¼Ç - ÕûÀí | ÍÌÍÂÁ¿ÓÅÏÈ | ÔÚºǫ́ÔËËã¶ø²»ÐèҪ̫¶à½»»¥µÄÈÎÎñ | -| **CMS** | ²¢·¢ | ÀÏÄê´ú | ±ê¼Ç - Çå³ý | ÏìÓ¦ËÙ¶ÈÓÅÏÈ | ¼¯ÖÐÔÚ»¥ÁªÍøÕ¾»ò B/S ϵͳ·þÎñ¶ËÉ쵀 Java Ó¦Óà | -| **G1** | ²¢·¢ | both | ±ê¼Ç - ÕûÀí + ¸´ÖÆËã·¨ | ÏìÓ¦ËÙ¶ÈÓÅÏÈ | ÃæÏò·þÎñ¶ËÓ¦Ó㬽«À´Ìæ»» CMS | +| **Serial** | 串行 | 新生代 | å¤�制算法 | å“�应速度优先 | å�• CPU 环境下的 Client 模å¼� | +| **Serial Old** | 串行 | è€�年代 | 标记 - æ•´ç�† | å“�应速度优先 | å�• CPU 环境下的 Client 模å¼�ã€�CMS çš„å�Žå¤‡é¢„案 | +| **ParNew** | 并行 | 新生代 | å¤�制算法 | å“�应速度优先 | 多 CPU 环境时在 Server 模å¼�下与 CMS é…�å�ˆ | +| **Parallel Scavenge** | 并行 | 新生代 | å¤�制算法 | å�žå��é‡�优先 | 在å�Žå�°è¿�算而ä¸�需è¦�太多交互的任务 | +| **Parallel Old** | 并行 | è€�年代 | 标记 - æ•´ç�† | å�žå��é‡�优先 | 在å�Žå�°è¿�算而ä¸�需è¦�太多交互的任务 | +| **CMS** | å¹¶å�‘ | è€�年代 | 标记 - 清除 | å“�应速度优先 | 集中在互è�”网站或 B/S 系统æœ�务端上的 Java 应用 | +| **G1** | å¹¶å�‘ | both | 标记 - æ•´ç�† + å¤�制算法 | å“�应速度优先 | é�¢å�‘æœ�务端应用,将æ�¥æ›¿æ�¢ CMS | -## 4. ÄÚ´æ·ÖÅäÓë»ØÊÕ²ßÂÔ +## 4. 内存分é…�与回收策略 -### 4.1 ÓÅÏÈÔÚ Eden ·ÖÅä +### 4.1 优先在 Eden 分é…� -´ó¶àÊýÇé¿öÏ£¬¶ÔÏóÔÚÐÂÉú´ú Eden Çø·ÖÅ䣬µ± Eden Çø¿Õ¼ä²»¹»Ê±£¬·¢Æð Minor GC£» +大多数情况下,对象在新生代 Eden 区分é…�,当 Eden 区空间ä¸�够时,å�‘èµ· Minor GCï¼› -### 4.2 ´ó¶ÔÏóÖ±½Ó½øÈëÀÏÄê´ú +### 4.2 大对象直接进入è€�年代 -Ìṩ -XX:PretenureSizeThreshold ²ÎÊý£¬´óÓÚ´ËÖµµÄ¶ÔÏóÖ±½ÓÔÚÀÏÄê´ú·ÖÅ䣬±ÜÃâÔÚ Eden ÇøºÍ Survivor ÇøÖ®¼äµÄ´óÁ¿ÄÚ´æ¸´ÖÆ£» -### 4.3 ³¤ÆÚ´æ»îµÄ¶ÔÏó½øÈëÀÏÄê´ú +æ��ä¾› -XX:PretenureSizeThreshold å�‚数,大于此值的对象直接在è€�年代分é…�,é�¿å…�在 Eden 区和 Survivor 区之间的大é‡�内存å¤�制; +### 4.3 长期存活的对象进入è€�年代 -JVM Ϊ¶ÔÏó¶¨ÒåÄêÁ伯ÊýÆ÷£¬¾­¹ý Minor GC ÒÀÈ»´æ»îÇÒ±» Survivor ÇøÈÝÄɵģ¬Òƶ¯µ½ Survivor Çø£¬ÄêÁä¼Ó 1£¬Ã¿¾­ÀúÒ»´Î Minor GC ²»±»ÇåÀíÔòÄêÁä¼Ó 1£¬Ôö¼Óµ½Ò»¶¨ÄêÁäÔòÒÆ¶¯µ½ÀÏÄêÇø£¨Ä¬ÈÏ 15 Ë꣬ͨ¹ý -XX:MaxTenuringThreshold ÉèÖã©£» +JVM 为对象定义年龄计数器,ç»�过 Minor GC ä¾�然存活且被 Survivor 区容纳的,移动到 Survivor 区,年龄加 1,æ¯�ç»�历一次 Minor GC ä¸�被清ç�†åˆ™å¹´é¾„加 1,增加到一定年龄则移动到è€�年区(默认 15 å²�,通过 -XX:MaxTenuringThreshold 设置); -### 4.4 ¶¯Ì¬¶ÔÏóÄêÁäÅж¨ +### 4.4 动æ€�对象年龄判定 -Èô Survivor ÇøÖÐͬÄêÁäËùÓжÔÏó´óС×ܺʹóÓÚ Survivor ¿Õ¼äÒ»°ë£¬ÔòÄêÁä´óÓÚµÈÓÚ¸ÃÄêÁäµÄ¶ÔÏó¿ÉÒÔÖ±½Ó½øÈëÀÏÄê´ú£» +è‹¥ Survivor 区中å�Œå¹´é¾„所有对象大å°�总和大于 Survivor 空间一å�Šï¼Œåˆ™å¹´é¾„大于等于该年龄的对象å�¯ä»¥ç›´æŽ¥è¿›å…¥è€�年代; -### 4.5 ¿Õ¼ä·ÖÅäµ£±£ +### 4.5 空间分é…�æ‹…ä¿� -ÔÚ·¢Éú Minor GC ֮ǰ£¬JVM Ïȼì²éÀÏÄê´ú×î´ó¿ÉÓÃÁ¬Ðø¿Õ¼äÊÇ·ñ´óÓÚÐÂÉú´úËùÓжÔÏó×ܿռ䣬³ÉÁ¢µÄ»° Minor GC È·ÈÏÊǰ²È«µÄ£»·ñÔò¼ÌÐø¼ì²éÀÏÄê´ú×î´ó¿ÉÓÃÁ¬Ðø¿Õ¼äÊÇ·ñ´óÓÚÀú´Î½úÉýµ½ÀÏÄê´ú¶ÔÏóµÄƽ¾ù´óС£¬´óÓڵϰ½øÐÐ Minor GC£¬Ð¡Óڵϰ½øÐÐ Full GC¡£ +在å�‘生 Minor GC 之å‰�,JVM 先检查è€�年代最大å�¯ç”¨è¿žç»­ç©ºé—´æ˜¯å�¦å¤§äºŽæ–°ç”Ÿä»£æ‰€æœ‰å¯¹è±¡æ€»ç©ºé—´ï¼Œæˆ�ç«‹çš„è¯� Minor GC 确认是安全的;å�¦åˆ™ç»§ç»­æ£€æŸ¥è€�年代最大å�¯ç”¨è¿žç»­ç©ºé—´æ˜¯å�¦å¤§äºŽåŽ†æ¬¡æ™‹å�‡åˆ°è€�年代对象的平å�‡å¤§å°�,大于的è¯�进行 Minor GC,å°�于的è¯�进行 Full GC。 -## 4.6 Full GC µÄ´¥·¢Ìõ¼þ +## 4.6 Full GC 的触å�‘æ�¡ä»¶ -¶ÔÓÚ Minor GC£¬Æä´¥·¢Ìõ¼þ·Ç³£¼òµ¥£¬µ± Eden Çø¿Õ¼äÂúʱ£¬¾Í½«´¥·¢Ò»´Î Minor GC¡£¶ø Full GC ÔòÏà¶Ô¸´ÔÓ£¬ÓÐÒÔÏÂÌõ¼þ£º +对于 Minor GC,其触å�‘æ�¡ä»¶é�žå¸¸ç®€å�•,当 Eden 区空间满时,就将触å�‘一次 Minor GC。而 Full GC 则相对å¤�æ�‚,有以下æ�¡ä»¶ï¼š -### 4.6.1 µ÷Óà System.gc() +### 4.6.1 调用 System.gc() -´Ë·½·¨µÄµ÷ÓÃÊǽ¨Òé JVM ½øÐÐ Full GC£¬ËäȻֻÊǽ¨Òé¶ø·ÇÒ»¶¨£¬µ«ºÜ¶àÇé¿öÏÂËü»á´¥·¢ Full GC£¬´Ó¶øÔö¼Ó Full GC µÄƵÂÊ£¬Ò²¼´Ôö¼ÓÁ˼äЪÐÔÍ£¶ÙµÄ´ÎÊý¡£Òò´ËÇ¿ÁÒ½¨ÒéÄܲ»Ê¹Óô˷½·¨¾Í²»ÒªÊ¹Óã¬ÈÃÐéÄâ»ú×Ô¼ºÈ¥¹ÜÀíËüµÄÄڴ棬¿Éͨ¹ý -XX:+ DisableExplicitGC À´½ûÖ¹ RMI µ÷Óà System.gc()¡£ +此方法的调用是建议 JVM 进行 Full GC,虽然å�ªæ˜¯å»ºè®®è€Œé�žä¸€å®šï¼Œä½†å¾ˆå¤šæƒ…况下它会触å�‘ Full GC,从而增加 Full GC 的频率,也å�³å¢žåŠ äº†é—´æ­‡æ€§å�œé¡¿çš„æ¬¡æ•°ã€‚因此强烈建议能ä¸�使用此方法就ä¸�è¦�使用,让虚拟机自己去管ç�†å®ƒçš„内存,å�¯é€šè¿‡ -XX:+ DisableExplicitGC æ�¥ç¦�æ­¢ RMI 调用 System.gc()。 -### 4.6.2 ÀÏÄê´ú¿Õ¼ä²»×ã +### 4.6.2 è€�年代空间ä¸�è¶³ -ÀÏÄê´ú¿Õ¼ä²»×ãµÄ³£¼û³¡¾°ÎªÇ°ÎÄËù½²µÄ´ó¶ÔÏóÖ±½Ó½øÈëÀÏÄê´ú¡¢³¤ÆÚ´æ»îµÄ¶ÔÏó½øÈëÀÏÄê´úµÈ£¬µ±Ö´ÐÐ Full GC ºó¿Õ¼äÈÔÈ»²»×㣬ÔòÅ׳öÈçÏ´íÎó£º Java.lang.OutOfMemoryError: Java heap space Ϊ±ÜÃâÒÔÉÏÁ½ÖÖ×´¿öÒýÆðµÄ Full GC£¬µ÷ÓÅʱӦ¾¡Á¿×öµ½ÈöÔÏóÔÚ Minor GC ½×¶Î±»»ØÊÕ¡¢ÈöÔÏóÔÚÐÂÉú´ú¶à´æ»îÒ»¶Îʱ¼ä¼°²»Òª´´½¨¹ý´óµÄ¶ÔÏó¼°Êý×é¡£ +è€�年代空间ä¸�足的常è§�场景为å‰�文所讲的大对象直接进入è€�年代ã€�长期存活的对象进入è€�年代等,当执行 Full GC å�Žç©ºé—´ä»�ç„¶ä¸�足,则抛出如下错误: Java.lang.OutOfMemoryError: Java heap space 为é�¿å…�以上两ç§�状况引起的 Full GC,调优时应尽é‡�å�šåˆ°è®©å¯¹è±¡åœ¨ Minor GC 阶段被回收ã€�让对象在新生代多存活一段时间å�Šä¸�è¦�创建过大的对象å�Šæ•°ç»„。 -### 4.6.3 ¿Õ¼ä·ÖÅäµ£±£Ê§°Ü +### 4.6.3 空间分é…�æ‹…ä¿�失败 -ʹÓø´ÖÆËã·¨µÄ Minor GC ÐèÒªÀÏÄê´úµÄÄÚ´æ¿Õ¼ä×÷µ£±££¬Èç¹û³öÏÖÁË HandlePromotionFailure µ£±£Ê§°Ü£¬Ôò»á´¥·¢ Full GC¡£ +使用å¤�制算法的 Minor GC 需è¦�è€�年代的内存空间作担ä¿�,如果出现了 HandlePromotionFailure æ‹…ä¿�失败,则会触å�‘ Full GC。 -### 4.6.4 JDK 1.7 ¼°ÒÔǰµÄÓÀ¾Ã´ú¿Õ¼ä²»×ã +### 4.6.4 JDK 1.7 å�Šä»¥å‰�的永久代空间ä¸�è¶³ -ÔÚ JDK 1.7 ¼°ÒÔǰ£¬HotSpot ÐéÄâ»úÖеķ½·¨ÇøÊÇÓÃÓÀ¾Ã´úʵÏֵģ¬ÓÀ¾Ã´úÖдæ·ÅµÄΪһЩ class µÄÐÅÏ¢¡¢³£Á¿¡¢¾²Ì¬±äÁ¿µÈÊý¾Ý£¬µ±ÏµÍ³ÖÐÒª¼ÓÔØµÄÀà¡¢·´ÉäµÄÀàºÍµ÷Óõķ½·¨½Ï¶àʱ£¬Permanet Generation ¿ÉÄܻᱻռÂú£¬ÔÚδÅäÖÃΪ²ÉÓà CMS GC µÄÇé¿öÏÂÒ²»áÖ´ÐÐ Full GC¡£Èç¹û¾­¹ý Full GC ÈÔÈ»»ØÊÕ²»ÁË£¬ÄÇô JVM »áÅ׳öÈçÏ´íÎóÐÅÏ¢£ºjava.lang.OutOfMemoryError: PermGen space Ϊ±ÜÃâ PermGen Õ¼ÂúÔì³É Full GC ÏÖÏ󣬿ɲÉÓõķ½·¨ÎªÔö´ó PermGen ¿Õ¼ä»òתΪʹÓà CMS GC¡£ +在 JDK 1.7 å�Šä»¥å‰�,HotSpot 虚拟机中的方法区是用永久代实现的,永久代中存放的为一些 class 的信æ�¯ã€�常é‡�ã€�é�™æ€�å�˜é‡�等数æ�®ï¼Œå½“系统中è¦�加载的类ã€�å��射的类和调用的方法较多时,Permanet Generation å�¯èƒ½ä¼šè¢«å� æ»¡ï¼Œåœ¨æœªé…�置为采用 CMS GC 的情况下也会执行 Full GC。如果ç»�过 Full GC ä»�然回收ä¸�了,那么 JVM 会抛出如下错误信æ�¯ï¼šjava.lang.OutOfMemoryError: PermGen space 为é�¿å…� PermGen å� æ»¡é€ æˆ� Full GC 现象,å�¯é‡‡ç”¨çš„æ–¹æ³•为增大 PermGen 空间或转为使用 CMS GC。 -ÔÚ JDK 1.8 ÖÐÓÃÔª¿Õ¼äÌæ»»ÁËÓÀ¾Ã´ú×÷Ϊ·½·¨ÇøµÄʵÏÖ£¬Ôª¿Õ¼äÊDZ¾µØÄڴ棬Òò´Ë¼õÉÙÁËÒ»ÖÖ Full GC ´¥·¢µÄ¿ÉÄÜÐÔ¡£ +在 JDK 1.8 中用元空间替æ�¢äº†æ°¸ä¹…代作为方法区的实现,元空间是本地内存,因此å‡�少了一ç§� Full GC 触å�‘çš„å�¯èƒ½æ€§ã€‚ ### 4.6.5 Concurrent Mode Failure -Ö´ÐÐ CMS GC µÄ¹ý³ÌÖÐͬʱÓжÔÏóÒª·ÅÈëÀÏÄê´ú£¬¶ø´ËʱÀÏÄê´ú¿Õ¼ä²»×㣨ÓÐʱºò¡°¿Õ¼ä²»×㡱ÊÇ CMS GC ʱµ±Ç°µÄ¸¡¶¯À¬»ø¹ý¶àµ¼ÖÂÔÝʱÐԵĿռ䲻×ã´¥·¢ Full GC£©£¬±ã»á±¨ Concurrent Mode Failure ´íÎ󣬲¢´¥·¢ Full GC¡£ +执行 CMS GC 的过程中å�Œæ—¶æœ‰å¯¹è±¡è¦�放入è€�年代,而此时è€�年代空间ä¸�足(有时候“空间ä¸�è¶³â€�是 CMS GC 时当å‰�的浮动垃圾过多导致暂时性的空间ä¸�足触å�‘ Full GC),便会报 Concurrent Mode Failure 错误,并触å�‘ Full GC。 -# Àà¼ÓÔØ»úÖÆ +# 类加载机制 -ÀàÊÇÔÚÔËÐÐÆÚ¼ä¶¯Ì¬¼ÓÔØµÄ¡£ +类是在è¿�行期间动æ€�加载的。 -## 1 ÀàµÄÉúÃüÖÜÆÚ +## 1 类的生命周期 -![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/32b8374a-e822-4720-af0b-c0f485095ea2.jpg) +![](https://github.com/CyC2018/InterviewNotes/blob/master/pics//32b8374a-e822-4720-af0b-c0f485095ea2.jpg) -°üÀ¨ÒÔÏ 7 ¸ö½×¶Î£º +包括以下 7 个阶段: -- **¼ÓÔØ£¨Loading£©** -- **ÑéÖ¤£¨Verification£©** -- **×¼±¸£¨Preparation£©** -- **½âÎö£¨Resolution£©** -- **³õʼ»¯£¨Initialization£©** -- ʹÓã¨Using£© -- Ð¶ÔØ£¨Unloading£© +- **加载(Loading)** +- **验è¯�(Verification)** +- **准备(Preparation)** +- **è§£æž�(Resolution)** +- **åˆ�始化(Initialization)** +- 使用(Using) +- å�¸è½½ï¼ˆUnloading) -ÆäÖнâÎö¹ý³ÌÔÚijЩÇé¿öÏ¿ÉÒÔÔÚ³õʼ»¯½×¶ÎÖ®ºóÔÙ¿ªÊ¼£¬ÕâÊÇΪÁËÖ§³Ö Java µÄ¶¯Ì¬°ó¶¨¡£ +其中解æž�过程在æŸ�些情况下å�¯ä»¥åœ¨åˆ�始化阶段之å�Žå†�开始,这是为了支æŒ� Java 的动æ€�绑定。 -## 2. Àà³õʼ»¯Ê±»ú +## 2. ç±»åˆ�始化时机 -ÐéÄâ»ú¹æ·¶Öв¢Ã»ÓÐÇ¿ÖÆÔ¼ÊøºÎʱ½øÐмÓÔØ£¬µ«Êǹ淶Ñϸñ¹æ¶¨ÁËÓÐÇÒÖ»ÓÐÏÂÁÐÎåÖÖÇé¿ö±ØÐë¶ÔÀà½øÐгõʼ»¯£º( ¼ÓÔØ¡¢ÑéÖ¤¡¢×¼±¸¶¼»áËæ×Å·¢Éú ) +虚拟机规范中并没有强制约æ�Ÿä½•时进行加载,但是规范严格规定了有且å�ªæœ‰ä¸‹åˆ—五ç§�情况必须对类进行åˆ�始化:( 加载ã€�验è¯�ã€�准备都会éš�ç�€å�‘生 ) -1. Óöµ½ new¡¢getstatic¡¢putstatic¡¢invokestatic ÕâËÄÌõ×Ö½ÚÂëÖ¸Áîʱ£¬Èç¹ûÀàûÓнøÐйý³õʼ»¯£¬Ôò±ØÐëÏÈ´¥·¢Æä³õʼ»¯¡£×î³£¼ûµÄÉú³ÉÕâ 4 ÌõÖ¸ÁîµÄ³¡¾°ÊÇ£ºÊ¹Óà new ¹Ø¼ü×ÖʵÀý»¯¶ÔÏóµÄʱºò£»¶ÁÈ¡»òÉèÖÃÒ»¸öÀàµÄ¾²Ì¬×ֶΣ¨±» final ÐÞÊΡ¢ÒÑÔÚ±àÒëÆ÷°Ñ½á¹û·ÅÈë³£Á¿³ØµÄ¾²Ì¬×ֶγýÍ⣩µÄʱºò£»ÒÔ¼°µ÷ÓÃÒ»¸öÀàµÄ¾²Ì¬·½·¨µÄʱºò¡£ +1. é�‡åˆ° newã€�getstaticã€�putstaticã€�invokestatic 这四æ�¡å­—节ç �指令时,如果类没有进行过åˆ�始化,则必须先触å�‘å…¶åˆ�始化。最常è§�的生æˆ�è¿™ 4 æ�¡æŒ‡ä»¤çš„场景是:使用 new 关键字实例化对象的时候;读å�–或设置一个类的é�™æ€�字段(被 final 修饰ã€�已在编译器把结果放入常é‡�æ± çš„é�™æ€�字段除外)的时候;以å�Šè°ƒç”¨ä¸€ä¸ªç±»çš„é�™æ€�方法的时候。 -2. ʹÓà java.lang.reflect °üµÄ·½·¨¶ÔÀà½øÐз´Éäµ÷ÓõÄʱºò£¬Èç¹ûÀàûÓнøÐгõʼ»¯£¬ÔòÐèÒªÏÈ´¥·¢Æä³õʼ»¯¡£ +2. 使用 java.lang.reflect 包的方法对类进行å��射调用的时候,如果类没有进行åˆ�始化,则需è¦�先触å�‘å…¶åˆ�始化。 -3. µ±³õʼ»¯Ò»¸öÀàµÄʱºò£¬Èç¹û·¢Ï֯䏏À໹ûÓнøÐйý³õʼ»¯£¬ÔòÐèÒªÏÈ´¥·¢Æä¸¸ÀàµÄ³õʼ»¯¡£ +3. 当åˆ�始化一个类的时候,如果å�‘现其父类还没有进行过åˆ�始化,则需è¦�先触å�‘其父类的åˆ�始化。 -4. µ±ÐéÄâ»úÆô¶¯Ê±£¬Óû§ÐèÒªÖ¸¶¨Ò»¸öÒªÖ´ÐеÄÖ÷Àࣨ°üº¬ main() ·½·¨µÄÄǸöÀࣩ£¬ÐéÄâ»ú»áÏȳõʼ»¯Õâ¸öÖ÷Àࣻ +4. 当虚拟机å�¯åŠ¨æ—¶ï¼Œç”¨æˆ·éœ€è¦�指定一个è¦�执行的主类(包å�« main() 方法的那个类),虚拟机会先åˆ�始化这个主类; -5. µ±Ê¹Óà jdk1.7 µÄ¶¯Ì¬ÓïÑÔÖ§³Öʱ£¬Èç¹ûÒ»¸ö java.lang.invoke.MethodHandle ʵÀý×îºóµÄ½âÎö½á¹ûΪ REF_getStatic, REF_putStatic, REF_invokeStatic µÄ·½·¨¾ä±ú£¬²¢ÇÒÕâ¸ö·½·¨¾ä±úËù¶ÔÓ¦µÄÀàûÓнøÐйý³õʼ»¯£¬ÔòÐèÒªÏÈ´¥·¢Æä³õʼ»¯£» +5. 当使用 jdk1.7 的动æ€�语言支æŒ�时,如果一个 java.lang.invoke.MethodHandle 实例最å�Žçš„è§£æž�结果为 REF_getStatic, REF_putStatic, REF_invokeStatic 的方法å�¥æŸ„,并且这个方法å�¥æŸ„所对应的类没有进行过åˆ�始化,则需è¦�先触å�‘å…¶åˆ�始化; -ÒÔÉÏ 5 ÖÖ³¡¾°ÖеÄÐÐΪ³ÆÎª¶ÔÒ»¸öÀà½øÐÐÖ÷¶¯ÒýÓᣳý´ËÖ®Í⣬ËùÓÐÒýÓÃÀàµÄ·½Ê½¶¼²»»á´¥·¢³õʼ»¯£¬³ÆÎª±»¶¯ÒýÓᣱ»¶¯ÒýÓõij£¼ûÀý×Ó°üÀ¨£º +以上 5 ç§�场景中的行为称为对一个类进行主动引用。除此之外,所有引用类的方å¼�都ä¸�会触å�‘åˆ�始化,称为被动引用。被动引用的常è§�例å­�包括: -1\. ͨ¹ý×ÓÀàÒýÓø¸ÀàµÄ¾²Ì¬×ֶΣ¬²»»áµ¼ÖÂ×ÓÀà³õʼ»¯¡£ +1\. 通过å­�类引用父类的é�™æ€�字段,ä¸�会导致å­�ç±»åˆ�始化。 ```java -System.out.println(SubClass.value); // value ×Ö¶ÎÔÚ SuperClass Öж¨Òå +System.out.println(SubClass.value); // value 字段在 SuperClass 中定义 ``` -2\. ͨ¹ýÊý×鶨ÒåÀ´ÒýÓÃÀ࣬²»»á´¥·¢´ËÀàµÄ³õʼ»¯¡£¸Ã¹ý³Ì»á¶ÔÊý×éÀà½øÐгõʼ»¯£¬Êý×éÀàÊÇÒ»¸öÓÉÐéÄâ»ú×Ô¶¯Éú³ÉµÄ¡¢Ö±½Ó¼Ì³Ð×Ô Object µÄ×ÓÀ࣬ÆäÖаüº¬ÁËÊý×éµÄÊôÐԺͷ½·¨¡£ +2\. 通过数组定义æ�¥å¼•用类,ä¸�会触å�‘此类的åˆ�始化。该过程会对数组类进行åˆ�始化,数组类是一个由虚拟机自动生æˆ�çš„ã€�直接继承自 Object çš„å­�类,其中包å�«äº†æ•°ç»„的属性和方法。 ```java SuperClass[] sca = new SuperClass[10]; ``` -3\. ³£Á¿ÔÚ±àÒë½×¶Î»á´æÈëµ÷ÓÃÀàµÄ³£Á¿³ØÖУ¬±¾ÖÊÉϲ¢Ã»ÓÐÖ±½ÓÒýÓõ½¶¨Òå³£Á¿µÄÀ࣬Òò´Ë²»»á´¥·¢¶¨Òå³£Á¿µÄÀàµÄ³õʼ»¯¡£ +3\. 常é‡�在编译阶段会存入调用类的常é‡�池中,本质上并没有直接引用到定义常é‡�的类,因此ä¸�会触å�‘定义常é‡�的类的åˆ�始化。 ```java System.out.println(ConstClass.HELLOWORLD); ``` -## 3. Àà¼ÓÔØ¹ý³Ì +## 3. 类加载过程 -°üº¬Á˼ÓÔØ¡¢ÑéÖ¤¡¢×¼±¸¡¢½âÎöºÍ³õʼ»¯Õâ 5 ¸ö½×¶Î¡£ +包å�«äº†åŠ è½½ã€�验è¯�ã€�准备ã€�è§£æž�å’Œåˆ�始化这 5 个阶段。 -### 3.1 ¼ÓÔØ +### 3.1 加载 -¼ÓÔØÊÇÀà¼ÓÔØµÄÒ»¸ö½×¶Î£¬×¢Òâ²»Òª»ìÏý¡£ +加载是类加载的一个阶段,注æ„�ä¸�è¦�混淆。 -¼ÓÔØ¹ý³ÌÍê³ÉÒÔÏÂÈý¼þÊ£º +加载过程完æˆ�以下三件事: -1. ͨ¹ýÒ»¸öÀàµÄÈ«ÏÞ¶¨ÃûÀ´»ñÈ¡¶¨Òå´ËÀàµÄ¶þ½øÖÆ×Ö½ÚÁ÷¡£ -2. ½«Õâ¸ö×Ö½ÚÁ÷Ëù´ú±íµÄ¾²Ì¬´æ´¢½á¹¹×ª»¯Îª·½·¨ÇøµÄÔËÐÐʱ´æ´¢½á¹¹¡£ -3. ÔÚÄÚ´æÖÐÉú³ÉÒ»¸ö´ú±íÕâ¸öÀàµÄ Class ¶ÔÏó£¬×÷Ϊ·½·¨ÇøÕâ¸öÀàµÄ¸÷ÖÖÊý¾ÝµÄ·ÃÎÊÈë¿Ú¡£ +1. 通过一个类的全é™�定å��æ�¥èŽ·å�–定义此类的二进制字节æµ�。 +2. 将这个字节æµ�所代表的é�™æ€�存储结构转化为方法区的è¿�行时存储结构。 +3. 在内存中生æˆ�一个代表这个类的 Class 对象,作为方法区这个类的å�„ç§�æ•°æ�®çš„访问入å�£ã€‚ -ÆäÖжþ½øÖÆ×Ö½ÚÁ÷¿ÉÒÔ´ÓÒÔÏ·½Ê½ÖлñÈ¡£º +其中二进制字节æµ�å�¯ä»¥ä»Žä»¥ä¸‹æ–¹å¼�中获å�–: -- ´Ó ZIP °ü¶ÁÈ¡£¬ÕâºÜ³£¼û£¬×îÖÕ³ÉΪÈÕºó JAR¡¢EAR¡¢WAR ¸ñʽµÄ»ù´¡¡£ -- ´ÓÍøÂçÖлñÈ¡£¬ÕâÖÖ³¡¾°×îµäÐ͵ÄÓ¦ÓÃÊÇ Applet¡£ -- ÔËÐÐʱ¼ÆËãÉú³É£¬ÕâÖÖ³¡¾°Ê¹ÓõÃ×î¶àµÃ¾ÍÊǶ¯Ì¬´úÀí¼¼Êõ£¬ÔÚ java.lang.reflect.Proxy ÖУ¬¾ÍÊÇÓÃÁË ProxyGenerator.generateProxyClass µÄ´úÀíÀàµÄ¶þ½øÖÆ×Ö½ÚÁ÷¡£ -- ÓÉÆäËûÎļþÉú³É£¬µäÐͳ¡¾°ÊÇ JSP Ó¦Ó㬼´ÓÉ JSP ÎļþÉú³É¶ÔÓ¦µÄ Class Àà¡£ -- ´ÓÊý¾Ý¿â¶ÁÈ¡£¬ÕâÖÖ³¡¾°Ïà¶ÔÉÙ¼û£¬ÀýÈçÓÐЩÖмä¼þ·þÎñÆ÷£¨Èç SAP Netweaver£©¿ÉÒÔÑ¡Ôñ°Ñ³ÌÐò°²×°µ½Êý¾Ý¿âÖÐÀ´Íê³É³ÌÐò´úÂëÔÚ¼¯Èº¼äµÄ·Ö·¢¡£ +- 从 ZIP 包读å�–,这很常è§�,最终æˆ�为日å�Ž JARã€�EARã€�WAR æ ¼å¼�的基础。 +- 从网络中获å�–,这ç§�场景最典型的应用是 Applet。 +- è¿�行时计算生æˆ�,这ç§�场景使用得最多得就是动æ€�代ç�†æŠ€æœ¯ï¼Œåœ¨ java.lang.reflect.Proxy 中,就是用了 ProxyGenerator.generateProxyClass 的代ç�†ç±»çš„二进制字节æµ�。 +- 由其他文件生æˆ�,典型场景是 JSP 应用,å�³ç”± JSP 文件生æˆ�对应的 Class 类。 +- 从数æ�®åº“读å�–,这ç§�场景相对少è§�,例如有些中间件æœ�务器(如 SAP Netweaver)å�¯ä»¥é€‰æ‹©æŠŠç¨‹åº�安装到数æ�®åº“中æ�¥å®Œæˆ�程åº�代ç �在集群间的分å�‘。 ... -### 3.2 ÑéÖ¤ +### 3.2 验è¯� -È·±£ Class ÎļþµÄ×Ö½ÚÁ÷Öаüº¬µÄÐÅÏ¢·ûºÏµ±Ç°ÐéÄâ»úµÄÒªÇ󣬲¢ÇÒ²»»áΣº¦ÐéÄâ»ú×ÔÉíµÄ°²È«¡£ +ç¡®ä¿� Class 文件的字节æµ�中包å�«çš„ä¿¡æ�¯ç¬¦å�ˆå½“å‰�虚拟机的è¦�求,并且ä¸�会å�±å®³è™šæ‹Ÿæœºè‡ªèº«çš„安全。 -Ö÷ÒªÓÐÒÔÏ 4 ¸ö½×¶Î£º +主è¦�有以下 4 个阶段: -1. Îļþ¸ñʽÑéÖ¤ -2. ÔªÊý¾ÝÑéÖ¤£¨¶Ô×Ö½ÚÂëÃèÊöµÄÐÅÏ¢½øÐÐÓïÒå·ÖÎö£© -3. ×Ö½ÚÂëÑéÖ¤£¨Í¨¹ýÊý¾ÝÁ÷ºÍ¿ØÖÆÁ÷·ÖÎö£¬È·±£³ÌÐòÓïÒåÊǺϷ¨¡¢·ûºÏÂß¼­µÄ£¬½«¶ÔÀàµÄ·½·¨Ìå½øÐÐУÑé·ÖÎö£© -4. ·ûºÅÒýÓÃÑéÖ¤ +1. 文件格å¼�验è¯� +2. 元数æ�®éªŒè¯�(对字节ç �æ��述的信æ�¯è¿›è¡Œè¯­ä¹‰åˆ†æž�) +3. 字节ç �验è¯�(通过数æ�®æµ�和控制æµ�分æž�,确ä¿�程åº�语义是å�ˆæ³•ã€�符å�ˆé€»è¾‘的,将对类的方法体进行校验分æž�) +4. 符å�·å¼•用验è¯� -### 3.3 ×¼±¸ +### 3.3 准备 -Àà±äÁ¿ÊDZ» static ÐÞÊεıäÁ¿£¬×¼±¸½×¶ÎΪÀà±äÁ¿·ÖÅäÄÚ´æ²¢ÉèÖóõʼֵ£¬Ê¹ÓõÄÊÇ·½·¨ÇøµÄÄÚ´æ¡£ +ç±»å�˜é‡�是被 static 修饰的å�˜é‡�,准备阶段为类å�˜é‡�分é…�内存并设置åˆ�始值,使用的是方法区的内存。 -ʵÀý±äÁ¿²»»áÔÚÕâ½×¶Î·ÖÅäÄڴ棬Ëü½«»áÔÚ¶ÔÏóʵÀý»¯Ê±Ëæ×ŶÔÏóÒ»Æð·ÖÅäÔÚ Java ¶ÑÖС£ +实例å�˜é‡�ä¸�会在这阶段分é…�内存,它将会在对象实例化时éš�ç�€å¯¹è±¡ä¸€èµ·åˆ†é…�在 Java 堆中。 -³õʼֵһ°ãΪ 0 Öµ£¬ÀýÈçÏÂÃæµÄÀà±äÁ¿ value ±»³õʼ»¯Îª 0 ¶ø²»ÊÇ 123¡£ +åˆ�始值一般为 0 值,例如下é�¢çš„ç±»å�˜é‡� value 被åˆ�始化为 0 而ä¸�是 123。 ```java public static int value = 123; ``` -Èç¹ûÀà±äÁ¿Êdz£Á¿£¬ÄÇô»á°´ÕÕ±í´ïʽÀ´½øÐгõʼ»¯£¬¶ø²»ÊǸ³ÖµÎª 0¡£ +如果类å�˜é‡�是常é‡�,那么会按照表达å¼�æ�¥è¿›è¡Œåˆ�始化,而ä¸�是赋值为 0。 ```java public static final int value = 123; ``` -### 3.4 ½âÎö +### 3.4 è§£æž� -½«³£Á¿³ØµÄ·ûºÅÒýÓÃÌæ»»ÎªÖ±½ÓÒýÓõĹý³Ì¡£ +将常é‡�池的符å�·å¼•用替æ�¢ä¸ºç›´æŽ¥å¼•用的过程。 -### 3.5 ³õʼ»¯ +### 3.5 åˆ�始化 -³õʼ»¯½×¶Î¼´ÐéÄâ»úÖ´ÐÐÀ๹ÔìÆ÷ <clinit>() ·½·¨µÄ¹ý³Ì¡£ +åˆ�始化阶段å�³è™šæ‹Ÿæœºæ‰§è¡Œç±»æž„造器 <clinit>() 方法的过程。 -ÔÚ×¼±¸½×¶Î£¬Àà±äÁ¿ÒѾ­¸³¹ýÒ»´ÎϵͳҪÇóµÄ³õʼֵ£¬¶øÔÚ³õʼ»¯½×¶Î£¬¸ù¾Ý³ÌÐòԱͨ¹ý³ÌÐòÖÆ¶¨µÄÖ÷¹Û¼Æ»®È¥³õʼ»¯Àà±äÁ¿ºÍÆäËü×ÊÔ´¡£ +在准备阶段,类å�˜é‡�å·²ç»�赋过一次系统è¦�求的åˆ�始值,而在åˆ�始化阶段,根æ�®ç¨‹åº�员通过程åº�制定的主观计划去åˆ�始化类å�˜é‡�和其它资æº�。 -<clinit>() ·½·¨¾ßÓÐÒÔÏÂÌØµã£º +<clinit>() 方法具有以下特点: -- ÊÇÓɱàÒëÆ÷×Ô¶¯ÊÕ¼¯ÀàÖÐËùÓÐÀà±äÁ¿µÄ¸³Öµ¶¯×÷ºÍ¾²Ì¬Óï¾ä¿é£¨static{} ¿é£©ÖеÄÓï¾äºÏ²¢²úÉúµÄ£¬±àÒëÆ÷ÊÕ¼¯µÄ˳ÐòÓÉÓï¾äÔÚÔ´ÎļþÖгöÏÖµÄ˳Ðò¾ö¶¨¡£Ìرð×¢ÒâµÄÊÇ£¬¾²Ì¬Óï¾ä¿éÖ»ÄÜ·ÃÎʵ½¶¨ÒåÔÚËü֮ǰµÄÀà±äÁ¿£¬¶¨ÒåÔÚËüÖ®ºóµÄÀà±äÁ¿Ö»Äܸ³Öµ£¬²»ÄÜ·ÃÎÊ¡£ÀýÈçÒÔÏ´úÂ룺 +- 是由编译器自动收集类中所有类å�˜é‡�的赋值动作和é�™æ€�语å�¥å�—(static{} å�—)中的语å�¥å�ˆå¹¶äº§ç”Ÿçš„,编译器收集的顺åº�由语å�¥åœ¨æº�文件中出现的顺åº�决定。特别注æ„�的是,é�™æ€�语å�¥å�—å�ªèƒ½è®¿é—®åˆ°å®šä¹‰åœ¨å®ƒä¹‹å‰�的类å�˜é‡�,定义在它之å�Žçš„ç±»å�˜é‡�å�ªèƒ½èµ‹å€¼ï¼Œä¸�能访问。例如以下代ç �: ```java public class Test { static { - i = 0; // ¸ø±äÁ¿¸³Öµ¿ÉÒÔÕý³£±àÒëͨ¹ý - System.out.print(i); // Õâ¾ä±àÒëÆ÷»áÌáʾ¡°·Ç·¨ÏòǰÒýÓá± + i = 0; // ç»™å�˜é‡�赋值å�¯ä»¥æ­£å¸¸ç¼–译通过 + System.out.print(i); // è¿™å�¥ç¼–译器会æ��示“é�žæ³•å�‘å‰�引用â€� } static int i = 1; } ``` -- ÓëÀàµÄ¹¹Ô캯Êý£¨»òÕß˵ʵÀý¹¹ÔìÆ÷ <init>()£©²»Í¬£¬²»ÐèÒªÏÔʽµÄµ÷Óø¸ÀàµÄ¹¹ÔìÆ÷¡£ÐéÄâ»ú»á×Ô¶¯±£Ö¤ÔÚ×ÓÀàµÄ <clinit>() ·½·¨ÔËÐÐ֮ǰ£¬¸¸ÀàµÄ <clinit>() ·½·¨ÒѾ­Ö´ÐнáÊø¡£Òò´ËÐéÄâ»úÖеÚÒ»¸öÖ´ÐÐ <clinit>() ·½·¨µÄÀà¿Ï¶¨Îª java.lang.Object¡£ +- 与类的构造函数(或者说实例构造器 <init>())ä¸�å�Œï¼Œä¸�需è¦�显å¼�的调用父类的构造器。虚拟机会自动ä¿�è¯�在å­�类的 <clinit>() 方法è¿�行之å‰�,父类的 <clinit>() 方法已ç»�执行结æ�Ÿã€‚因此虚拟机中第一个执行 <clinit>() 方法的类肯定为 java.lang.Object。 -- ÓÉÓÚ¸¸ÀàµÄ <clinit>() ·½·¨ÏÈÖ´ÐУ¬Ò²¾ÍÒâζן¸ÀàÖж¨ÒåµÄ¾²Ì¬Óï¾ä¿éÒªÓÅÓÚ×ÓÀàµÄ±äÁ¿¸³Öµ²Ù×÷¡£ÀýÈçÒÔÏ´úÂ룺 +- 由于父类的 <clinit>() 方法先执行,也就æ„�味ç�€çˆ¶ç±»ä¸­å®šä¹‰çš„é�™æ€�语å�¥å�—è¦�优于å­�类的å�˜é‡�赋值æ“�作。例如以下代ç �: ```java static class Parent { @@ -573,53 +574,53 @@ static class Sub extends Parent { } public static void main(String[] args) { - System.out.println(Sub.B); // Êä³ö½á¹ûÊǸ¸ÀàÖеľ²Ì¬±äÁ¿Öµ A£¬Ò²¾ÍÊÇ 2 + System.out.println(Sub.B); // 输出结果是父类中的é�™æ€�å�˜é‡�值 A,也就是 2 } ``` -- <clinit>() ·½·¨¶ÔÓÚÀà»ò½Ó¿Ú²»ÊDZØÐëµÄ£¬Èç¹ûÒ»¸öÀàÖв»°üº¬¾²Ì¬Óï¾ä¿é£¬Ò²Ã»ÓжÔÀà±äÁ¿µÄ¸³Öµ²Ù×÷£¬±àÒëÆ÷¿ÉÒÔ²»Îª¸ÃÀàÉú³É <clinit>() ·½·¨¡£ +- <clinit>() 方法对于类或接å�£ä¸�是必须的,如果一个类中ä¸�包å�«é�™æ€�语å�¥å�—,也没有对类å�˜é‡�的赋值æ“�作,编译器å�¯ä»¥ä¸�为该类生æˆ� <clinit>() 方法。 -- ½Ó¿ÚÖв»¿ÉÒÔʹÓþ²Ì¬Óï¾ä¿é£¬µ«ÈÔÈ»ÓÐÀà±äÁ¿³õʼ»¯µÄ¸³Öµ²Ù×÷£¬Òò´Ë½Ó¿ÚÓëÀàÒ»Ñù¶¼»áÉú³É <clinit>() ·½·¨¡£µ«½Ó¿ÚÓëÀ಻ͬµÄÊÇ£¬Ö´ÐÐ½Ó¿ÚµÄ <clinit>() ·½·¨²»ÐèÒªÏÈÖ´Ðи¸½Ó¿ÚµÄ <clinit>() ·½·¨¡£Ö»Óе±¸¸½Ó¿ÚÖж¨ÒåµÄ±äÁ¿Ê¹ÓÃʱ£¬¸¸½Ó¿Ú²Å»á³õʼ»¯¡£ÁíÍ⣬½Ó¿ÚµÄʵÏÖÀàÔÚ³õʼ»¯Ê±Ò²Ò»Ñù²»»áÖ´ÐÐ½Ó¿ÚµÄ <clinit>() ·½·¨¡£ +- 接å�£ä¸­ä¸�å�¯ä»¥ä½¿ç”¨é�™æ€�语å�¥å�—,但ä»�然有类å�˜é‡�åˆ�始化的赋值æ“�作,因此接å�£ä¸Žç±»ä¸€æ ·éƒ½ä¼šç”Ÿæˆ� <clinit>() 方法。但接å�£ä¸Žç±»ä¸�å�Œçš„æ˜¯ï¼Œæ‰§è¡ŒæŽ¥å�£çš„ <clinit>() 方法ä¸�需è¦�先执行父接å�£çš„ <clinit>() 方法。å�ªæœ‰å½“父接å�£ä¸­å®šä¹‰çš„å�˜é‡�使用时,父接å�£æ‰�会åˆ�始化。å�¦å¤–,接å�£çš„实现类在åˆ�始化时也一样ä¸�会执行接å�£çš„ <clinit>() 方法。 -- ÐéÄâ»ú»á±£Ö¤Ò»¸öÀàµÄ <clinit>() ·½·¨ÔÚ¶àÏ̻߳·¾³Ï±»ÕýÈ·µÄ¼ÓËøºÍͬ²½£¬Èç¹û¶à¸öÏß³Ìͬʱ³õʼ»¯Ò»¸öÀֻ࣬»áÓÐÒ»¸öÏß³ÌÖ´ÐÐÕâ¸öÀàµÄ <clinit>() ·½·¨£¬ÆäËüÏ̶߳¼»á×èÈûµÈ´ý£¬Ö±µ½»î¶¯Ïß³ÌÖ´ÐÐ <clinit>() ·½·¨Íê±Ï¡£Èç¹ûÔÚÒ»¸öÀàµÄ <clinit>() ·½·¨ÖÐÓкÄʱµÄ²Ù×÷£¬¾Í¿ÉÄÜÔì³É¶à¸ö½ø³Ì×èÈû£¬ÔÚʵ¼Ê¹ý³ÌÖдËÖÖ×èÈûºÜÒþ±Î¡£ +- 虚拟机会ä¿�è¯�一个类的 <clinit>() 方法在多线程环境下被正确的加é”�å’Œå�Œæ­¥ï¼Œå¦‚果多个线程å�Œæ—¶åˆ�始化一个类,å�ªä¼šæœ‰ä¸€ä¸ªçº¿ç¨‹æ‰§è¡Œè¿™ä¸ªç±»çš„ <clinit>() 方法,其它线程都会阻塞等待,直到活动线程执行 <clinit>() 方法完毕。如果在一个类的 <clinit>() 方法中有耗时的æ“�作,就å�¯èƒ½é€ æˆ�多个进程阻塞,在实际过程中此ç§�阻塞很éš�蔽。 -## 4. Àà¼ÓÔØÆ÷ +## 4. 类加载器 -ÐéÄâ»úÉè¼ÆÍŶӰÑÀà¼ÓÔØ½×¶ÎÖеġ°Í¨¹ýÒ»¸öÀàµÄÈ«ÏÞ¶¨ÃûÀ´»ñÈ¡ÃèÊö´ËÀàµÄ¶þ½øÖÆ×Ö½ÚÁ÷ ( ¼´×Ö½ÚÂë )¡±Õâ¸ö¶¯×÷·Åµ½ Java ÐéÄâ»úÍⲿȥʵÏÖ£¬ÒÔ±ãÈÃÓ¦ÓóÌÐò×Ô¼º¾ö¶¨ÈçºÎÈ¥»ñÈ¡ËùÐèÒªµÄÀࡣʵÏÖÕâ¸ö¶¯×÷µÄ´úÂëÄ£¿é³ÆÎª¡°Àà¼ÓÔØÆ÷¡±¡£ +虚拟机设计团队把类加载阶段中的“通过一个类的全é™�定å��æ�¥èŽ·å�–æ��述此类的二进制字节æµ� ( å�³å­—节ç � )â€�这个动作放到 Java 虚拟机外部去实现,以便让应用程åº�自己决定如何去获å�–所需è¦�的类。实现这个动作的代ç �模å�—称为“类加载器â€�。 -### 4.1 ÀàÓëÀà¼ÓÔØÆ÷ +### 4.1 类与类加载器 -¶ÔÓÚÈÎÒâÒ»¸öÀ࣬¶¼ÐèÒªÓɼÓÔØËüµÄÀà¼ÓÔØÆ÷ºÍÕâ¸öÀà±¾ÉíһͬȷÁ¢ÆäÔÚ Java ÐéÄâ»úÖеÄΨһÐÔ£¬Ã¿Ò»¸öÀà¼ÓÔØÆ÷£¬¶¼ÓµÓÐÒ»¸ö¶ÀÁ¢µÄÀàÃû³Æ¿Õ¼ä¡£Í¨Ë×¶øÑÔ£º±È½ÏÁ½¸öÀàÊÇ·ñ¡°ÏàµÈ¡±£¨ÕâÀïËùÖ¸µÄ¡°ÏàµÈ¡±£¬°üÀ¨ÀàµÄ Class ¶ÔÏóµÄ equals() ·½·¨¡¢isAssignableFrom() ·½·¨¡¢isInstance() ·½·¨µÄ·µ»Ø½á¹û£¬Ò²°üÀ¨Ê¹Óà instanceof() ¹Ø¼ü×Ö¶Ô×ö¶ÔÏóËùÊô¹ØÏµÅж¨µÈÇé¿ö£©£¬Ö»ÓÐÔÚÕâÁ½¸öÀàʱÓÉͬһ¸öÀà¼ÓÔØÆ÷¼ÓÔØµÄǰÌáϲÅÓÐÒâÒ壬·ñÔò£¬¼´Ê¹ÕâÁ½¸öÀàÀ´Ô´ÓÚͬһ¸ö Class Îļþ£¬±»Í¬Ò»¸öÐéÄâ»ú¼ÓÔØ£¬Ö»Òª¼ÓÔØËüÃǵÄÀà¼ÓÔØÆ÷²»Í¬£¬ÄÇÕâÁ½¸öÀà¾Í±Ø¶¨²»ÏàµÈ¡£ +对于任æ„�一个类,都需è¦�由加载它的类加载器和这个类本身一å�Œç¡®ç«‹å…¶åœ¨ Java 虚拟机中的唯一性,æ¯�一个类加载器,都拥有一个独立的类å��称空间。通俗而言:比较两个类是å�¦â€œç›¸ç­‰â€�(这里所指的“相等â€�,包括类的 Class 对象的 equals() 方法ã€�isAssignableFrom() 方法ã€�isInstance() 方法的返回结果,也包括使用 instanceof() 关键字对å�šå¯¹è±¡æ‰€å±žå…³ç³»åˆ¤å®šç­‰æƒ…况),å�ªæœ‰åœ¨è¿™ä¸¤ä¸ªç±»æ—¶ç”±å�Œä¸€ä¸ªç±»åŠ è½½å™¨åŠ è½½çš„å‰�æ��下æ‰�有æ„�义,å�¦åˆ™ï¼Œå�³ä½¿è¿™ä¸¤ä¸ªç±»æ�¥æº�于å�Œä¸€ä¸ª Class 文件,被å�Œä¸€ä¸ªè™šæ‹ŸæœºåŠ è½½ï¼Œå�ªè¦�加载它们的类加载器ä¸�å�Œï¼Œé‚£è¿™ä¸¤ä¸ªç±»å°±å¿…定ä¸�相等。 -### 4.2 Àà¼ÓÔØÆ÷·ÖÀà +### 4.2 类加载器分类 -´Ó Java ÐéÄâ»úµÄ½Ç¶ÈÀ´½²£¬Ö»´æÔÚÒÔÏÂÁ½ÖÖ²»Í¬µÄÀà¼ÓÔØÆ÷£º +从 Java 虚拟机的角度æ�¥è®²ï¼Œå�ªå­˜åœ¨ä»¥ä¸‹ä¸¤ç§�ä¸�å�Œçš„类加载器: -Ò»ÖÖÊÇÆô¶¯Àà¼ÓÔØÆ÷£¨Bootstrap ClassLoader£©£¬Õâ¸öÀà¼ÓÔØÆ÷Óà C++ ʵÏÖ£¬ÊÇÐéÄâ»ú×ÔÉíµÄÒ»²¿·Ö£»ÁíÒ»ÖÖ¾ÍÊÇËùÓÐÆäËûÀàµÄ¼ÓÔØÆ÷£¬ÕâЩÀàÓÉ Java ʵÏÖ£¬¶ÀÁ¢ÓÚÐéÄâ»úÍⲿ£¬²¢ÇÒÈ«¶¼¼Ì³Ð×Ô³éÏóÀà java.lang.ClassLoader¡£ +一ç§�是å�¯åŠ¨ç±»åŠ è½½å™¨ï¼ˆBootstrap ClassLoader),这个类加载器用 C++ 实现,是虚拟机自身的一部分;å�¦ä¸€ç§�就是所有其他类的加载器,这些类由 Java 实现,独立于虚拟机外部,并且全都继承自抽象类 java.lang.ClassLoader。 -´Ó Java ¿ª·¢ÈËÔ±µÄ½Ç¶È¿´£¬Àà¼ÓÔØÆ÷¿ÉÒÔ»®·ÖµÃ¸üϸÖÂһЩ£º +从 Java å¼€å�‘人员的角度看,类加载器å�¯ä»¥åˆ’分得更细致一些: -- Æô¶¯Àà¼ÓÔØÆ÷£¨Bootstrap ClassLoader£© ´ËÀà¼ÓÔØÆ÷¸ºÔ𽫴æ·ÅÔÚ \lib Ŀ¼Öе쬻òÕß±» -Xbootclasspath ²ÎÊýËùÖ¸¶¨µÄ·¾¶Öе쬲¢ÇÒÊÇÐéÄâ»úʶ±ðµÄ£¨½ö°´ÕÕÎļþÃûʶ±ð£¬Èç rt.jar£¬Ãû×Ö²»·ûºÏµÄÀà¿â¼´Ê¹·ÅÔÚ lib Ŀ¼ÖÐÒ²²»»á±»¼ÓÔØ£©Àà¿â¼ÓÔØµ½ÐéÄâ»úÄÚ´æÖС£ Æô¶¯Àà¼ÓÔØÆ÷ÎÞ·¨±» Java ³ÌÐòÖ±½ÓÒýÓã¬Óû§ÔÚ±àд×Ô¶¨ÒåÀà¼ÓÔØÆ÷ʱ£¬Èç¹ûÐèÒª°Ñ¼ÓÔØÇëÇóίÅɸøÒýµ¼Àà¼ÓÔØÆ÷£¬Ö±½ÓʹÓà null ´úÌæ¼´¿É¡£ +- å�¯åŠ¨ç±»åŠ è½½å™¨ï¼ˆBootstrap ClassLoader) 此类加载器负责将存放在 \lib 目录中的,或者被 -Xbootclasspath å�‚数所指定的路径中的,并且是虚拟机识别的(仅按照文件å��识别,如 rt.jar,å��å­—ä¸�符å�ˆçš„类库å�³ä½¿æ”¾åœ¨ lib 目录中也ä¸�会被加载)类库加载到虚拟机内存中。 å�¯åŠ¨ç±»åŠ è½½å™¨æ— æ³•è¢« Java 程åº�直接引用,用户在编写自定义类加载器时,如果需è¦�把加载请求委派给引导类加载器,直接使用 null 代替å�³å�¯ã€‚ -- À©Õ¹Àà¼ÓÔØÆ÷£¨Extension ClassLoader£© Õâ¸öÀà¼ÓÔØÆ÷ÊÇÓÉ ExtClassLoader£¨sun.misc.Launcher$ExtClassLoader£©ÊµÏֵġ£Ëü¸ºÔ𽫠/lib/ext »òÕß±» java.ext.dir ϵͳ±äÁ¿ËùÖ¸¶¨Â·¾¶ÖеÄËùÓÐÀà¿â¼ÓÔØµ½ÄÚ´æÖУ¬¿ª·¢Õß¿ÉÒÔÖ±½ÓʹÓÃÀ©Õ¹Àà¼ÓÔØÆ÷¡£ +- 扩展类加载器(Extension ClassLoader) 这个类加载器是由 ExtClassLoader(sun.misc.Launcher$ExtClassLoader)实现的。它负责将 /lib/ext 或者被 java.ext.dir 系统å�˜é‡�所指定路径中的所有类库加载到内存中,开å�‘者å�¯ä»¥ç›´æŽ¥ä½¿ç”¨æ‰©å±•类加载器。 -- Ó¦ÓóÌÐòÀà¼ÓÔØÆ÷£¨Application ClassLoader£© Õâ¸öÀà¼ÓÔØÆ÷ÊÇÓÉ AppClassLoader£¨sun.misc.Launcher$AppClassLoader£©ÊµÏֵġ£ÓÉÓÚÕâ¸öÀà¼ÓÔØÆ÷ÊÇ ClassLoader ÖÐµÄ getSystemClassLoader() ·½·¨µÄ·µ»ØÖµ£¬Òò´ËÒ»°ã³ÆÎªÏµÍ³Àà¼ÓÔØÆ÷¡£Ëü¸ºÔð¼ÓÔØÓû§Àà·¾¶£¨ClassPath£©ÉÏËùÖ¸¶¨µÄÀà¿â£¬¿ª·¢Õß¿ÉÒÔÖ±½ÓʹÓÃÕâ¸öÀà¼ÓÔØÆ÷£¬Èç¹ûÓ¦ÓóÌÐòÖÐûÓÐ×Ô¶¨Òå¹ý×Ô¼ºµÄÀà¼ÓÔØÆ÷£¬Ò»°ãÇé¿öÏÂÕâ¸ö¾ÍÊdzÌÐòÖÐĬÈϵÄÀà¼ÓÔØÆ÷¡£ +- 应用程åº�类加载器(Application ClassLoader) 这个类加载器是由 AppClassLoader(sun.misc.Launcher$AppClassLoader)实现的。由于这个类加载器是 ClassLoader 中的 getSystemClassLoader() 方法的返回值,因此一般称为系统类加载器。它负责加载用户类路径(ClassPath)上所指定的类库,开å�‘者å�¯ä»¥ç›´æŽ¥ä½¿ç”¨è¿™ä¸ªç±»åŠ è½½å™¨ï¼Œå¦‚æžœåº”ç”¨ç¨‹åº�中没有自定义过自己的类加载器,一般情况下这个就是程åº�中默认的类加载器。 -### 4.3 Ë«Ç×ίÅÉÄ£ÐÍ +### 4.3 å�Œäº²å§”派模型 -Ó¦ÓóÌÐò¶¼ÊÇÓÉÈýÖÖÀà¼ÓÔØÆ÷Ï໥ÅäºÏ½øÐмÓÔØµÄ£¬Èç¹ûÓбØÒª£¬»¹¿ÉÒÔ¼ÓÈë×Ô¼º¶¨ÒåµÄÀà¼ÓÔØÆ÷¡£ÏÂͼչʾµÄÀà¼ÓÔØÆ÷Ö®¼äµÄ²ã´Î¹ØÏµ£¬³ÆÎªÀà¼ÓÔØÆ÷µÄË«Ç×ίÅÉÄ£ÐÍ£¨Parents Delegation Model£©¡£¸ÃÄ£ÐÍÒªÇó³ýÁ˶¥²ãµÄÆô¶¯Àà¼ÓÔØÆ÷Í⣬ÆäÓàµÄÀà¼ÓÔØÆ÷¶¼Ó¦ÓÐ×Ô¼ºµÄ¸¸Àà¼ÓÔØÆ÷£¬ÕâÀïÀà¼ÓÔØÆ÷Ö®¼äµÄ¸¸×Ó¹ØÏµÒ»°ãͨ¹ý×éºÏ£¨Composition£©¹ØÏµÀ´ÊµÏÖ£¬¶ø²»ÊÇͨ¹ý¼Ì³Ð£¨Inheritance£©µÄ¹ØÏµÊµÏÖ¡£ +应用程åº�都是由三ç§�类加载器相互é…�å�ˆè¿›è¡ŒåŠ è½½çš„ï¼Œå¦‚æžœæœ‰å¿…è¦�,还å�¯ä»¥åŠ å…¥è‡ªå·±å®šä¹‰çš„ç±»åŠ è½½å™¨ã€‚ä¸‹å›¾å±•ç¤ºçš„ç±»åŠ è½½å™¨ä¹‹é—´çš„å±‚æ¬¡å…³ç³»ï¼Œç§°ä¸ºç±»åŠ è½½å™¨çš„å�Œäº²å§”派模型(Parents Delegation Model)。该模型è¦�求除了顶层的å�¯åŠ¨ç±»åŠ è½½å™¨å¤–ï¼Œå…¶ä½™çš„ç±»åŠ è½½å™¨éƒ½åº”æœ‰è‡ªå·±çš„çˆ¶ç±»åŠ è½½å™¨ï¼Œè¿™é‡Œç±»åŠ è½½å™¨ä¹‹é—´çš„çˆ¶å­�关系一般通过组å�ˆï¼ˆComposition)关系æ�¥å®žçŽ°ï¼Œè€Œä¸�是通过继承(Inheritance)的关系实现。 -![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/2cdc3ce2-fa82-4c22-baaa-000c07d10473.jpg) +![](https://github.com/CyC2018/InterviewNotes/blob/master/pics//2cdc3ce2-fa82-4c22-baaa-000c07d10473.jpg) -**¹¤×÷¹ý³Ì** +**工作过程** -Èç¹ûÒ»¸öÀà¼ÓÔØÆ÷ÊÕµ½ÁËÀà¼ÓÔØµÄÇëÇó£¬ËüÊ×ÏȲ»»á×Ô¼ºÈ¥³¢ÊÔ¼ÓÔØ£¬¶øÊǰÑÕâ¸öÇëÇóίÅɸø¸¸Àà¼ÓÔØÆ÷£¬Ã¿Ò»¸ö²ã´ÎµÄ¼ÓÔØÆ÷¶¼ÊÇÈç´Ë£¬ÒÀ´ÎµÝ¹é£¬Òò´ËËùÓеļÓÔØÇëÇó×îÖÕ¶¼Ó¦¸Ã´«Ë͵½¶¥²ãµÄÆô¶¯Àà¼ÓÔØÆ÷ÖУ¬Ö»Óе±¸¸¼ÓÔØÆ÷·´À¡×Ô¼ºÎÞ·¨Íê³É´Ë¼ÓÔØÇëÇó£¨ËüËÑË÷·¶Î§ÖÐûÓÐÕÒµ½ËùÐèÀࣩʱ£¬×Ó¼ÓÔØÆ÷²Å»á³¢ÊÔ×Ô¼º¼ÓÔØ¡£ +如果一个类加载器收到了类加载的请求,它首先ä¸�会自己去å°�试加载,而是把这个请求委派给父类加载器,æ¯�一个层次的加载器都是如此,ä¾�次递归,因此所有的加载请求最终都应该传é€�到顶层的å�¯åŠ¨ç±»åŠ è½½å™¨ä¸­ï¼Œå�ªæœ‰å½“父加载器å��馈自己无法完æˆ�此加载请求(它æ�œç´¢èŒƒå›´ä¸­æ²¡æœ‰æ‰¾åˆ°æ‰€éœ€ç±»ï¼‰æ—¶ï¼Œå­�加载器æ‰�会å°�试自己加载。 -**ºÃ´¦** +**好处** -ʹÓÃË«Ç×ίÅÉÄ£ÐÍÀ´×éÖ¯Àà¼ÓÔØÆ÷Ö®¼äµÄ¹ØÏµ£¬Ê¹µÃ Java ÀàËæ×ÅËüµÄÀà¼ÓÔØÆ÷Ò»Æð¾ß±¸ÁËÒ»ÖÖ´øÓÐÓÅÏȼ¶µÄ²ã´Î¹ØÏµ¡£ÀýÈçÀà java.lang.Object£¬Ëü´æ·ÅÔÙ rt.jar ÖУ¬ÎÞÂÛÄĸöÀà¼ÓÔØÆ÷Òª¼ÓÔØÕâ¸öÀ࣬×îÖÕ¶¼ÊÇίÅɸø´¦ÓÚÄ£ÐÍ×î¶¥¶ËµÄÆô¶¯Àà¼ÓÔØÆ÷½øÐмÓÔØ£¬Òò´Ë Object ÀàÔÚ³ÌÐòµÄ¸÷ÖÖÀà¼ÓÔØÆ÷»·¾³Öж¼ÊÇͬһ¸öÀà¡£Ïà·´£¬Èç¹ûûÓÐË«Ç×ίÅÉÄ£ÐÍ£¬Óɸ÷¸öÀà¼ÓÔØÆ÷×ÔÐмÓÔØµÄ»°£¬Èç¹ûÓû§±àдÁËÒ»¸ö³ÆÎª£àjava.lang.Object µÄÀ࣬²¢·ÅÔÚ³ÌÐòµÄ ClassPath ÖУ¬ÄÇϵͳÖн«»á³öÏÖ¶à¸ö²»Í¬µÄ Object À࣬³ÌÐò½«±äµÃһƬ»ìÂÒ¡£Èç¹û¿ª·¢Õß³¢ÊÔ±àдһ¸öÓë rt.jar Àà¿âÖÐÒÑÓÐÀàÖØÃûµÄ Java À࣬½«»á·¢ÏÖ¿ÉÒÔÕý³£±àÒ룬µ«ÊÇÓÀÔ¶ÎÞ·¨±»¼ÓÔØÔËÐС£ +使用å�Œäº²å§”派模型æ�¥ç»„织类加载器之间的关系,使得 Java ç±»éš�ç�€å®ƒçš„类加载器一起具备了一ç§�带有优先级的层次关系。例如类 java.lang.Object,它存放å†� rt.jar 中,无论哪个类加载器è¦�加载这个类,最终都是委派给处于模型最顶端的å�¯åŠ¨ç±»åŠ è½½å™¨è¿›è¡ŒåŠ è½½ï¼Œå› æ­¤ Object 类在程åº�çš„å�„ç§�类加载器环境中都是å�Œä¸€ä¸ªç±»ã€‚相å��,如果没有å�Œäº²å§”派模型,由å�„个类加载器自行加载的è¯�,如果用户编写了一个称为`java.lang.Object 的类,并放在程åº�çš„ ClassPath 中,那系统中将会出现多个ä¸�å�Œçš„ Object 类,程åº�å°†å�˜å¾—一片混乱。如果开å�‘者å°�试编写一个与 rt.jar 类库中已有类é‡�å��çš„ Java 类,将会å�‘现å�¯ä»¥æ­£å¸¸ç¼–译,但是永远无法被加载è¿�行。 -**ʵÏÖ** +**实现** ```java protected synchronized Class loadClass(String name, boolean resolve) throws ClassNotFoundException{ @@ -646,27 +647,27 @@ protected synchronized Class loadClass(String name, boolean resolve) throws C } ``` -# JVM ²ÎÊý +# JVM å�‚æ•° -## GC ÓÅ»¯ÅäÖà +## GC 优化é…�ç½® -| ÅäÖà | ÃèÊö | +| é…�ç½® | æ��è¿° | | --- | --- | -| -Xms | ³õʼ»¯¶ÑÄÚ´æ´óС | -| -Xmx | ¶ÑÄÚ´æ×î´óÖµ | -| -Xmn | ÐÂÉú´ú´óС | -| -XX:PermSize | ³õʼ»¯ÓÀ¾Ã´ú´óС | -| -XX:MaxPermSize | ÓÀ¾Ã´ú×î´óÈÝÁ¿ | +| -Xms | åˆ�始化堆内存大å°� | +| -Xmx | 堆内存最大值 | +| -Xmn | 新生代大å°� | +| -XX:PermSize | åˆ�始化永久代大å°� | +| -XX:MaxPermSize | 永久代最大容é‡� | -## GC ÀàÐÍÉèÖà +## GC 类型设置 -| ÅäÖà | ÃèÊö | +| é…�ç½® | æ��è¿° | | --- | --- | -| -XX:+UseSerialGC | ´®ÐÐÀ¬»ø»ØÊÕÆ÷ | -| -XX:+UseParallelGC | ²¢ÐÐÀ¬»ø»ØÊÕÆ÷ | -| -XX:+UseConcMarkSweepGC | ²¢·¢±ê¼ÇɨÃèÀ¬»ø»ØÊÕÆ÷ | -| -XX:ParallelCMSThreads= | ²¢·¢±ê¼ÇɨÃèÀ¬»ø»ØÊÕÆ÷ = ΪʹÓõÄÏß³ÌÊýÁ¿ | -| -XX:+UseG1GC | G1 À¬»ø»ØÊÕÆ÷ | +| -XX:+UseSerialGC | 串行垃圾回收器 | +| -XX:+UseParallelGC | 并行垃圾回收器 | +| -XX:+UseConcMarkSweepGC | å¹¶å�‘标记扫æ��垃圾回收器 | +| -XX:ParallelCMSThreads= | å¹¶å�‘标记扫æ��垃圾回收器 = 为使用的线程数é‡� | +| -XX:+UseG1GC | G1 垃圾回收器 | ```java java -Xmx12m -Xms3m -Xmn1m -XX:PermSize=20m -XX:MaxPermSize=20m -XX:+UseSerialGC -jar java-application.jar diff --git a/notes/Java IO.md b/notes/Java IO.md index c4aa5d39..1737ca9d 100644 --- a/notes/Java IO.md +++ b/notes/Java IO.md @@ -1,129 +1,130 @@ -* [¸ÅÀÀ](#¸ÅÀÀ) -* [´ÅÅ̲Ù×÷](#´ÅÅ̲Ù×÷) -* [×Ö½Ú²Ù×÷](#×Ö½Ú²Ù×÷) -* [×Ö·û²Ù×÷](#×Ö·û²Ù×÷) -* [¶ÔÏó²Ù×÷](#¶ÔÏó²Ù×÷) -* [ÍøÂç²Ù×÷](#ÍøÂç²Ù×÷) +* [概览](#概览) +* [ç£�盘æ“�作](#ç£�盘æ“�作) +* [字节æ“�作](#字节æ“�作) +* [字符æ“�作](#字符æ“�作) +* [对象æ“�作](#对象æ“�作) +* [网络æ“�作](#网络æ“�作) * [1. InetAddress](#1-inetaddress) * [2. URL](#2-url) * [3. Sockets](#3-sockets) * [4. Datagram](#4-datagram) * [NIO](#nio) - * [1. Á÷Óë¿é](#1-Á÷Óë¿é) - * [2. ͨµÀÓ뻺³åÇø](#2-ͨµÀÓ뻺³åÇø) - * [2.1 ͨµÀ](#21-ͨµÀ) - * [2.2 »º³åÇø](#22-»º³åÇø) - * [3. »º³åÇø×´Ì¬±äÁ¿](#3-»º³åÇø×´Ì¬±äÁ¿) - * [4. ¶ÁдÎļþʵÀý](#4-¶ÁдÎļþʵÀý) - * [5. ×èÈûÓë·Ç×èÈû](#5-×èÈûÓë·Ç×èÈû) - * [5.1 ×èÈûʽ I/O](#51-×èÈûʽ-io) - * [5.2 ·Ç×èÈûʽ I/O](#52-·Ç×èÈûʽ-io) - * [6. Ì×½Ó×ÖʵÀý](#6-Ì×½Ó×ÖʵÀý) + * [1. æµ�与å�—](#1-æµ�与å�—) + * [2. 通é�“与缓冲区](#2-通é�“与缓冲区) + * [2.1 通é�“](#21-通é�“) + * [2.2 缓冲区](#22-缓冲区) + * [3. 缓冲区状æ€�å�˜é‡�](#3-缓冲区状æ€�å�˜é‡�) + * [4. 读写文件实例](#4-读写文件实例) + * [5. 阻塞与é�žé˜»å¡ž](#5-阻塞与é�žé˜»å¡ž) + * [5.1 阻塞å¼� I/O](#51-阻塞å¼�-io) + * [5.2 é�žé˜»å¡žå¼� I/O](#52-é�žé˜»å¡žå¼�-io) + * [6. 套接字实例](#6-套接字实例) * [6.1 ServerSocketChannel](#61-serversocketchannel) * [6.2 Selectors](#62-selectors) - * [6.3 Ö÷Ñ­»·](#63-Ö÷Ñ­»·) - * [6.4 ¼àÌýÐÂÁ¬½Ó](#64-¼àÌýÐÂÁ¬½Ó) - * [6.5 ½ÓÊÜеÄÁ¬½Ó](#65-½ÓÊÜеÄÁ¬½Ó) - * [6.6 ɾ³ý´¦Àí¹ýµÄ SelectionKey](#66-ɾ³ý´¦Àí¹ýµÄ-selectionkey) - * [6.7 ´«ÈëµÄ I/O](#67-´«ÈëµÄ-io) -* [²Î¿¼×ÊÁÏ](#²Î¿¼×ÊÁÏ) + * [6.3 主循环](#63-主循环) + * [6.4 监å�¬æ–°è¿žæŽ¥](#64-监å�¬æ–°è¿žæŽ¥) + * [6.5 接å�—新的连接](#65-接å�—新的连接) + * [6.6 删除处ç�†è¿‡çš„ SelectionKey](#66-删除处ç�†è¿‡çš„-selectionkey) + * [6.7 传入的 I/O](#67-传入的-io) +* [å�‚考资料](#å�‚考资料) -# ¸ÅÀÀ -Java µÄ I/O ´ó¸Å¿ÉÒÔ·Ö³ÉÒÔϼ¸Àà +# 概览 -1. ´ÅÅ̲Ù×÷£ºFile -2. ×Ö½Ú²Ù×÷£ºInputStream ºÍ OutputStream -3. ×Ö·û²Ù×÷£ºReader ºÍ Writer -4. ¶ÔÏó²Ù×÷£ºSerializable -5. ÍøÂç²Ù×÷£ºSocket -6. ·Ç×èÈûʽ IO£ºNIO +Java çš„ I/O 大概å�¯ä»¥åˆ†æˆ�以下几类 -# ´ÅÅ̲Ù×÷ +1. ç£�盘æ“�作:File +2. 字节æ“�作:InputStream å’Œ OutputStream +3. 字符æ“�作:Reader å’Œ Writer +4. 对象æ“�作:Serializable +5. 网络æ“�作:Socket +6. é�žé˜»å¡žå¼� IO:NIO -File Àà¿ÉÒÔÓÃÓÚ±íʾÎļþºÍĿ¼£¬µ«ÊÇËüÖ»ÓÃÓÚ±íʾÎļþµÄÐÅÏ¢£¬¶ø²»±íʾÎļþµÄÄÚÈÝ¡£ +# ç£�盘æ“�作 -# ×Ö½Ú²Ù×÷ +File ç±»å�¯ä»¥ç”¨äºŽè¡¨ç¤ºæ–‡ä»¶å’Œç›®å½•,但是它å�ªç”¨äºŽè¡¨ç¤ºæ–‡ä»¶çš„ä¿¡æ�¯ï¼Œè€Œä¸�表示文件的内容。 -![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/8143787f-12eb-46ea-9bc3-c66d22d35285.jpg) +# 字节æ“�作 -Java I/O ʹÓÃÁË×°ÊÎÕßģʽÀ´ÊµÏÖ¡£ÒÔ InputStream ΪÀý£¬InputStream ÊdzéÏó×é¼þ£¬FileInputStream ÊÇ InputStream µÄ×ÓÀ࣬ÊôÓÚ¾ßÌå×é¼þ£¬ÌṩÁË×Ö½ÚÁ÷µÄÊäÈë²Ù×÷¡£FilterInputStream ÊôÓÚ³éÏó×°ÊÎÕߣ¬×°ÊÎÕßÓÃÓÚ×°ÊÎ×é¼þ£¬Îª×é¼þÌṩ¶îÍâµÄ¹¦ÄÜ£¬ÀýÈç BufferedInputStream Ϊ FileInputStream Ìṩ»º´æµÄ¹¦ÄÜ¡£ÊµÀý»¯Ò»¸ö¾ßÓлº´æ¹¦ÄܵÄ×Ö½ÚÁ÷¶ÔÏóʱ£¬Ö»ÐèÒªÔÚ FileInputStream ¶ÔÏóÉÏÔÙÌ×Ò»²ã BufferedInputStream ¶ÔÏó¼´¿É¡£ +![](https://github.com/CyC2018/InterviewNotes/blob/master/pics//8143787f-12eb-46ea-9bc3-c66d22d35285.jpg) + +Java I/O 使用了装饰者模å¼�æ�¥å®žçŽ°ã€‚ä»¥ InputStream 为例,InputStream 是抽象组件,FileInputStream 是 InputStream çš„å­�类,属于具体组件,æ��供了字节æµ�的输入æ“�作。FilterInputStream 属于抽象装饰者,装饰者用于装饰组件,为组件æ��ä¾›é¢�外的功能,例如 BufferedInputStream 为 FileInputStream æ��供缓存的功能。实例化一个具有缓存功能的字节æµ�对象时,å�ªéœ€è¦�在 FileInputStream 对象上å†�套一层 BufferedInputStream 对象å�³å�¯ã€‚ ```java BufferedInputStream bis = new BufferedInputStream(new FileInputStream(file)); ``` -DataInputStream ×°ÊÎÕßÌṩÁ˶Ըü¶àÊý¾ÝÀàÐͽøÐÐÊäÈëµÄ²Ù×÷£¬±ÈÈç int¡¢double µÈ»ù±¾ÀàÐÍ¡£ +DataInputStream 装饰者æ��供了对更多数æ�®ç±»åž‹è¿›è¡Œè¾“入的æ“�作,比如 intã€�double 等基本类型。 -ÅúÁ¿¶ÁÈëÎļþÖеÄÄÚÈݵ½×Ö½ÚÊý×éÖÐ +批é‡�读入文件中的内容到字节数组中 ```java byte[] buf = new byte[20*1024]; int bytes = 0; -// ×î¶à¶ÁÈ¡ buf.length ¸ö×Ö½Ú£¬·µ»ØµÄÊÇʵ¼Ê¶ÁÈ¡µÄ¸öÊý£¬·µ»Ø -1 µÄʱºò±íʾ¶Áµ½ eof£¬¼´Îļþβ +// 最多读å�– buf.length 个字节,返回的是实际读å�–的个数,返回 -1 的时候表示读到 eof,å�³æ–‡ä»¶å°¾ while((bytes = in.read(buf, 0 , buf.length)) != -1) { // ... } ``` -# ×Ö·û²Ù×÷ +# 字符æ“�作 -²»¹ÜÊÇ´ÅÅÌ»¹ÊÇÍøÂç´«Ê䣬×îСµÄ´æ´¢µ¥Ôª¶¼ÊÇ×Ö½Ú£¬¶ø²»ÊÇ×Ö·û£¬ËùÒÔ I/O ²Ù×÷µÄ¶¼ÊÇ×Ö½Ú¶ø²»ÊÇ×Ö·û¡£µ«ÊÇÔÚ³ÌÐòÖвÙ×÷µÄÊý¾Ýͨ³£ÊÇ×Ö·ûÐÎʽ£¬Òò´ËÐèÒªÌṩ¶Ô×Ö·û½øÐвÙ×÷µÄ·½·¨¡£ +ä¸�管是ç£�盘还是网络传输,最å°�的存储å�•元都是字节,而ä¸�是字符,所以 I/O æ“�作的都是字节而ä¸�是字符。但是在程åº�中æ“�作的数æ�®é€šå¸¸æ˜¯å­—符形å¼�,因此需è¦�æ��供对字符进行æ“�作的方法。 -InputStreamReader ʵÏÖ´ÓÎı¾ÎļþµÄ×Ö½ÚÁ÷½âÂë³É×Ö·ûÁ÷£»OutputStreamWriter ʵÏÖ×Ö·ûÁ÷±àÂë³ÉΪÎı¾ÎļþµÄ×Ö½ÚÁ÷¡£ËüÃǶ¼¼Ì³Ð×Ô Reader ºÍ Writer¡£ +InputStreamReader 实现从文本文件的字节æµ�è§£ç �æˆ�字符æµ�ï¼›OutputStreamWriter 实现字符æµ�ç¼–ç �æˆ�为文本文件的字节æµ�。它们都继承自 Reader å’Œ Writer。 -±àÂë¾ÍÊǰÑ×Ö·ûת»»Îª×Ö½Ú£¬¶ø½âÂëÊǰÑ×Ö½ÚÖØÐÂ×éºÏ³É×Ö·û¡£ +ç¼–ç �就是把字符转æ�¢ä¸ºå­—节,而解ç �是把字节é‡�新组å�ˆæˆ�字符。 ```java -byte[] bytes = str.getBytes(encoding); // ±àÂë -String str = new String(bytes, encoding)£» // ½âÂë +byte[] bytes = str.getBytes(encoding); // ç¼–ç � +String str = new String(bytes, encoding)ï¼› // è§£ç � ``` -GBK ±àÂëÖУ¬ÖÐÎÄÕ¼ 2 ¸ö×Ö½Ú£¬Ó¢ÎÄÕ¼ 1 ¸ö×Ö½Ú£»UTF-8 ±àÂëÖУ¬ÖÐÎÄÕ¼ 3 ¸ö×Ö½Ú£¬Ó¢ÎÄÕ¼ 1 ¸ö×Ö½Ú£»Java ʹÓÃË«×Ö½Ú±àÂë UTF-16be£¬ÖÐÎĺÍÓ¢Îͼռ 2 ¸ö×Ö½Ú¡£ +GBK ç¼–ç �中,中文å�  2 个字节,英文å�  1 个字节;UTF-8 ç¼–ç �中,中文å�  3 个字节,英文å�  1 个字节;Java 使用å�Œå­—节编ç � UTF-16be,中文和英文都å�  2 个字节。 -Èç¹û±àÂëºÍ½âÂë¹ý³ÌʹÓò»Í¬µÄ±àÂ뷽ʽÄÇô¾Í³öÏÖÁËÂÒÂë¡£ +如果编ç �和解ç �过程使用ä¸�å�Œçš„ç¼–ç �æ–¹å¼�那么就出现了乱ç �。 -# ¶ÔÏó²Ù×÷ +# 对象æ“�作 -ÐòÁл¯¾ÍÊǽ«Ò»¸ö¶ÔÏóת»»³É×Ö½ÚÐòÁУ¬·½±ã´æ´¢ºÍ´«Êä¡£ +åº�列化就是将一个对象转æ�¢æˆ�字节åº�列,方便存储和传输。 -ÐòÁл¯£ºObjectOutputStream.writeObject() +åº�列化:ObjectOutputStream.writeObject() -·´ÐòÁл¯£ºObjectInputStream.readObject() +å��åº�列化:ObjectInputStream.readObject() -ÐòÁл¯µÄÀàÐèҪʵÏÖ Serializable ½Ó¿Ú£¬ËüÖ»ÊÇÒ»¸ö±ê×¼£¬Ã»ÓÐÈκη½·¨ÐèҪʵÏÖ¡£ +åº�列化的类需è¦�实现 Serializable 接å�£ï¼Œå®ƒå�ªæ˜¯ä¸€ä¸ªæ ‡å‡†ï¼Œæ²¡æœ‰ä»»ä½•方法需è¦�实现。 -transient ¹Ø¼ü×Ö¿ÉÒÔʹһЩÊôÐÔ²»»á±»ÐòÁл¯¡£ +transient 关键字å�¯ä»¥ä½¿ä¸€äº›å±žæ€§ä¸�会被åº�列化。 -**ArrayList ÐòÁл¯ºÍ·´ÐòÁл¯µÄʵÏÖ**£ºArrayList Öд洢Êý¾ÝµÄÊý×éÊÇÓà transient ÐÞÊεģ¬ÒòΪÕâ¸öÊý×éÊǶ¯Ì¬À©Õ¹µÄ£¬²¢²»ÊÇËùÓеĿռ䶼±»Ê¹Óã¬Òò´Ë¾Í²»ÐèÒªËùÓеÄÄÚÈݶ¼±»ÐòÁл¯¡£Í¨¹ýÖØÐ´ÐòÁл¯ºÍ·´ÐòÁл¯·½·¨£¬Ê¹µÃ¿ÉÒÔÖ»ÐòÁл¯Êý×éÖÐÓÐÄÚÈݵÄÄDz¿·ÖÊý¾Ý¡£ +**ArrayList åº�列化和å��åº�列化的实现**:ArrayList 中存储数æ�®çš„æ•°ç»„是用 transient 修饰的,因为这个数组是动æ€�扩展的,并ä¸�是所有的空间都被使用,因此就ä¸�需è¦�所有的内容都被åº�列化。通过é‡�写åº�列化和å��åº�列化方法,使得å�¯ä»¥å�ªåº�列化数组中有内容的那部分数æ�®ã€‚ ``` private transient Object[] elementData; ``` -# ÍøÂç²Ù×÷ +# 网络æ“�作 -Java ÖеÄÍøÂçÖ§³Ö£º +Java 中的网络支æŒ�: -1. InetAddress£ºÓÃÓÚ±íÊ¾ÍøÂçÉϵÄÓ²¼þ×ÊÔ´£¬¼´ IP µØÖ·£» -2. URL£ºÍ³Ò»×ÊÔ´¶¨Î»·û£¬Í¨¹ý URL ¿ÉÒÔÖ±½Ó¶ÁÈ¡»òÕßдÈëÍøÂçÉϵÄÊý¾Ý£» -3. Sockets£ºÊ¹Óà TCP ЭÒéʵÏÖÍøÂçͨÐÅ£» -4. Datagram£ºÊ¹Óà UDP ЭÒéʵÏÖÍøÂçͨÐÅ¡£ +1. InetAddress:用于表示网络上的硬件资æº�,å�³ IP 地å�€ï¼› +2. URL:统一资æº�定ä½�符,通过 URL å�¯ä»¥ç›´æŽ¥è¯»å�–或者写入网络上的数æ�®ï¼› +3. Sockets:使用 TCP å��议实现网络通信; +4. Datagram:使用 UDP å��议实现网络通信。 ## 1. InetAddress -ûÓй«Óй¹Ô캯Êý£¬Ö»ÄÜͨ¹ý¾²Ì¬·½·¨À´´´½¨ÊµÀý£¬±ÈÈç InetAddress.getByName(String host)¡¢InetAddress.getByAddress(byte[] addr)¡£ +没有公有构造函数,å�ªèƒ½é€šè¿‡é�™æ€�方法æ�¥åˆ›å»ºå®žä¾‹ï¼Œæ¯”如 InetAddress.getByName(String host)ã€�InetAddress.getByAddress(byte[] addr)。 ## 2. URL -¿ÉÒÔÖ±½Ó´Ó URL ÖжÁÈ¡×Ö½ÚÁ÷Êý¾Ý +å�¯ä»¥ç›´æŽ¥ä»Ž URL 中读å�–字节æµ�æ•°æ�® ```java URL url = new URL("http://www.baidu.com"); -InputStream is = url.openStream(); // ×Ö½ÚÁ÷ -InputStreamReader isr = new InputStreamReader(is, "utf-8"); // ×Ö·ûÁ÷ +InputStream is = url.openStream(); // 字节æµ� +InputStreamReader isr = new InputStreamReader(is, "utf-8"); // 字符æµ� BufferedReader br = new BufferedReader(isr); String line = br.readLine(); while (line != null) { @@ -137,56 +138,56 @@ is.close(); ## 3. Sockets -Socket ͨÐÅÄ£ÐÍ +Socket 通信模型 -![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/fa4101d7-19ce-4a69-a84f-20bbe64320e5.jpg) +![](https://github.com/CyC2018/InterviewNotes/blob/master/pics//fa4101d7-19ce-4a69-a84f-20bbe64320e5.jpg) -- ServerSocket£º·þÎñÆ÷¶ËÀà -- Socket£º¿Í»§¶ËÀà +- ServerSocket:æœ�务器端类 +- Socket:客户端类 -·þÎñÆ÷ºÍ¿Í»§¶Ëͨ¹ý InputStream ºÍ OutputStream ½øÐÐÊäÈëÊä³ö¡£ +æœ�务器和客户端通过 InputStream å’Œ OutputStream 进行输入输出。 ## 4. Datagram -- DatagramPacket£ºÊý¾Ý°üÀà -- DatagramSocket£ºÍ¨ÐÅÀà +- DatagramPacket:数æ�®åŒ…ç±» +- DatagramSocket:通信类 # NIO -NIO ½«×îºÄʱµÄ I/O ²Ù×÷ ( ¼´Ìî³äºÍÌáÈ¡»º³åÇø ) ×ªÒÆ»Ø²Ù×÷ϵͳ£¬Òò¶ø ²»ÐèÒª³ÌÐòԱȥ¿ØÖƾͿÉÒÔ¼«´óµØÌá¸ßÔËÐÐËÙ¶È¡£ +NIO 将最耗时的 I/O æ“�作 ( å�³å¡«å……å’Œæ��å�–缓冲区 ) 转移回æ“�作系统,因而 ä¸�需è¦�程åº�员去控制就å�¯ä»¥æž�大地æ��高è¿�行速度。 -## 1. Á÷Óë¿é +## 1. æµ�与å�— -I/O Óë NIO ×îÖØÒªµÄÇø±ðÊÇÊý¾Ý´ò°üºÍ´«ÊäµÄ·½Ê½¡£ÕýÈçÇ°ÃæÌáµ½µÄ£¬I/O ÒÔÁ÷µÄ·½Ê½´¦ÀíÊý¾Ý£¬¶ø NIO ÒÔ¿éµÄ·½Ê½´¦ÀíÊý¾Ý¡£ +I/O 与 NIO 最é‡�è¦�的区别是数æ�®æ‰“包和传输的方å¼�。正如å‰�é�¢æ��到的,I/O 以æµ�的方å¼�处ç�†æ•°æ�®ï¼Œè€Œ NIO 以å�—的方å¼�处ç�†æ•°æ�®ã€‚ -ÃæÏòÁ÷µÄ I/O Ò»´ÎÒ»¸ö×Ö½Ú½øÐд¦ÀíÊý¾Ý£¬Ò»¸öÊäÈëÁ÷²úÉúÒ»¸ö×Ö½ÚµÄÊý¾Ý£¬Ò»¸öÊä³öÁ÷Ïû·ÑÒ»¸ö×Ö½ÚµÄÊý¾Ý¡£ÎªÁ÷ʽÊý¾Ý´´½¨¹ýÂËÆ÷·Ç³£ÈÝÒ×£¬Á´½Ó¼¸¸ö¹ýÂËÆ÷£¬ÒÔ±ãÿ¸ö¹ýÂËÆ÷Ö»¸ºÔ𵥸ö¸´ÔÓ´¦Àí»úÖÆµÄÒ»²¿·Ö£¬ÕâÑùÒ²ÊÇÏà¶Ô¼òµ¥µÄ¡£²»ÀûµÄÒ»ÃæÊÇ£¬ÃæÏòÁ÷µÄ I/O ͨ³£Ï൱Âý¡£ +é�¢å�‘æµ�çš„ I/O 一次一个字节进行处ç�†æ•°æ�®ï¼Œä¸€ä¸ªè¾“å…¥æµ�产生一个字节的数æ�®ï¼Œä¸€ä¸ªè¾“出æµ�消费一个字节的数æ�®ã€‚为æµ�å¼�æ•°æ�®åˆ›å»ºè¿‡æ»¤å™¨é�žå¸¸å®¹æ˜“,链接几个过滤器,以便æ¯�个过滤器å�ªè´Ÿè´£å�•个å¤�æ�‚处ç�†æœºåˆ¶çš„一部分,这样也是相对简å�•的。ä¸�利的一é�¢æ˜¯ï¼Œé�¢å�‘æµ�çš„ I/O 通常相当慢。 -Ò»¸öÃæÏò¿éµÄ I/O ϵͳÒÔ¿éµÄÐÎʽ´¦ÀíÊý¾Ý£¬Ã¿Ò»¸ö²Ù×÷¶¼ÔÚÒ»²½ÖвúÉú»òÕßÏû·ÑÒ»¸öÊý¾Ý¿é¡£°´¿é´¦ÀíÊý¾Ý±È°´Á÷´¦ÀíÊý¾ÝÒª¿ìµÃ¶à¡£µ«ÊÇÃæÏò¿éµÄ I/O ȱÉÙÒ»Ð©ÃæÏòÁ÷µÄ I/O Ëù¾ßÓеÄÓÅÑÅÐԺͼòµ¥ÐÔ¡£ +一个é�¢å�‘å�—çš„ I/O 系统以å�—的形å¼�处ç�†æ•°æ�®ï¼Œæ¯�一个æ“�作都在一步中产生或者消费一个数æ�®å�—。按å�—处ç�†æ•°æ�®æ¯”按æµ�处ç�†æ•°æ�®è¦�快得多。但是é�¢å�‘å�—çš„ I/O 缺少一些é�¢å�‘æµ�çš„ I/O 所具有的优雅性和简å�•性。 -I/O °üºÍ NIO ÒѾ­ºÜºÃµØ¼¯³ÉÁË£¬java.io.\* ÒѾ­ÒÔ NIO Ϊ»ù´¡ÖØÐÂʵÏÖÁË£¬ËùÒÔÏÖÔÚËü¿ÉÒÔÀûÓà NIO µÄÒ»Ð©ÌØÐÔ¡£ÀýÈ磬 java.io.\* °üÖеÄһЩÀà°üº¬ÒÔ¿éµÄÐÎʽ¶ÁдÊý¾ÝµÄ·½·¨£¬ÕâʹµÃ¼´Ê¹ÔÚ¸üÃæÏòÁ÷µÄϵͳÖУ¬´¦ÀíËÙ¶ÈÒ²»á¸ü¿ì¡£ +I/O 包和 NIO å·²ç»�很好地集æˆ�了,java.io.\* å·²ç»�以 NIO 为基础é‡�新实现了,所以现在它å�¯ä»¥åˆ©ç”¨ NIO 的一些特性。例如, java.io.\* 包中的一些类包å�«ä»¥å�—的形å¼�读写数æ�®çš„æ–¹æ³•,这使得å�³ä½¿åœ¨æ›´é�¢å�‘æµ�的系统中,处ç�†é€Ÿåº¦ä¹Ÿä¼šæ›´å¿«ã€‚ -## 2. ͨµÀÓ뻺³åÇø +## 2. 通é�“与缓冲区 -### 2.1 ͨµÀ +### 2.1 通é�“ -ͨµÀ Channel ÊǶÔÔ­ I/O °üÖеÄÁ÷µÄÄ£Ä⣬¿ÉÒÔͨ¹ýËü¶ÁÈ¡ºÍдÈëÊý¾Ý¡£ +通é�“ Channel 是对原 I/O 包中的æµ�的模拟,å�¯ä»¥é€šè¿‡å®ƒè¯»å�–和写入数æ�®ã€‚ -ͨµÀÓëÁ÷µÄ²»Í¬Ö®´¦ÔÚÓÚ£¬Á÷Ö»ÄÜÔÚÒ»¸ö·½ÏòÉÏÒÆ¶¯£¬(Ò»¸öÁ÷±ØÐëÊÇ InputStream »òÕß OutputStream µÄ×ÓÀà)£¬ ¶øÍ¨µÀÊÇË«ÏòµÄ£¬¿ÉÒÔÓÃÓÚ¶Á¡¢Ð´»òÕßͬʱÓÃÓÚ¶Áд¡£ +通é�“与æµ�çš„ä¸�å�Œä¹‹å¤„在于,æµ�å�ªèƒ½åœ¨ä¸€ä¸ªæ–¹å�‘上移动,(一个æµ�必须是 InputStream 或者 OutputStream çš„å­�ç±»), 而通é�“是å�Œå�‘的,å�¯ä»¥ç”¨äºŽè¯»ã€�写或者å�Œæ—¶ç”¨äºŽè¯»å†™ã€‚ -ͨµÀ°üÀ¨ÒÔÏÂÀàÐÍ£º +通é�“包括以下类型: -- FileChannel£º´ÓÎļþÖжÁдÊý¾Ý£» -- DatagramChannel£ºÍ¨¹ý UDP ¶ÁÐ´ÍøÂçÖÐÊý¾Ý£» -- SocketChannel£ºÍ¨¹ý TCP ¶ÁÐ´ÍøÂçÖÐÊý¾Ý£» -- ServerSocketChannel£º¿ÉÒÔ¼àÌýнøÀ´µÄ TCP Á¬½Ó£¬¶Ôÿһ¸öнøÀ´µÄÁ¬½Ó¶¼»á´´½¨Ò»¸ö SocketChannel¡£ +- FileChannel:从文件中读写数æ�®ï¼› +- DatagramChannel:通过 UDP 读写网络中数æ�®ï¼› +- SocketChannel:通过 TCP 读写网络中数æ�®ï¼› +- ServerSocketChannel:å�¯ä»¥ç›‘å�¬æ–°è¿›æ�¥çš„ TCP 连接,对æ¯�一个新进æ�¥çš„连接都会创建一个 SocketChannel。 -### 2.2 »º³åÇø +### 2.2 缓冲区 -·¢Ë͸øÒ»¸öͨµÀµÄËùÓжÔÏó¶¼±ØÐëÊ×Ïȷŵ½»º³åÇøÖУ»Í¬ÑùµØ£¬´ÓͨµÀÖжÁÈ¡µÄÈκÎÊý¾Ý¶¼Òª¶Áµ½»º³åÇøÖС£Ò²¾ÍÊÇ˵£¬²»»áÖ±½Ó¶ÔͨµÀ½øÐжÁдÊý¾Ý£¬¶øÊÇÏȾ­¹ý»º³åÇø¡£ +å�‘é€�给一个通é�“的所有对象都必须首先放到缓冲区中;å�Œæ ·åœ°ï¼Œä»Žé€šé�“中读å�–的任何数æ�®éƒ½è¦�读到缓冲区中。也就是说,ä¸�会直接对通é�“进行读写数æ�®ï¼Œè€Œæ˜¯å…ˆç»�过缓冲区。 -»º³åÇøÊµÖÊÉÏÊÇÒ»¸öÊý×飬µ«Ëü²»½ö½öÊÇÒ»¸öÊý×é¡£»º³åÇøÌṩÁ˶ÔÊý¾ÝµÄ½á¹¹»¯·ÃÎÊ£¬¶øÇÒ»¹¿ÉÒÔ¸ú×ÙϵͳµÄ¶Á/д½ø³Ì¡£ +缓冲区实质上是一个数组,但它ä¸�仅仅是一个数组。缓冲区æ��供了对数æ�®çš„结构化访问,而且还å�¯ä»¥è·Ÿè¸ªç³»ç»Ÿçš„读/写进程。 -»º³åÇø°üÀ¨ÒÔÏÂÀàÐÍ£º +缓冲区包括以下类型: - ByteBuffer - CharBuffer @@ -197,50 +198,50 @@ I/O - DoubleBuffer -## 3. »º³åÇø×´Ì¬±äÁ¿ +## 3. 缓冲区状æ€�å�˜é‡� -- capacity£º×î´óÈÝÁ¿£» -- position£ºµ±Ç°ÒѾ­¶ÁдµÄ×Ö½ÚÊý£» -- limit£º»¹¿ÉÒÔ¶ÁдµÄ×Ö½ÚÊý¡£ +- capacity:最大容é‡�ï¼› +- position:当å‰�å·²ç»�读写的字节数; +- limit:还å�¯ä»¥è¯»å†™çš„字节数。 -״̬±äÁ¿µÄ¸Ä±ä¹ý³Ì£º +状æ€�å�˜é‡�的改å�˜è¿‡ç¨‹ï¼š -1\. н¨Ò»¸ö´óСΪ 8 ¸ö×ֽڵĻº³åÇø£¬´Ëʱ position Ϊ 0£¬¶ø limit == capacity == 9¡£capacity ±äÁ¿²»»á¸Ä±ä£¬ÏÂÃæµÄÌÖÂÛ»áºöÂÔËü¡£ +1\. 新建一个大å°�为 8 个字节的缓冲区,此时 position 为 0,而 limit == capacity == 9。capacity å�˜é‡�ä¸�会改å�˜ï¼Œä¸‹é�¢çš„讨论会忽略它。 -![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/1bea398f-17a7-4f67-a90b-9e2d243eaa9a.png) +![](https://github.com/CyC2018/InterviewNotes/blob/master/pics//1bea398f-17a7-4f67-a90b-9e2d243eaa9a.png) -2\. ´ÓÊäÈëͨµÀÖжÁÈ¡ 3 ¸ö×Ö½ÚÊý¾ÝдÈ뻺³åÇøÖУ¬´Ëʱ position ÒÆ¶¯ÉèΪ 3£¬limit ±£³Ö²»±ä¡£ +2\. 从输入通é�“中读å�– 3 个字节数æ�®å†™å…¥ç¼“冲区中,此时 position 移动设为 3,limit ä¿�æŒ�ä¸�å�˜ã€‚ -![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/4628274c-25b6-4053-97cf-d1239b44c43d.png) +![](https://github.com/CyC2018/InterviewNotes/blob/master/pics//4628274c-25b6-4053-97cf-d1239b44c43d.png) -3\. ÔÚ½«»º³åÇøµÄÊý¾Ýдµ½Êä³öͨµÀ֮ǰ£¬ÐèÒªÏȵ÷Óà flip() ·½·¨£¬Õâ¸ö·½·¨½« limit ÉèÖÃΪµ±Ç° position£¬²¢½« position ÉèÖÃΪ 0¡£ +3\. 在将缓冲区的数æ�®å†™åˆ°è¾“出通é�“之å‰�,需è¦�先调用 flip() 方法,这个方法将 limit 设置为当å‰� position,并将 position 设置为 0。 -![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/952e06bd-5a65-4cab-82e4-dd1536462f38.png) +![](https://github.com/CyC2018/InterviewNotes/blob/master/pics//952e06bd-5a65-4cab-82e4-dd1536462f38.png) -4\. ´Ó»º³åÇøÖÐÈ¡ 4 ¸ö×Ö½Úµ½Êä³ö»º³åÖУ¬´Ëʱ position ÉèΪ 4¡£ +4\. 从缓冲区中å�– 4 个字节到输出缓冲中,此时 position 设为 4。 -![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/b5bdcbe2-b958-4aef-9151-6ad963cb28b4.png) +![](https://github.com/CyC2018/InterviewNotes/blob/master/pics//b5bdcbe2-b958-4aef-9151-6ad963cb28b4.png) -5\. ×îºóÐèÒªµ÷Óà clear() ·½·¨À´Çå¿Õ»º³åÇø£¬´Ëʱ position ºÍ limit ¶¼±»ÉèÖÃΪ×î³õλÖᣠ+5\. 最å�Žéœ€è¦�调用 clear() 方法æ�¥æ¸…空缓冲区,此时 position å’Œ limit 都被设置为最åˆ�ä½�置。 -![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/67bf5487-c45d-49b6-b9c0-a058d8c68902.png) +![](https://github.com/CyC2018/InterviewNotes/blob/master/pics//67bf5487-c45d-49b6-b9c0-a058d8c68902.png) -## 4. ¶ÁдÎļþʵÀý +## 4. 读写文件实例 -1\. ΪҪ¶ÁÈ¡µÄÎļþ´´½¨ FileInputStream£¬Ö®ºóͨ¹ý FileInputStream »ñÈ¡ÊäÈë FileChannel£» +1\. 为è¦�读å�–的文件创建 FileInputStream,之å�Žé€šè¿‡ FileInputStream 获å�–输入 FileChannelï¼› ```java FileInputStream fin = new FileInputStream("readandshow.txt"); FileChannel fic = fin.getChannel(); ``` -2\. ´´½¨Ò»¸öÈÝÁ¿Îª 1024 µÄ Buffer +2\. 创建一个容é‡�为 1024 çš„ Buffer ```java ByteBuffer buffer = ByteBuffer.allocate(1024); ``` -3\. ½«Êý¾Ý´ÓÊäÈë FileChannel дÈëµ½ Buffer ÖУ¬Èç¹ûûÓÐÊý¾ÝµÄ»°£¬ read() ·½·¨»á·µ»Ø -1 +3\. 将数æ�®ä»Žè¾“å…¥ FileChannel 写入到 Buffer 中,如果没有数æ�®çš„è¯�, read() 方法会返回 -1 ```java int r = fcin.read(buffer); @@ -249,86 +250,86 @@ if (r == -1) { } ``` -4\. ΪҪдÈëµÄÎļþ´´½¨ FileOutputStream£¬Ö®ºóͨ¹ý FileOutputStream »ñÈ¡Êä³ö FileChannel +4\. 为è¦�写入的文件创建 FileOutputStream,之å�Žé€šè¿‡ FileOutputStream 获å�–输出 FileChannel ```java FileOutputStream fout = new FileOutputStream("writesomebytes.txt"); FileChannel foc = fout.getChannel(); ``` -5\. µ÷Óà flip() Çл»¶Áд +5\. 调用 flip() 切æ�¢è¯»å†™ ```java buffer.flip(); ``` -6\. °Ñ Buffer ÖеÄÊý¾Ý¶ÁÈ¡µ½Êä³ö FileChannel ÖÐ +6\. 把 Buffer 中的数æ�®è¯»å�–到输出 FileChannel 中 ```java foc.write(buffer); ``` -7\. ×îºóµ÷Óà clear() ÖØÖûº³åÇø +7\. 最å�Žè°ƒç”¨ clear() é‡�置缓冲区 ```java buffer.clear(); ``` -## 5. ×èÈûÓë·Ç×èÈû +## 5. 阻塞与é�žé˜»å¡ž -Ó¦µ±×¢Ò⣬FileChannel ²»ÄÜÇл»µ½·Ç×èÈûģʽ£¬Ì×½Ó×Ö Channel ¿ÉÒÔ¡£ +应当注æ„�,FileChannel ä¸�能切æ�¢åˆ°é�žé˜»å¡žæ¨¡å¼�,套接字 Channel å�¯ä»¥ã€‚ -### 5.1 ×èÈûʽ I/O +### 5.1 阻塞å¼� I/O -×èÈûʽ I/O ÔÚµ÷Óà InputStream.read() ·½·¨Ê±»áÒ»Ö±µÈµ½Êý¾Ýµ½À´Ê±£¨»ò³¬Ê±£©²Å»á·µ»Ø£¬ÔÚµ÷Óà ServerSocket.accept() ·½·¨Ê±£¬Ò²»áÒ»Ö±×èÈûµ½Óпͻ§¶ËÁ¬½Ó²Å»á·µ»Ø£¬Ã¿¸ö¿Í»§¶ËÁ¬½Ó¹ýÀ´ºó£¬·þÎñ¶Ë¶¼»áÆô¶¯Ò»¸öÏß³ÌÈ¥´¦Àí¸Ã¿Í»§¶ËµÄÇëÇó¡£ +阻塞å¼� I/O 在调用 InputStream.read() 方法时会一直等到数æ�®åˆ°æ�¥æ—¶ï¼ˆæˆ–超时)æ‰�会返回,在调用 ServerSocket.accept() 方法时,也会一直阻塞到有客户端连接æ‰�会返回,æ¯�个客户端连接过æ�¥å�Žï¼Œæœ�务端都会å�¯åŠ¨ä¸€ä¸ªçº¿ç¨‹åŽ»å¤„ç�†è¯¥å®¢æˆ·ç«¯çš„请求。 -![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/edc23f99-c46c-4200-b64e-07516828720d.jpg) +![](https://github.com/CyC2018/InterviewNotes/blob/master/pics//edc23f99-c46c-4200-b64e-07516828720d.jpg) -### 5.2 ·Ç×èÈûʽ I/O +### 5.2 é�žé˜»å¡žå¼� I/O -ÓÉÒ»¸öרÃŵÄÏß³ÌÀ´´¦ÀíËùÓÐµÄ I/O ʼþ£¬²¢¸ºÔð·Ö·¢¡£ +由一个专门的线程æ�¥å¤„ç�†æ‰€æœ‰çš„ I/O 事件,并负责分å�‘。 -ʼþÇý¶¯»úÖÆ£ºÊ¼þµ½µÄʱºò´¥·¢£¬¶ø²»ÊÇͬ²½µÄÈ¥¼àÊÓʼþ¡£ +事件驱动机制:事件到的时候触å�‘,而ä¸�是å�Œæ­¥çš„去监视事件。 -Ïß³ÌͨÐÅ£ºÏß³ÌÖ®¼äͨ¹ý wait()¡¢notify() µÈ·½Ê½Í¨ÐÅ£¬±£Ö¤Ã¿´ÎÉÏÏÂÎÄÇл»¶¼ÊÇÓÐÒâÒåµÄ£¬¼õÉÙÎÞνµÄÏß³ÌÇл»¡£ +线程通信:线程之间通过 wait()ã€�notify() 等方å¼�通信,ä¿�è¯�æ¯�次上下文切æ�¢éƒ½æ˜¯æœ‰æ„�义的,å‡�少无谓的线程切æ�¢ã€‚ -![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/7fcb2fb0-2cd9-4396-bc2d-282becf963c3.jpg) +![](https://github.com/CyC2018/InterviewNotes/blob/master/pics//7fcb2fb0-2cd9-4396-bc2d-282becf963c3.jpg) -## 6. Ì×½Ó×ÖʵÀý +## 6. 套接字实例 ### 6.1 ServerSocketChannel -ÿһ¸ö¶Ë¿Ú¶¼ÐèÒªÓÐÒ»¸ö ServerSocketChannel ÓÃÀ´¼àÌýÁ¬½Ó¡£ +æ¯�一个端å�£éƒ½éœ€è¦�有一个 ServerSocketChannel 用æ�¥ç›‘å�¬è¿žæŽ¥ã€‚ ```java ServerSocketChannel ssc = ServerSocketChannel.open(); -ssc.configureBlocking(false); // ÉèÖÃΪ·Ç×èÈû +ssc.configureBlocking(false); // 设置为é�žé˜»å¡ž ServerSocket ss = ssc.socket(); InetSocketAddress address = new InetSocketAddress(ports[i]); -ss.bind(address); // °ó¶¨¶Ë¿ÚºÅ +ss.bind(address); // 绑定端å�£å�· ``` ### 6.2 Selectors -Òì²½ I/O ͨ¹ý Selector ×¢²á¶ÔÌØ¶¨ I/O ʼþµÄÐËȤ ¨D ¿É¶ÁµÄÊý¾ÝµÄµ½´ï¡¢ÐµÄÌ×½Ó×ÖÁ¬½ÓµÈµÈ£¬ÔÚ·¢ÉúÕâÑùµÄʼþʱ£¬ÏµÍ³½«»á·¢ËÍ֪ͨ¡£ +异步 I/O 通过 Selector 注册对特定 I/O 事件的兴趣 ― å�¯è¯»çš„æ•°æ�®çš„到达ã€�新的套接字连接等等,在å�‘生这样的事件时,系统将会å�‘é€�通知。 -´´½¨ Selectors Ö®ºó£¬¾Í¿ÉÒÔ¶Ô²»Í¬µÄͨµÀ¶ÔÏóµ÷Óà register() ·½·¨¡£register() µÄµÚÒ»¸ö²ÎÊý×ÜÊÇÕâ¸ö Selector¡£µÚ¶þ¸ö²ÎÊýÊÇ OP_ACCEPT£¬ÕâÀïËüÖ¸¶¨ÎÒÃÇÏëÒª¼àÌý accept ʼþ£¬Ò²¾ÍÊÇÔÚеÄÁ¬½Ó½¨Á¢Ê±Ëù·¢ÉúµÄʼþ¡£ +创建 Selectors 之å�Žï¼Œå°±å�¯ä»¥å¯¹ä¸�å�Œçš„通é�“对象调用 register() 方法。register() 的第一个å�‚数总是这个 Selector。第二个å�‚数是 OP_ACCEPT,这里它指定我们想è¦�监å�¬ accept 事件,也就是在新的连接建立时所å�‘生的事件。 -SelectionKey ´ú±íÕâ¸öͨµÀÔÚ´Ë Selector ÉϵÄÕâ¸ö×¢²á¡£µ±Ä³¸ö Selector ֪ͨÄúij¸ö´«Èëʼþʱ£¬ËüÊÇͨ¹ýÌṩ¶ÔÓ¦ÓÚ¸ÃʼþµÄ SelectionKey À´½øÐеġ£SelectionKey »¹¿ÉÒÔÓÃÓÚÈ¡ÏûͨµÀµÄ×¢²á¡£ +SelectionKey 代表这个通é�“在此 Selector 上的这个注册。当æŸ�个 Selector 通知您æŸ�个传入事件时,它是通过æ��供对应于该事件的 SelectionKey æ�¥è¿›è¡Œçš„。SelectionKey 还å�¯ä»¥ç”¨äºŽå�–消通é�“的注册。 ```java Selector selector = Selector.open(); SelectionKey key = ssc.register(selector, SelectionKey.OP_ACCEPT); ``` -### 6.3 Ö÷Ñ­»· +### 6.3 主循环 -Ê×ÏÈ£¬ÎÒÃǵ÷Óà Selector µÄ select() ·½·¨¡£Õâ¸ö·½·¨»á×èÈû£¬Ö±µ½ÖÁÉÙÓÐÒ»¸öÒÑ×¢²áµÄʼþ·¢Éú¡£µ±Ò»¸ö»òÕ߸ü¶àµÄʼþ·¢Éúʱ£¬ select() ·½·¨½«·µ»ØËù·¢ÉúµÄʼþµÄÊýÁ¿¡£ +首先,我们调用 Selector çš„ select() 方法。这个方法会阻塞,直到至少有一个已注册的事件å�‘生。当一个或者更多的事件å�‘生时, select() 方法将返回所å�‘生的事件的数é‡�。 -½ÓÏÂÀ´£¬ÎÒÃǵ÷Óà Selector µÄ selectedKeys() ·½·¨£¬Ëü·µ»Ø·¢ÉúÁËʼþµÄ SelectionKey ¶ÔÏóµÄÒ»¸ö ¼¯ºÏ ¡£ +接下æ�¥ï¼Œæˆ‘们调用 Selector çš„ selectedKeys() 方法,它返回å�‘生了事件的 SelectionKey 对象的一个 集å�ˆ 。 -ÎÒÃÇͨ¹ýµü´ú SelectionKeys ²¢ÒÀ´Î´¦Àíÿ¸ö SelectionKey À´´¦Àíʼþ¡£¶ÔÓÚÿһ¸ö SelectionKey£¬Äú±ØÐëÈ·¶¨·¢ÉúµÄÊÇʲô I/O ʼþ£¬ÒÔ¼°Õâ¸öʼþÓ°ÏìÄÄЩ I/O ¶ÔÏó¡£ +我们通过迭代 SelectionKeys å¹¶ä¾�次处ç�†æ¯�个 SelectionKey æ�¥å¤„ç�†äº‹ä»¶ã€‚对于æ¯�一个 SelectionKey,您必须确定å�‘生的是什么 I/O 事件,以å�Šè¿™ä¸ªäº‹ä»¶å½±å“�哪些 I/O 对象。 ```java int num = selector.select(); @@ -342,9 +343,9 @@ while (it.hasNext()) { } ``` -### 6.4 ¼àÌýÐÂÁ¬½Ó +### 6.4 监å�¬æ–°è¿žæŽ¥ -³ÌÐòÖ´Ðе½ÕâÀÎÒÃǽö×¢²áÁË ServerSocketChannel£¬²¢ÇÒ½ö×¢²áËüÃÇ¡°½ÓÊÕ¡±Ê¼þ¡£ÎªÈ·ÈÏÕâÒ»µã£¬ÎÒÃÇ¶Ô SelectionKey µ÷Óà readyOps() ·½·¨£¬²¢¼ì²é·¢ÉúÁËʲôÀàÐ͵Äʼþ£º +程åº�执行到这里,我们仅注册了 ServerSocketChannel,并且仅注册它们“接收â€�事件。为确认这一点,我们对 SelectionKey 调用 readyOps() 方法,并检查å�‘生了什么类型的事件: ```java if ((key.readyOps() & SelectionKey.OP_ACCEPT) @@ -354,39 +355,39 @@ if ((key.readyOps() & SelectionKey.OP_ACCEPT) } ``` -¿ÉÒԿ϶¨µØËµ£¬ readOps() ·½·¨¸æËßÎÒÃǸÃʼþÊÇеÄÁ¬½Ó¡£ +å�¯ä»¥è‚¯å®šåœ°è¯´ï¼Œ readOps() 方法告诉我们该事件是新的连接。 -### 6.5 ½ÓÊÜеÄÁ¬½Ó +### 6.5 接å�—新的连接 -ÒòΪÎÒÃÇÖªµÀÕâ¸ö·þÎñÆ÷Ì×½Ó×ÖÉÏÓÐÒ»¸ö´«ÈëÁ¬½ÓÔڵȴý£¬ËùÒÔ¿ÉÒÔ°²È«µØ½ÓÊÜËü£»Ò²¾ÍÊÇ˵£¬²»Óõ£ÐÄ accept() ²Ù×÷»á×èÈû£º +因为我们知é�“这个æœ�务器套接字上有一个传入连接在等待,所以å�¯ä»¥å®‰å…¨åœ°æŽ¥å�—它;也就是说,ä¸�用担心 accept() æ“�作会阻塞: ```java ServerSocketChannel ssc = (ServerSocketChannel)key.channel(); SocketChannel sc = ssc.accept(); ``` -ÏÂÒ»²½Êǽ«ÐÂÁ¬½ÓµÄ SocketChannel ÅäÖÃΪ·Ç×èÈûµÄ¡£¶øÇÒÓÉÓÚ½ÓÊÜÕâ¸öÁ¬½ÓµÄÄ¿µÄÊÇΪÁ˶ÁÈ¡À´×ÔÌ×½Ó×ÖµÄÊý¾Ý£¬ËùÒÔÎÒÃÇ»¹±ØÐ뽫 SocketChannel ×¢²áµ½ SelectorÉÏ£¬ÈçÏÂËùʾ£º +下一步是将新连接的 SocketChannel é…�置为é�žé˜»å¡žçš„。而且由于接å�—这个连接的目的是为了读å�–æ�¥è‡ªå¥—接字的数æ�®ï¼Œæ‰€ä»¥æˆ‘们还必须将 SocketChannel 注册到 Selector上,如下所示: ```java sc.configureBlocking( false ); SelectionKey newKey = sc.register( selector, SelectionKey.OP_READ ); ``` -×¢ÒâÎÒÃÇʹÓà register() µÄ OP_READ ²ÎÊý£¬½« SocketChannel ×¢²áÓÃÓÚ ¶ÁÈ¡ ¶ø²»ÊÇ ½ÓÊÜ ÐÂÁ¬½Ó¡£ +注æ„�我们使用 register() çš„ OP_READ å�‚数,将 SocketChannel 注册用于 读å�– 而ä¸�是 接å�— 新连接。 -### 6.6 ɾ³ý´¦Àí¹ýµÄ SelectionKey +### 6.6 删除处ç�†è¿‡çš„ SelectionKey -ÔÚ´¦Àí SelectionKey Ö®ºó£¬ÎÒÃǼ¸ºõ¿ÉÒÔ·µ»ØÖ÷Ñ­»·ÁË¡£µ«ÊÇÎÒÃDZØÐëÊ×ÏȽ«´¦Àí¹ýµÄ SelectionKey ´ÓÑ¡¶¨µÄ¼ü¼¯ºÏÖÐɾ³ý¡£Èç¹ûÎÒÃÇûÓÐɾ³ý´¦Àí¹ýµÄ¼ü£¬ÄÇôËüÈÔÈ»»áÔÚÖ÷¼¯ºÏÖÐÒÔÒ»¸ö¼¤»îµÄ¼ü³öÏÖ£¬Õâ»áµ¼ÖÂÎÒÃdz¢ÊÔÔٴδ¦ÀíËü¡£ÎÒÃǵ÷Óõü´úÆ÷µÄ remove() ·½·¨À´É¾³ý´¦Àí¹ýµÄ SelectionKey£º +在处ç�† SelectionKey 之å�Žï¼Œæˆ‘们几乎å�¯ä»¥è¿”回主循环了。但是我们必须首先将处ç�†è¿‡çš„ SelectionKey 从选定的键集å�ˆä¸­åˆ é™¤ã€‚如果我们没有删除处ç�†è¿‡çš„键,那么它ä»�然会在主集å�ˆä¸­ä»¥ä¸€ä¸ªæ¿€æ´»çš„键出现,这会导致我们å°�试å†�次处ç�†å®ƒã€‚我们调用迭代器的 remove() 方法æ�¥åˆ é™¤å¤„ç�†è¿‡çš„ SelectionKey: ```java it.remove(); ``` -ÏÖÔÚÎÒÃÇ¿ÉÒÔ·µ»ØÖ÷Ñ­»·²¢½ÓÊÜ´ÓÒ»¸öÌ×½Ó×ÖÖд«ÈëµÄÊý¾Ý(»òÕßÒ»¸ö´«ÈëµÄ I/O ʼþ)ÁË¡£ +现在我们å�¯ä»¥è¿”回主循环并接å�—从一个套接字中传入的数æ�®(或者一个传入的 I/O 事件)了。 -### 6.7 ´«ÈëµÄ I/O +### 6.7 传入的 I/O -µ±À´×ÔÒ»¸öÌ×½Ó×ÖµÄÊý¾Ýµ½´ïʱ£¬Ëü»á´¥·¢Ò»¸ö I/O ʼþ¡£Õâ»áµ¼ÖÂÔÚÖ÷Ñ­»·Öе÷Óà Selector.select()£¬²¢·µ»ØÒ»¸ö»òÕß¶à¸ö I/O ʼþ¡£ÕâÒ»´Î£¬ SelectionKey ½«±»±ê¼ÇΪ OP_READ ʼþ£¬ÈçÏÂËùʾ£º +当æ�¥è‡ªä¸€ä¸ªå¥—接字的数æ�®åˆ°è¾¾æ—¶ï¼Œå®ƒä¼šè§¦å�‘一个 I/O 事件。这会导致在主循环中调用 Selector.select(),并返回一个或者多个 I/O 事件。这一次, SelectionKey 将被标记为 OP_READ 事件,如下所示: ```java } else if ((key.readyOps() & SelectionKey.OP_READ) @@ -398,9 +399,9 @@ it.remove(); ``` -# ²Î¿¼×ÊÁÏ +# å�‚考资料 -- Eckel B, °£¿Ë¶û , ê»Åô , µÈ . Java ±à³Ì˼Ïë [M]. »úе¹¤Òµ³ö°æÉç , 2002. -- [IBM: NIO ÈëÃÅ](https://www.ibm.com/developerworks/cn/education/java/j-nio/j-nio.html) -- [ ÉîÈë·ÖÎö Java I/O µÄ¹¤×÷»úÖÆ ](https://www.ibm.com/developerworks/cn/java/j-lo-javaio/index.html) -- [NIO Ó봫ͳ IO µÄÇø±ð ](http://blog.csdn.net/shimiso/article/details/24990499) +- Eckel B, 埃克尔 , 昊é¹� , ç­‰ . Java 编程æ€�想 [M]. 机械工业出版社 , 2002. +- [IBM: NIO 入门](https://www.ibm.com/developerworks/cn/education/java/j-nio/j-nio.html) +- [ 深入分æž� Java I/O 的工作机制 ](https://www.ibm.com/developerworks/cn/java/j-lo-javaio/index.html) +- [NIO 与传统 IO 的区别 ](http://blog.csdn.net/shimiso/article/details/24990499) diff --git a/notes/Java 容器.md b/notes/Java 容器.md index 8bbc9b45..ffc1cba8 100644 --- a/notes/Java 容器.md +++ b/notes/Java 容器.md @@ -1,78 +1,79 @@ -* [¸ÅÀÀ](#¸ÅÀÀ) +* [概览](#概览) * [1. List](#1-list) * [2. Set](#2-set) * [3. Queue](#3-queue) * [4. Map](#4-map) - * [5. Java 1.0/1.1 ÈÝÆ÷](#5-java-1011-ÈÝÆ÷) -* [ÈÝÆ÷ÖеÄÉè¼ÆÄ£Ê½](#ÈÝÆ÷ÖеÄÉè¼ÆÄ£Ê½) - * [1. µü´úÆ÷ģʽ](#1-µü´úÆ÷ģʽ) - * [2. ÊÊÅäÆ÷ģʽ](#2-ÊÊÅäÆ÷ģʽ) -* [É¢ÁÐ](#É¢ÁÐ) -* [Ô´Âë·ÖÎö](#Ô´Âë·ÖÎö) + * [5. Java 1.0/1.1 容器](#5-java-1011-容器) +* [容器中的设计模å¼�](#容器中的设计模å¼�) + * [1. 迭代器模å¼�](#1-迭代器模å¼�) + * [2. 适é…�器模å¼�](#2-适é…�器模å¼�) +* [散列](#散列) +* [æº�ç �分æž�](#æº�ç �分æž�) * [1. ArraList](#1-arralist) - * [2. Vector Óë Stack](#2-vector-Óë-stack) + * [2. Vector 与 Stack](#2-vector-与-stack) * [3. LinkedList](#3-linkedlist) * [4. TreeMap](#4-treemap) * [5. HashMap](#5-hashmap) * [6. LinkedHashMap](#6-linkedhashmap) * [7. ConcurrentHashMap](#7-concurrenthashmap) -* [²Î¿¼×ÊÁÏ](#²Î¿¼×ÊÁÏ) +* [å�‚考资料](#å�‚考资料) -# ¸ÅÀÀ -![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/ebf03f56-f957-4435-9f8f-0f605661484d.jpg) +# 概览 -ÈÝÆ÷Ö÷Òª°üÀ¨ Collection ºÍ Map Á½ÖÖ£¬Collection ÓÖ°üº¬ÁË List¡¢Set ÒÔ¼° Queue¡£ +![](https://github.com/CyC2018/InterviewNotes/blob/master/pics//ebf03f56-f957-4435-9f8f-0f605661484d.jpg) + +容器主è¦�包括 Collection å’Œ Map 两ç§�,Collection å�ˆåŒ…å�«äº† Listã€�Set 以å�Š Queue。 ## 1. List -- ArrayList£º»ùÓÚ¶¯Ì¬Êý×éʵÏÖ£¬Ö§³ÖËæ»ú·ÃÎÊ£» +- ArrayList:基于动æ€�数组实现,支æŒ�éš�机访问; -- LinkedList£º»ùÓÚË«ÏòÑ­»·Á´±íʵÏÖ£¬Ö»ÄÜ˳Ðò·ÃÎÊ£¬µ«ÊÇ¿ÉÒÔ¿ìËÙµØÔÚÁ´±íÖмä²åÈëºÍɾ³ýÔªËØ¡£²»½öÈç´Ë£¬LinkedList »¹¿ÉÒÔÓÃ×÷Õ»¡¢¶ÓÁкÍË«¶Ë¶ÓÁС£ +- LinkedList:基于å�Œå�‘循环链表实现,å�ªèƒ½é¡ºåº�访问,但是å�¯ä»¥å¿«é€Ÿåœ°åœ¨é“¾è¡¨ä¸­é—´æ�’入和删除元素。ä¸�仅如此,LinkedList 还å�¯ä»¥ç”¨ä½œæ ˆã€�队列和å�Œç«¯é˜Ÿåˆ—。 ## 2. Set -- HashSet£º»ùÓÚ Hash ʵÏÖ£¬Ö§³Ö¿ìËÙ²éÕÒ£¬µ«ÊÇʧȥÓÐÐòÐÔ£» +- HashSet:基于 Hash 实现,支æŒ�快速查找,但是失去有åº�性; -- TreeSet£º»ùÓÚºìºÚÊ÷ʵÏÖ£¬±£³ÖÓÐÐò£¬µ«ÊDzéÕÒЧÂʲ»Èç HashSet£» +- TreeSet:基于红黑树实现,ä¿�æŒ�有åº�,但是查找效率ä¸�如 HashSetï¼› -- LinkedListHashSet£º¾ßÓÐ HashSet µÄ²éÕÒЧÂÊ£¬ÇÒÄÚ²¿Ê¹ÓÃÁ´±íά»¤ÔªËصIJåÈë˳Ðò£¬Òò´Ë¾ßÓÐÓÐÐòÐÔ¡£ +- LinkedListHashSet:具有 HashSet 的查找效率,且内部使用链表维护元素的æ�’入顺åº�,因此具有有åº�性。 ## 3. Queue -Ö»ÓÐÁ½¸öʵÏÖ£ºLinkedList ºÍ PriorityQueue£¬ÆäÖÐ LinkedList Ö§³ÖË«Ïò¶ÓÁУ¬PriorityQueue ÊÇ»ùÓڶѽṹʵÏÖ¡£ +å�ªæœ‰ä¸¤ä¸ªå®žçŽ°ï¼šLinkedList å’Œ PriorityQueue,其中 LinkedList 支æŒ�å�Œå�‘队列,PriorityQueue 是基于堆结构实现。 ## 4. Map -- HashMap£º»ùÓÚ Hash ʵÏÖ +- HashMap:基于 Hash 实现 -- LinkedHashMap£ºÊ¹ÓÃÁ´±íÀ´Î¬»¤ÔªËصÄ˳Ðò£¬Ë³ÐòΪ²åÈë˳Ðò»òÕß×î½ü×îÉÙʹÓã¨LRU£©Ë³Ðò +- LinkedHashMap:使用链表æ�¥ç»´æŠ¤å…ƒç´ çš„顺åº�,顺åº�为æ�’入顺åº�或者最近最少使用(LRU)顺åº� -- TreeMap£º»ùÓÚºìºÚÊ÷ʵÏÖ +- TreeMap:基于红黑树实现 -- ConcurrentHashMap£ºḬ̈߳²È« Map£¬²»Éæ¼°ÀàËÆÓÚ HashTable µÄͬ²½¼ÓËø +- ConcurrentHashMap:线程安全 Map,ä¸�涉å�Šç±»ä¼¼äºŽ HashTable çš„å�Œæ­¥åŠ é”� -## 5. Java 1.0/1.1 ÈÝÆ÷ +## 5. Java 1.0/1.1 容器 -¶ÔÓھɵÄÈÝÆ÷£¬ÎÒÃǾö²»Ó¦¸ÃʹÓÃËüÃÇ£¬Ö»ÐèÒª¶ÔËüÃǽøÐÐÁ˽⡣ +对于旧的容器,我们决ä¸�应该使用它们,å�ªéœ€è¦�对它们进行了解。 -- Vector£ººÍ ArrayList ÀàËÆ£¬µ«ËüÊÇḬ̈߳²È«µÄ +- Vector:和 ArrayList 类似,但它是线程安全的 -- HashTable£ººÍ HashMap ÀàËÆ£¬µ«ËüÊÇḬ̈߳²È«µÄ +- HashTable:和 HashMap 类似,但它是线程安全的 -# ÈÝÆ÷ÖеÄÉè¼ÆÄ£Ê½ +# 容器中的设计模å¼� -## 1. µü´úÆ÷ģʽ +## 1. 迭代器模å¼� -´Ó¸ÅÀÀͼ¿ÉÒÔ¿´µ½£¬Ã¿¸ö¼¯ºÏÀà¶¼ÓÐÒ»¸ö Iterator ¶ÔÏ󣬿ÉÒÔͨ¹ýÕâ¸öµü´úÆ÷¶ÔÏóÀ´±éÀú¼¯ºÏÖеÄÔªËØ¡£ +从概览图å�¯ä»¥çœ‹åˆ°ï¼Œæ¯�个集å�ˆç±»éƒ½æœ‰ä¸€ä¸ª Iterator 对象,å�¯ä»¥é€šè¿‡è¿™ä¸ªè¿­ä»£å™¨å¯¹è±¡æ�¥é��历集å�ˆä¸­çš„元素。 -[Java Öеĵü´úÆ÷ģʽ ](https://github.com/CyC2018/InterviewNotes/blob/master/notes/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F.md#92-java-%E5%86%85%E7%BD%AE%E7%9A%84%E8%BF%AD%E4%BB%A3%E5%99%A8) +[Java 中的迭代器模å¼� ](https://github.com/CyC2018/InterviewNotes/blob/master/notes/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F.md#92-java-%E5%86%85%E7%BD%AE%E7%9A%84%E8%BF%AD%E4%BB%A3%E5%99%A8) -## 2. ÊÊÅäÆ÷ģʽ +## 2. 适é…�器模å¼� -java.util.Arrays#asList() ¿ÉÒÔ°ÑÊý×éÀàÐÍת»»Îª List ÀàÐÍ¡£ +java.util.Arrays#asList() å�¯ä»¥æŠŠæ•°ç»„类型转æ�¢ä¸º List 类型。 ```java List list = Arrays.asList(1, 2, 3); @@ -80,44 +81,44 @@ java.util.Arrays#asList() list = Arrays.asList(arr); ``` -# É¢ÁÐ +# 散列 -ʹÓà hasCode() À´·µ»ØÉ¢ÁÐÖµ£¬Ê¹ÓõÄÊǶÔÏóµÄµØÖ·¡£ +使用 hasCode() æ�¥è¿”回散列值,使用的是对象的地å�€ã€‚ -¶ø equals() ÊÇÓÃÀ´ÅжÏÁ½¸ö¶ÔÏóÊÇ·ñÏàµÈµÄ£¬ÏàµÈµÄÁ½¸ö¶ÔÏóÉ¢ÁÐÖµÒ»¶¨ÒªÏàͬ£¬µ«ÊÇÉ¢ÁÐÖµÏàͬµÄÁ½¸ö¶ÔÏó²»Ò»¶¨ÏàµÈ¡£ +而 equals() 是用æ�¥åˆ¤æ–­ä¸¤ä¸ªå¯¹è±¡æ˜¯å�¦ç›¸ç­‰çš„,相等的两个对象散列值一定è¦�相å�Œï¼Œä½†æ˜¯æ•£åˆ—值相å�Œçš„两个对象ä¸�一定相等。 -ÏàµÈ±ØÐëÂú×ãÒÔÏÂÎå¸öÐÔÖÊ£º +相等必须满足以下五个性质: -1. ×Ô·´ÐÔ -2. ¶Ô³ÆÐÔ -3. ´«µÝÐÔ -4. Ò»ÖÂÐÔ£¨¶à´Îµ÷Óà x.equals(y)£¬½á¹û²»±ä£© -5. ¶ÔÈκβ»ÊÇ null µÄ¶ÔÏó x µ÷Óà x.equals(nul) ½á¹û¶¼Îª false +1. 自å��性 +2. 对称性 +3. 传递性 +4. 一致性(多次调用 x.equals(y),结果ä¸�å�˜ï¼‰ +5. 对任何ä¸�是 null 的对象 x 调用 x.equals(nul) 结果都为 false -# Ô´Âë·ÖÎö +# æº�ç �分æž� -½¨ÒéÏÈÔĶÁ [ Ëã·¨ - ²éÕÒ ](https://github.com/CyC2018/InterviewNotes/blob/master/notes/%E7%AE%97%E6%B3%95.md#%E7%AC%AC%E4%B8%89%E7%AB%A0-%E6%9F%A5%E6%89%BE) ²¿·Ö£¬¶Ô¼¯ºÏÀàÔ´ÂëµÄÀí½âÓкܴó°ïÖú¡£ +建议先阅读 [ 算法 - 查找 ](https://github.com/CyC2018/InterviewNotes/blob/master/notes/%E7%AE%97%E6%B3%95.md#%E7%AC%AC%E4%B8%89%E7%AB%A0-%E6%9F%A5%E6%89%BE) 部分,对集å�ˆç±»æº�ç �çš„ç�†è§£æœ‰å¾ˆå¤§å¸®åŠ©ã€‚ -Ô´ÂëÏÂÔØ£º[OpenJDK 1.7](http://download.java.net/openjdk/jdk7) +æº�ç �下载:[OpenJDK 1.7](http://download.java.net/openjdk/jdk7) ## 1. ArraList [ArraList.java](https://github.com/CyC2018/InterviewNotes/blob/master/notes/src/ArrayList.java) -ʵÏÖÁË RandomAccess ½Ó¿Ú£¬Òò´ËÖ§³ÖËæ»ú·ÃÎÊ£¬ÕâÊÇÀíËùµ±È»µÄ£¬ÒòΪ ArrayList ÊÇ»ùÓÚÊý×éʵÏֵġ£ +实现了 RandomAccess 接å�£ï¼Œå› æ­¤æ”¯æŒ�éš�机访问,这是ç�†æ‰€å½“然的,因为 ArrayList 是基于数组实现的。 ```java public class ArrayList extends AbstractList implements List, RandomAccess, Cloneable, java.io.Serializable ``` -»ùÓÚÊý×éʵÏÖ£¬±£´æÔªËصÄÊý×éʹÓà transient ÐÞÊΣ¬ÕâÊÇÒòΪ¸ÃÊý×é²»Ò»¶¨ËùÓÐλÖö¼Õ¼ÂúÔªËØ£¬Òò´ËÒ²¾Íû±ØÒªÈ«²¿¶¼½øÐÐÐòÁл¯¡£ÐèÒªÖØÐ´ writeObject() ºÍ readObject()¡£ +基于数组实现,ä¿�存元素的数组使用 transient 修饰,这是因为该数组ä¸�一定所有ä½�置都å� æ»¡å…ƒç´ ï¼Œå› æ­¤ä¹Ÿå°±æ²¡å¿…è¦�全部都进行åº�列化。需è¦�é‡�写 writeObject() å’Œ readObject()。 ```java private transient Object[] elementData; ``` -Êý×éµÄĬÈÏ´óСΪ 10 +数组的默认大å°�为 10 ```java public ArrayList(int initialCapacity) { @@ -132,7 +133,7 @@ public ArrayList() { } ``` -ɾ³ýÔªËØÊ±µ÷Óà System.arraycopy() ¶ÔÔªËØ½øÐи´ÖÆ£¬Òò´Ëɾ³ý²Ù×÷³É±¾ºÜ¸ß£¬×îºÃÔÚ´´½¨Ê±¾ÍÖ¸¶¨´ó¸ÅµÄÈÝÁ¿´óС£¬¼õÉÙ¸´ÖƲÙ×÷µÄÖ´ÐдÎÊý¡£ +删除元素时调用 System.arraycopy() 对元素进行å¤�制,因此删除æ“�作æˆ�本很高,最好在创建时就指定大概的容é‡�大å°�,å‡�å°‘å¤�制æ“�作的执行次数。 ```java public E remove(int index) { @@ -150,9 +151,9 @@ public E remove(int index) { } ``` -Ìí¼ÓÔªËØÊ±Ê¹Óà ensureCapacity() ·½·¨À´±£Ö¤ÈÝÁ¿×ã¹»£¬Èç¹û²»¹»Ê±£¬ÐèÒª½øÐÐÀ©ÈÝ£¬Ê¹µÃÐÂÈÝÁ¿Îª¾ÉÈÝÁ¿µÄ 1.5 ±¶¡£ +添加元素时使用 ensureCapacity() 方法æ�¥ä¿�è¯�容é‡�足够,如果ä¸�够时,需è¦�进行扩容,使得新容é‡�为旧容é‡�çš„ 1.5 å€�。 -modCount ÓÃÀ´¼Ç¼ ArrayList ·¢Éú±ä»¯µÄ´ÎÊý£¬ÒòΪÿ´ÎÔÚ½øÐÐ add() ºÍ addAll() ʱ¶¼ÐèÒªµ÷Óà ensureCapacity()£¬Òò´ËÖ±½ÓÔÚ ensureCapacity() ÖÐ¶Ô modCount ½øÐÐÐ޸ġ£ +modCount 用æ�¥è®°å½• ArrayList å�‘生å�˜åŒ–的次数,因为æ¯�次在进行 add() å’Œ addAll() 时都需è¦�调用 ensureCapacity(),因此直接在 ensureCapacity() 中对 modCount 进行修改。 ```java public void ensureCapacity(int minCapacity) { @@ -190,7 +191,7 @@ private static int hugeCapacity(int minCapacity) { } ``` -ÔÚ½øÐÐÐòÁл¯»òÕßµü´úµÈ²Ù×÷ʱ£¬ÐèÒª±È½Ï²Ù×÷ǰºó modCount ÊÇ·ñ¸Ä±ä£¬Èç¹û¸Ä±äÁËÐèÒªÅ׳ö ConcurrentModificationException¡£ +在进行åº�列化或者迭代等æ“�作时,需è¦�比较æ“�作å‰�å�Ž modCount 是å�¦æ”¹å�˜ï¼Œå¦‚果改å�˜äº†éœ€è¦�抛出 ConcurrentModificationException。 ```java private void writeObject(java.io.ObjectOutputStream s) @@ -213,20 +214,20 @@ private void writeObject(java.io.ObjectOutputStream s) } ``` -**ºÍ Vector µÄÇø±ð** +**å’Œ Vector 的区别** -1. Vector ºÍ ArrayList ¼¸ºõÊÇÍêÈ«ÏàͬµÄ£¬Î¨Ò»µÄÇø±ðÔÚÓÚ Vector ÊÇͬ²½µÄ£¬Òò´Ë¿ªÏú¾Í±È ArrayList Òª´ó£¬·ÃÎÊÒªÂý¡£×îºÃʹÓà ArrayList ¶ø²»ÊÇ Vector£¬ÒòΪͬ²½ÍêÈ«¿ÉÒÔÓɳÌÐòÔ±×Ô¼ºÀ´¿ØÖÆ£» -2. Vector ÿ´ÎÀ©ÈÝÇëÇóÆä´óСµÄ 2 ±¶¿Õ¼ä£¬¶ø ArrayList ÊÇ 1.5 ±¶¡£ +1. Vector å’Œ ArrayList 几乎是完全相å�Œçš„,唯一的区别在于 Vector 是å�Œæ­¥çš„,因此开销就比 ArrayList è¦�大,访问è¦�慢。最好使用 ArrayList 而ä¸�是 Vector,因为å�Œæ­¥å®Œå…¨å�¯ä»¥ç”±ç¨‹åº�员自己æ�¥æŽ§åˆ¶ï¼› +2. Vector æ¯�次扩容请求其大å°�çš„ 2 å€�空间,而 ArrayList 是 1.5 å€�。 -ΪÁËʹÓÃḬ̈߳²È«µÄ ArrayList£¬¿ÉÒÔʹÓà Collections.synchronizedList(new ArrayList<>()); ·µ»ØÒ»¸öḬ̈߳²È«µÄ ArrayList£¬Ò²¿ÉÒÔʹÓà concurrent ²¢·¢°üÏ嵀 CopyOnWriteArrayList Àࣻ +为了使用线程安全的 ArrayList,å�¯ä»¥ä½¿ç”¨ Collections.synchronizedList(new ArrayList<>()); 返回一个线程安全的 ArrayList,也å�¯ä»¥ä½¿ç”¨ concurrent å¹¶å�‘包下的 CopyOnWriteArrayList 类; -**ºÍ LinkedList µÄÇø±ð** +**å’Œ LinkedList 的区别** -1. ArrayList »ùÓÚ¶¯Ì¬Êý×éʵÏÖ£¬LinkedList »ùÓÚË«ÏòÑ­»·Á´±íʵÏÖ£» -2. ArrayList Ö§³ÖËæ»ú·ÃÎÊ£¬LinkedList ²»Ö§³Ö£» -3. LinkedList ÔÚÈÎÒâλÖÃÌí¼Óɾ³ýÔªËØ¸ü¿ì¡£ +1. ArrayList 基于动æ€�数组实现,LinkedList 基于å�Œå�‘循环链表实现; +2. ArrayList 支æŒ�éš�机访问,LinkedList ä¸�支æŒ�ï¼› +3. LinkedList 在任æ„�ä½�置添加删除元素更快。 -## 2. Vector Óë Stack +## 2. Vector 与 Stack [Vector.java](https://github.com/CyC2018/InterviewNotes/blob/master/notes/src/Vector.java) @@ -242,13 +243,13 @@ private void writeObject(java.io.ObjectOutputStream s) [HashMap.java](https://github.com/CyC2018/InterviewNotes/blob/master/notes/src/HashMap.java) -ʹÓÃÀ­Á´·¨À´½â¾ö³åÍ»¡£ +使用拉链法æ�¥è§£å†³å†²çª�。 -ĬÈÏÈÝÁ¿ capacity Ϊ 16£¬ÐèҪעÒâµÄÊÇÈÝÁ¿±ØÐ뱣֤Ϊ 2 µÄ´Î·½¡£ÈÝÁ¿¾ÍÊÇ Entry[] table Êý×éµÄ³¤¶È£¬size ÊÇÊý×éµÄʵ¼ÊʹÓÃÁ¿¡£ +默认容é‡� capacity 为 16,需è¦�注æ„�的是容é‡�å¿…é¡»ä¿�è¯�为 2 的次方。容é‡�就是 Entry[] table 数组的长度,size 是数组的实际使用é‡�。 -threshold ¹æ¶¨ÁËÒ»¸ö size µÄÁÙ½çÖµ£¬size ±ØÐëСÓÚ threshold£¬Èç¹û´óÓÚµÈÓÚ£¬¾Í±ØÐë½øÐÐÀ©ÈݲÙ×÷¡£ +threshold 规定了一个 size 的临界值,size å¿…é¡»å°�于 threshold,如果大于等于,就必须进行扩容æ“�作。 -threshold = capacity * load_factor£¬ÆäÖÐ load_factor Ϊ table Êý×éÄܹ»Ê¹ÓõıÈÀý£¬load_factor ¹ý´ó»áµ¼Ö¾۴صijöÏÖ£¬´Ó¶øÓ°Ïì²éѯºÍ²åÈëµÄЧÂÊ£¬Ïê¼ûËã·¨±Ê¼Ç¡£ +threshold = capacity * load_factor,其中 load_factor 为 table 数组能够使用的比例,load_factor 过大会导致è�šç°‡çš„出现,从而影å“�查询和æ�’入的效率,详è§�算法笔记。 ```java static final int DEFAULT_INITIAL_CAPACITY = 16; @@ -268,7 +269,7 @@ final float loadFactor; transient int modCount; ``` -´ÓÏÂÃæµÄÌí¼ÓÔªËØ´úÂëÖпÉÒÔ¿´³ö£¬µ±ÐèÒªÀ©ÈÝʱ£¬Áî capacity ΪԭÀ´µÄÁ½±¶¡£ +从下é�¢çš„æ·»åŠ å…ƒç´ ä»£ç �中å�¯ä»¥çœ‹å‡ºï¼Œå½“需è¦�扩容时,令 capacity 为原æ�¥çš„两å€�。 ```java void addEntry(int hash, K key, V value, int bucketIndex) { @@ -279,7 +280,7 @@ void addEntry(int hash, K key, V value, int bucketIndex) { } ``` -Entry ÓÃÀ´±íʾһ¸ö¼üÖµ¶ÔÔªËØ£¬ÆäÖÐµÄ next Ö¸ÕëÔÚÐòÁл¯Ê±»áʹÓᣠ+Entry 用æ�¥è¡¨ç¤ºä¸€ä¸ªé”®å€¼å¯¹å…ƒç´ ï¼Œå…¶ä¸­çš„ next 指针在åº�列化时会使用。 ```java static class Entry implements Map.Entry { @@ -290,7 +291,7 @@ static class Entry implements Map.Entry { } ``` -get() ²Ù×÷ÐèÒª·Ö³ÉÁ½ÖÖÇé¿ö£¬key Ϊ null ºÍ ²»Îª null£¬´ÓÖпÉÒÔ¿´³ö HashMap ÔÊÐí²åÈë null ×÷Ϊ¼ü¡£ +get() æ“�作需è¦�分æˆ�两ç§�情况,key 为 null å’Œ ä¸�为 null,从中å�¯ä»¥çœ‹å‡º HashMap å…�许æ�’å…¥ null 作为键。 ```java public V get(Object key) { @@ -306,7 +307,7 @@ public V get(Object key) { } ``` -put() ²Ù×÷Ò²ÐèÒª¸ù¾Ý key ÊÇ·ñΪ null ×ö²»Í¬µÄ´¦Àí£¬ÐèҪעÒâµÄÊÇÈç¹û±¾À´Ã»ÓÐ key Ϊ null µÄ¼üÖµ¶Ô£¬Ð²åÈëÒ»¸ö key Ϊ null µÄ¼üÖµ¶ÔʱĬÈÏÊÇ·ÅÔÚÊý×éµÄ 0 λÖã¬ÕâÊÇÒòΪ null ²»ÄܼÆËã hash Öµ£¬Ò²¾ÍÎÞ·¨ÖªµÀÓ¦¸Ã·ÅÔÚÄĸöÁ´±íÉÏ¡£ +put() æ“�作也需è¦�æ ¹æ�® key 是å�¦ä¸º null å�šä¸�å�Œçš„处ç�†ï¼Œéœ€è¦�注æ„�的是如果本æ�¥æ²¡æœ‰ key 为 null 的键值对,新æ�’入一个 key 为 null 的键值对时默认是放在数组的 0 ä½�置,这是因为 null ä¸�能计算 hash 值,也就无法知é�“应该放在哪个链表上。 ```java public V put(K key, V value) { @@ -354,8 +355,8 @@ private V putForNullKey(V value) { [ConcurrentHashMap.java](https://github.com/CyC2018/InterviewNotes/blob/master/notes/src/HashMap.java) -[ ̽Ë÷ ConcurrentHashMap ¸ß²¢·¢ÐÔµÄʵÏÖ»úÖÆ ](https://www.ibm.com/developerworks/cn/java/java-lo-concurrenthashmap/) +[ 探索 ConcurrentHashMap 高并å�‘性的实现机制 ](https://www.ibm.com/developerworks/cn/java/java-lo-concurrenthashmap/) -# ²Î¿¼×ÊÁÏ +# å�‚考资料 -- Java ±à³Ì˼Ïë +- Java 编程æ€�想 diff --git a/notes/Leetcode 题解.md b/notes/Leetcode 题解.md index e7c0d9a2..8af37740 100644 --- a/notes/Leetcode 题解.md +++ b/notes/Leetcode 题解.md @@ -1,66 +1,67 @@ -* [Ë㷨˼Ïë](#Ë㷨˼Ïë) - * [¶þ·Ö²éÕÒ](#¶þ·Ö²éÕÒ) - * [̰ÐÄ˼Ïë](#̰ÐÄ˼Ïë) - * [˫ָÕë](#˫ָÕë) - * [ÅÅÐò](#ÅÅÐò) - * [¿ìËÙÑ¡Ôñ](#¿ìËÙÑ¡Ôñ) - * [¶ÑÅÅÐò](#¶ÑÅÅÐò) - * [ͰÅÅÐò](#ͰÅÅÐò) - * [ËÑË÷](#ËÑË÷) +* [算法æ€�想](#算法æ€�想) + * [二分查找](#二分查找) + * [贪心æ€�想](#贪心æ€�想) + * [å�ŒæŒ‡é’ˆ](#å�ŒæŒ‡é’ˆ) + * [排åº�](#排åº�) + * [快速选择](#快速选择) + * [堆排åº�](#堆排åº�) + * [桶排åº�](#桶排åº�) + * [æ�œç´¢](#æ�œç´¢) * [BFS](#bfs) * [DFS](#dfs) * [Backtracking](#backtracking) - * [·ÖÖÎ](#·ÖÖÎ) - * [¶¯Ì¬¹æ»®](#¶¯Ì¬¹æ»®) - * [·Ö¸îÕûÊý](#·Ö¸îÕûÊý) - * [¾ØÕó·¾¶](#¾ØÕó·¾¶) - * [ì³²¨ÄÇÆõÊýÁÐ](#ì³²¨ÄÇÆõÊýÁÐ) - * [×µÝÔö×ÓÐòÁÐ](#×µÝÔö×ÓÐòÁÐ) - * [×¹«¹²×ÓϵÁÐ](#×¹«¹²×ÓϵÁÐ) - * [0-1 ±³°ü](#0-1-±³°ü) - * [Êý×éÇø¼ä](#Êý×éÇø¼ä) - * [×Ö·û´®±à¼­](#×Ö·û´®±à¼­) - * [ÆäËüÎÊÌâ](#ÆäËüÎÊÌâ) - * [Êýѧ](#Êýѧ) - * [ËØÊý](#ËØÊý) - * [×î´ó¹«Ô¼Êý](#×î´ó¹«Ô¼Êý) - * [½øÖÆ×ª»»](#½øÖÆ×ª»») - * [½×³Ë](#½×³Ë) - * [×Ö·û´®¼Ó·¨¼õ·¨](#×Ö·û´®¼Ó·¨¼õ·¨) - * [ÏàÓöÎÊÌâ](#ÏàÓöÎÊÌâ) - * [¶àÊýͶƱÎÊÌâ](#¶àÊýͶƱÎÊÌâ) - * [ÆäËü](#ÆäËü) -* [Êý¾Ý½á¹¹Ïà¹Ø](#Êý¾Ý½á¹¹Ïà¹Ø) - * [Õ»ºÍ¶ÓÁÐ](#Õ»ºÍ¶ÓÁÐ) - * [¹þÏ£±í](#¹þÏ£±í) - * [×Ö·û´®](#×Ö·û´®) - * [Êý×éÓë¾ØÕó](#Êý×éÓë¾ØÕó) - * [ÓÐÐò¾ØÕó](#ÓÐÐò¾ØÕó) - * [Á´±í](#Á´±í) - * [Ê÷](#Ê÷) - * [µÝ¹é](#µÝ¹é) - * [²ã´Î±éÀú](#²ã´Î±éÀú) - * [ǰÖкóÐò±éÀú](#ǰÖкóÐò±éÀú) + * [分治](#分治) + * [动æ€�规划](#动æ€�规划) + * [分割整数](#分割整数) + * [矩阵路径](#矩阵路径) + * [æ–�波那契数列](#æ–�波那契数列) + * [最长递增å­�åº�列](#最长递增å­�åº�列) + * [最长公共å­�系列](#最长公共å­�系列) + * [0-1 背包](#0-1-背包) + * [数组区间](#数组区间) + * [字符串编辑](#字符串编辑) + * [其它问题](#其它问题) + * [æ•°å­¦](#æ•°å­¦) + * [ç´ æ•°](#ç´ æ•°) + * [最大公约数](#最大公约数) + * [进制转æ�¢](#进制转æ�¢) + * [阶乘](#阶乘) + * [字符串加法å‡�法](#字符串加法å‡�法) + * [相é�‡é—®é¢˜](#相é�‡é—®é¢˜) + * [多数投票问题](#多数投票问题) + * [其它](#其它) +* [æ•°æ�®ç»“构相关](#æ•°æ�®ç»“构相关) + * [栈和队列](#栈和队列) + * [哈希表](#哈希表) + * [字符串](#字符串) + * [数组与矩阵](#数组与矩阵) + * [有åº�矩阵](#有åº�矩阵) + * [链表](#链表) + * [æ ‘](#æ ‘) + * [递归](#递归) + * [层次é��历](#层次é��历) + * [å‰�中å�Žåº�é��历](#å‰�中å�Žåº�é��历) * [BST](#bst) * [Trie](#trie) - * [ͼ](#ͼ) - * [λÔËËã](#λÔËËã) -* [²Î¿¼×ÊÁÏ](#²Î¿¼×ÊÁÏ) + * [图](#图) + * [ä½�è¿�ç®—](#ä½�è¿�ç®—) +* [å�‚考资料](#å�‚考资料) -# Ë㷨˼Ïë -## ¶þ·Ö²éÕÒ +# 算法æ€�想 -¶þ·Ö²éÕÒ˼Ïë¼òµ¥£¬µ«ÊÇÔÚʵÏÖʱÓÐһЩÐèҪעÒâµÄϸ½Ú£º +## 二分查找 -1. ÔÚ¼ÆËã mid ʱ²»ÄÜʹÓà mid = (l + h) / 2 ÕâÖÖ·½Ê½£¬ÒòΪ l + h ¿ÉÄܻᵼÖ¼ӷ¨Òç³ö£¬Ó¦¸ÃʹÓà mid = l + (h - l) / 2¡£ +二分查找æ€�想简å�•,但是在实现时有一些需è¦�注æ„�的细节: -2. ¶Ô h µÄ¸³ÖµºÍÑ­»·Ìõ¼þÓйأ¬µ±Ñ­»·Ìõ¼þΪ l <= h ʱ£¬h = mid - 1£»µ±Ñ­»·Ìõ¼þΪ l < h ʱ£¬h = mid¡£ -½âÊÍÈçÏ£ºÔÚÑ­»·Ìõ¼þΪ l <= h ʱ£¬Èç¹û h = mid£¬»á³öÏÖÑ­»·ÎÞ·¨Í˳öµÄÇé¿ö£¬ÀýÈç l = 1£¬h = 1£¬´Ëʱ mid Ò²µÈÓÚ 1£¬Èç¹û´Ëʱ¼ÌÐøÖ´ÐÐ h = mid£¬ÄÇô¾Í»áÎÞÏÞÑ­»·£»ÔÚÑ­»·Ìõ¼þΪ l < h£¬Èç¹û h = mid - 1£¬»á´íÎóÌø¹ý²éÕÒµÄÊý£¬ÀýÈç¶ÔÓÚÊý×é [1,2,3]£¬Òª²éÕÒ 1£¬×ʼ l = 0£¬h = 2£¬mid = 1£¬ÅÐ¶Ï key < arr[mid] Ö´ÐÐ h = mid - 1 = 0£¬´Ëʱѭ»·Í˳ö£¬Ö±½Ó°Ñ²éÕÒµÄÊýÌø¹ýÁË¡£ +1. 在计算 mid æ—¶ä¸�能使用 mid = (l + h) / 2 è¿™ç§�æ–¹å¼�,因为 l + h å�¯èƒ½ä¼šå¯¼è‡´åŠ æ³•æº¢å‡ºï¼Œåº”è¯¥ä½¿ç”¨ mid = l + (h - l) / 2。 -3. l µÄ¸³ÖµÒ»°ã¶¼Îª l = mid + 1¡£ +2. 对 h 的赋值和循环æ�¡ä»¶æœ‰å…³ï¼Œå½“循环æ�¡ä»¶ä¸º l <= h 时,h = mid - 1;当循环æ�¡ä»¶ä¸º l < h 时,h = mid。 +解释如下:在循环æ�¡ä»¶ä¸º l <= h 时,如果 h = mid,会出现循环无法退出的情况,例如 l = 1,h = 1,此时 mid 也等于 1,如果此时继续执行 h = mid,那么就会无é™�循环;在循环æ�¡ä»¶ä¸º l < h,如果 h = mid - 1,会错误跳过查找的数,例如对于数组 [1,2,3],è¦�查找 1,最开始 l = 0,h = 2,mid = 1,判断 key < arr[mid] 执行 h = mid - 1 = 0,此时循环退出,直接把查找的数跳过了。 + +3. l 的赋值一般都为 l = mid + 1。 ```java public int search(int key, int[] arr) { @@ -75,11 +76,11 @@ public int search(int key, int[] arr) { } ``` -**Ç󿪷½** +**求开方** [Leetcode : 69. Sqrt(x) (Easy)](https://leetcode.com/problems/sqrtx/description/) -Ò»¸öÊý x µÄ¿ª·½ sqrt Ò»¶¨ÔÚ 0 \~ x Ö®¼ä£¬²¢ÇÒÂú×ã sqrt == x / sqrt ¡£¿ÉÒÔÀûÓöþ·Ö²éÕÒÔÚ 0 \~ x Ö®¼ä²éÕÒ sqrt¡£ +一个数 x 的开方 sqrt 一定在 0 \~ x 之间,并且满足 sqrt == x / sqrt 。å�¯ä»¥åˆ©ç”¨äºŒåˆ†æŸ¥æ‰¾åœ¨ 0 \~ x 之间查找 sqrt。 ```java public int mySqrt(int x) { @@ -96,7 +97,7 @@ public int mySqrt(int x) { } ``` -**°ÚÓ²±Ò** +**摆硬å¸�** [Leetcode : 441. Arranging Coins (Easy)](https://leetcode.com/problems/arranging-coins/description/) @@ -104,17 +105,17 @@ public int mySqrt(int x) { n = 8 The coins can form the following rows: -¡è -¡è ¡è -¡è ¡è ¡è -¡è ¡è +¤ +¤ ¤ +¤ ¤ ¤ +¤ ¤ Because the 4th row is incomplete, we return 3. ``` -ÌâÄ¿ÃèÊö£ºµÚ i ÐÐ°Ú i ¸ö£¬Í³¼ÆÄܹ»°ÚµÄÐÐÊý¡£ +题目æ��述:第 i 行摆 i 个,统计能够摆的行数。 -·µ»Ø h ¶ø²»ÊÇ l£¬ÒòΪ°ÚµÄÓ²±Ò×îºóÒ»Ðв»ÄÜËã½øÈ¥¡£ +返回 h 而ä¸�是 l,因为摆的硬å¸�最å�Žä¸€è¡Œä¸�能算进去。 ```java public int arrangeCoins(int n) { @@ -130,7 +131,7 @@ public int arrangeCoins(int n) { } ``` -¿ÉÒÔ²»Óöþ·Ö²éÕÒ£¬¸üÖ±¹ÛµÄ½â·¨ÈçÏ£º +å�¯ä»¥ä¸�用二分查找,更直观的解法如下: ```java public int arrangeCoins(int n) { @@ -143,18 +144,18 @@ public int arrangeCoins(int n) { } ``` -**ÓÐÐòÊý×éµÄ Single Element** +**有åº�数组的 Single Element** [Leetcode : 540. Single Element in a Sorted Array (Medium)](https://leetcode.com/problems/single-element-in-a-sorted-array/description/) -ÌâÄ¿ÃèÊö£ºÒ»¸öÓÐÐòÊý×éÖ»ÓÐÒ»¸öÊý²»³öÏÖÁ½´Î£¬ÕÒ³öÕâ¸öÊý¡£ +题目æ��述:一个有åº�数组å�ªæœ‰ä¸€ä¸ªæ•°ä¸�出现两次,找出这个数。 ```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(m % 2 == 1) m--; // ä¿�è¯� l/h/m 都在å�¶æ•°ä½�,使得查找区间大å°�一直都是奇数 if(nums[m] == nums[m + 1]) l = m + 2; else h = m; } @@ -162,19 +163,19 @@ public int singleNonDuplicate(int[] nums) { } ``` -## ̰ÐÄ˼Ïë +## 贪心æ€�想 -̰ÐÄ˼Ï뱣֤ÿ´Î²Ù×÷¶¼ÊǾֲ¿×îÓŵ쬲¢ÇÒ×îºóµÃµ½µÄ½á¹ûÊÇÈ«¾Ö×îÓŵġ£ +贪心æ€�想ä¿�è¯�æ¯�次æ“�作都是局部最优的,并且最å�Žå¾—到的结果是全局最优的。 -**·ÖÅä±ý¸É** +**分é…�饼干** [Leetcode : 455. Assign Cookies (Easy)](https://leetcode.com/problems/assign-cookies/description/) -ÌâÄ¿ÃèÊö£ºÃ¿¸öº¢×Ó¶¼ÓÐÒ»¸öÂú×ã¶È£¬Ã¿¸ö±ý¸É¶¼ÓÐÒ»¸ö´óС£¬Ö»Óбý¸ÉµÄ´óС´óÓÚÒ»¸öº¢×ÓµÄÂú×ã¶È£¬¸Ãº¢×ӲŻá»ñµÃÂú×ã¡£Çó½â×î¶à¿ÉÒÔ»ñµÃÂú×ãµÄº¢×ÓÊýÁ¿¡£ +题目æ��述:æ¯�个孩å­�都有一个满足度,æ¯�个饼干都有一个大å°�,å�ªæœ‰é¥¼å¹²çš„大å°�大于一个孩å­�的满足度,该孩å­�æ‰�会获得满足。求解最多å�¯ä»¥èŽ·å¾—æ»¡è¶³çš„å­©å­�æ•°é‡�。 -ÒòΪ×îСµÄº¢×Ó×îÈÝÒ׵õ½Âú×㣬Òò´ËÏÈÂú×ã×îСº¢×Ó¡£¸øÒ»¸öº¢×ӵıý¸ÉÓ¦µ±¾¡Á¿Ð¡ÓÖÄÜÂú×ã¸Ãº¢×Ó£¬ÕâÑù´ó±ý¸É¾ÍÄÜÄÃÀ´¸øÂú×ã¶È±È½Ï´óµÄº¢×Ó¡£ +因为最å°�的孩å­�最容易得到满足,因此先满足最å°�å­©å­�。给一个孩å­�的饼干应当尽é‡�å°�å�ˆèƒ½æ»¡è¶³è¯¥å­©å­�,这样大饼干就能拿æ�¥ç»™æ»¡è¶³åº¦æ¯”较大的孩å­�。 -Ö¤Ã÷£º¼ÙÉèÔÚij´ÎÑ¡ÔñÖУ¬Ì°ÐIJßÂÔÑ¡Ôñ¸øµÚ i ¸öº¢×Ó·ÖÅäµÚ m ¸ö±ý¸É£¬²¢ÇÒµÚ i ¸öº¢×ÓÂú×ã¶È×îС£¬µÚ m ¸ö±ý¸ÉΪ¿ÉÒÔÂú×ãµÚ i ¸öº¢×ÓµÄ×îС±ý¸É£¬ÀûÓÃ̰ÐIJßÂÔ×îÖÕ¿ÉÒÔÂú×ã k ¸öº¢×Ó¡£¼ÙÉè×îÓŲßÂÔÔÚÕâ´ÎÑ¡ÔñÖиø i ¸öº¢×Ó·ÖÅäµÚ n ¸ö±ý¸É£¬²¢ÇÒÕâ¸ö±ý¸É´óÓÚµÚ m ¸ö±ý¸É¡£ÎÒÃÇ·¢ÏÖʹÓÃµÚ m ¸ö±ý¸ÉÈ¥Ìæ´úµÚ n ¸ö±ý¸ÉÍêÈ«²»Ó°ÏìºóÐøµÄ½á¹û£¬Òò´Ë²»´æÔÚ±Ḛ̀ÐIJßÂÔ¸üÓŵIJßÂÔ£¬¼´Ì°ÐIJßÂÔ¾ÍÊÇ×îÓŲßÂÔ¡£ +è¯�明:å�‡è®¾åœ¨æŸ�次选择中,贪心策略选择给第 i 个孩å­�分é…�第 m 个饼干,并且第 i 个孩å­�满足度最å°�,第 m 个饼干为å�¯ä»¥æ»¡è¶³ç¬¬ i 个孩å­�的最å°�饼干,利用贪心策略最终å�¯ä»¥æ»¡è¶³ k 个孩å­�。å�‡è®¾æœ€ä¼˜ç­–略在这次选择中给 i 个孩å­�分é…�第 n 个饼干,并且这个饼干大于第 m 个饼干。我们å�‘现使用第 m 个饼干去替代第 n 个饼干完全ä¸�å½±å“�å�Žç»­çš„结果,因此ä¸�存在比贪心策略更优的策略,å�³è´ªå¿ƒç­–略就是最优策略。 ```java public int findContentChildren(int[] g, int[] s) { @@ -189,7 +190,7 @@ public int findContentChildren(int[] g, int[] s) { } ``` -**Ͷ·ÉïÚ´ÌÆÆÆøÇò** +**投飞镖刺破气ç�ƒ** [Leetcode : 452. Minimum Number of Arrows to Burst Balloons (Medium)](https://leetcode.com/problems/minimum-number-of-arrows-to-burst-balloons/description/) @@ -201,12 +202,12 @@ Output: 2 ``` -ÌâÄ¿ÃèÊö£ºÆøÇòÔÚÒ»¸öˮƽÊýÖáÉϰڷţ¬¿ÉÒÔÖØµþ£¬·ÉïÚ´¹Ö±ÉäÏò×ø±êÖᣬʹµÃ·¾¶ÉÏµÄÆøÇò¶¼»á´ÌÆÆ¡£Çó½â×îСµÄͶ·ÉïÚ´ÎÊýʹËùÓÐÆøÇò¶¼±»´ÌÆÆ¡£ +题目æ��述:气ç�ƒåœ¨ä¸€ä¸ªæ°´å¹³æ•°è½´ä¸Šæ‘†æ”¾ï¼Œå�¯ä»¥é‡�å� ï¼Œé£žé•–垂直射å�‘å��标轴,使得路径上的气ç�ƒéƒ½ä¼šåˆºç ´ã€‚求解最å°�的投飞镖次数使所有气ç�ƒéƒ½è¢«åˆºç ´ã€‚ -´Ó×óÍùÓÒͶ·ÉïÚ£¬²¢ÇÒÔÚÿ´ÎͶ·ÉïÚʱÂú×ãÒÔÏÂÌõ¼þ£º +从左往å�³æŠ•飞镖,并且在æ¯�次投飞镖时满足以下æ�¡ä»¶ï¼š -1. ×ó±ßÒѾ­Ã»ÓÐÆøÇòÁË£» -2. ±¾´ÎͶ·ÉïÚÄܹ»´ÌÆÆ×î¶àµÄÆøÇò¡£ +1. 左边已ç»�没有气ç�ƒäº†ï¼› +2. 本次投飞镖能够刺破最多的气ç�ƒã€‚ ```java public int findMinArrowShots(int[][] points) { @@ -225,13 +226,13 @@ public int findMinArrowShots(int[][] points) { } ``` -**¹ÉƱµÄ×î´óÊÕÒæ** +**股票的最大收益** [Leetcode : 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] Ìí¼Ó¼Óµ½ÊÕÒæÖУ¬´Ó¶øÔÚ¾Ö²¿×îÓŵÄÇé¿öÏÂÒ²±£Ö¤È«¾Ö×îÓÅ¡£ +对于 [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) { @@ -243,7 +244,7 @@ public int maxProfit(int[] prices) { } ``` -**ÖÖÖ²»¨¶ä** +**ç§�æ¤�花朵** [Leetcode : 605. Can Place Flowers (Easy)](https://leetcode.com/problems/can-place-flowers/description/) @@ -252,7 +253,7 @@ Input: flowerbed = [1,0,0,0,1], n = 1 Output: True ``` -ÌâÄ¿ÃèÊö£º»¨¶äÖ®¼äÖÁÉÙÐèÒªÒ»¸öµ¥Î»µÄ¼ä¸ô¡£ +题目æ��述:花朵之间至少需è¦�一个å�•ä½�的间隔。 ```java public boolean canPlaceFlowers(int[] flowerbed, int n) { @@ -270,13 +271,13 @@ public boolean canPlaceFlowers(int[] flowerbed, int n) { } ``` -**ÐÞ¸ÄÒ»¸öÊý³ÉΪ·ÇµÝ¼õÊý×é** +**修改一个数æˆ�为é�žé€’å‡�数组** [Leetcode : 665. Non-decreasing Array (Easy)](https://leetcode.com/problems/non-decreasing-array/description/) -ÌâÄ¿ÃèÊö£ºÅжÏÒ»¸öÊý×éÄܲ»ÄÜÖ»ÐÞ¸ÄÒ»¸öÊý¾Í³ÉΪ·ÇµÝ¼õÊý×é¡£ +题目æ��述:判断一个数组能ä¸�能å�ªä¿®æ”¹ä¸€ä¸ªæ•°å°±æˆ�为é�žé€’å‡�数组。 -ÔÚ³öÏÖ 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] ²ÅÐС£ +在出现 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) { @@ -292,7 +293,7 @@ public boolean checkPossibility(int[] nums) { } ``` -**ÅжÏÊÇ·ñΪ×Ó´®** +**判断是å�¦ä¸ºå­�串** [Leetcode : 392. Is Subsequence (Medium)](https://leetcode.com/problems/is-subsequence/description/) @@ -311,7 +312,7 @@ public boolean isSubsequence(String s, String t) { } ``` -**·Ö¸ô×Ö·û´®Ê¹Í¬ÖÖ×Ö·û³öÏÖÔÚÒ»Æð** +**分隔字符串使å�Œç§�字符出现在一起** [Leetcode : 763. Partition Labels (Medium)](https://leetcode.com/problems/partition-labels/description/) @@ -344,7 +345,7 @@ public List partitionLabels(String S) { } ``` -**¸ù¾ÝÉí¸ßºÍÐòºÅÖØ×é¶ÓÁÐ** +**æ ¹æ�®èº«é«˜å’Œåº�å�·é‡�组队列** [Leetcode : 406. Queue Reconstruction by Height(Medium)](https://leetcode.com/problems/queue-reconstruction-by-height/description/) @@ -356,11 +357,11 @@ Output: [[5,0], [7,0], [5,2], [6,1], [4,4], [7,1]] ``` -ÌâÄ¿ÃèÊö£ºÒ»¸öѧÉúÓÃÁ½¸ö·ÖÁ¿ (h, k) ÃèÊö£¬h ±íʾÉí¸ß£¬k ±íʾÅÅÔÚÇ°ÃæµÄÓÐ k ¸öѧÉúµÄÉí¸ß±ÈËû¸ß»òÕߺÍËûÒ»Ñù¸ß¡£ +题目æ��述:一个学生用两个分é‡� (h, k) æ��述,h 表示身高,k 表示排在å‰�é�¢çš„æœ‰ k 个学生的身高比他高或者和他一样高。 -ΪÁËÔÚÿ´Î²åÈë²Ù×÷ʱ²»Ó°ÏìºóÐøµÄ²Ù×÷£¬Éí¸ß½Ï¸ßµÄѧÉúÓ¦¸ÃÏÈ×ö²åÈë²Ù×÷£¬·ñÔòÉí¸ß½ÏСµÄѧÉúÔ­ÏÈÕýÈ·²åÈëµÚ k ¸öλÖÿÉÄÜ»á±ä³ÉµÚ k+1 ¸öλÖᣠ+为了在æ¯�次æ�’å…¥æ“�作时ä¸�å½±å“�å�Žç»­çš„æ“�作,身高较高的学生应该先å�šæ�’å…¥æ“�作,å�¦åˆ™èº«é«˜è¾ƒå°�的学生原先正确æ�’入第 k 个ä½�ç½®å�¯èƒ½ä¼šå�˜æˆ�第 k+1 个ä½�置。 -Éí¸ß½µÐò¡¢k ÖµÉýÐò£¬È»ºó°´ÅźÃÐòµÄ˳Ðò²åÈë¶ÓÁÐµÄµÚ k ¸öλÖÃÖС£ +身高é™�åº�ã€�k 值å�‡åº�,然å�ŽæŒ‰æŽ’好åº�的顺åº�æ�’入队列的第 k 个ä½�置中。 ```java public int[][] reconstructQueue(int[][] people) { @@ -388,17 +389,17 @@ public int[][] reconstructQueue(int[][] people) { } ``` -## ˫ָÕë +## å�ŒæŒ‡é’ˆ -˫ָÕëÖ÷ÒªÓÃÓÚ±éÀúÊý×飬Á½¸öÖ¸ÕëÖ¸Ïò²»Í¬µÄÔªËØ£¬´Ó¶øÐ­Í¬Íê³ÉÈÎÎñ¡£ +å�ŒæŒ‡é’ˆä¸»è¦�用于é��历数组,两个指针指å�‘ä¸�å�Œçš„元素,从而å��å�Œå®Œæˆ�任务。 -**´ÓÒ»¸öÒѾ­ÅÅÐòµÄÊý×éÖвéÕÒ³öÁ½¸öÊý£¬Ê¹ËüÃǵĺÍΪ 0** +**从一个已ç»�排åº�的数组中查找出两个数,使它们的和为 0** -[Leetcode £º167. Two Sum II - Input array is sorted (Easy)](https://leetcode.com/problems/two-sum-ii-input-array-is-sorted/description/) +[Leetcode :167. Two Sum II - Input array is sorted (Easy)](https://leetcode.com/problems/two-sum-ii-input-array-is-sorted/description/) -ʹÓÃ˫ָÕ룬һ¸öÖ¸ÕëÖ¸ÏòÔªËØ½ÏСµÄÖµ£¬Ò»¸öÖ¸ÕëÖ¸ÏòÔªËØ½Ï´óµÄÖµ¡£Ö¸Ïò½ÏÐ¡ÔªËØµÄÖ¸Õë´ÓÍ·Ïòβ±éÀú£¬Ö¸Ïò½Ï´óÔªËØµÄÖ¸Õë´ÓβÏòÍ·±éÀú¡£ +使用å�ŒæŒ‡é’ˆï¼Œä¸€ä¸ªæŒ‡é’ˆæŒ‡å�‘元素较å°�的值,一个指针指å�‘元素较大的值。指å�‘较å°�元素的指针从头å�‘å°¾é��历,指å�‘较大元素的指针从尾å�‘头é��历。 -Èç¹ûÁ½¸öÖ¸ÕëÖ¸ÏòÔªËØµÄºÍ sum == target£¬ÄÇôµÃµ½ÒªÇóµÄ½á¹û£»Èç¹û sum > target£¬Òƶ¯½Ï´óµÄÔªËØ£¬Ê¹ sum ±äСһЩ£»Èç¹û sum < target£¬Òƶ¯½ÏСµÄÔªËØ£¬Ê¹ sum ±ä´óһЩ¡£ +如果两个指针指å�‘元素的和 sum == target,那么得到è¦�求的结果;如果 sum > target,移动较大的元素,使 sum å�˜å°�一些;如果 sum < target,移动较å°�的元素,使 sum å�˜å¤§ä¸€äº›ã€‚ ```java public int[] twoSum(int[] numbers, int target) { @@ -413,11 +414,11 @@ public int[] twoSum(int[] numbers, int target) { } ``` -**·´×ª×Ö·û´®ÖеÄÔªÒô×Ö·û** +**å��转字符串中的元音字符** [Leetcode : 345. Reverse Vowels of a String (Easy)](https://leetcode.com/problems/reverse-vowels-of-a-string/description/) -ʹÓÃ˫ָÕ룬ָÏò´ý·´×ªµÄÁ½¸öÔªÒô×Ö·û£¬Ò»¸öÖ¸Õë´ÓÍ·Ïòβ±éÀú£¬Ò»¸öÖ¸Õë´Óβµ½Í·±éÀú¡£ +使用å�ŒæŒ‡é’ˆï¼ŒæŒ‡å�‘å¾…å��转的两个元音字符,一个指针从头å�‘å°¾é��历,一个指针从尾到头é��历。 ```java private HashSet vowels = new HashSet<>(Arrays.asList('a','e','i','o','u','A','E','I','O','U')); @@ -446,11 +447,11 @@ public String reverseVowels(String s) { } ``` -**Á½Êýƽ·½ºÍ** +**两数平方和** [Leetcode : 633. Sum of Square Numbers (Easy)](https://leetcode.com/problems/sum-of-square-numbers/description/) -ÌâÄ¿ÃèÊö£ºÅжÏÒ»¸öÊýÊÇ·ñΪÁ½¸öÊýµÄƽ·½ºÍ£¬ÀýÈç 5 = 12 + 22¡£ +题目æ��述:判断一个数是å�¦ä¸ºä¸¤ä¸ªæ•°çš„平方和,例如 5 = 12 + 22。 ```java public boolean judgeSquareSum(int c) { @@ -465,11 +466,11 @@ public boolean judgeSquareSum(int c) { } ``` -**»ØÎÄ×Ö·û´®** +**回文字符串** [Leetcode : 680. Valid Palindrome II (Easy)](https://leetcode.com/problems/valid-palindrome-ii/description/) -ÌâÄ¿ÃèÊö£º×Ö·û´®¿ÉÒÔɾ³ýÒ»¸ö×Ö·û£¬ÅжÏÊÇ·ñÄܹ¹³É»ØÎÄ×Ö·û´®¡£ +题目æ��述:字符串å�¯ä»¥åˆ é™¤ä¸€ä¸ªå­—符,判断是å�¦èƒ½æž„æˆ�回文字符串。 ```java public boolean validPalindrome(String s) { @@ -495,15 +496,15 @@ private boolean isPalindrome(String s, int l, int r){ } ``` -**¹é²¢Á½¸öÓÐÐòÊý×é** +**归并两个有åº�数组** [Leetcode : 88. Merge Sorted Array (Easy)](https://leetcode.com/problems/merge-sorted-array/description/) -ÌâÄ¿ÃèÊö£º°Ñ¹é²¢½á¹û´æµ½µÚÒ»¸öÊý×éÉÏ +题目æ��述:把归并结果存到第一个数组上 ```java public void merge(int[] nums1, int m, int[] nums2, int n) { - int i = m - 1, j = n - 1; // ÐèÒª´Óβ¿ªÊ¼±éÀú£¬·ñÔòÔÚ nums1 ÉϹ鲢µÃµ½µÄÖµ»á¸²¸Ç»¹Î´½øÐй鲢±È½ÏµÄÖµ + int i = m - 1, j = n - 1; // 需è¦�从尾开始é��历,å�¦åˆ™åœ¨ nums1 上归并得到的值会覆盖还未进行归并比较的值 int idx = m + n - 1; while(i >= 0 || j >= 0){ if(i < 0) nums1[idx] = nums2[j--]; @@ -515,11 +516,11 @@ public void merge(int[] nums1, int m, int[] nums2, int n) { } ``` -**ÅжÏÁ´±íÊÇ·ñ´æÔÚ»·** +**判断链表是å�¦å­˜åœ¨çޝ** [Leetcode : 141. Linked List Cycle (Easy)](https://leetcode.com/problems/linked-list-cycle/description/) -ʹÓÃ˫ָÕ룬һ¸öÖ¸Õëÿ´ÎÒÆ¶¯Ò»¸ö½Úµã£¬Ò»¸öÖ¸Õëÿ´ÎÒÆ¶¯Á½¸ö½Úµã£¬Èç¹û´æÔÚ»·£¬ÄÇôÕâÁ½¸öÖ¸ÕëÒ»¶¨»áÏàÓö¡£ +使用å�ŒæŒ‡é’ˆï¼Œä¸€ä¸ªæŒ‡é’ˆæ¯�次移动一个节点,一个指针æ¯�次移动两个节点,如果存在环,那么这两个指针一定会相é�‡ã€‚ ```java public boolean hasCycle(ListNode head) { @@ -535,7 +536,7 @@ public boolean hasCycle(ListNode head) { } ``` -**××ÓÐòÁÐ** +**最长å­�åº�列** [Leetcode : 524. Longest Word in Dictionary through Deleting (Medium)](https://leetcode.com/problems/longest-word-in-dictionary-through-deleting/description/) @@ -547,7 +548,7 @@ Output: "apple" ``` -ÌâÄ¿ÃèÊö£º¿ÉÒÔɾ³ý s ÖеÄһЩ×Ö·û£¬Ê¹µÃËü³ÉΪ×Ö·û´®Áбí d ÖеÄÒ»¸ö×Ö·û´®¡£ÒªÇóÔÚ d ÖÐÕÒµ½Âú×ãÌõ¼þµÄ××Ö·û´®¡£ +题目æ��述:å�¯ä»¥åˆ é™¤ s 中的一些字符,使得它æˆ�为字符串列表 d 中的一个字符串。è¦�求在 d 中找到满足æ�¡ä»¶çš„æœ€é•¿å­—符串。 ```java public String findLongestWord(String s, List d) { @@ -567,23 +568,23 @@ public String findLongestWord(String s, List d) { } ``` -## ÅÅÐò +## 排åº� -### ¿ìËÙÑ¡Ôñ +### 快速选择 -Ò»°ãÓÃÓÚÇó½â **Kth Element** ÎÊÌ⣬¿ÉÒÔÔÚ O(n) ʱ¼ä¸´ÔÓ¶È£¬O(1) ¿Õ¼ä¸´ÔÓ¶ÈÍê³ÉÇó½â¹¤×÷¡£ +一般用于求解 **Kth Element** 问题,å�¯ä»¥åœ¨ O(n) æ—¶é—´å¤�æ�‚度,O(1) 空间å¤�æ�‚度完æˆ�求解工作。 -Óë¿ìËÙÅÅÐòÒ»Ñù£¬¿ìËÙÑ¡ÔñÒ»°ãÐèÒªÏÈ´òÂÒÊý×飬·ñÔò×Çé¿öÏÂʱ¼ä¸´ÔÓ¶ÈΪ O(n2)¡£ +与快速排åº�一样,快速选择一般需è¦�先打乱数组,å�¦åˆ™æœ€å��情况下时间å¤�æ�‚度为 O(n2)。 -### ¶ÑÅÅÐò +### 堆排åº� -¶ÑÅÅÐòÓÃÓÚÇó½â **TopK Elements** ÎÊÌ⣬ͨ¹ýά»¤Ò»¸ö´óСΪ K µÄ¶Ñ£¬¶ÑÖеÄÔªËØ¾ÍÊÇ TopK Elements¡£µ±È»ËüÒ²¿ÉÒÔÓÃÓÚÇó½â Kth Element ÎÊÌ⣬ÒòΪ×îºó³ö¶ÑµÄÄǸöÔªËØ¾ÍÊÇ Kth Element¡£¿ìËÙÑ¡ÔñÒ²¿ÉÒÔÇó½â TopK Elements ÎÊÌ⣬ÒòΪÕÒµ½ Kth Element Ö®ºó£¬ÔÙ±éÀúÒ»´ÎÊý×飬ËùÓÐСÓÚµÈÓÚ Kth Element µÄÔªËØ¶¼ÊÇ TopK Elements¡£¿ÉÒÔ¿´µ½£¬¿ìËÙÑ¡ÔñºÍ¶ÑÅÅÐò¶¼¿ÉÒÔÇó½â Kth Element ºÍ TopK Elements ÎÊÌâ¡£ +堆排åº�用于求解 **TopK Elements** 问题,通过维护一个大å°�为 K 的堆,堆中的元素就是 TopK Elements。当然它也å�¯ä»¥ç”¨äºŽæ±‚è§£ Kth Element 问题,因为最å�Žå‡ºå †çš„那个元素就是 Kth Element。快速选择也å�¯ä»¥æ±‚è§£ TopK Elements 问题,因为找到 Kth Element 之å�Žï¼Œå†�é��历一次数组,所有å°�于等于 Kth Element 的元素都是 TopK Elements。å�¯ä»¥çœ‹åˆ°ï¼Œå¿«é€Ÿé€‰æ‹©å’Œå †æŽ’åº�都å�¯ä»¥æ±‚è§£ Kth Element å’Œ TopK Elements 问题。 **Kth Element** [Leetocde : 215. Kth Largest Element in an Array (Medium)](https://leetcode.com/problems/kth-largest-element-in-an-array/description/) -**ÅÅÐò**£ºÊ±¼ä¸´ÔÓ¶È O(nlgn)£¬¿Õ¼ä¸´ÔÓ¶È O(1) ½â·¨ +**排åº�**:时间å¤�æ�‚度 O(nlgn),空间å¤�æ�‚度 O(1) 解法 ```java public int findKthLargest(int[] nums, int k) { @@ -593,7 +594,7 @@ public int findKthLargest(int[] nums, int k) { } ``` -**¶ÑÅÅÐò**£ºÊ±¼ä¸´ÔÓ¶È O(nlgk)£¬¿Õ¼ä¸´ÔÓ¶È O(k) +**堆排åº�**:时间å¤�æ�‚度 O(nlgk),空间å¤�æ�‚度 O(k) ```java public int findKthLargest(int[] nums, int k) { @@ -608,7 +609,7 @@ public int findKthLargest(int[] nums, int k) { } ``` -**¿ìËÙÑ¡Ôñ**£ºÊ±¼ä¸´ÔÓ¶È O(n)£¬¿Õ¼ä¸´ÔÓ¶È O(1) +**快速选择**:时间å¤�æ�‚度 O(n),空间å¤�æ�‚度 O(1) ```java public int findKthLargest(int[] nums, int k) { @@ -655,9 +656,9 @@ public int findKthLargest(int[] nums, int k) { } ``` -### ͰÅÅÐò +### 桶排åº� -**ÕÒ³ö³öÏÖÆµÂÊ×î¶àµÄ k ¸öÊý** +**找出出现频率最多的 k 个数** [Leetcode : 347. Top K Frequent Elements (Medium)](https://leetcode.com/problems/top-k-frequent-elements/description/) @@ -686,28 +687,28 @@ public List topKFrequent(int[] nums, int k) { } ``` -## ËÑË÷ +## æ�œç´¢ -Éî¶ÈÓÅÏÈËÑË÷ºÍ¹ã¶ÈÓÅÏÈËÑË÷¹ã·ºÔËÓÃÓÚÊ÷ºÍͼÖУ¬µ«ÊÇËüÃǵÄÓ¦ÓÃÔ¶Ô¶²»Ö¹Èç´Ë¡£ +深度优先æ�œç´¢å’Œå¹¿åº¦ä¼˜å…ˆæ�œç´¢å¹¿æ³›è¿�用于树和图中,但是它们的应用远远ä¸�止如此。 ### BFS -![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/4ff355cf-9a7f-4468-af43-e5b02038facc.jpg) +![](https://github.com/CyC2018/InterviewNotes/blob/master/pics//4ff355cf-9a7f-4468-af43-e5b02038facc.jpg) -¹ã¶ÈÓÅÏÈËÑË÷µÄËÑË÷¹ý³ÌÓеãÏñÒ»²ãÒ»²ãµØ½øÐбéÀú£º´Ó½Úµã 0 ³ö·¢£¬±éÀúµ½ 6¡¢2¡¢1 ºÍ 5 ÕâËĸöнڵ㡣 +广度优先æ�œç´¢çš„æ�œç´¢è¿‡ç¨‹æœ‰ç‚¹åƒ�一层一层地进行é��历:从节点 0 出å�‘,é��历到 6ã€�2ã€�1 å’Œ 5 这四个新节点。 -¼ÌÐø´Ó 6 ¿ªÊ¼±éÀú£¬µÃµ½½Úµã 4 £»´Ó 2 ¿ªÊ¼±éÀú£¬Ã»ÓÐÏÂÒ»¸ö½Úµã£»´Ó 1 ¿ªÊ¼±éÀú£¬Ã»ÓÐÏÂÒ»¸ö½Úµã£»´Ó 5 ¿ªÊ¼±éÀú£¬µÃµ½ 3 ºÍ 4 ½Úµã¡£ÕâÒ»ÂÖ×ܹ²µÃµ½Á½¸öнڵ㣺4 ºÍ 3 ¡£ +继续从 6 开始é��历,得到节点 4 ;从 2 开始é��历,没有下一个节点;从 1 开始é��历,没有下一个节点;从 5 开始é��历,得到 3 å’Œ 4 节点。这一轮总共得到两个新节点:4 å’Œ 3 。 -·´¸´´Óнڵã³ö·¢½øÐÐÉÏÊöµÄ±éÀú²Ù×÷¡£ +å��å¤�从新节点出å�‘进行上述的é��历æ“�作。 -¿ÉÒÔ¿´µ½£¬Ã¿Ò»ÂÖ±éÀúµÄ½Úµã¶¼Óë¸ù½Úµã·¾¶³¤¶ÈÏàͬ¡£Éè di ±íʾµÚ i ¸ö½ÚµãÓë¸ù½ÚµãµÄ·¾¶³¤¶È£¬ÍƵ¼³öÒ»¸ö½áÂÛ£º¶ÔÓÚÏȱéÀúµÄ½Úµã i Óëºó±éÀúµÄ½Úµã j£¬ÓÐ di<=dj¡£ÀûÓÃÕâ¸ö½áÂÛ£¬¿ÉÒÔÇó½â×î¶Ì·¾¶ **×îÓŽâ** ÎÊÌ⣺µÚÒ»´Î±éÀúµ½Ä¿µÄ½Úµã£¬ÆäËù¾­¹ýµÄ·¾¶Îª×î¶Ì·¾¶£¬Èç¹û¼ÌÐø±éÀú£¬Ö®ºóÔÙ±éÀúµ½Ä¿µÄ½Úµã£¬Ëù¾­¹ýµÄ·¾¶¾Í²»ÊÇ×î¶Ì·¾¶¡£ +å�¯ä»¥çœ‹åˆ°ï¼Œæ¯�一轮é��历的节点都与根节点路径长度相å�Œã€‚设 di 表示第 i 个节点与根节点的路径长度,推导出一个结论:对于先é��历的节点 i 与å�Žé��历的节点 j,有 di<=dj。利用这个结论,å�¯ä»¥æ±‚解最短路径 **最优解** 问题:第一次é��历到目的节点,其所ç»�过的路径为最短路径,如果继续é��历,之å�Žå†�é��历到目的节点,所ç»�过的路径就ä¸�是最短路径。 -ÔÚ³ÌÐòʵÏÖ BFS ʱÐèÒª¿¼ÂÇÒÔÏÂÎÊÌ⣺ +在程åº�实现 BFS 时需è¦�考虑以下问题: -- ¶ÓÁУºÓÃÀ´´æ´¢Ã¿Ò»ÂÖ±éÀúµÄ½Úµã -- ±ê¼Ç£º¶ÔÓÚ±éÀú¹ýµÃ½Úµã£¬Ó¦¸Ã½«Ëü±ê¼Ç£¬·ÀÖ¹ÖØ¸´±éÀú£» +- 队列:用æ�¥å­˜å‚¨æ¯�一轮é��历的节点 +- 标记:对于é��历过得节点,应该将它标记,防止é‡�å¤�é��历; -**¼ÆËãÔÚÍø¸ñÖдÓÔ­µãµ½Ìض¨µãµÄ×î¶Ì·¾¶³¤¶È** +**计算在网格中从原点到特定点的最短路径长度** ```html [[1,1,0,1], @@ -749,18 +750,18 @@ private class Position { ### DFS -![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/f7f7e3e5-7dd4-4173-9999-576b9e2ac0a2.png) +![](https://github.com/CyC2018/InterviewNotes/blob/master/pics//f7f7e3e5-7dd4-4173-9999-576b9e2ac0a2.png) -¹ã¶ÈÓÅÏÈËÑË÷Ò»²ãÒ»²ã±éÀú£¬Ã¿Ò»²ã±éÀúµ½µÄËùÓÐнڵ㣬ҪÓöÓÁÐÏÈ´æ´¢ÆðÀ´ÒÔ±¸ÏÂÒ»²ã±éÀúµÄʱºòÔÙ±éÀú£»¶øÉî¶ÈÓÅÏÈËÑË÷ÔÚ±éÀúµ½Ò»¸öнڵãʱÁ¢Âí¶ÔÐÂ½Úµã½øÐбéÀú£º´Ó½Úµã 0 ³ö·¢¿ªÊ¼±éÀú£¬µÃµ½µ½Ð½ڵã 6 ʱ£¬Á¢Âí¶Ôнڵã 6 ½øÐбéÀú£¬µÃµ½Ð½ڵã 4£»Èç´Ë·´¸´ÒÔÕâÖÖ·½Ê½±éÀúнڵ㣬ֱµ½Ã»ÓÐнڵãÁË£¬´Ëʱ·µ»Ø¡£·µ»Øµ½¸ù½Úµã 0 µÄÇé¿öÊÇ£¬¼ÌÐø¶Ô¸ù½Úµã 0 ½øÐбéÀú£¬µÃµ½Ð½ڵã 2£¬È»ºó¼ÌÐøÒÔÉϲ½Öè¡£ +广度优先æ�œç´¢ä¸€å±‚一层é��历,æ¯�一层é��历到的所有新节点,è¦�用队列先存储起æ�¥ä»¥å¤‡ä¸‹ä¸€å±‚é��历的时候å†�é��历;而深度优先æ�œç´¢åœ¨é��历到一个新节点时立马对新节点进行é��历:从节点 0 出å�‘开始é��历,得到到新节点 6 时,立马对新节点 6 进行é��历,得到新节点 4;如此å��å¤�以这ç§�æ–¹å¼�é��历新节点,直到没有新节点了,此时返回。返回到根节点 0 的情况是,继续对根节点 0 进行é��历,得到新节点 2,然å�Žç»§ç»­ä»¥ä¸Šæ­¥éª¤ã€‚ -´ÓÒ»¸ö½Úµã³ö·¢£¬Ê¹Óà DFS ¶ÔÒ»¸öͼ½øÐбéÀúʱ£¬Äܹ»±éÀúµ½µÄ½Úµã¶¼ÊÇ´Ó³õʼ½Úµã¿É´ïµÄ£¬DFS ³£ÓÃÀ´Çó½âÕâÖÖ **¿É´ïÐÔ** ÎÊÌâ¡£ +从一个节点出å�‘,使用 DFS 对一个图进行é��历时,能够é��历到的节点都是从åˆ�始节点å�¯è¾¾çš„,DFS 常用æ�¥æ±‚解这ç§� **å�¯è¾¾æ€§** 问题。 -ÔÚ³ÌÐòʵÏÖ DFS ʱÐèÒª¿¼ÂÇÒÔÏÂÎÊÌ⣺ +在程åº�实现 DFS 时需è¦�考虑以下问题: -- Õ»£ºÓÃÕ»À´±£´æµ±Ç°½ÚµãÐÅÏ¢£¬µ±±éÀúнڵ㷵»ØÊ±Äܹ»¼ÌÐø±éÀúµ±Ç°½Úµã¡£Ò²¿ÉÒÔʹÓõݹéÕ»¡£ -- ±ê¼Ç£ººÍ BFS Ò»ÑùͬÑùÐèÒª¶ÔÒѾ­±éÀú¹ýµÃ½Úµã½øÐбê¼Ç¡£ +- 栈:用栈æ�¥ä¿�存当å‰�节点信æ�¯ï¼Œå½“é��历新节点返回时能够继续é��历当å‰�节点。也å�¯ä»¥ä½¿ç”¨é€’归栈。 +- 标记:和 BFS 一样å�Œæ ·éœ€è¦�对已ç»�é��历过得节点进行标记。 -**²éÕÒ×î´óµÄÁ¬Í¨Ãæ»ý** +**查找最大的连通é�¢ç§¯** [Leetcode : 695. Max Area of Island (Easy)](https://leetcode.com/problems/max-area-of-island/description/) @@ -796,7 +797,7 @@ private int dfs(int[][] grid, int i, int j){ } ``` -**ͼµÄÁ¬Í¨·ÖÁ¿** +**图的连通分é‡�** [Leetcode : 547. Friend Circles (Medium)](https://leetcode.com/problems/friend-circles/description/) @@ -835,7 +836,7 @@ private void dfs(int[][] M, int i, boolean[] hasFind) { } ``` -**¾ØÕóÖеÄÁ¬Í¨ÇøÓòÊýÁ¿** +**矩阵中的连通区域数é‡�** [Leetcode : 200. Number of Islands (Medium)](https://leetcode.com/problems/number-of-islands/description/) @@ -876,7 +877,7 @@ private void dfs(char[][] grid, int i, int j) { } ``` -**Êä³ö¶þ²æÊ÷ÖÐËùÓдӸùµ½Ò¶×ӵķ¾¶** +**输出二å�‰æ ‘中所有从根到å�¶å­�的路径** [Leetcode : 257. Binary Tree Paths (Easy)](https://leetcode.com/problems/binary-tree-paths/description/) @@ -911,7 +912,7 @@ private void dfs(TreeNode root, String prefix, List ret){ } ``` -**Ìî³ä·â±ÕÇøÓò** +**å¡«å……å°�闭区域** [Leetcode : 130. Surrounded Regions (Medium)](https://leetcode.com/problems/surrounded-regions/description/) @@ -929,9 +930,9 @@ X X X X X O X X ``` -ÌâÄ¿ÃèÊö£ºÊ¹µÃ±» 'X' µÄ 'O' ת»»Îª 'X'¡£ +题目æ��述:使得被 'X' çš„ 'O' 转æ�¢ä¸º 'X'。 -ÏÈÌî³ä×îÍâ²à£¬Ê£ÏµľÍÊÇÀï²àÁË¡£ +先填充最外侧,剩下的就是里侧了。 ```java private int[][] direction = {{0, 1}, {0, -1}, {1, 0}, {-1, 0}}; @@ -966,26 +967,26 @@ private void dfs(char[][] board, int r, int c) { } ``` -**´ÓÁ½¸ö·½Ïò¶¼Äܵ½´ïµÄÇøÓò** +**从两个方å�‘都能到达的区域** [Leetcode : 417. Pacific Atlantic Water Flow (Medium)](https://leetcode.com/problems/pacific-atlantic-water-flow/description/) ```html Given the following 5x5 matrix: - Pacific \~ \~ \~ \~ \~ - \~ 1 2 2 3 (5) * - \~ 3 2 3 (4) (4) * - \~ 2 4 (5) 3 1 * - \~ (6) (7) 1 4 5 * - \~ (5) 1 1 2 4 * + Pacific ~ ~ ~ ~ ~ + ~ 1 2 2 3 (5) * + ~ 3 2 3 (4) (4) * + ~ 2 4 (5) 3 1 * + ~ (6) (7) 1 4 5 * + ~ (5) 1 1 2 4 * * * * * * Atlantic Return: [[0, 4], [1, 3], [1, 4], [2, 2], [3, 0], [3, 1], [4, 0]] (positions with parentheses in above matrix). ``` -ÌâÄ¿ÃèÊö£º×ó±ßºÍÉϱßÊÇ̫ƽÑó£¬ÓұߺÍϱßÊÇ´óÎ÷Ñó£¬ÄÚ²¿µÄÊý×Ö´ú±íº£°Î£¬º£°Î¸ßµÄµØ·½µÄË®Äܹ»Á÷µ½µÍµÄµØ·½£¬Çó½âË®Äܹ»Á÷µ½Ì«Æ½ÑóºÍ´óÎ÷ÑóµÄËùÓÐλÖᣠ+题目æ��述:左边和上边是太平洋,å�³è¾¹å’Œä¸‹è¾¹æ˜¯å¤§è¥¿æ´‹ï¼Œå†…部的数字代表海拔,海拔高的地方的水能够æµ�到低的地方,求解水能够æµ�到太平洋和大西洋的所有ä½�置。 ```java private int m, n; @@ -1031,23 +1032,23 @@ private void dfs(int r, int c, boolean[][] canReach) { } ``` -**N »Êºó** +**N 皇å�Ž** [Leetcode : 51. N-Queens (Hard)](https://leetcode.com/problems/n-queens/description/) -![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/1f080e53-4758-406c-bb5f-dbedf89b63ce.jpg) +![](https://github.com/CyC2018/InterviewNotes/blob/master/pics//1f080e53-4758-406c-bb5f-dbedf89b63ce.jpg) -ÌâÄ¿ÃèÊö£ºÔÚ n\*n µÄ¾ØÕóÖаڷŠn ¸ö»Êºó£¬²¢ÇÒÿ¸ö»Êºó²»ÄÜÔÚͬһÐУ¬Í¬Ò»ÁУ¬Í¬Ò»¶Ô½ÇÏßÉÏ£¬ÒªÇó½âËùÓÐµÄ n »Êºó½â¡£ +题目æ��述:在 n\*n 的矩阵中摆放 n 个皇å�Žï¼Œå¹¶ä¸”æ¯�个皇å�Žä¸�能在å�Œä¸€è¡Œï¼Œå�Œä¸€åˆ—,å�Œä¸€å¯¹è§’线上,è¦�求解所有的 n 皇å�Žè§£ã€‚ -Ò»ÐÐÒ»Ðеذڷţ¬ÔÚÈ·¶¨Ò»ÐÐÖеÄÄǸö»ÊºóÓ¦¸Ã°ÚÔÚÄÄÒ»ÁÐʱ£¬ÐèÒªÓÃÈý¸ö±ê¼ÇÊý×éÀ´È·¶¨Ä³Ò»ÁÐÊÇ·ñºÏ·¨£¬ÕâÈý¸ö±ê¼ÇÊý×é·Ö±ðΪ£ºÁбê¼ÇÊý×é¡¢45 ¶È¶Ô½ÇÏß±ê¼ÇÊý×éºÍ 135 ¶È¶Ô½ÇÏß±ê¼ÇÊý×é¡£ +一行一行地摆放,在确定一行中的那个皇å�Žåº”该摆在哪一列时,需è¦�用三个标记数组æ�¥ç¡®å®šæŸ�一列是å�¦å�ˆæ³•,这三个标记数组分别为:列标记数组ã€�45 度对角线标记数组和 135 度对角线标记数组。 -45 ¶È¶Ô½ÇÏß±ê¼ÇÊý×éµÄά¶ÈΪ 2\*n - 1£¬Í¨¹ýÏÂͼ¿ÉÒÔÃ÷È· (r,c) µÄλÖÃËùÔÚµÄÊý×éϱêΪ r + c¡£ +45 度对角线标记数组的维度为 2\*n - 1,通过下图å�¯ä»¥æ˜Žç¡® (r,c) çš„ä½�置所在的数组下标为 r + c。 -![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/85583359-1b45-45f2-9811-4f7bb9a64db7.jpg) +![](https://github.com/CyC2018/InterviewNotes/blob/master/pics//85583359-1b45-45f2-9811-4f7bb9a64db7.jpg) -135 ¶È¶Ô½ÇÏß±ê¼ÇÊý×éµÄά¶ÈÒ²ÊÇ 2\*n - 1£¬(r,c) µÄλÖÃËùÔÚµÄÊý×éϱêΪ n - 1 - (r - c)¡£ +135 度对角线标记数组的维度也是 2\*n - 1,(r,c) çš„ä½�置所在的数组下标为 n - 1 - (r - c)。 -![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/9e80f75a-b12b-4344-80c8-1f9ccc2d5246.jpg) +![](https://github.com/CyC2018/InterviewNotes/blob/master/pics//9e80f75a-b12b-4344-80c8-1f9ccc2d5246.jpg) ```java private List> ret; @@ -1096,15 +1097,15 @@ private void backstracking(int row) { ### Backtracking -»ØËÝÊÇ DFS µÄÒ»ÖÖ£¬Ëü²»ÊÇÓÃÔÚ±éÀúͼµÄ½ÚµãÉÏ£¬¶øÊÇÓÃÓÚÇó½â **ÅÅÁÐ×éºÏ** ÎÊÌ⣬ÀýÈçÓÐ { 'a','b','c' } Èý¸ö×Ö·û£¬Çó½âËùÓÐÓÉÕâÈý¸ö×Ö·ûÅÅÁеõ½µÄ×Ö·û´®¡£ +回溯是 DFS 的一ç§�,它ä¸�是用在é��历图的节点上,而是用于求解 **排列组å�ˆ** 问题,例如有 { 'a','b','c' } 三个字符,求解所有由这三个字符排列得到的字符串。 -ÔÚ³ÌÐòʵÏÖʱ£¬»ØËÝÐèҪעÒâ¶ÔÔªËØ½øÐбê¼ÇµÄÎÊÌ⡣ʹÓõݹéʵÏֵĻØËÝ£¬ÔÚ·ÃÎÊÒ»¸öÐÂÔªËØ½øÈëеĵݹéµ÷Ó㬴ËʱÐèÒª½«ÐÂÔªËØ±ê¼ÇΪÒѾ­·ÃÎÊ£¬ÕâÑù²ÅÄÜÔÚ¼ÌÐøµÝ¹éµ÷ÓÃʱ²»ÓÃÖØ¸´·ÃÎʸÃÔªËØ£»µ«ÊÇÔڵݹ鷵»ØÊ±£¬ÐèÒª½«¸ÃÔªËØ±ê¼ÇΪδ·ÃÎÊ£¬ÒòΪֻÐèÒª±£Ö¤ÔÚÒ»¸öµÝ¹éÁ´Öв»Í¬Ê±·ÃÎÊÒ»¸öÔªËØ£¬¶øÔÚ²»Í¬µÄµÝ¹éÁ´ÊÇ¿ÉÒÔ·ÃÎÊÒѾ­·ÃÎʹýµ«ÊDz»ÔÚµ±Ç°µÝ¹éÁ´ÖеÄÔªËØ¡£ +在程åº�实现时,回溯需è¦�注æ„�对元素进行标记的问题。使用递归实现的回溯,在访问一个新元素进入新的递归调用,此时需è¦�将新元素标记为已ç»�访问,这样æ‰�能在继续递归调用时ä¸�用é‡�å¤�访问该元素;但是在递归返回时,需è¦�将该元素标记为未访问,因为å�ªéœ€è¦�ä¿�è¯�在一个递归链中ä¸�å�Œæ—¶è®¿é—®ä¸€ä¸ªå…ƒç´ ï¼Œè€Œåœ¨ä¸�å�Œçš„递归链是å�¯ä»¥è®¿é—®å·²ç»�访问过但是ä¸�在当å‰�递归链中的元素。 -**Êý×Ö¼üÅÌ×éºÏ** +**数字键盘组å�ˆ** [Leetcode : 17. Letter Combinations of a Phone Number (Medium)](https://leetcode.com/problems/letter-combinations-of-a-phone-number/description/) -![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/a3f34241-bb80-4879-8ec9-dff2d81b514e.jpg) +![](https://github.com/CyC2018/InterviewNotes/blob/master/pics//a3f34241-bb80-4879-8ec9-dff2d81b514e.jpg) ```html Input:Digit string "23" @@ -1134,7 +1135,7 @@ private void combination(String prefix, String digits, int offset, List } ``` -**ÔÚ¾ØÕóÖÐѰÕÒ×Ö·û´®** +**在矩阵中寻找字符串** [Leetcode : 79. Word Search (Medium)](https://leetcode.com/problems/word-search/description/) @@ -1189,7 +1190,7 @@ private boolean dfs(char[][] board, String word, int start, int r, int c) { } ``` -**IP µØÖ·»®·Ö** +**IP 地å�€åˆ’分** [Leetcode : 93. Restore IP Addresses(Medium)](https://leetcode.com/problems/restore-ip-addresses/description/) @@ -1224,7 +1225,7 @@ private void doRestore(int k, String path, String s) { } ``` -**ÅÅÁÐ** +**排列** [Leetcode : 46. Permutations (Medium)](https://leetcode.com/problems/permutations/description/) @@ -1266,7 +1267,7 @@ private void backtracking(List permuteList, boolean[] visited, int[] nu } ``` -**º¬ÓÐÏàÍ¬ÔªËØÇóÅÅÁÐ** +**å�«æœ‰ç›¸å�Œå…ƒç´ æ±‚排列** [Leetcode : 47. Permutations II (Medium)](https://leetcode.com/problems/permutations-ii/description/) @@ -1275,9 +1276,9 @@ private void backtracking(List permuteList, boolean[] visited, int[] nu [[1,1,2], [1,2,1], [2,1,1]] ``` -ÌâÄ¿ÃèÊö£ºÊý×éÔªËØ¿ÉÄܺ¬ÓÐÏàͬµÄÔªËØ£¬½øÐÐÅÅÁÐʱ¾ÍÓпÉÄܳöÏÈÖØ¸´µÄÅÅÁУ¬ÒªÇóÖØ¸´µÄÅÅÁÐÖ»·µ»ØÒ»¸ö¡£ +题目æ��述:数组元素å�¯èƒ½å�«æœ‰ç›¸å�Œçš„元素,进行排列时就有å�¯èƒ½å‡ºå…ˆé‡�å¤�的排列,è¦�求é‡�å¤�的排列å�ªè¿”回一个。 -ÔÚʵÏÖÉÏ£¬ºÍ Permutations ²»Í¬µÄÊÇÒªÏÈÅÅÐò£¬È»ºóÔÚÌí¼ÓÒ»¸öÔªËØÊ±£¬ÅжÏÕâ¸öÔªËØÊÇ·ñµÈÓÚǰһ¸öÔªËØ£¬Èç¹ûµÈÓÚ£¬²¢ÇÒǰһ¸öÔªËØ»¹Î´·ÃÎÊ£¬ÄÇô¾ÍÌø¹ýÕâ¸öÔªËØ¡£ +在实现上,和 Permutations ä¸�å�Œçš„æ˜¯è¦�先排åº�,然å�Žåœ¨æ·»åŠ ä¸€ä¸ªå…ƒç´ æ—¶ï¼Œåˆ¤æ–­è¿™ä¸ªå…ƒç´ æ˜¯å�¦ç­‰äºŽå‰�一个元素,如果等于,并且å‰�一个元素还未访问,那么就跳过这个元素。 ```java public List> permuteUnique(int[] nums) { @@ -1307,7 +1308,7 @@ private void backtracking(List permuteList, boolean[] visited, int[] nu } ``` -**×éºÏ** +**组å�ˆ** [Leetcode : 77. Combinations (Medium)](https://leetcode.com/problems/combinations/description/) @@ -1333,20 +1334,20 @@ public List> combine(int n, int k) { private void backtracking(int start, int n, int k, List combineList, List> ret){ if(k == 0){ - ret.add(new ArrayList(combineList)); // ÕâÀïÒªÖØÐ¹¹ÔìÒ»¸ö List + ret.add(new ArrayList(combineList)); // 这里è¦�é‡�新构造一个 List return; } - for(int i = start; i <= n - k + 1; i++){ // ¼ôÖ¦ + for(int i = start; i <= n - k + 1; i++){ // 剪æž� - combineList.add(i); // °Ñ i ±ê¼ÇΪÒÑ·ÃÎÊ + combineList.add(i); // 把 i 标记为已访问 backtracking(i + 1, n, k - 1, combineList, ret); - combineList.remove(combineList.size() - 1); // °Ñ i ±ê¼ÇΪδ·ÃÎÊ + combineList.remove(combineList.size() - 1); // 把 i 标记为未访问 } } ``` -**×éºÏÇóºÍ** +**组å�ˆæ±‚å’Œ** [Leetcode : 39. Combination Sum (Medium)](https://leetcode.com/problems/combination-sum/description/) @@ -1380,7 +1381,7 @@ A solution set is: } ``` -**º¬ÓÐÏàÍ¬ÔªËØµÄÇó×éºÏÇóºÍ** +**å�«æœ‰ç›¸å�Œå…ƒç´ çš„æ±‚组å�ˆæ±‚å’Œ** [Leetcode : 40. Combination Sum II (Medium)](https://leetcode.com/problems/combination-sum-ii/description/) @@ -1423,11 +1424,11 @@ private void doCombination(int[] candidates, int target, int start, List> ret; @@ -1450,13 +1451,13 @@ private void backtracking(int startIdx, int size, int[] nums) { for (int i = startIdx; i < nums.length; i++) { subsetList.add(nums[i]); - backtracking(i + 1, size, nums); // startIdx ÉèΪÏÂÒ»¸öÔªËØ£¬Ê¹ subset ÖеÄÔªËØ¶¼µÝÔöÅÅÐò + backtracking(i + 1, size, nums); // startIdx 设为下一个元素,使 subset 中的元素都递增排åº� subsetList.remove(subsetList.size() - 1); } } ``` -**º¬ÓÐÏàÍ¬ÔªËØÇó×Ó¼¯** +**å�«æœ‰ç›¸å�Œå…ƒç´ æ±‚å­�集** [Leetcode : 90. Subsets II (Medium)](https://leetcode.com/problems/subsets-ii/description/) @@ -1507,7 +1508,7 @@ private void backtracking(int startIdx, int size, int[] nums) { } ``` -**·Ö¸î×Ö·û´®Ê¹µÃÿ²¿·Ö¶¼ÊÇ»ØÎÄÊý** +**分割字符串使得æ¯�部分都是回文数** [Leetcode : 131. Palindrome Partitioning (Medium)](https://leetcode.com/problems/palindrome-partitioning/description/) @@ -1542,11 +1543,11 @@ private boolean isPalindrome(String s, int begin, int end) { } ``` -**Êý¶À** +**数独** [Leetcode : 37. Sudoku Solver (Hard)](https://leetcode.com/problems/sudoku-solver/description/) -![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/1ca52246-c443-48ae-b1f8-1cafc09ec75c.png) +![](https://github.com/CyC2018/InterviewNotes/blob/master/pics//1ca52246-c443-48ae-b1f8-1cafc09ec75c.png) ```java private boolean[][] rowsUsed = new boolean[9][10]; @@ -1598,9 +1599,9 @@ private int cubeNum(int i, int j) { } ``` -## ·ÖÖÎ +## 分治 -**¸ø±í´ïʽ¼ÓÀ¨ºÅ** +**给表达å¼�加括å�·** [Leetcode : 241. Different Ways to Add Parentheses (Medium)](https://leetcode.com/problems/different-ways-to-add-parentheses/description/) @@ -1638,17 +1639,17 @@ public List diffWaysToCompute(String input) { } ``` -## ¶¯Ì¬¹æ»® +## 动æ€�规划 -µÝ¹éºÍ¶¯Ì¬¹æ»®¶¼Êǽ«Ô­ÎÊÌâ²ð³É¶à¸ö×ÓÎÊÌâÈ»ºóÇó½â£¬ËûÃÇÖ®¼ä×î±¾ÖʵÄÇø±ðÊÇ£¬¶¯Ì¬¹æ»®±£´æÁË×ÓÎÊÌâµÄ½â¡£ +递归和动æ€�规划都是将原问题拆æˆ�多个å­�问题然å�Žæ±‚解,他们之间最本质的区别是,动æ€�规划ä¿�存了å­�问题的解。 -### ·Ö¸îÕûÊý +### 分割整数 -**·Ö¸îÕûÊýµÄ×î´ó³Ë»ý** +**分割整数的最大乘积** [Leetcode : 343. Integer Break (Medim)](https://leetcode.com/problems/integer-break/description/) -ÌâÄ¿ÃèÊö£ºFor example, given n = 2, return 1 (2 = 1 + 1); given n = 10, return 36 (10 = 3 + 3 + 4). +题目æ��述:For example, given n = 2, return 1 (2 = 1 + 1); given n = 10, return 36 (10 = 3 + 3 + 4). ```java public int integerBreak(int n) { @@ -1663,15 +1664,15 @@ public int integerBreak(int n) { } ``` -**°´Æ½·½ÊýÀ´·Ö¸îÕûÊý** +**按平方数æ�¥åˆ†å‰²æ•´æ•°** [Leetcode : 279. Perfect Squares(Medium)](https://leetcode.com/problems/perfect-squares/description/) -ÌâÄ¿ÃèÊö£ºFor example, given n = 12, return 3 because 12 = 4 + 4 + 4; given n = 13, return 2 because 13 = 4 + 9. +题目æ��述:For example, given n = 12, return 3 because 12 = 4 + 4 + 4; given n = 13, return 2 because 13 = 4 + 9. ```java public int numSquares(int n) { - List squares = new ArrayList<>(); // ´æ´¢Ð¡ÓÚ n µÄƽ·½Êý + List squares = new ArrayList<>(); // 存储å°�于 n 的平方数 int diff = 3; while(square <= n) { squares.add(square); @@ -1691,11 +1692,11 @@ public int numSquares(int n) { } ``` -**·Ö¸îÕûÊý¹¹³É×Öĸ×Ö·û´®** +**分割整数构æˆ�å­—æ¯�字符串** [Leetcode : 91. Decode Ways (Medium)](https://leetcode.com/problems/decode-ways/description/) -ÌâÄ¿ÃèÊö£ºGiven encoded message "12", it could be decoded as "AB" (1 2) or "L" (12). +题目æ��述:Given encoded message "12", it could be decoded as "AB" (1 2) or "L" (12). ```java public int numDecodings(String s) { @@ -1715,13 +1716,13 @@ public int numDecodings(String s) { } ``` -### ¾ØÕó·¾¶ +### 矩阵路径 -**¾ØÕóµÄ×Ü·¾¶Êý** +**矩阵的总路径数** [Leetcode : 62. Unique Paths (Medium)](https://leetcode.com/problems/unique-paths/description/) -ÌâÄ¿ÃèÊö£ºÍ³¼Æ´Ó¾ØÕó×óÉϽǵ½ÓÒϽǵÄ·¾¶×ÜÊý£¬Ã¿´ÎÖ»ÄÜÏò×óºÍÏòÏÂÒÆ¶¯¡£ +题目æ��述:统计从矩阵左上角到å�³ä¸‹è§’的路径总数,æ¯�次å�ªèƒ½å�‘左和å�‘下移动。 ```java public int uniquePaths(int m, int n) { @@ -1736,11 +1737,11 @@ public int uniquePaths(int m, int n) { } ``` -**¾ØÕóµÄ×îС·¾¶ºÍ** +**矩阵的最å°�路径和** [Leetcode : 64. Minimum Path Sum (Medium)](https://leetcode.com/problems/minimum-path-sum/description/) -ÌâÄ¿ÃèÊö£ºÇó´Ó¾ØÕóµÄ×óÉϽǵ½ÓÒϽǵÄ×îС·¾¶ºÍ£¬Ã¿´ÎÖ»ÄÜÏò×óºÍÏòÏÂÒÆ¶¯¡£ +题目æ��述:求从矩阵的左上角到å�³ä¸‹è§’的最å°�路径和,æ¯�次å�ªèƒ½å�‘左和å�‘下移动。 ```java public int minPathSum(int[][] grid) { @@ -1758,27 +1759,27 @@ public int minPathSum(int[][] grid) { } ``` -### ì³²¨ÄÇÆõÊýÁÐ +### æ–�波那契数列 -**ÅÀÂ¥ÌÝ** +**爬楼梯** [Leetcode : 70. Climbing Stairs (Easy)](https://leetcode.com/problems/climbing-stairs/description/) -ÌâÄ¿ÃèÊö£ºÓÐ N ½×Â¥ÌÝ£¬Ã¿´Î¿ÉÒÔÉÏÒ»½×»òÕßÁ½½×£¬ÇóÓжàÉÙÖÖÉÏÂ¥Ìݵķ½·¨¡£ +题目æ��述:有 N 阶楼梯,æ¯�次å�¯ä»¥ä¸Šä¸€é˜¶æˆ–者两阶,求有多少ç§�上楼梯的方法。 -¶¨ÒåÒ»¸öÊý×é dp ´æ´¢ÉÏÂ¥Ìݵķ½·¨Êý£¨ÎªÁË·½±ãÌÖÂÛ£¬Êý×éϱê´Ó 1 ¿ªÊ¼£©£¬dp[i] ±íʾ×ßµ½µÚ i ¸öÂ¥Ìݵķ½·¨ÊýÄ¿¡£µÚ i ¸öÂ¥ÌÝ¿ÉÒÔ´ÓµÚ i-1 ºÍ i-2 ¸öÂ¥ÌÝÔÙ×ßÒ»²½µ½´ï£¬×ßµ½µÚ i ¸öÂ¥Ìݵķ½·¨ÊýΪ×ßµ½µÚ i-1 ºÍµÚ i-2 ¸öÂ¥Ìݵķ½·¨ÊýÖ®ºÍ¡£ +定义一个数组 dp 存储上楼梯的方法数(为了方便讨论,数组下标从 1 开始),dp[i] 表示走到第 i 个楼梯的方法数目。第 i 个楼梯å�¯ä»¥ä»Žç¬¬ i-1 å’Œ i-2 个楼梯å†�走一步到达,走到第 i 个楼梯的方法数为走到第 i-1 和第 i-2 个楼梯的方法数之和。 -![](http://latex.codecogs.com/gif.latex?\\\\dp[i]=dp[i-1]+dp[i-2]) +
-dp[N] ¼´ÎªËùÇó¡£ +dp[N] å�³ä¸ºæ‰€æ±‚。 -¿¼Âǵ½ dp[i] Ö»Óë dp[i - 1] ºÍ dp[i - 2] Óйأ¬Òò´Ë¿ÉÒÔÖ»ÓÃÁ½¸ö±äÁ¿À´´æ´¢ dp[i - 1] ºÍ dp[i - 2] ¼´¿É£¬Ê¹µÃÔ­À´µÄ O(n) ¿Õ¼ä¸´ÔÓ¶ÈÓÅ»¯Îª O(1) ¸´ÔÓ¶È¡£ +考虑到 dp[i] å�ªä¸Ž dp[i - 1] å’Œ dp[i - 2] 有关,因此å�¯ä»¥å�ªç”¨ä¸¤ä¸ªå�˜é‡�æ�¥å­˜å‚¨ dp[i - 1] å’Œ dp[i - 2] å�³å�¯ï¼Œä½¿å¾—原æ�¥çš„ O(n) 空间å¤�æ�‚度优化为 O(1) å¤�æ�‚度。 ```java public int climbStairs(int n) { if(n == 1) return 1; if(n == 2) return 2; - // ǰһ¸öÂ¥ÌÝ¡¢ºóÒ»¸öÂ¥ÌÝ + // å‰�一个楼梯ã€�å�Žä¸€ä¸ªæ¥¼æ¢¯ int pre1 = 2, pre2 = 1; for(int i = 2; i < n; i++){ int cur = pre1 + pre2; @@ -1789,27 +1790,27 @@ public int climbStairs(int n) { } ``` -**ĸţÉú²ú** +**æ¯�牛生产** -[³ÌÐòÔ±´úÂëÃæÊÔÖ¸ÄÏ-P181](#) +[程åº�员代ç �é�¢è¯•指å�—-P181](#) -ÌâÄ¿ÃèÊö£º¼ÙÉèÅ©³¡ÖгÉÊìµÄĸţÿÄê¶¼»áÉú 1 ͷСĸţ£¬²¢ÇÒÓÀÔ¶²»»áËÀ¡£µÚÒ»ÄêÓÐ 1 ֻСĸţ£¬´ÓµÚ¶þÄ꿪ʼ£¬Ä¸Å£¿ªÊ¼ÉúСĸţ¡£Ã¿Ö»Ð¡Ä¸Å£ 3 ÄêÖ®ºó³ÉÊìÓÖ¿ÉÒÔÉúСĸţ¡£¸ø¶¨ÕûÊý N£¬Çó N ÄêºóÅ£µÄÊýÁ¿¡£ +题目æ��述:å�‡è®¾å†œåœºä¸­æˆ�熟的æ¯�牛æ¯�年都会生 1 头å°�æ¯�牛,并且永远ä¸�会死。第一年有 1 å�ªå°�æ¯�牛,从第二年开始,æ¯�牛开始生å°�æ¯�牛。æ¯�å�ªå°�æ¯�牛 3 年之å�Žæˆ�熟å�ˆå�¯ä»¥ç”Ÿå°�æ¯�牛。给定整数 N,求 N å¹´å�Žç‰›çš„æ•°é‡�。 -µÚ i Äê³ÉÊìµÄÅ£µÄÊýÁ¿Îª£º +第 i å¹´æˆ�熟的牛的数é‡�为: -![](http://latex.codecogs.com/gif.latex?\\\\dp[i]=dp[i-1]+dp[i-3]) +
-**Ç¿µÁÇÀ½Ù** +**强盗抢劫** [Leetcode : 198. House Robber (Easy)](https://leetcode.com/problems/house-robber/description/) -ÌâÄ¿ÃèÊö£ºÇÀ½ÙÒ»ÅÅס»§£¬µ«ÊDz»ÄÜÇÀÁÚ½üµÄס»§£¬Çó×î´óÇÀ½ÙÁ¿¡£ +题目æ��述:抢劫一排ä½�户,但是ä¸�能抢邻近的ä½�户,求最大抢劫é‡�。 -¶¨Òå dp Êý×éÓÃÀ´´æ´¢×î´óµÄÇÀ½ÙÁ¿£¬ÆäÖÐ dp[i] ±íʾÇÀµ½µÚ i ¸öס»§Ê±µÄ×î´óÇÀ½ÙÁ¿¡£ÓÉÓÚ²»ÄÜÇÀ½ÙÁÚ½üס»§£¬Òò´ËÈç¹ûÇÀ½ÙÁËµÚ i ¸öס»§ÄÇôֻÄÜÇÀ½Ù i - 2 ºÍ i - 3 µÄס»§£¬ËùÒÔ +定义 dp 数组用æ�¥å­˜å‚¨æœ€å¤§çš„æŠ¢åŠ«é‡�,其中 dp[i] 表示抢到第 i 个ä½�户时的最大抢劫é‡�。由于ä¸�能抢劫邻近ä½�户,因此如果抢劫了第 i 个ä½�户那么å�ªèƒ½æŠ¢åŠ« i - 2 å’Œ i - 3 çš„ä½�户,所以 -![](http://latex.codecogs.com/gif.latex?\\\\dp[i]=max(dp[i-2],dp[i-3])+nums[i]) +
-O(n) ¿Õ¼ä¸´ÔÓ¶ÈʵÏÖ·½·¨£º +O(n) 空间å¤�æ�‚度实现方法: ```java public int rob(int[] nums) { @@ -1828,7 +1829,7 @@ public int rob(int[] nums) { } ``` -O(1) ¿Õ¼ä¸´ÔÓ¶ÈʵÏÖ·½·¨£º +O(1) 空间å¤�æ�‚度实现方法: ```java public int rob(int[] nums) { @@ -1847,7 +1848,7 @@ public int rob(int[] nums) { } ``` -**Ç¿µÁÔÚ»·ÐνÖÇøÇÀ½Ù** +**强盗在环形街区抢劫** [Leetcode : 213. House Robber II (Medium)](https://leetcode.com/problems/house-robber-ii/description/) @@ -1875,39 +1876,39 @@ private int rob(int[] nums, int s, int e) { ``` -**Ðżþ´íÅÅ** +**信件错排** -ÌâÄ¿ÃèÊö£ºÓÐ N ¸ö ÐÅ ºÍ Ðŷ⣬ËüÃDZ»´òÂÒ£¬Çó´íÎó×°Ðŵķ½Ê½ÊýÁ¿¡£ +题目æ��述:有 N 个 ä¿¡ å’Œ ä¿¡å°�,它们被打乱,求错误装信的方å¼�æ•°é‡�。 -¶¨ÒåÒ»¸öÊý×é dp ´æ´¢´íÎó·½Ê½ÊýÁ¿£¬dp[i] ±íʾǰ i ¸öÐźÍÐÅ·âµÄ´íÎó·½Ê½ÊýÁ¿¡£¼ÙÉèµÚ i ¸öÐÅ×°µ½µÚ j ¸öÐÅ·âÀïÃæ£¬¶øµÚ j ¸öÐÅ×°µ½µÚ k ¸öÐÅ·âÀïÃæ¡£¸ù¾Ý i ºÍ k ÊÇ·ñÏàµÈ£¬ÓÐÁ½ÖÖÇé¿ö£º +定义一个数组 dp 存储错误方å¼�æ•°é‡�,dp[i] 表示å‰� i 个信和信å°�的错误方å¼�æ•°é‡�。å�‡è®¾ç¬¬ i 个信装到第 j 个信å°�里é�¢ï¼Œè€Œç¬¬ j 个信装到第 k 个信å°�里é�¢ã€‚æ ¹æ�® i å’Œ k 是å�¦ç›¸ç­‰ï¼Œæœ‰ä¸¤ç§�情况: -¢Ù i==k£¬½»»» i ºÍ k µÄÐźó£¬ËüÃǵÄÐźÍÐÅ·âÔÚÕýÈ·µÄλÖ㬵«ÊÇÆäÓà i-2 ·âÐÅÓÐ dp[i-2] ÖÖ´íÎó×°Ðŵķ½Ê½¡£ÓÉÓÚ j ÓÐ i-1 ÖÖȡֵ£¬Òò´Ë¹²ÓÐ (i-1)\*dp[i-2] ÖÖ´íÎó×°ÐÅ·½Ê½¡£ +â‘  i==k,交æ�¢ i å’Œ k 的信å�Žï¼Œå®ƒä»¬çš„信和信å°�在正确的ä½�置,但是其余 i-2 å°�信有 dp[i-2] ç§�错误装信的方å¼�。由于 j 有 i-1 ç§�å�–值,因此共有 (i-1)\*dp[i-2] ç§�错误装信方å¼�。 -¢Ú i != k£¬½»»» i ºÍ j µÄÐÅºó£¬µÚ i ¸öÐźÍÐÅ·âÔÚÕýÈ·µÄλÖã¬ÆäÓà i-1 ·âÐÅÓÐ dp[i-1] ÖÖ´íÎó×°ÐÅ·½Ê½¡£ÓÉÓÚ j ÓÐ i-1 ÖÖȡֵ£¬Òò´Ë¹²ÓÐ (n-1)\*dp[i-1] ÖÖ´íÎó×°ÐÅ·½Ê½¡£ +â‘¡ i != k,交æ�¢ i å’Œ j 的信å�Žï¼Œç¬¬ i 个信和信å°�在正确的ä½�置,其余 i-1 å°�信有 dp[i-1] ç§�错误装信方å¼�。由于 j 有 i-1 ç§�å�–值,因此共有 (n-1)\*dp[i-1] ç§�错误装信方å¼�。 -×ÛÉÏËùÊö£¬´íÎó×°ÐÅÊýÁ¿·½Ê½ÊýÁ¿Îª£º +综上所述,错误装信数é‡�æ–¹å¼�æ•°é‡�为: -![](http://latex.codecogs.com/gif.latex?\\\\dp[i]=(i-1)*dp[i-2]+(i-1)*dp[i-1]) +
-dp[N] ¼´ÎªËùÇó¡£ +dp[N] å�³ä¸ºæ‰€æ±‚。 -ºÍÉÏÂ¥ÌÝÎÊÌâÒ»Ñù£¬dp[i] Ö»Óë dp[i-1] ºÍ dp[i-2] Óйأ¬Òò´ËÒ²¿ÉÒÔÖ»ÓÃÁ½¸ö±äÁ¿À´´æ´¢ dp[i-1] ºÍ dp[i-2]¡£ +和上楼梯问题一样,dp[i] å�ªä¸Ž dp[i-1] å’Œ dp[i-2] 有关,因此也å�¯ä»¥å�ªç”¨ä¸¤ä¸ªå�˜é‡�æ�¥å­˜å‚¨ dp[i-1] å’Œ dp[i-2]。 -### ×µÝÔö×ÓÐòÁÐ +### 最长递增å­�åº�列 -ÒÑÖªÒ»¸öÐòÁÐ {S1, S2,...,Sn} £¬È¡³öÈô¸ÉÊý×é³ÉеÄÐòÁÐ {Si1, Si2,..., Sim}£¬ÆäÖÐ i1¡¢i2 ... im ±£³ÖµÝÔö£¬¼´ÐÂÐòÁÐÖи÷¸öÊýÈÔÈ»±£³ÖÔ­ÊýÁÐÖеÄÏȺó˳Ðò£¬³ÆÐÂÐòÁÐΪԭÐòÁеÄÒ»¸ö**×ÓÐòÁÐ**¡£ +已知一个åº�列 {S1, S2,...,Sn} ,å�–出若干数组æˆ�æ–°çš„åº�列 {Si1, Si2,..., Sim},其中 i1ã€�i2 ... im ä¿�æŒ�递增,å�³æ–°åº�列中å�„个数ä»�ç„¶ä¿�æŒ�原数列中的先å�Žé¡ºåº�,称新åº�列为原åº�列的一个**å­�åº�列**。 -Èç¹ûÔÚ×ÓÐòÁÐÖУ¬µ±Ï±ê ix > iy ʱ£¬Six > Siy£¬³Æ×ÓÐòÁÐΪԭÐòÁеÄÒ»¸ö**µÝÔö×ÓÐòÁÐ**¡£ +如果在å­�åº�列中,当下标 ix > iy 时,Six > Siy,称å­�åº�列为原åº�列的一个**递增å­�åº�列**。 -¶¨ÒåÒ»¸öÊý×é dp ´æ´¢×µÝÔö×ÓÐòÁеij¤¶È£¬dp[n] ±íʾÒÔ Sn ½áβµÄÐòÁеÄ×µÝÔö×ÓÐòÁг¤¶È¡£¶ÔÓÚÒ»¸öµÝÔö×ÓÐòÁÐ {Si1, Si2,...,Sim}£¬Èç¹û im < n ²¢ÇÒ Sim < Sn £¬´Ëʱ {Si1, Si2,..., Sim, Sn} Ϊһ¸öµÝÔö×ÓÐòÁУ¬µÝÔö×ÓÐòÁеij¤¶ÈÔö¼Ó 1¡£Âú×ãÉÏÊöÌõ¼þµÄµÝÔö×ÓÐòÁÐÖУ¬³¤¶È×µÄÄǸöµÝÔö×ÓÐòÁоÍÊÇÒªÕҵģ¬ÔÚ³¤¶È×µÄµÝÔö×ÓÐòÁÐÉϼÓÉÏ Sn ¾Í¹¹³ÉÁËÒÔ Sn Ϊ½áβµÄ×µÝÔö×ÓÐòÁС£Òò´Ë dp[n] = max{ dp[i]+1 | Si < Sn && i < n} ¡£ +定义一个数组 dp 存储最长递增å­�åº�列的长度,dp[n] 表示以 Sn 结尾的åº�列的最长递增å­�åº�列长度。对于一个递增å­�åº�列 {Si1, Si2,...,Sim},如果 im < n 并且 Sim < Sn ,此时 {Si1, Si2,..., Sim, Sn} 为一个递增å­�åº�列,递增å­�åº�列的长度增加 1。满足上述æ�¡ä»¶çš„递增å­�åº�列中,长度最长的那个递增å­�åº�列就是è¦�找的,在长度最长的递增å­�åº�列上加上 Sn 就构æˆ�了以 Sn 为结尾的最长递增å­�åº�列。因此 dp[n] = max{ dp[i]+1 | Si < Sn && i < n} 。 -ÒòΪÔÚÇó dp[n] ʱ¿ÉÄÜÎÞ·¨ÕÒµ½Ò»¸öÂú×ãÌõ¼þµÄµÝÔö×ÓÐòÁУ¬´Ëʱ {Sn} ¾Í¹¹³ÉÁ˵ÝÔö×ÓÐòÁУ¬Òò´ËÐèÒª¶ÔÇ°ÃæµÄÇó½â·½³Ì×öÐ޸ģ¬Áî dp[n] ×îСΪ 1£¬¼´£º +因为在求 dp[n] æ—¶å�¯èƒ½æ— æ³•找到一个满足æ�¡ä»¶çš„递增å­�åº�列,此时 {Sn} 就构æˆ�了递增å­�åº�列,因此需è¦�对å‰�é�¢çš„æ±‚解方程å�šä¿®æ”¹ï¼Œä»¤ dp[n] 最å°�为 1,å�³ï¼š -![](http://latex.codecogs.com/gif.latex?\\\\dp[n]=max\{1,dp[i]+1|S_i -¶ÔÓÚÒ»¸ö³¤¶ÈΪ N µÄÐòÁУ¬××ÓÐòÁв¢²»Ò»¶¨»áÒÔ SN Ϊ½á⣬Òò´Ë dp[N] ²»ÊÇÐòÁеÄ×µÝÔö×ÓÐòÁеij¤¶È£¬ÐèÒª±éÀú dp Êý×éÕÒ³ö×î´óÖµ²ÅÊÇËùÒªµÄ½á¹û£¬¼´ max{ dp[i] | 1 <= i <= N} ¼´ÎªËùÇó¡£ +对于一个长度为 N çš„åº�列,最长å­�åº�列并ä¸�一定会以 SN 为结尾,因此 dp[N] ä¸�是åº�列的最长递增å­�åº�列的长度,需è¦�é��历 dp 数组找出最大值æ‰�是所è¦�的结果,å�³ max{ dp[i] | 1 <= i <= N} å�³ä¸ºæ‰€æ±‚。 -**×µÝÔö×ÓÐòÁÐ** +**最长递增å­�åº�列** [Leetcode : 300. Longest Increasing Subsequence (Medium)](https://leetcode.com/problems/longest-increasing-subsequence/description/) @@ -1930,7 +1931,7 @@ public int lengthOfLIS(int[] nums) { } ``` -ÒÔÉϽⷨµÄʱ¼ä¸´ÔÓ¶ÈΪ O(n2) £¬¿ÉÒÔʹÓöþ·Ö²éÕÒʹµÃʱ¼ä¸´ÔӶȽµµÍΪ O(nlogn)¡£¶¨ÒåÒ»¸ö tails Êý×飬ÆäÖÐ tails[i] ´æ´¢³¤¶ÈΪ i + 1 µÄ×µÝÔö×ÓÐòÁеÄ×îºóÒ»¸öÔªËØ£¬ÀýÈç¶ÔÓÚÊý×é [4,5,6,3]£¬ÓÐ +以上解法的时间å¤�æ�‚度为 O(n2) ,å�¯ä»¥ä½¿ç”¨äºŒåˆ†æŸ¥æ‰¾ä½¿å¾—æ—¶é—´å¤�æ�‚度é™�低为 O(nlogn)。定义一个 tails 数组,其中 tails[i] 存储长度为 i + 1 的最长递增å­�åº�列的最å�Žä¸€ä¸ªå…ƒç´ ï¼Œä¾‹å¦‚对于数组 [4,5,6,3],有 ```html len = 1 : [4], [5], [6], [3] => tails[0] = 3 @@ -1938,9 +1939,9 @@ len = 2 : [4, 5], [5, 6] => tails[1] = 5 len = 3 : [4, 5, 6] => tails[2] = 6 ``` -¶ÔÓÚÒ»¸öÔªËØ x£¬Èç¹ûËü´óÓÚ tails Êý×éËùÓеÄÖµ£¬ÄÇô°ÑËüÌí¼Óµ½ tails ºóÃæ£»Èç¹û tails[i-1] < x <= tails[i]£¬ÄÇô¸üРtails[i] = x ¡£ +对于一个元素 x,如果它大于 tails 数组所有的值,那么把它添加到 tails å�Žé�¢ï¼›å¦‚æžœ tails[i-1] < x <= tails[i],那么更新 tails[i] = x 。 -¿ÉÒÔ¿´³ö tails Êý×é±£³ÖÓÐÐò£¬Òò´ËÔÚ²éÕÒ Si λÓÚ tails Êý×éµÄλÖÃʱ¾Í¿ÉÒÔʹÓöþ·Ö²éÕÒ¡£ +å�¯ä»¥çœ‹å‡º tails 数组ä¿�æŒ�有åº�,因此在查找 Si ä½�于 tails 数组的ä½�置时就å�¯ä»¥ä½¿ç”¨äºŒåˆ†æŸ¥æ‰¾ã€‚ ```java public int lengthOfLIS(int[] nums) { @@ -1966,13 +1967,13 @@ private int binarySearch(int[] nums, int sIdx, int eIdx, int key){ } ``` -**×°Ú¶¯×ÓÐòÁÐ** +**最长摆动å­�åº�列** [Leetcode : 376. Wiggle Subsequence (Medium)](https://leetcode.com/problems/wiggle-subsequence/description/) -ÒªÇó£ºÊ¹Óà O(n) ʱ¼ä¸´ÔÓ¶ÈÇó½â¡£ +è¦�求:使用 O(n) æ—¶é—´å¤�æ�‚度求解。 -ʹÓÃÁ½¸ö״̬ up ºÍ down¡£ +使用两个状æ€� up å’Œ down。 ```java public int wiggleMaxLength(int[] nums) { @@ -1987,35 +1988,35 @@ public int wiggleMaxLength(int[] nums) { } ``` -### ×¹«¹²×ÓϵÁÐ +### 最长公共å­�系列 -¶ÔÓÚÁ½¸ö×ÓÐòÁÐ S1 ºÍ S2£¬ÕÒ³öËüÃÇ×µÄ¹«¹²×ÓÐòÁС£ +对于两个å­�åº�列 S1 å’Œ S2,找出它们最长的公共å­�åº�列。 -¶¨ÒåÒ»¸ö¶þάÊý×é dp ÓÃÀ´´æ´¢×¹«¹²×ÓÐòÁеij¤¶È£¬ÆäÖÐ dp[i][j] ±íʾ S1 µÄǰ i ¸ö×Ö·ûÓë S2 µÄǰ j ¸ö×Ö·û×¹«¹²×ÓÐòÁеij¤¶È¡£¿¼ÂÇ S1i Óë S2j ÖµÊÇ·ñÏàµÈ£¬·ÖΪÁ½ÖÖÇé¿ö£º +定义一个二维数组 dp 用æ�¥å­˜å‚¨æœ€é•¿å…¬å…±å­�åº�列的长度,其中 dp[i][j] 表示 S1 çš„å‰� i 个字符与 S2 çš„å‰� j 个字符最长公共å­�åº�列的长度。考虑 S1i 与 S2j 值是å�¦ç›¸ç­‰ï¼Œåˆ†ä¸ºä¸¤ç§�情况: -¢Ù µ± S1i==S2j ʱ£¬ÄÇô¾ÍÄÜÔÚ S1 µÄǰ i-1 ¸ö×Ö·ûÓë S2 µÄǰ j-1 ¸ö×Ö·û×¹«¹²×ÓÐòÁеĻù´¡ÉÏÔÙ¼ÓÉÏ S1i Õâ¸öÖµ£¬×¹«¹²×ÓÐòÁг¤¶È¼Ó 1 £¬¼´ dp[i][j] = dp[i-1][j-1] + 1¡£ +â‘  当 S1i==S2j 时,那么就能在 S1 çš„å‰� i-1 个字符与 S2 çš„å‰� j-1 个字符最长公共å­�åº�列的基础上å†�加上 S1i 这个值,最长公共å­�åº�列长度加 1 ,å�³ dp[i][j] = dp[i-1][j-1] + 1。 -¢Ú µ± S1i != S2j ʱ£¬´Ëʱ×¹«¹²×ÓÐòÁÐΪ S1 µÄǰ i-1 ¸ö×Ö·ûºÍ S2 µÄǰ j ¸ö×Ö·û×¹«¹²×ÓÐòÁУ¬Óë S1 µÄǰ i ¸ö×Ö·ûºÍ S2 µÄǰ j-1 ¸ö×Ö·û×¹«¹²×ÓÐòÁУ¬ËüÃǵÄ×î´óÕߣ¬¼´ dp[i][j] = max{ dp[i-1][j], dp[i][j-1] }¡£ +â‘¡ 当 S1i != S2j 时,此时最长公共å­�åº�列为 S1 çš„å‰� i-1 个字符和 S2 çš„å‰� j 个字符最长公共å­�åº�列,与 S1 çš„å‰� i 个字符和 S2 çš„å‰� j-1 个字符最长公共å­�åº�列,它们的最大者,å�³ dp[i][j] = max{ dp[i-1][j], dp[i][j-1] }。 -×ÛÉÏ£¬×¹«¹²×ÓϵÁеÄ×´Ì¬×ªÒÆ·½³ÌΪ£º +综上,最长公共å­�系列的状æ€�转移方程为: -![](http://latex.codecogs.com/gif.latex?\\\\ +$$ dp[i][j]=\left\{ \begin{array}{rcl} -dp[i-1][j-1]&&{S1_i==S2_j}\\ -max(dp[i-1][j],dp[i][j-1])&&{S1_i<>S2_j} -\end{array}\right. -) +dp[i-1][j-1] && { S1_i==S2_j }\\ +max(dp[i-1][j], dp[i][j-1]) &&{ S1_i <> S2_j } +\end{array} \right. +$$ -![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/1dc481cc-99f6-4fa8-8f68-fbd563995bf5.png) +![](https://github.com/CyC2018/InterviewNotes/blob/master/pics//1dc481cc-99f6-4fa8-8f68-fbd563995bf5.png) -¶ÔÓÚ³¤¶ÈΪ N µÄÐòÁÐ S1 ºÍ ³¤¶ÈΪ M µÄÐòÁÐ S2£¬dp[N][M] ¾ÍÊÇÐòÁÐ S1 ºÍÐòÁÐ S2 µÄ×¹«¹²×ÓÐòÁг¤¶È¡£ +对于长度为 N çš„åº�列 S1 å’Œ 长度为 M çš„åº�列 S2,dp[N][M] 就是åº�列 S1 å’Œåº�列 S2 的最长公共å­�åº�列长度。 -Óë×µÝÔö×ÓÐòÁÐÏà±È£¬×¹«¹²×ÓÐòÁÐÓÐÒÔϲ»Í¬µã£º +与最长递增å­�åº�列相比,最长公共å­�åº�列有以下ä¸�å�Œç‚¹ï¼š -¢Ù Õë¶ÔµÄÊÇÁ½¸öÐòÁУ¬ÇóËüÃǵÄ×¹«¹²×ÓÐòÁС£ -¢Ú ÔÚ×µÝÔö×ÓÐòÁÐÖУ¬dp[i] ±íʾÒÔ Si Ϊ½áβµÄ×µÝÔö×ÓÐòÁг¤¶È£¬×ÓÐòÁбØÐë°üº¬ Si £»ÔÚ×¹«¹²×ÓÐòÁÐÖУ¬dp[i][j] ±íʾ S1 ÖÐǰ i ¸ö×Ö·ûÓë S2 ÖÐǰ j ¸ö×Ö·ûµÄ×¹«¹²×ÓÐòÁг¤¶È£¬²»Ò»¶¨°üº¬ S1i ºÍ S2j ¡£ -¢Û ÓÉÓÚ 2 £¬ÔÚÇó×îÖÕ½âʱ£¬×¹«¹²×ÓÐòÁÐÖÐ dp[N][M] ¾ÍÊÇ×îÖս⣬¶ø×µÝÔö×ÓÐòÁÐÖÐ dp[N] ²»ÊÇ×îÖս⣬ÒòΪÒÔ SN Ϊ½áβµÄ×µÝÔö×ÓÐòÁв»Ò»¶¨ÊÇÕû¸öÐòÁÐ×µÝÔö×ÓÐòÁУ¬ÐèÒª±éÀúÒ»±é dp Êý×éÕÒµ½×î´óÕß¡£ +â‘  针对的是两个åº�列,求它们的最长公共å­�åº�列。 +â‘¡ 在最长递增å­�åº�列中,dp[i] 表示以 Si 为结尾的最长递增å­�åº�列长度,å­�åº�列必须包å�« Si ;在最长公共å­�åº�列中,dp[i][j] 表示 S1 中å‰� i 个字符与 S2 中å‰� j 个字符的最长公共å­�åº�列长度,ä¸�一定包å�« S1i å’Œ S2j 。 +â‘¢ 由于 2 ,在求最终解时,最长公共å­�åº�列中 dp[N][M] 就是最终解,而最长递增å­�åº�列中 dp[N] ä¸�是最终解,因为以 SN 为结尾的最长递增å­�åº�列ä¸�一定是整个åº�列最长递增å­�åº�列,需è¦�é��历一é�� dp 数组找到最大者。 ```java public int lengthOfLCS(int[] nums1, int[] nums2) { @@ -2031,20 +2032,20 @@ public int lengthOfLCS(int[] nums1, int[] nums2) { } ``` -### 0-1 ±³°ü +### 0-1 背包 -ÓÐÒ»¸öÈÝÁ¿Îª N µÄ±³°ü£¬ÒªÓÃÕâ¸ö±³°ü×°ÏÂÎïÆ·µÄ¼ÛÖµ×î´ó£¬ÕâЩÎïÆ·ÓÐÁ½¸öÊôÐÔ£ºÌå»ý w ºÍ¼ÛÖµ v¡£ +有一个容é‡�为 N 的背包,è¦�用这个背包装下物å“�的价值最大,这些物å“�有两个属性:体积 w 和价值 v。 -¶¨ÒåÒ»¸ö¶þάÊý×é dp ´æ´¢×î´ó¼ÛÖµ£¬ÆäÖÐ dp[i][j] ±íʾÌå»ý²»³¬¹ý j µÄÇé¿öÏ£¬Ç° i ¼þÎïÆ·ÄÜ´ïµ½µÄ×î´ó¼ÛÖµ¡£ÉèµÚ i ¼þÎïÆ·Ìå»ýΪ w£¬¼ÛֵΪ v£¬¸ù¾ÝµÚ i ¼þÎïÆ·ÊÇ·ñÌí¼Óµ½±³°üÖУ¬¿ÉÒÔ·ÖÁ½ÖÖÇé¿öÌÖÂÛ£º +定义一个二维数组 dp 存储最大价值,其中 dp[i][j] 表示体积ä¸�超过 j 的情况下,å‰� i 件物å“�能达到的最大价值。设第 i 件物å“�体积为 w,价值为 v,根æ�®ç¬¬ i 件物å“�是å�¦æ·»åŠ åˆ°èƒŒåŒ…ä¸­ï¼Œå�¯ä»¥åˆ†ä¸¤ç§�情况讨论: -¢Ù µÚ i ¼þÎïÆ·Ã»Ìí¼Óµ½±³°ü£¬×ÜÌå»ý²»³¬¹ý j µÄǰ i ¼þÎïÆ·µÄ×î´ó¼ÛÖµ¾ÍÊÇ×ÜÌå»ý²»³¬¹ý j µÄǰ i-1 ¼þÎïÆ·µÄ×î´ó¼ÛÖµ£¬dp[i][j] = dp[i-1][j]¡£ -¢Ú µÚ i ¼þÎïÆ·Ìí¼Óµ½±³°üÖУ¬dp[i][j] = dp[i-1][j-w] + v¡£ +â‘  第 i 件物å“�没添加到背包,总体积ä¸�超过 j çš„å‰� i 件物å“�的最大价值就是总体积ä¸�超过 j çš„å‰� i-1 件物å“�的最大价值,dp[i][j] = dp[i-1][j]。 +â‘¡ 第 i 件物å“�添加到背包中,dp[i][j] = dp[i-1][j-w] + v。 -µÚ i ¼þÎïÆ·¿ÉÌí¼ÓÒ²¿ÉÒÔ²»Ìí¼Ó£¬È¡¾öÓÚÄÄÖÖÇé¿öÏÂ×î´ó¼ÛÖµ¸ü´ó¡£ +第 i 件物å“�å�¯æ·»åŠ ä¹Ÿå�¯ä»¥ä¸�添加,å�–决于哪ç§�情况下最大价值更大。 -×ÛÉÏ£¬0-1 ±³°üµÄ×´Ì¬×ªÒÆ·½³ÌΪ£º +综上,0-1 背包的状æ€�转移方程为: -![](http://latex.codecogs.com/gif.latex?\\\\dp[i][j]=max(dp[i-1][j],dp[i-1][j-w]+v)) +
```java public int knapsack(int W, int N, int[] weights, int[] values) { @@ -2064,17 +2065,17 @@ public int knapsack(int W, int N, int[] weights, int[] values) { } ``` -**¿Õ¼äÓÅ»¯** +**空间优化** -ÔÚ³ÌÐòʵÏÖʱ¿ÉÒÔ¶Ô 0-1 ±³°ü×öÓÅ»¯¡£¹Û²ì×´Ì¬×ªÒÆ·½³Ì¿ÉÒÔÖªµÀ£¬Ç° i ¼þÎïÆ·µÄ״̬½öÓÉǰ i-1 ¼þÎïÆ·µÄ״̬Óйأ¬Òò´Ë¿ÉÒÔ½« dp ¶¨ÒåΪһάÊý×飬ÆäÖÐ dp[j] ¼È¿ÉÒÔ±íʾ dp[i-1][j] Ò²¿ÉÒÔ±íʾ dp[i][j]¡£´Ëʱ£¬ +在程åº�实现时å�¯ä»¥å¯¹ 0-1 背包å�šä¼˜åŒ–。观察状æ€�转移方程å�¯ä»¥çŸ¥é�“,å‰� i 件物å“�的状æ€�ä»…ç”±å‰� i-1 件物å“�的状æ€�有关,因此å�¯ä»¥å°† dp 定义为一维数组,其中 dp[j] æ—¢å�¯ä»¥è¡¨ç¤º dp[i-1][j] 也å�¯ä»¥è¡¨ç¤º dp[i][j]。此时, -![](http://latex.codecogs.com/gif.latex?\\\\dp[j]=max(dp[j],dp[j-w]+v)) +
-ÒòΪ dp[j-w] ±íʾ dp[i-1][j-w]£¬Òò´Ë²»ÄÜÏÈÇó dp[i][j-w] ·ÀÖ¹½« dp[i-1][j-w] ¸²¸Ç¡£Ò²¾ÍÊÇ˵ҪÏȼÆËã dp[i][j] ÔÙ¼ÆËã dp[i][j-w]£¬ÔÚ³ÌÐòʵÏÖʱÐèÒª°´µ¹ÐòÀ´Ñ­»·Çó½â¡£ +因为 dp[j-w] 表示 dp[i-1][j-w],因此ä¸�能先求 dp[i][j-w] 防止将 dp[i-1][j-w] 覆盖。也就是说è¦�先计算 dp[i][j] å†�计算 dp[i][j-w],在程åº�实现时需è¦�按倒åº�æ�¥å¾ªçŽ¯æ±‚è§£ã€‚ -**ÎÞ·¨Ê¹ÓÃ̰ÐÄËã·¨µÄ½âÊÍ** +**无法使用贪心算法的解释** -0-1 ±³°üÎÊÌâÎÞ·¨Ê¹ÓÃ̰ÐÄËã·¨À´Çó½â£¬Ò²¾ÍÊÇ˵²»Äܰ´ÕÕÏÈÌí¼ÓÐÔ¼Û±È×î¸ßµÄÎïÆ·À´´ïµ½×îÓÅ£¬ÕâÊÇÒòΪÕâÖÖ·½Ê½¿ÉÄÜÔì³É±³°ü¿Õ¼äµÄÀË·Ñ£¬´Ó¶øÎÞ·¨´ïµ½×îÓÅ¡£¿¼ÂÇÏÂÃæµÄÎïÆ·ºÍÒ»¸öÈÝÁ¿Îª 5 µÄ±³°ü£¬Èç¹ûÏÈÌí¼ÓÎïÆ· 0 ÔÙÌí¼ÓÎïÆ· 1£¬ÄÇôֻÄÜ´æ·ÅµÄ¼ÛֵΪ 16£¬ÀË·ÑÁË´óСΪ 2 µÄ¿Õ¼ä¡£×îÓŵķ½Ê½ÊÇ´æ·ÅÎïÆ· 1 ºÍÎïÆ· 2£¬¼ÛֵΪ 22. +0-1 背包问题无法使用贪心算法æ�¥æ±‚解,也就是说ä¸�能按照先添加性价比最高的物å“�æ�¥è¾¾åˆ°æœ€ä¼˜ï¼Œè¿™æ˜¯å› ä¸ºè¿™ç§�æ–¹å¼�å�¯èƒ½é€ æˆ�背包空间的浪费,从而无法达到最优。考虑下é�¢çš„物å“�和一个容é‡�为 5 的背包,如果先添加物å“� 0 å†�添加物å“� 1,那么å�ªèƒ½å­˜æ”¾çš„价值为 16,浪费了大å°�为 2 的空间。最优的方å¼�是存放物å“� 1 和物å“� 2,价值为 22. | id | w | v | v/w | | --- | --- | --- | --- | @@ -2082,23 +2083,23 @@ public int knapsack(int W, int N, int[] weights, int[] values) { | 1 | 2 | 10 | 5 | | 2 | 3 | 12 | 4 | -**±äÖÖ** +**å�˜ç§�** -ÍêÈ«±³°ü£ºÎïÆ·¿ÉÒÔÎÞÏÞ¸ö£¬¿ÉÒÔת»»Îª 0-1 ±³°ü£¬ÁîÿÖÖÎïÆ·µÄÌå»ýºÍ¼ÛÖµ±äΪ 1/2/4... ±¶Êý£¬°ÑËüÃǶ¼µ±³ÉÒ»¸öÐÂÎïÆ·£¬È»ºóÒ»ÖÖÎïÆ·Ö»ÄÜÌí¼ÓÒ»´Î¡£ +完全背包:物å“�å�¯ä»¥æ— é™�个,å�¯ä»¥è½¬æ�¢ä¸º 0-1 背包,令æ¯�ç§�物å“�的体积和价值å�˜ä¸º 1/2/4... å€�数,把它们都当æˆ�一个新物å“�,然å�Žä¸€ç§�物å“�å�ªèƒ½æ·»åŠ ä¸€æ¬¡ã€‚ -¶àÖØ±³°ü£ºÎïÆ·ÊýÁ¿ÓÐÏÞÖÆ£¬Í¬Ñù¿ÉÒÔת»»Îª 0-1 ±³°ü¡£ +多é‡�背包:物å“�æ•°é‡�有é™�制,å�Œæ ·å�¯ä»¥è½¬æ�¢ä¸º 0-1 背包。 -¶àά·ÑÓñ³°ü£ºÎïÆ·²»½öÓÐÖØÁ¿£¬»¹ÓÐÌå»ý£¬Í¬Ê±¿¼ÂÇÕâÁ½ÖÖÏÞÖÆ¡£ +多维费用背包:物å“�ä¸�仅有é‡�é‡�,还有体积,å�Œæ—¶è€ƒè™‘这两ç§�é™�制。 -ÆäËü£ºÎïÆ·Ö®¼äÏà»¥Ô¼Êø»òÕßÒÀÀµ¡£ +其它:物å“�之间相互约æ�Ÿæˆ–者ä¾�赖。 -**»®·ÖÊý×éΪºÍÏàµÈµÄÁ½²¿·Ö** +**划分数组为和相等的两部分** [Leetcode : 416. Partition Equal Subset Sum (Medium)](https://leetcode.com/problems/partition-equal-subset-sum/description/) -¿ÉÒÔ¿´³ÉÒ»¸ö±³°ü´óСΪ sum/2 µÄ 0-1 ±³°üÎÊÌ⣬µ«ÊÇÒ²Óв»Í¬µÄµØ·½£¬ÕâÀïûÓмÛÖµÊôÐÔ£¬²¢ÇÒ±³°ü±ØÐë±»ÌîÂú¡£ +å�¯ä»¥çœ‹æˆ�一个背包大å°�为 sum/2 çš„ 0-1 背包问题,但是也有ä¸�å�Œçš„地方,这里没有价值属性,并且背包必须被填满。 -ÒÔÏÂʵÏÖʹÓÃÁ˿ռäÓÅ»¯¡£ +以下实现使用了空间优化。 ```java public boolean canPartition(int[] nums) { @@ -2125,7 +2126,7 @@ public boolean canPartition(int[] nums) { } ``` -**×Ö·û´®°´µ¥´ÊÁбí·Ö¸î** +**字符串按å�•è¯�列表分割** [Leetcode : 139. Word Break (Medium)](https://leetcode.com/problems/word-break/description/) @@ -2152,7 +2153,7 @@ public boolean wordBreak(String s, List wordDict) { } ``` -**¸Ä±äÒ»×éÊýµÄÕý¸ººÅʹµÃËüÃǵĺÍΪһ¸ø¶¨Êý** +**改å�˜ä¸€ç»„数的正负å�·ä½¿å¾—它们的和为一给定数** [Leetcode : 494. Target Sum (Medium)](https://leetcode.com/problems/target-sum/description/) @@ -2170,7 +2171,7 @@ Explanation: There are 5 ways to assign symbols to make the sum of nums be target 3. ``` -¸ÃÎÊÌâ¿ÉÒÔת»»Îª subset sum ÎÊÌ⣬´Ó¶øÊ¹Óà 0-1 ±³°üµÄ·½·¨À´Çó½â¡£¿ÉÒÔ½«Õâ×éÊý¿´³ÉÁ½²¿·Ö£¬P ºÍ N£¬ÆäÖÐ P ʹÓÃÕýºÅ£¬N ʹÓøººÅ£¬ÓÐÒÔÏÂÍÆµ¼£º +该问题å�¯ä»¥è½¬æ�¢ä¸º subset sum 问题,从而使用 0-1 背包的方法æ�¥æ±‚解。å�¯ä»¥å°†è¿™ç»„数看æˆ�两部分,P å’Œ N,其中 P 使用正å�·ï¼ŒN 使用负å�·ï¼Œæœ‰ä»¥ä¸‹æŽ¨å¯¼ï¼š ```html sum(P) - sum(N) = target @@ -2178,7 +2179,7 @@ sum(P) + sum(N) + sum(P) - sum(N) = target + sum(P) + sum(N) 2 * sum(P) = target + sum(nums) ``` -Òò´ËÖ»ÒªÕÒµ½Ò»¸ö×Ó¼¯£¬ÁîËüÃǶ¼È¡ÕýºÅ£¬²¢ÇҺ͵ÈÓÚ (target + sum(nums))/2£¬¾ÍÖ¤Ã÷´æÔڽ⡣ +å› æ­¤å�ªè¦�找到一个å­�集,令它们都å�–æ­£å�·ï¼Œå¹¶ä¸”和等于 (target + sum(nums))/2,就è¯�明存在解。 ```java public int findTargetSumWays(int[] nums, int S) { @@ -2206,7 +2207,7 @@ private int subsetSum(int[] nums, int targetSum) { } ``` -**01×Ö·û¹¹³É×î¶àµÄ×Ö·û´®** +**01字符构æˆ�最多的字符串** [Leetcode : 474. Ones and Zeroes (Medium)](https://leetcode.com/problems/ones-and-zeroes/description/) @@ -2214,10 +2215,10 @@ private int subsetSum(int[] nums, int targetSum) { Input: Array = {"10", "0001", "111001", "1", "0"}, m = 5, n = 3 Output: 4 -Explanation: This are totally 4 strings can be formed by the using of 5 0s and 3 1s, which are ¡°10,¡±0001¡±,¡±1¡±,¡±0¡± +Explanation: This are totally 4 strings can be formed by the using of 5 0s and 3 1s, which are “10,â€�0001â€�,â€�1â€�,â€�0â€� ``` -ÕâÊÇÒ»¸ö¶àά·ÑÓÃµÄ 0-1 ±³°üÎÊÌ⣬ÓÐÁ½¸ö±³°ü´óС£¬0 µÄÊýÁ¿ºÍ 1 µÄÊýÁ¿¡£ +这是一个多维费用的 0-1 背包问题,有两个背包大å°�,0 的数é‡�å’Œ 1 的数é‡�。 ```java public int findMaxForm(String[] strs, int m, int n) { @@ -2243,13 +2244,13 @@ public int findMaxForm(String[] strs, int m, int n) { } ``` -**ÕÒÁãÇ®** +**找零钱** [Leetcode : 322. Coin Change (Medium)](https://leetcode.com/problems/coin-change/description/) -ÌâÄ¿ÃèÊö£º¸øÒ»Ð©Ãæ¶îµÄÓ²±Ò£¬ÒªÇóÓÃÕâЩӲ±ÒÀ´×é³É¸ø¶¨Ãæ¶îµÄÇ®Êý£¬²¢ÇÒʹµÃÓ²±ÒÊýÁ¿×îÉÙ¡£Ó²±Ò¿ÉÒÔÖØ¸´Ê¹Óᣠ+题目æ��述:给一些é�¢é¢�的硬å¸�,è¦�求用这些硬å¸�æ�¥ç»„æˆ�给定é�¢é¢�的钱数,并且使得硬å¸�æ•°é‡�最少。硬å¸�å�¯ä»¥é‡�å¤�使用。 -ÕâÊÇÒ»¸öÍêÈ«±³°üÎÊÌ⣬ÍêÈ«±³°üÎÊÌâºÍ 0-1±³°üÎÊÌâÔÚʵÏÖÉÏΨһµÄ²»Í¬ÊÇ£¬µÚ¶þ²ãÑ­»·ÊÇ´Ó 0 ¿ªÊ¼µÄ£¬¶ø²»ÊÇ´Óβ²¿¿ªÊ¼¡£ +这是一个完全背包问题,完全背包问题和 0-1背包问题在实现上唯一的ä¸�å�Œæ˜¯ï¼Œç¬¬äºŒå±‚循环是从 0 开始的,而ä¸�是从尾部开始。 ```java public int coinChange(int[] coins, int amount) { @@ -2267,7 +2268,7 @@ public int coinChange(int[] coins, int amount) { } ``` -**×éºÏ×ܺÍ** +**组å�ˆæ€»å’Œ** [Leetcode : 377. Combination Sum IV (Medium)](https://leetcode.com/problems/combination-sum-iv/description/) @@ -2304,7 +2305,7 @@ public int combinationSum4(int[] nums, int target) { } ``` -**Ö»ÄܽøÐÐÁ½´ÎµÄ¹ÉƱ½»Ò×** +**å�ªèƒ½è¿›è¡Œä¸¤æ¬¡çš„股票交易** [Leetcode : 123. Best Time to Buy and Sell Stock III (Hard)](https://leetcode.com/problems/best-time-to-buy-and-sell-stock-iii/description/) @@ -2322,7 +2323,7 @@ public int maxProfit(int[] prices) { } ``` -**Ö»ÄܽøÐÐ k ´ÎµÄ¹ÉƱ½»Ò×** +**å�ªèƒ½è¿›è¡Œ k 次的股票交易** [Leetcode : 188. Best Time to Buy and Sell Stock IV (Hard)](https://leetcode.com/problems/best-time-to-buy-and-sell-stock-iv/description/) @@ -2353,13 +2354,13 @@ public int maxProfit(int k, int[] prices) { } ``` -### Êý×éÇø¼ä +### 数组区间 -**Êý×éÇø¼äºÍ** +**数组区间和** [Leetcode : 303. Range Sum Query - Immutable (Easy)](https://leetcode.com/problems/range-sum-query-immutable/description/) -ÇóÇø¼ä i \~ j µÄºÍ£¬¿ÉÒÔת»»Îª sum[j] - sum[i-1]£¬ÆäÖÐ sum[i] Ϊ 0 \~ j µÄºÍ¡£ +求区间 i \~ j 的和,å�¯ä»¥è½¬æ�¢ä¸º sum[j] - sum[i-1],其中 sum[i] 为 0 \~ j 的和。 ```java class NumArray { @@ -2378,11 +2379,11 @@ class NumArray { } ``` -**×ÓÊý×é×î´óµÄºÍ** +**å­�数组最大的和** [Leetcode : 53. Maximum Subarray (Easy)](https://leetcode.com/problems/maximum-subarray/description/) -Áî sum[i] ΪÒÔ num[i] Ϊ½áβµÄ×ÓÊý×é×î´óµÄºÍ£¬¿ÉÒÔÓÉ sum[i-1] µÃµ½ sum[i] µÄÖµ£¬Èç¹û sum[i-1] СÓÚ 0£¬ÄÇôÒÔ num[i] Ϊ½áβµÄ×ÓÊý×é²»Äܰüº¬Ç°ÃæµÄÄÚÈÝ£¬ÒòΪ¼ÓÉÏÇ°ÃæµÄ²¿·Ö£¬ÄÇôºÍÒ»¶¨»á±È num[i] »¹Ð¡¡£ +令 sum[i] 为以 num[i] 为结尾的å­�数组最大的和,å�¯ä»¥ç”± sum[i-1] 得到 sum[i] 的值,如果 sum[i-1] å°�于 0,那么以 num[i] 为结尾的å­�数组ä¸�能包å�«å‰�é�¢çš„内容,因为加上å‰�é�¢çš„部分,那么和一定会比 num[i] 还å°�。 ```java public int maxSubArray(int[] nums) { @@ -2398,7 +2399,7 @@ public int maxSubArray(int[] nums) { } ``` -**Êý×éÖеȲîµÝÔö×ÓÇø¼äµÄ¸öÊý** +**数组中等差递增å­�区间的个数** [Leetcode : 413. Arithmetic Slices (Medium)](https://leetcode.com/problems/arithmetic-slices/description/) @@ -2408,7 +2409,7 @@ A = [1, 2, 3, 4] return: 3, for 3 arithmetic slices in A: [1, 2, 3], [2, 3, 4] and [1, 2, 3, 4] itself. ``` -¶ÔÓÚ (1,2,3,4)£¬ËüÓÐÈýÖÖ×é³ÉµÝÔö×ÓÇø¼äµÄ·½Ê½£¬¶ø¶ÔÓÚ (1,2,3,4,5)£¬Ëü×é³ÉµÝÔö×ÓÇø¼äµÄ·½Ê½³ýÁË (1,2,3,4) µÄÈýÖÖÍ⻹¶àÁËÒ»ÖÖ£¬¼´ (1,2,3,4,5)£¬Òò´Ë dp[i] = dp[i - 1] + 1¡£ +对于 (1,2,3,4),它有三ç§�组æˆ�递增å­�区间的方å¼�,而对于 (1,2,3,4,5),它组æˆ�递增å­�区间的方å¼�除了 (1,2,3,4) 的三ç§�外还多了一ç§�,å�³ (1,2,3,4,5),因此 dp[i] = dp[i - 1] + 1。 ```java public int numberOfArithmeticSlices(int[] A) { @@ -2427,13 +2428,13 @@ public int numberOfArithmeticSlices(int[] A) { } ``` -### ×Ö·û´®±à¼­ +### 字符串编辑 -**ɾ³ýÁ½¸ö×Ö·û´®µÄ×Ö·ûʹËüÃÇÏàµÈ** +**删除两个字符串的字符使它们相等** [Leetcode : 583. Delete Operation for Two Strings (Medium)](https://leetcode.com/problems/delete-operation-for-two-strings/description/) -¿ÉÒÔת»»ÎªÇóÁ½¸ö×Ö·û´®µÄ×¹«¹²×ÓÐòÁÐÎÊÌâ¡£ +å�¯ä»¥è½¬æ�¢ä¸ºæ±‚两个字符串的最长公共å­�åº�列问题。 ```java public int minDistance(String word1, String word2) { @@ -2451,20 +2452,20 @@ public int minDistance(String word1, String word2) { ``` -**ÐÞ¸ÄÒ»¸ö×Ö·û´®³ÆÎªÁíÒ»¸ö×Ö·û´®** // TODO +**修改一个字符串称为å�¦ä¸€ä¸ªå­—符串** // TODO [Leetcode : 72. Edit Distance (Hard)](https://leetcode.com/problems/edit-distance/description/) -### ÆäËüÎÊÌâ +### 其它问题 -**ÐèÒªÀäÈ´ÆÚµÄ¹ÉƱ½»Ò×** +**需è¦�冷å�´æœŸçš„股票交易** [Leetcode : 309. Best Time to Buy and Sell Stock with Cooldown(Medium)](https://leetcode.com/problems/best-time-to-buy-and-sell-stock-with-cooldown/description/) -ÌâÄ¿ÃèÊö£º½»Ò×Ö®ºóÐèÒªÓÐÒ»ÌìµÄÀäȴʱ¼ä¡£ +题目æ��述:交易之å�Žéœ€è¦�有一天的冷å�´æ—¶é—´ã€‚ -![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/ac9b31ec-cef1-4880-a875-fc4571ca10e1.png) +![](https://github.com/CyC2018/InterviewNotes/blob/master/pics//ac9b31ec-cef1-4880-a875-fc4571ca10e1.png) ```html s0[i] = max(s0[i - 1], s2[i - 1]); // Stay at s0, or rest from s2 @@ -2493,11 +2494,11 @@ public int maxProfit(int[] prices) { ``` -**ͳ¼Æ´Ó 0 \~ n ÿ¸öÊýµÄ¶þ½øÖƱíʾÖÐ 1 µÄ¸öÊý** +**统计从 0 \~ n æ¯�个数的二进制表示中 1 的个数** [Leetcode : 338. Counting Bits (Medium)](https://leetcode.com/problems/counting-bits/description/) -¶ÔÓÚÊý×Ö 6(110)£¬Ëü¿ÉÒÔ¿´³ÉÊÇÊý×Ö 2(10) Ç°Ãæ¼ÓÉÏÒ»¸ö 1 £¬Òò´Ë dp[i] = dp[i&(i-1)] + 1; +对于数字 6(110),它å�¯ä»¥çœ‹æˆ�是数字 2(10) å‰�é�¢åŠ ä¸Šä¸€ä¸ª 1 ,因此 dp[i] = dp[i&(i-1)] + 1; ```java public int[] countBits(int num) { @@ -2509,11 +2510,11 @@ public int maxProfit(int[] prices) { } ``` -**Ò»×éÕûÊý¶ÔÄܹ»¹¹³ÉµÄ×Á´** +**一组整数对能够构æˆ�的最长链** [Leetcode : 646. Maximum Length of Pair Chain (Medium)](https://leetcode.com/problems/maximum-length-of-pair-chain/description/) -¶ÔÓÚ (a, b) ºÍ (c, d) £¬Èç¹û b < c£¬ÔòËüÃÇ¿ÉÒÔ¹¹³ÉÒ»ÌõÁ´¡£ +对于 (a, b) å’Œ (c, d) ,如果 b < c,则它们å�¯ä»¥æž„æˆ�一æ�¡é“¾ã€‚ ```java public int findLongestChain(int[][] pairs) { @@ -2540,13 +2541,13 @@ public int findLongestChain(int[][] pairs) { } ``` -**ÂòÈëºÍÊÛ³ö¹ÉƱ×î´óµÄÊÕÒæ** +**买入和售出股票最大的收益** [Leetcode : 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) { @@ -2562,7 +2563,7 @@ public int maxProfit(int[] prices) { } ``` -**¸´ÖÆÕ³Ìù×Ö·û** +**å¤�制粘贴字符** [Leetcode : 650. 2 Keys Keyboard (Medium)](https://leetcode.com/problems/2-keys-keyboard/description/) @@ -2592,30 +2593,30 @@ public int minSteps(int n) { } ``` -## Êýѧ +## æ•°å­¦ -### ËØÊý +### ç´ æ•° -**ËØÊý·Ö½â** +**素数分解** -ÿһ¸öÊý¶¼¿ÉÒÔ·Ö½â³ÉËØÊýµÄ³Ë»ý£¬ÀýÈç 84 = 22 \* 31 \* 50 \* 71 \* 110 \* 130 \* 170 \* ¡­ +æ¯�一个数都å�¯ä»¥åˆ†è§£æˆ�素数的乘积,例如 84 = 22 \* 31 \* 50 \* 71 \* 110 \* 130 \* 170 \* … -**Õû³ý** +**整除** -Áî x = 2m0 \* 3m1 \* 5m2 \* 7m3 \* 11m4 \* ¡­ -Áî y = 2n0 \* 3n1 \* 5n2 \* 7n3 \* 11n4 \* ¡­ +令 x = 2m0 \* 3m1 \* 5m2 \* 7m3 \* 11m4 \* … +令 y = 2n0 \* 3n1 \* 5n2 \* 7n3 \* 11n4 \* … -Èç¹û x Õû³ý y£¨y mod x == 0£©£¬Ôò¶ÔÓÚËùÓÐ i£¬mi <= ni¡£ +如果 x 整除 y(y mod x == 0),则对于所有 i,mi <= ni。 -x ºÍ y µÄ **×î´ó¹«Ô¼Êý** Ϊ£ºgcd(x,y) = 2min(m0,n0) \* 3min(m1,n1) \* 5min(m2,n2) \* ... +x å’Œ y çš„ **最大公约数** 为:gcd(x,y) = 2min(m0,n0) \* 3min(m1,n1) \* 5min(m2,n2) \* ... -x ºÍ y µÄ **×îС¹«±¶Êý** Ϊ£ºlcm(x,y) = 2max(m0,n0) \* 3max(m1,n1) \* 5max(m2,n2) \* ... +x å’Œ y çš„ **最å°�å…¬å€�æ•°** 为:lcm(x,y) = 2max(m0,n0) \* 3max(m1,n1) \* 5max(m2,n2) \* ... -**Éú³ÉËØÊýÐòÁÐ** +**生æˆ�ç´ æ•°åº�列** [Leetcode : 204. Count Primes (Easy)](https://leetcode.com/problems/count-primes/description/) -°£À­ÍÐË¹ÌØÄáɸ·¨ÔÚÿ´ÎÕÒµ½Ò»¸öËØÊýʱ£¬½«Äܱ»ËØÊýÕû³ýµÄÊýÅųýµô¡£ +埃拉托斯特尼筛法在æ¯�次找到一个素数时,将能被素数整除的数排除掉。 ```java public int countPrimes(int n) { @@ -2624,7 +2625,7 @@ public int countPrimes(int n) { for(int i = 2; i < n; i++){ if(notPrimes[i]) continue; cnt++; - // ´Ó i * i ¿ªÊ¼£¬ÒòΪÈç¹û k < i£¬ÄÇô k * i ÔÚ֮ǰ¾ÍÒѾ­±»È¥³ý¹ýÁË + // 从 i * i 开始,因为如果 k < i,那么 k * i 在之å‰�就已ç»�被去除过了 for(long j = (long) i * i; j < n; j += i){ notPrimes[(int) j] = true; } @@ -2633,7 +2634,7 @@ public int countPrimes(int n) { } ``` -### ×î´ó¹«Ô¼Êý +### 最大公约数 ```java int gcd(int a, int b) { @@ -2642,7 +2643,7 @@ int gcd(int a, int b) { } ``` -×î´ó¹«±¶ÊýΪÁ½ÊýµÄ³Ë»ý³ýÒÔ×î´ó¹«Ô¼Êý¡£ +最大公å€�数为两数的乘积除以最大公约数。 ```java int lcm(int a, int b){ @@ -2650,22 +2651,22 @@ int lcm(int a, int b){ } ``` -¶ÔÓÚ×î´ó¹«Ô¼ÊýÎÊÌ⣬ÒòΪÐèÒª¼ÆËã a % b £¬¶øÕâ¸ö²Ù×÷ÊDZȽϺÄʱµÄ£¬¿ÉÒÔʹÓà [ ±à³ÌÖ®ÃÀ£º2.7]() µÄ·½·¨£¬ÀûÓüõ·¨ºÍÒÆÎ»²Ù×÷À´Ìæ»»Ëü¡£ +对于最大公约数问题,因为需è¦�计算 a % b ,而这个æ“�作是比较耗时的,å�¯ä»¥ä½¿ç”¨ [ 编程之美:2.7]() 的方法,利用å‡�法和移ä½�æ“�作æ�¥æ›¿æ�¢å®ƒã€‚ -¶ÔÓÚ a ºÍ b µÄ×î´ó¹«Ô¼Êý f(a, b)£¬ÓУº +对于 a å’Œ b 的最大公约数 f(a, b),有: -1\. Èç¹û a ºÍ b ¾ùΪżÊý£¬f(a, b) = 2\*f(a/2, b/2); -2\. Èç¹û a ÊÇżÊý b ÊÇÆæÊý£¬f(a, b) = f(a/2, b); -3\. Èç¹û b ÊÇżÊý a ÊÇÆæÊý£¬f(a, b) = f(a, b/2); -4\. Èç¹û a ºÍ b ¾ùÎªÆæÊý£¬f(a, b) = f(a, a-b); +1\. 如果 a å’Œ b å�‡ä¸ºå�¶æ•°ï¼Œf(a, b) = 2\*f(a/2, b/2); +2\. 如果 a 是å�¶æ•° b 是奇数,f(a, b) = f(a/2, b); +3\. 如果 b 是å�¶æ•° a 是奇数,f(a, b) = f(a, b/2); +4\. 如果 a å’Œ b å�‡ä¸ºå¥‡æ•°ï¼Œf(a, b) = f(a, a-b); -³Ë 2 ºÍ³ý 2 ¶¼¿ÉÒÔת»»ÎªÒÆÎ»²Ù×÷¡£ +乘 2 和除 2 都å�¯ä»¥è½¬æ�¢ä¸ºç§»ä½�æ“�作。 -### ½øÖÆ×ª»» +### 进制转æ�¢ -Java ÖÐ static String toString(int num, int radix) ¿ÉÒÔ½«Ò»¸öÕûÊý×°»»Îª redix ½øÖƱíʾµÄ×Ö·û´®¡£ +Java 中 static String toString(int num, int radix) å�¯ä»¥å°†ä¸€ä¸ªæ•´æ•°è£…æ�¢ä¸º redix 进制表示的字符串。 -**7 ½øÖÆ** +**7 进制** [Leetcode : 504. Base 7 (Easy)](https://leetcode.com/problems/base-7/description/) @@ -2681,7 +2682,7 @@ public String convertToBase7(int num) { } ``` -**16 ½øÖÆ** +**16 进制** [Leetcode : 405. Convert a Number to Hexadecimal (Easy)](https://leetcode.com/problems/convert-a-number-to-hexadecimal/description/) @@ -2698,15 +2699,15 @@ public String toHex(int num) { } ``` -### ½×³Ë +### 阶乘 -**ͳ¼Æ½×³Ëβ²¿ÓжàÉÙ¸ö 0** +**统计阶乘尾部有多少个 0** [Leetcode : 172. Factorial Trailing Zeroes (Easy)](https://leetcode.com/problems/factorial-trailing-zeroes/description/) -β²¿µÄ 0 ÓÉ 2 * 5 µÃÀ´£¬2 µÄÊýÁ¿Ã÷ÏÔ¶àÓÚ 5 µÄÊýÁ¿£¬Òò´ËֻҪͳ¼ÆÓжàÉÙ¸ö 5 ¼´¿É¡£ +尾部的 0 ç”± 2 * 5 å¾—æ�¥ï¼Œ2 的数é‡�明显多于 5 的数é‡�,因此å�ªè¦�统计有多少个 5 å�³å�¯ã€‚ -¶ÔÓÚÒ»¸öÊý N£¬ËüËù°üº¬ 5 µÄ¸öÊýΪ£ºN/5 + N/52 + N/53 + ...£¬ÆäÖÐ N/5 ±íʾ²»´óÓÚ N µÄÊýÖÐ 5 µÄ±¶Êý¹±Ï×Ò»¸ö 5£¬N/52 ±íʾ²»´óÓÚ N µÄÊýÖÐ 52 µÄ±¶ÊýÔÙ¹±Ï×Ò»¸ö 5 ...¡£ +对于一个数 N,它所包å�« 5 的个数为:N/5 + N/52 + N/53 + ...,其中 N/5 表示ä¸�大于 N 的数中 5 çš„å€�数贡献一个 5,N/52 表示ä¸�大于 N 的数中 52 çš„å€�æ•°å†�贡献一个 5 ...。 ```java public int trailingZeroes(int n) { @@ -2714,11 +2715,11 @@ public int trailingZeroes(int n) { } ``` -Èç¹ûͳ¼ÆµÄÊÇ N! µÄ¶þ½øÖƱíʾÖÐ×îµÍλ 1 µÄλÖã¬Ö»ÒªÍ³¼ÆÓжàÉÙ¸ö 2 ¼´¿É£¬¸ÃÌâÄ¿³ö×Ô [ ±à³ÌÖ®ÃÀ£º2.2](#) ¡£ºÍÇó½âÓжàÉÙ¸ö 5 Ò»Ñù£¬2 µÄ¸öÊýΪ N/2 + N/22 + N/23 + ... +如果统计的是 N! 的二进制表示中最低ä½� 1 çš„ä½�置,å�ªè¦�统计有多少个 2 å�³å�¯ï¼Œè¯¥é¢˜ç›®å‡ºè‡ª [ 编程之美:2.2](#) 。和求解有多少个 5 一样,2 的个数为 N/2 + N/22 + N/23 + ... -### ×Ö·û´®¼Ó·¨¼õ·¨ +### 字符串加法å‡�法 -**¶þ½øÖƼӷ¨** +**二进制加法** [Leetcode : 67. Add Binary (Easy)](https://leetcode.com/problems/add-binary/description/) @@ -2737,11 +2738,11 @@ public String addBinary(String a, String b) { } ``` -**×Ö·û´®¼Ó·¨** +**字符串加法** [Leetcode : 415. Add Strings (Easy)](https://leetcode.com/problems/add-strings/description/) -ÌâÄ¿ÃèÊö£º×Ö·û´®µÄֵΪ·Ç¸ºÕûÊý +题目æ��述:字符串的值为é�žè´Ÿæ•´æ•° ```java public String addStrings(String num1, String num2) { @@ -2757,23 +2758,23 @@ public String addStrings(String num1, String num2) { } ``` -### ÏàÓöÎÊÌâ +### 相é�‡é—®é¢˜ -**¸Ä±äÊý×éÔªËØÊ¹ËùÓеÄÊý×éÔªËØ¶¼ÏàµÈ** +**改å�˜æ•°ç»„元素使所有的数组元素都相等** [Leetcode : 462. Minimum Moves to Equal Array Elements II (Medium)](https://leetcode.com/problems/minimum-moves-to-equal-array-elements-ii/description/) -ÌâÄ¿ÃèÊö£ºÃ¿´Î¿ÉÒÔ¶ÔÒ»¸öÊý×éÔªËØ¼ÓÒ»»òÕß¼õÒ»£¬Çó×îСµÄ¸Ä±ä´ÎÊý¡£ +题目æ��述:æ¯�次å�¯ä»¥å¯¹ä¸€ä¸ªæ•°ç»„元素加一或者å‡�一,求最å°�的改å�˜æ¬¡æ•°ã€‚ -ÕâÊǸöµäÐ͵ÄÏàÓöÎÊÌâ£¬ÒÆ¶¯¾àÀë×îСµÄ·½Ê½ÊÇËùÓÐÔªËØ¶¼Òƶ¯µ½ÖÐλÊý¡£ÀíÓÉÈçÏ£º +这是个典型的相é�‡é—®é¢˜ï¼Œç§»åЍè·�离最å°�的方å¼�是所有元素都移动到中ä½�数。ç�†ç”±å¦‚下: -Éè m ΪÖÐλÊý¡£a ºÍ b ÊÇ m Á½±ßµÄÁ½¸öÔªËØ£¬ÇÒ b > a¡£ÒªÊ¹ a ºÍ b ÏàµÈ£¬ËüÃÇ×ܹ²Òƶ¯µÄ´ÎÊýΪ b - a£¬Õâ¸öÖµµÈÓÚ (b - m) + (m - a)£¬Ò²¾ÍÊǰÑÕâÁ½¸öÊýÒÆ¶¯µ½ÖÐλÊýµÄÒÆ¶¯´ÎÊý¡£ +设 m 为中ä½�数。a å’Œ b 是 m 两边的两个元素,且 b > a。è¦�使 a å’Œ b 相等,它们总共移动的次数为 b - a,这个值等于 (b - m) + (m - a),也就是把这两个数移动到中ä½�数的移动次数。 -ÉèÊý×鳤¶ÈΪ N£¬Ôò¿ÉÒÔÕÒµ½ N/2 ¶Ô a ºÍ b µÄ×éºÏ£¬Ê¹ËüÃǶ¼Òƶ¯µ½ m µÄλÖᣠ+设数组长度为 N,则å�¯ä»¥æ‰¾åˆ° N/2 对 a å’Œ b 的组å�ˆï¼Œä½¿å®ƒä»¬éƒ½ç§»åŠ¨åˆ° m çš„ä½�置。 -**½â·¨ 1** +**解法 1** -ÏÈÅÅÐò£¬Ê±¼ä¸´ÔÓ¶È£ºO(NlgN) +先排åº�,时间å¤�æ�‚度:O(NlgN) ```java public int minMoves2(int[] nums) { @@ -2789,9 +2790,9 @@ public int minMoves2(int[] nums) { } ``` -**½â·¨ 2** +**解法 2** -ʹÓÿìËÙÅÅÐòÕÒµ½ÖÐλÊý£¬Ê±¼ä¸´ÔÓ¶È O(N) +使用快速排åº�找到中ä½�数,时间å¤�æ�‚度 O(N) ```java public int minMoves2(int[] nums) { @@ -2823,13 +2824,13 @@ private void swap(int[] nums, int i, int j) { } ``` -### ¶àÊýͶƱÎÊÌâ +### 多数投票问题 -**Êý×éÖгöÏÖ´ÎÊý¶àÓÚ n / 2 µÄÔªËØ** +**数组中出现次数多于 n / 2 的元素** [Leetcode : 169. Majority Element (Easy)](https://leetcode.com/problems/majority-element/description/) -ÏȶÔÊý×éÅÅÐò£¬×îÖмäÄǸöÊý³öÏÖ´ÎÊýÒ»¶¨¶àÓÚ n / 2 +先对数组排åº�,最中间那个数出现次数一定多于 n / 2 ```java public int majorityElement(int[] nums) { @@ -2838,7 +2839,7 @@ public int majorityElement(int[] nums) { } ``` -¿ÉÒÔÀûÓà Boyer-Moore Majority Vote Algorithm À´½â¾öÕâ¸öÎÊÌ⣬ʹµÃʱ¼ä¸´ÔÓ¶ÈΪ O(n)¡£¿ÉÒÔÕâôÀí½â¸ÃËã·¨£ºÊ¹Óà cnt À´Í³¼ÆÒ»¸öÔªËØ³öÏֵĴÎÊý£¬µ±±éÀúµ½µÄÔªËØºÍͳ¼ÆÔªËز»ÏëµÈʱ£¬Áî cnt--¡£Èç¹ûÇ°Ãæ²éÕÒÁË i ¸öÔªËØ£¬ÇÒ cnt == 0 £¬ËµÃ÷ǰ i ¸öÔªËØÃ»ÓÐ majority£¬»òÕßÓÐ majority£¬µ«ÊdzöÏֵĴÎÊýÉÙÓÚ i / 2 £¬ÒòΪÈç¹û¶àÓÚ i / 2 µÄ»° cnt ¾ÍÒ»¶¨²»»áΪ 0 ¡£´ËʱʣÏ嵀 n - i ¸öÔªËØÖУ¬majority µÄÊýÄ¿¶àÓÚ (n - i) / 2£¬Òò´Ë¼ÌÐø²éÕÒ¾ÍÄÜÕÒ³ö majority¡£ +å�¯ä»¥åˆ©ç”¨ 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) { @@ -2855,16 +2856,16 @@ public int majorityElement(int[] nums) { } ``` -### ÆäËü +### 其它 -**ƽ·½Êý** +**平方数** [Leetcode : 367. Valid Perfect Square (Easy)](https://leetcode.com/problems/valid-perfect-square/description/) -ƽ·½ÐòÁУº1,4,9,16,.. -¼ä¸ô£º3,5,7,... +平方åº�列:1,4,9,16,.. +间隔:3,5,7,... -¼ä¸ôΪµÈ²îÊýÁУ¬Ê¹ÓÃÕâ¸öÌØÐÔ¿ÉÒԵõ½´Ó 1 ¿ªÊ¼µÄƽ·½ÐòÁС£ +间隔为等差数列,使用这个特性å�¯ä»¥å¾—到从 1 开始的平方åº�列。 ```java public boolean isPerfectSquare(int num) { @@ -2877,7 +2878,7 @@ public boolean isPerfectSquare(int num) { } ``` -**3 µÄ n ´Î·½** +**3 çš„ n 次方** [Leetcode : 326. Power of Three (Easy)](https://leetcode.com/problems/power-of-three/description/) @@ -2887,7 +2888,7 @@ public boolean isPowerOfThree(int n) { } ``` -**ÕÒ³öÊý×éÖеij˻ý×î´óµÄÈý¸öÊý** +**找出数组中的乘积最大的三个数** [Leetcode : 628. Maximum Product of Three Numbers (Easy)](https://leetcode.com/problems/maximum-product-of-three-numbers/description/) @@ -2917,13 +2918,13 @@ public int maximumProduct(int[] nums) { } ``` -**³Ë»ýÊý×é** +**乘积数组** [Leetcode : 238. Product of Array Except Self (Medium)](https://leetcode.com/problems/product-of-array-except-self/description/) -ÌâÄ¿ÃèÊö£º¸ø¶¨Ò»¸öÊý×飬´´½¨Ò»¸öÐÂÊý×飬ÐÂÊý×éµÄÿ¸öÔªËØÎªÔ­Ê¼Êý×éÖгýÁ˸ÃλÖÃÉϵÄÔªËØÖ®ÍâËùÓÐÔªËØµÄ³Ë»ý¡£ +题目æ��述:给定一个数组,创建一个新数组,新数组的æ¯�个元素为原始数组中除了该ä½�置上的元素之外所有元素的乘积。 -ÌâĿҪÇó£ºÊ±¼ä¸´ÔÓ¶ÈΪ O(n)£¬²¢ÇÒ²»ÄÜʹÓóý·¨¡£ +题目è¦�求:时间å¤�æ�‚度为 O(n),并且ä¸�能使用除法。 ```java public int[] productExceptSelf(int[] nums) { @@ -2942,13 +2943,13 @@ public int[] productExceptSelf(int[] nums) { } ``` -# Êý¾Ý½á¹¹Ïà¹Ø +# æ•°æ�®ç»“构相关 -## Õ»ºÍ¶ÓÁÐ +## 栈和队列 -**ÓÃջʵÏÖ¶ÓÁÐ** +**用栈实现队列** -Ò»¸öջʵÏÖ£º +一个栈实现: ```java class MyQueue { @@ -2979,7 +2980,7 @@ class MyQueue { } ``` -Á½¸öջʵÏÖ£º +两个栈实现: ```java class MyQueue { @@ -3014,7 +3015,7 @@ class MyQueue { } ``` -**ÓöÓÁÐʵÏÖÕ»** +**用队列实现栈** [Leetcode : 225. Implement Stack using Queues (Easy)](https://leetcode.com/problems/implement-stack-using-queues/description/) @@ -3029,7 +3030,7 @@ class MyStack { public void push(int x) { queue.add(x); - for(int i = 1; i < queue.size(); i++){ // ·­×ª + for(int i = 1; i < queue.size(); i++){ // 翻转 queue.add(queue.remove()); } } @@ -3048,11 +3049,11 @@ class MyStack { } ``` -**×îСֵջ** +**最å°�值栈** [Leetcode : 155. Min Stack (Easy)](https://leetcode.com/problems/min-stack/description/) -ÓÃÁ½¸öջʵÏÖ£¬Ò»¸ö´æ´¢Êý¾Ý£¬Ò»¸ö´æ´¢×îСֵ¡£ +用两个栈实现,一个存储数æ�®ï¼Œä¸€ä¸ªå­˜å‚¨æœ€å°�值。 ```java class MinStack { @@ -3095,9 +3096,9 @@ class MinStack { } ``` -¶ÔÓÚʵÏÖ×îСֵ¶ÓÁÐÎÊÌ⣬¿ÉÒÔÏȽ«¶ÓÁÐʹÓÃÕ»À´ÊµÏÖ£¬È»ºó¾Í½«ÎÊÌâת»»Îª×îСֵջ£¬Õâ¸öÎÊÌâ³öÏÖÔÚ ±à³ÌÖ®ÃÀ£º3.7¡£ +对于实现最å°�值队列问题,å�¯ä»¥å…ˆå°†é˜Ÿåˆ—使用栈æ�¥å®žçŽ°ï¼Œç„¶å�Žå°±å°†é—®é¢˜è½¬æ�¢ä¸ºæœ€å°�值栈,这个问题出现在 编程之美:3.7。 -**ÓÃջʵÏÖÀ¨ºÅÆ¥Åä** +**用栈实现括å�·åŒ¹é…�** [Leetcode : 20. Valid Parentheses (Easy)](https://leetcode.com/problems/valid-parentheses/description/) @@ -3127,7 +3128,7 @@ public boolean isValid(String s) { } ``` -**Êý×éÖбȵ±Ç°ÔªËØ´óµÄÏÂÒ»¸öÊý×éÔªËØµÄ¾àÀë** +**数组中比当å‰�元素大的下一个数组元素的è·�离** ```html Input: [73, 74, 75, 71, 69, 72, 76, 73] @@ -3136,7 +3137,7 @@ Output: [1, 1, 4, 2, 1, 1, 0, 0] [Leetcode : 739. Daily Temperatures (Medium)](https://leetcode.com/problems/daily-temperatures/description/) -ʹÓÃÕ»À´´æ´¢»¹Î´¼ÆËãµÄÔªËØ¡£¿ÉÒÔ±£Ö¤´ÓÕ»¶¥ÏòÏÂÔªËØµÝÔö£¬·ñÔòÉÏÃæÓÐÒ»¸ö±ÈÏÂÃæÄ³¸öÔªËØ´óµÄÔªËØ½øÈëÕ»ÖУ¬ÏÂÃæÄǸöÔªËØÒѾ­ÕÒµ½±ÈËü´óµÄÔªËØ£¬Òò´Ë»á³öÕ»¡£ +使用栈æ�¥å­˜å‚¨è¿˜æœªè®¡ç®—的元素。å�¯ä»¥ä¿�è¯�从栈顶å�‘下元素递增,å�¦åˆ™ä¸Šé�¢æœ‰ä¸€ä¸ªæ¯”下é�¢æŸ�个元素大的元素进入栈中,下é�¢é‚£ä¸ªå…ƒç´ å·²ç»�找到比它大的元素,因此会出栈。 ```java public int[] dailyTemperatures(int[] temperatures) { @@ -3154,7 +3155,7 @@ public int[] dailyTemperatures(int[] temperatures) { } ``` -**Êý×éÖÐÏÂÒ»¸ö±Èµ±Ç°Êý´óµÄÊý** +**数组中下一个比当å‰�数大的数** [Leetcode : 496. Next Greater Element I (Easy)](https://leetcode.com/problems/next-greater-element-i/description/) @@ -3163,7 +3164,7 @@ Input: nums1 = [4,1,2], nums2 = [1,3,4,2]. Output: [-1,3,-1] ``` -ÔÚ±éÀúÊý×éʱÓà Stack °ÑÊý×éÖеÄÊý´æÆðÀ´£¬Èç¹ûµ±Ç°±éÀúµÄÊý±ÈÕ»¶¥ÔªËØÀ´µÄ´ó£¬ËµÃ÷Õ»¶¥ÔªËصÄÏÂÒ»¸ö±ÈËü´óµÄÊý¾ÍÊǵ±Ç°ÔªËØ¡£ +在é��历数组时用 Stack 把数组中的数存起æ�¥ï¼Œå¦‚果当å‰�é��历的数比栈顶元素æ�¥çš„大,说明栈顶元素的下一个比它大的数就是当å‰�元素。 ```java public int[] nextGreaterElement(int[] nums1, int[] nums2) { @@ -3184,7 +3185,7 @@ public int[] nextGreaterElement(int[] nums1, int[] nums2) { } ``` -**Ñ­»·Êý×éÖÐÏÂÒ»¸ö±Èµ±Ç°ÔªËØ´óµÄÊý** +**循环数组中下一个比当å‰�元素大的数** [Leetcode : 503. Next Greater Element II (Medium)](https://leetcode.com/problems/next-greater-element-ii/description/) @@ -3204,28 +3205,28 @@ public int[] nextGreaterElements(int[] nums) { ``` -## ¹þÏ£±í +## 哈希表 -ÀûÓà Hash Table ¿ÉÒÔ¿ìËÙ²éÕÒÒ»¸öÔªËØÊÇ·ñ´æÔÚµÈÎÊÌ⣬µ«ÊÇÐèÒªÒ»¶¨µÄ¿Õ¼äÀ´´æ´¢¡£ÔÚÓÅÏÈ¿¼ÂÇʱ¼ä¸´ÔӶȵÄÇé¿öÏ£¬¿ÉÒÔÀûÓà Hash Table ÕâÖֿռ任ȡʱ¼äµÄ×ö·¨¡£ +利用 Hash Table å�¯ä»¥å¿«é€ŸæŸ¥æ‰¾ä¸€ä¸ªå…ƒç´ æ˜¯å�¦å­˜åœ¨ç­‰é—®é¢˜ï¼Œä½†æ˜¯éœ€è¦�一定的空间æ�¥å­˜å‚¨ã€‚在优先考虑时间å¤�æ�‚度的情况下,å�¯ä»¥åˆ©ç”¨ Hash Table è¿™ç§�空间æ�¢å�–æ—¶é—´çš„å�šæ³•ã€‚ -Java ÖÐµÄ **HashSet** ÓÃÓÚ´æ´¢Ò»¸ö¼¯ºÏ£¬²¢ÒÔ O(1) µÄʱ¼ä¸´ÔӶȲéÕÒÔªËØÊÇ·ñÔÚ¼¯ºÏÖС£ +Java 中的 **HashSet** 用于存储一个集å�ˆï¼Œå¹¶ä»¥ O(1) 的时间å¤�æ�‚度查找元素是å�¦åœ¨é›†å�ˆä¸­ã€‚ -Èç¹ûÔªËØÓÐÇ²¢ÇÒ·¶Î§²»´ó£¬ÄÇô¿ÉÒÔÓÃÒ»¸ö²¼¶ûÊý×éÀ´´æ´¢Ò»¸öÔªËØÊÇ·ñ´æÔÚ£¬ÀýÈç¶ÔÓÚÖ»ÓÐСд×Ö·ûµÄÔªËØ£¬¾Í¿ÉÒÔÓÃÒ»¸ö³¤¶ÈΪ 26 µÄ²¼¶ûÊý×éÀ´´æ´¢Ò»¸ö×Ö·û¼¯ºÏ£¬Ê¹µÃ¿Õ¼ä¸´ÔӶȽµµÍΪ O(1)¡£ +如果元素有穷,并且范围ä¸�大,那么å�¯ä»¥ç”¨ä¸€ä¸ªå¸ƒå°”数组æ�¥å­˜å‚¨ä¸€ä¸ªå…ƒç´ æ˜¯å�¦å­˜åœ¨ï¼Œä¾‹å¦‚对于å�ªæœ‰å°�写字符的元素,就å�¯ä»¥ç”¨ä¸€ä¸ªé•¿åº¦ä¸º 26 的布尔数组æ�¥å­˜å‚¨ä¸€ä¸ªå­—符集å�ˆï¼Œä½¿å¾—空间å¤�æ�‚度é™�低为 O(1)。 -Java ÖÐµÄ **HashMap** Ö÷ÒªÓÃÓÚÓ³Éä¹ØÏµ£¬´Ó¶ø°ÑÁ½¸öÔªËØÁªÏµÆðÀ´¡£ +Java 中的 **HashMap** 主è¦�用于映射关系,从而把两个元素è�”系起æ�¥ã€‚ -ÔÚ¶ÔÒ»¸öÄÚÈݽøÐÐѹËõ»òÕ߯äËüת»»Ê±£¬ÀûÓà HashMap ¿ÉÒÔ°ÑԭʼÄÚÈݺÍת»»ºóµÄÄÚÈÝÁªÏµÆðÀ´¡£ÀýÈçÔÚÒ»¸ö¼ò»¯ url µÄϵͳÖУ¨[Leetcdoe : 535. Encode and Decode TinyURL (Medium)](https://leetcode.com/problems/encode-and-decode-tinyurl/description/)£©£¬ÀûÓà HashMap ¾Í¿ÉÒÔ´æ´¢¾«¼òºóµÄ url µ½Ô­Ê¼ url µÄÓ³É䣬ʹµÃ²»½ö¿ÉÒÔÏÔʾ¼ò»¯µÄ url£¬Ò²¿ÉÒÔ¸ù¾Ý¼ò»¯µÄ url µÃµ½Ô­Ê¼ url ´Ó¶ø¶¨Î»µ½ÕýÈ·µÄ×ÊÔ´¡£ +在对一个内容进行压缩或者其它转æ�¢æ—¶ï¼Œåˆ©ç”¨ HashMap å�¯ä»¥æŠŠåŽŸå§‹å†…å®¹å’Œè½¬æ�¢å�Žçš„内容è�”系起æ�¥ã€‚例如在一个简化 url 的系统中([Leetcdoe : 535. Encode and Decode TinyURL (Medium)](https://leetcode.com/problems/encode-and-decode-tinyurl/description/)),利用 HashMap å°±å�¯ä»¥å­˜å‚¨ç²¾ç®€å�Žçš„ url 到原始 url 的映射,使得ä¸�ä»…å�¯ä»¥æ˜¾ç¤ºç®€åŒ–çš„ url,也å�¯ä»¥æ ¹æ�®ç®€åŒ–çš„ url 得到原始 url 从而定ä½�到正确的资æº�。 -HashMap Ò²¿ÉÒÔÓÃÀ´¶ÔÔªËØ½øÐмÆÊýͳ¼Æ£¬´Ëʱ¼üÎªÔªËØ£¬ÖµÎª¼ÆÊý¡£ºÍ HashSet ÀàËÆ£¬Èç¹ûÔªËØÓÐÇî²¢ÇÒ·¶Î§²»´ó£¬¿ÉÒÔÓÃÕûÐÍÊý×éÀ´½øÐÐͳ¼Æ¡£ +HashMap 也å�¯ä»¥ç”¨æ�¥å¯¹å…ƒç´ è¿›è¡Œè®¡æ•°ç»Ÿè®¡ï¼Œæ­¤æ—¶é”®ä¸ºå…ƒç´ ï¼Œå€¼ä¸ºè®¡æ•°ã€‚å’Œ HashSet 类似,如果元素有穷并且范围ä¸�大,å�¯ä»¥ç”¨æ•´åž‹æ•°ç»„æ�¥è¿›è¡Œç»Ÿè®¡ã€‚ -**Êý×éÖеÄÁ½¸öÊýºÍΪ¸ø¶¨Öµ** +**数组中的两个数和为给定值** [Leetcode : 1. Two Sum (Easy)](https://leetcode.com/problems/two-sum/description/) -¿ÉÒÔÏȶÔÊý×é½øÐÐÅÅÐò£¬È»ºóʹÓÃ˫ָÕë·½·¨»òÕß¶þ·Ö²éÕÒ·½·¨¡£ÕâÑù×öµÄʱ¼ä¸´ÔÓ¶ÈΪ O(nlgn)£¬¿Õ¼ä¸´ÔÓ¶ÈΪ O(1)¡£ +å�¯ä»¥å…ˆå¯¹æ•°ç»„进行排åº�,然å�Žä½¿ç”¨å�ŒæŒ‡é’ˆæ–¹æ³•或者二分查找方法。这样å�šçš„æ—¶é—´å¤�æ�‚度为 O(nlgn),空间å¤�æ�‚度为 O(1)。 -Óà HashMap ´æ´¢Êý×éÔªËØºÍË÷ÒýµÄÓ³É䣬ÔÚ·ÃÎʵ½ nums[i] ʱ£¬ÅÐ¶Ï HashMap ÖÐÊÇ·ñ´æÔÚ target - nums[i] £¬Èç¹û´æÔÚ˵Ã÷ target - nums[i] ËùÔÚµÄË÷ÒýºÍ i ¾ÍÊÇÒªÕÒµÄÁ½¸öÊý¡£¸Ã·½·¨µÄʱ¼ä¸´ÔÓ¶ÈΪ O(n)£¬¿Õ¼ä¸´ÔÓ¶ÈΪ O(n)£¬Ê¹ÓÿռäÀ´»»È¡Ê±¼ä¡£ +用 HashMap 存储数组元素和索引的映射,在访问到 nums[i] 时,判断 HashMap 中是å�¦å­˜åœ¨ target - nums[i] ,如果存在说明 target - nums[i] 所在的索引和 i 就是è¦�找的两个数。该方法的时间å¤�æ�‚度为 O(n),空间å¤�æ�‚度为 O(n),使用空间æ�¥æ�¢å�–时间。 ```java public int[] twoSum(int[] nums, int target) { @@ -3238,9 +3239,9 @@ public int[] twoSum(int[] nums, int target) { } ``` -**×ºÍгÐòÁÐ** +**最长和è°�åº�列** -ºÍгÐòÁÐÖÐ×î´óÊýºÍ×îСÊýÖ»²îÕýºÃΪ 1 +å’Œè°�åº�列中最大数和最å°�æ•°å�ªå·®æ­£å¥½ä¸º 1 [Leetcode : 594. Longest Harmonious Subsequence (Easy)](https://leetcode.com/problems/longest-harmonious-subsequence/description/) @@ -3260,15 +3261,15 @@ public int findLHS(int[] nums) { } ``` -## ×Ö·û´® +## 字符串 -**Á½¸ö×Ö·û´®µÄ°üº¬µÄ×Ö·ûÊÇ·ñÍêÈ«Ïàͬ** +**两个字符串的包å�«çš„字符是å�¦å®Œå…¨ç›¸å�Œ** [Leetcode : 242. Valid Anagram (Easy)](https://leetcode.com/problems/valid-anagram/description/) -×Ö·û´®Ö»°üº¬Ð¡Ð´×Ö·û£¬×ܹ²ÓÐ 26 ¸öСд×Ö·û¡£¿ÉÒÔÓà Hash Table À´Ó³Éä×Ö·ûÓë³öÏÖ´ÎÊý£¬ÒòΪ¼üÖµ·¶Î§ºÜС£¬Òò´Ë¿ÉÒÔÓÃÊý×éÀ´½øÐÐÓ³Éä¡£ +字符串å�ªåŒ…å�«å°�写字符,总共有 26 个å°�写字符。å�¯ä»¥ç”¨ Hash Table æ�¥æ˜ å°„字符与出现次数,因为键值范围很å°�,因此å�¯ä»¥ç”¨æ•°ç»„æ�¥è¿›è¡Œæ˜ å°„。 -ʹÓó¤¶ÈΪ 26 µÄÕûÐÍÊý×é¶Ô×Ö·û´®³öÏÖµÄ×Ö·û½øÐÐͳ¼Æ£¬±È½ÏÁ½¸ö×Ö·û´®³öÏÖµÄ×Ö·ûÊýÁ¿ÊÇ·ñÏàͬ¡£ +使用长度为 26 的整型数组对字符串出现的字符进行统计,比较两个字符串出现的字符数é‡�是å�¦ç›¸å�Œã€‚ ```java public boolean isAnagram(String s, String t) { @@ -3280,13 +3281,13 @@ public boolean isAnagram(String s, String t) { } ``` -**×Ö·û´®Í¬¹¹** +**字符串å�Œæž„** [Leetcode : 205. Isomorphic Strings (Easy)](https://leetcode.com/problems/isomorphic-strings/description/) -ÀýÈç "egg" ºÍ "add" ¾ÍÊôÓÚͬ¹¹×Ö·û´®¡£ +例如 "egg" å’Œ "add" 就属于å�Œæž„字符串。 -¼Ç¼һ¸ö×Ö·ûÉϴγöÏÖµÄλÖã¬Èç¹ûÁ½¸ö×Ö·û´®ÖÐij¸ö×Ö·ûÉϴγöÏÖµÄλÖÃÒ»Ñù£¬ÄÇô¾ÍÊôÓÚͬ¹¹¡£ +记录一个字符上次出现的ä½�置,如果两个字符串中æŸ�个字符上次出现的ä½�置一样,那么就属于å�Œæž„。 ```java public boolean isIsomorphic(String s, String t) { @@ -3303,30 +3304,30 @@ public boolean isIsomorphic(String s, String t) { } ``` -**¼ÆËãÒ»×é×Ö·û¼¯ºÏ¿ÉÒÔ×é³ÉµÄ»ØÎÄ×Ö·û´®µÄ×î´ó³¤¶È** +**计算一组字符集å�ˆå�¯ä»¥ç»„æˆ�的回文字符串的最大长度** [Leetcode : 409. Longest Palindrome](https://leetcode.com/problems/longest-palindrome/description/) -ʹÓó¤¶ÈΪ 128 µÄÕûÐÍÊý×éÀ´Í³¼ÆÃ¿¸ö×Ö·û³öÏֵĸöÊý£¬Ã¿¸ö×Ö·ûÓÐżÊý¸ö¿ÉÒÔÓÃÀ´¹¹³É»ØÎÄ×Ö·û´®¡£ÒòΪ»ØÎÄ×Ö·û´®×îÖмäµÄÄǸö×Ö·û¿ÉÒÔµ¥¶À³öÏÖ£¬ËùÒÔÈç¹ûÓе¥¶ÀµÄ×Ö·û¾Í°ÑËü·Åµ½×îÖм䡣 +使用长度为 128 的整型数组æ�¥ç»Ÿè®¡æ¯�个字符出现的个数,æ¯�个字符有å�¶æ•°ä¸ªå�¯ä»¥ç”¨æ�¥æž„æˆ�回文字符串。因为回文字符串最中间的那个字符å�¯ä»¥å�•独出现,所以如果有å�•独的字符就把它放到最中间。 ```java public int longestPalindrome(String s) { - int[] cnts = new int[128]; // ascii Âë×ܹ² 128 ¸ö + int[] cnts = new int[128]; // ascii ç �总共 128 个 for(char c : s.toCharArray()) cnts[c]++; int ret = 0; for(int cnt : cnts) ret += (cnt / 2) * 2; - if(ret < s.length()) ret ++; // Õâ¸öÌõ¼þÏ s ÖÐÒ»¶¨Óе¥¸öδʹÓõÄ×Ö·û´æÔÚ£¬¿ÉÒÔ°ÑÕâ¸ö×Ö·û·Åµ½»ØÎĵÄ×îÖмä + if(ret < s.length()) ret ++; // 这个æ�¡ä»¶ä¸‹ s 中一定有å�•个未使用的字符存在,å�¯ä»¥æŠŠè¿™ä¸ªå­—符放到回文的最中间 return ret; } ``` -**ÅжÏÒ»¸öÕûÊýÊÇ·ñÊÇ»ØÎÄÊý** +**判断一个整数是å�¦æ˜¯å›žæ–‡æ•°** [Leetcode : 9. Palindrome Number (Easy)](https://leetcode.com/problems/palindrome-number/description/) -ÒªÇó²»ÄÜʹÓöîÍâ¿Õ¼ä£¬Ò²¾Í²»Äܽ«ÕûÊýת»»Îª×Ö·û´®½øÐÐÅжϡ£ +è¦�求ä¸�能使用é¢�外空间,也就ä¸�能将整数转æ�¢ä¸ºå­—符串进行判断。 -½«ÕûÊý·Ö³É×óÓÒÁ½²¿·Ö£¬ÓÒ±ßÄDz¿·ÖÐèҪתÖã¬È»ºóÅжÏÕâÁ½²¿·ÖÊÇ·ñÏàµÈ¡£ +将整数分æˆ�å·¦å�³ä¸¤éƒ¨åˆ†ï¼Œå�³è¾¹é‚£éƒ¨åˆ†éœ€è¦�转置,然å�Žåˆ¤æ–­è¿™ä¸¤éƒ¨åˆ†æ˜¯å�¦ç›¸ç­‰ã€‚ ```java public boolean isPalindrome(int x) { @@ -3342,18 +3343,18 @@ public boolean isPalindrome(int x) { } ``` -**»ØÎÄ×Ó×Ö·û´®** +**回文å­�字符串** [Leetcode : 647. Palindromic Substrings (Medium)](https://leetcode.com/problems/palindromic-substrings/description/) -½â¾ö·½°¸ÊÇ´Ó×Ö·û´®µÄijһλ¿ªÊ¼£¬³¢ÊÔ×ÅÈ¥À©Õ¹×Ó×Ö·û´®¡£ +解决方案是从字符串的æŸ�一ä½�开始,å°�试ç�€åŽ»æ‰©å±•å­�字符串。 ```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); // żÊý³¤¶È + extendSubstrings(s, i, i); // 奇数长度 + extendSubstrings(s, i, i + 1); // å�¶æ•°é•¿åº¦ } return cnt; } @@ -3367,7 +3368,7 @@ private void extendSubstrings(String s, int start, int end) { } ``` -**ͳ¼Æ¶þ½øÖÆ×Ö·û´®ÖÐÁ¬Ðø 1 ºÍ Á¬Ðø 0 ÊýÁ¿ÏàͬµÄ×Ó×Ö·û´®¸öÊý** +**统计二进制字符串中连续 1 å’Œ 连续 0 æ•°é‡�相å�Œçš„å­�字符串个数** ```html Input: "00110011" @@ -3393,40 +3394,40 @@ public int countBinarySubstrings(String s) { } ``` -**×Ö·û´®Ñ­»·ÒÆÎ»°üº¬** +**字符串循环移ä½�包å�«** -[ ±à³ÌÖ®ÃÀ£º3.1](#) +[ 编程之美:3.1](#) -¸ø¶¨Á½¸ö×Ö·û´® s1 ºÍ s2 £¬ÒªÇóÅж¨ s2 ÊÇ·ñÄܹ»±» s1 ×öÑ­»·ÒÆÎ»µÃµ½µÄ×Ö·û´®°üº¬¡£ +给定两个字符串 s1 å’Œ s2 ,è¦�求判定 s2 是å�¦èƒ½å¤Ÿè¢« s1 å�šå¾ªçŽ¯ç§»ä½�得到的字符串包å�«ã€‚ ```html s1 = AABCD, s2 = CDAA Return : true ``` -s1 ½øÐÐÑ­»·ÒÆÎ»µÄ½á¹ûÊÇ s1s1 µÄ×Ó×Ö·û´®£¬Òò´ËÖ»ÒªÅÐ¶Ï s2 ÊÇ·ñÊÇ s1s1 µÄ×Ó×Ö·û´®¼´¿É¡£ +s1 进行循环移ä½�的结果是 s1s1 çš„å­�字符串,因此å�ªè¦�判断 s2 是å�¦æ˜¯ s1s1 çš„å­�字符串å�³å�¯ã€‚ -**×Ö·û´®Ñ­»·ÒÆÎ»** +**字符串循环移ä½�** -[ ±à³ÌÖ®ÃÀ£º2.17](#) +[ 编程之美:2.17](#) -½«×Ö·û´®ÏòÓÒÑ­»·Òƶ¯ k λ¡£ +将字符串å�‘å�³å¾ªçŽ¯ç§»åŠ¨ k ä½�。 -ÀýÈç abcd123 ÏòÓÒÒÆ¶¯ 3 λ µÃµ½ 123abcd +例如 abcd123 å�‘å�³ç§»åЍ 3 ä½� 得到 123abcd -½« abcd123 ÖÐµÄ abcd ºÍ 123 µ¥¶ÀÄæÐò£¬µÃµ½ dcba321£¬È»ºó¶ÔÕû¸ö×Ö·û´®½øÐÐÄæÐò£¬µÃµ½123abcd¡£ +å°† abcd123 中的 abcd å’Œ 123 å�•独逆åº�,得到 dcba321,然å�Žå¯¹æ•´ä¸ªå­—符串进行逆åº�,得到123abcd。 -**×Ö·û´®Öе¥´ÊµÄ·­×ª** +**字符串中å�•è¯�的翻转** -[³ÌÐòÔ±´úÂëÃæÊÔÖ¸ÄÏ](#) +[程åº�员代ç �é�¢è¯•指å�—](#) -ÀýÈ罫 "I am a student" ·­×ª³É "student a am I" +例如将 "I am a student" 翻转æˆ� "student a am I" -½«Ã¿¸öµ¥´ÊÄæÐò£¬È»ºó½«Õû¸ö×Ö·û´®ÄæÐò¡£ +å°†æ¯�个å�•è¯�逆åº�,然å�Žå°†æ•´ä¸ªå­—符串逆åº�。 -## Êý×éÓë¾ØÕó +## 数组与矩阵 -**°ÑÊý×éÖÐµÄ 0 ÒÆµ½Ä©Î²** +**把数组中的 0 移到末尾** [Leetcode : 283. Move Zeroes (Easy)](https://leetcode.com/problems/move-zeroes/description/) @@ -3443,20 +3444,20 @@ s1 } ``` -**Ò»¸öÊý×éÔªËØÔÚ [1, n] Ö®¼ä£¬ÆäÖÐÒ»¸öÊý±»Ì滻ΪÁíÒ»¸öÊý£¬ÕÒ³ö¶ªÊ§µÄÊýºÍÖØ¸´µÄÊý** +**一个数组元素在 [1, n] 之间,其中一个数被替æ�¢ä¸ºå�¦ä¸€ä¸ªæ•°ï¼Œæ‰¾å‡ºä¸¢å¤±çš„æ•°å’Œé‡�å¤�的数** [Leetcode : 645. Set Mismatch (Easy)](https://leetcode.com/problems/set-mismatch/description/) -×îÖ±½ÓµÄ·½·¨ÊÇÏȶÔÊý×é½øÐÐÅÅÐò£¬ÕâÖÖ·½·¨Ê±¼ä¸´ÔÓ¶ÈΪ O(nlogn)£¬±¾Ìâ¿ÉÒÔÒÔ O(n) µÄʱ¼ä¸´ÔÓ¶È¡¢O(1) ¿Õ¼ä¸´ÔÓ¶ÈÀ´Çó½â¡£ +最直接的方法是先对数组进行排åº�,这ç§�方法时间å¤�æ�‚度为 O(nlogn),本题å�¯ä»¥ä»¥ O(n) 的时间å¤�æ�‚度ã€�O(1) 空间å¤�æ�‚度æ�¥æ±‚解。 -Ö÷Ҫ˼ÏëÊÇÈÃͨ¹ý½»»»Êý×éÔªËØ£¬Ê¹µÃÊý×éÉϵÄÔªËØÔÚÕýÈ·µÄλÖÃÉÏ¡£ +主è¦�æ€�想是让通过交æ�¢æ•°ç»„元素,使得数组上的元素在正确的ä½�置上。 -±éÀúÊý×飬Èç¹ûµÚ i λÉϵÄÔªËØ²»ÊÇ i + 1 £¬ÄÇô¾Í½»»»µÚ i λ ºÍ nums[i] - 1 λÉϵÄÔªËØ£¬Ê¹µÃ num[i] - 1 µÄÔªËØÎª nums[i] £¬Ò²¾ÍÊǸÃλµÄÔªËØÊÇÕýÈ·µÄ¡£½»»»²Ù×÷ÐèҪѭ»·½øÐУ¬ÒòΪһ´Î½»»»Ã»°ì·¨Ê¹µÃµÚ i λÉϵÄÔªËØÊÇÕýÈ·µÄ¡£µ«ÊÇÒª½»»»µÄÁ½¸öÔªËØ¿ÉÄܾÍÊÇÖØ¸´ÔªËØ£¬ÄÇôѭ»·¾Í¿ÉÄÜÓÀÔ¶½øÐÐÏÂÈ¥£¬ÖÕֹѭ»·µÄ·½·¨ÊǼÓÉÏ nums[i] != nums[nums[i] - 1 Ìõ¼þ¡£ +é��历数组,如果第 i ä½�上的元素ä¸�是 i + 1 ,那么就交æ�¢ç¬¬ i ä½� å’Œ nums[i] - 1 ä½�上的元素,使得 num[i] - 1 的元素为 nums[i] ,也就是该ä½�的元素是正确的。交æ�¢æ“�作需è¦�循环进行,因为一次交æ�¢æ²¡åŠžæ³•ä½¿å¾—ç¬¬ i ä½�上的元素是正确的。但是è¦�交æ�¢çš„两个元素å�¯èƒ½å°±æ˜¯é‡�å¤�元素,那么循环就å�¯èƒ½æ°¸è¿œè¿›è¡Œä¸‹åŽ»ï¼Œç»ˆæ­¢å¾ªçŽ¯çš„æ–¹æ³•æ˜¯åŠ ä¸Š nums[i] != nums[nums[i] - 1 æ�¡ä»¶ã€‚ -ÀàËÆÌâÄ¿£º +类似题目: -- [Leetcode :448. Find All Numbers Disappeared in an Array (Easy)](https://leetcode.com/problems/find-all-numbers-disappeared-in-an-array/description/)£¬Ñ°ÕÒËùÓжªÊ§µÄÔªËØ -- [Leetcode : 442. Find All Duplicates in an Array (Medium)](https://leetcode.com/problems/find-all-duplicates-in-an-array/description/)£¬Ñ°ÕÒËùÓÐÖØ¸´µÄÔªËØ¡£ +- [Leetcode :448. Find All Numbers Disappeared in an Array (Easy)](https://leetcode.com/problems/find-all-numbers-disappeared-in-an-array/description/),寻找所有丢失的元素 +- [Leetcode : 442. Find All Duplicates in an Array (Medium)](https://leetcode.com/problems/find-all-duplicates-in-an-array/description/),寻找所有é‡�å¤�的元素。 ```java public int[] findErrorNums(int[] nums) { @@ -3478,11 +3479,11 @@ private void swap(int[] nums, int i, int j){ } ``` -**ÕÒ³öÊý×éÖÐÖØ¸´µÄÊý£¬Êý×éÖµÔÚ [0, n-1] Ö®¼ä** +**找出数组中é‡�å¤�的数,数组值在 [0, n-1] 之间** [Leetcode : 287. Find the Duplicate Number (Medium)](https://leetcode.com/problems/find-the-duplicate-number/description/) -¶þ·Ö²éÕҽⷨ£º +二分查找解法: ```java public int findDuplicate(int[] nums) { @@ -3500,7 +3501,7 @@ public int findDuplicate(int[] nums) { } ``` -˫ָÕë½â·¨£¬ÀàËÆÓÚÓл·Á´±íÖÐÕÒ³ö»·µÄÈë¿Ú£º +å�ŒæŒ‡é’ˆè§£æ³•,类似于有环链表中找出环的入å�£ï¼š ```java public int findDuplicate(int[] nums) { @@ -3519,11 +3520,11 @@ public int findDuplicate(int[] nums) { } ``` -### ÓÐÐò¾ØÕó +### 有åº�矩阵 -ÓÐÐò¾ØÕóÖ¸µÄÊÇÐкÍÁзֱðÓÐÐòµÄ¾ØÕó¡£ +有åº�矩阵指的是行和列分别有åº�的矩阵。 -Ò»°ã¿ÉÒÔÀûÓÃÓÐÐòÐÔʹÓöþ·Ö²éÕÒ·½·¨¡£ +一般å�¯ä»¥åˆ©ç”¨æœ‰åº�性使用二分查找方法。 ```html [ @@ -3533,7 +3534,7 @@ public int findDuplicate(int[] nums) { ] ``` -**ÓÐÐò¾ØÕó²éÕÒ** +**有åº�矩阵查找** [Leetocde : 240. Search a 2D Matrix II (Medium)](https://leetcode.com/problems/search-a-2d-matrix-ii/description/) @@ -3551,7 +3552,7 @@ public boolean searchMatrix(int[][] matrix, int target) { } ``` -**ÓÐÐò¾ØÕóµÄ Kth Element** +**有åº�矩阵的 Kth Element** [Leetcode : 378. Kth Smallest Element in a Sorted Matrix ((Medium))](https://leetcode.com/problems/kth-smallest-element-in-a-sorted-matrix/description/) @@ -3566,9 +3567,9 @@ k = 8, return 13. ``` -½âÌâ²Î¿¼£º[Share my thoughts and Clean Java Code](https://leetcode.com/problems/kth-smallest-element-in-a-sorted-matrix/discuss/85173) +解题å�‚考:[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) { @@ -3589,14 +3590,14 @@ public int kthSmallest(int[][] matrix, int k) { } ``` -¶Ñ½â·¨£º +堆解法: ```java public int kthSmallest(int[][] matrix, int k) { int m = matrix.length, n = matrix[0].length; PriorityQueue pq = new PriorityQueue(); 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 µÄÊý + 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])); @@ -3617,25 +3618,25 @@ class Tuple implements Comparable { } ``` -## Á´±í +## 链表 -**ÅжÏÁ½¸öÁ´±íµÄ½»µã** +**判断两个链表的交点** [Leetcode : 160. Intersection of Two Linked Lists](https://leetcode.com/problems/intersection-of-two-linked-lists/description/) ```html -A: a1 ¡ú a2 - ¨K - c1 ¡ú c2 ¡ú c3 - ¨J -B: b1 ¡ú b2 ¡ú b3 +A: a1 → a2 + ↘ + c1 → c2 → c3 + ↗ +B: b1 → b2 → b3 ``` -ÒªÇó£ºÊ±¼ä¸´ÔÓ¶ÈΪ O(n) ¿Õ¼ä¸´ÔÓ¶ÈΪ O(1) +è¦�求:时间å¤�æ�‚度为 O(n) 空间å¤�æ�‚度为 O(1) -Éè A µÄ³¤¶ÈΪ a + c£¬B µÄ³¤¶ÈΪ b + c£¬ÆäÖÐ c Ϊβ²¿¹«¹²²¿·Ö³¤¶È£¬¿ÉÖª a + c + b = b + c + a¡£ +设 A 的长度为 a + c,B 的长度为 b + c,其中 c 为尾部公共部分长度,å�¯çŸ¥ a + c + b = b + c + a。 -µ±·ÃÎÊ A Á´±íµÄÖ¸Õë·ÃÎʵ½Á´±íβ²¿Ê±£¬ÁîËü´ÓÁ´±í B µÄÍ·²¿¿ªÊ¼·ÃÎÊÁ´±í B£»Í¬ÑùµØ£¬µ±·ÃÎÊ B Á´±íµÄÖ¸Õë·ÃÎʵ½Á´±íβ²¿Ê±£¬ÁîËü´ÓÁ´±í A µÄÍ·²¿¿ªÊ¼·ÃÎÊÁ´±í A¡£ÕâÑù¾ÍÄÜ¿ØÖÆ·ÃÎÊ A ºÍ B Á½¸öÁ´±íµÄÖ¸ÕëÄÜͬʱ·ÃÎʵ½½»µã¡£ +当访问 A 链表的指针访问到链表尾部时,令它从链表 B 的头部开始访问链表 Bï¼›å�Œæ ·åœ°ï¼Œå½“访问 B 链表的指针访问到链表尾部时,令它从链表 A 的头部开始访问链表 A。这样就能控制访问 A å’Œ B 两个链表的指针能å�Œæ—¶è®¿é—®åˆ°äº¤ç‚¹ã€‚ ```java public ListNode getIntersectionNode(ListNode headA, ListNode headB) { @@ -3649,19 +3650,19 @@ public ListNode getIntersectionNode(ListNode headA, ListNode headB) { } ``` -Èç¹ûÖ»ÊÇÅжÏÊÇ·ñ´æÔÚ½»µã£¬ÄÇô¾ÍÊÇÁíÒ»¸öÎÊÌ⣬¼´ ±à³ÌÖ®ÃÀ£º3.6 µÄÎÊÌâ¡£ÓÐÁ½Öֽⷨ£º°ÑµÚÒ»¸öÁ´±íµÄ½áβÁ¬½Óµ½µÚ¶þ¸öÁ´±íµÄ¿ªÍ·£¬¿´µÚ¶þ¸öÁ´±íÊÇ·ñ´æÔÚ»·£»»òÕßÖ±½Ó±È½ÏµÚÒ»¸öÁ´±í×îºóÒ»¸ö½ÚµãºÍµÚ¶þ¸öÁ´±í×îºóÒ»¸ö½ÚµãÊÇ·ñÏàͬ¡£ +如果å�ªæ˜¯åˆ¤æ–­æ˜¯å�¦å­˜åœ¨äº¤ç‚¹ï¼Œé‚£ä¹ˆå°±æ˜¯å�¦ä¸€ä¸ªé—®é¢˜ï¼Œå�³ 编程之美:3.6 的问题。有两ç§�解法:把第一个链表的结尾连接到第二个链表的开头,看第二个链表是å�¦å­˜åœ¨çŽ¯ï¼›æˆ–è€…ç›´æŽ¥æ¯”è¾ƒç¬¬ä¸€ä¸ªé“¾è¡¨æœ€å�Žä¸€ä¸ªèŠ‚ç‚¹å’Œç¬¬äºŒä¸ªé“¾è¡¨æœ€å�Žä¸€ä¸ªèŠ‚ç‚¹æ˜¯å�¦ç›¸å�Œã€‚ -**Á´±í·´×ª** +**链表å��转** [Leetcode : 206. Reverse Linked List](https://leetcode.com/problems/reverse-linked-list/description/) -Í·²å·¨Äܹ»°´ÄæÐò¹¹½¨Á´±í¡£ +头æ�’法能够按逆åº�构建链表。 ```java public ListNode reverseList(ListNode head) { - ListNode newHead = null; // ÉèΪ null £¬×÷ΪÐÂÁ´±íµÄ½áβ + ListNode newHead = null; // 设为 null ,作为新链表的结尾 while(head != null){ ListNode nextNode = head.next; head.next = newHead; @@ -3672,11 +3673,11 @@ public ListNode reverseList(ListNode head) { } ``` -**¹é²¢Á½¸öÓÐÐòµÄÁ´±í** +**归并两个有åº�的链表** [Leetcode : 21. Merge Two Sorted Lists](https://leetcode.com/problems/merge-two-sorted-lists/description/) -Á´±íºÍÊ÷Ò»Ñù£¬¿ÉÒÔÓõݹ鷽ʽÀ´¶¨Ò壺Á´±íÊǿսڵ㣬»òÕßÓÐÒ»¸öÖµºÍÒ»¸öÖ¸ÏòÏÂÒ»¸öÁ´±íµÄÖ¸Õ룬Òò´ËºÜ¶àÁ´±íÎÊÌâ¿ÉÒÔÓõݹéÀ´´¦Àí¡£ +链表和树一样,å�¯ä»¥ç”¨é€’å½’æ–¹å¼�æ�¥å®šä¹‰ï¼šé“¾è¡¨æ˜¯ç©ºèŠ‚ç‚¹ï¼Œæˆ–è€…æœ‰ä¸€ä¸ªå€¼å’Œä¸€ä¸ªæŒ‡å�‘下一个链表的指针,因此很多链表问题å�¯ä»¥ç”¨é€’å½’æ�¥å¤„ç�†ã€‚ ```java public ListNode mergeTwoLists(ListNode l1, ListNode l2) { @@ -3694,7 +3695,7 @@ public ListNode mergeTwoLists(ListNode l1, ListNode l2) { } ``` -**´ÓÓÐÐòÁ´±íÖÐɾ³ýÖØ¸´½Úµã** +**从有åº�链表中删除é‡�å¤�节点** [Leetcode : 83. Remove Duplicates from Sorted List (Easy)](https://leetcode.com/problems/remove-duplicates-from-sorted-list/description/) @@ -3706,11 +3707,11 @@ public ListNode deleteDuplicates(ListNode head) { } ``` -**»ØÎÄÁ´±í** +**回文链表** [Leetcode : 234. Palindrome Linked List (Easy)](https://leetcode.com/problems/palindrome-linked-list/description/) -ÇгÉÁ½°ë£¬°Ñºó°ë¶Î·´×ª£¬È»ºó±È½ÏÁ½°ëÊÇ·ñÏàµÈ¡£ +切æˆ�两å�Šï¼ŒæŠŠå�Žå�Šæ®µå��转,然å�Žæ¯”较两å�Šæ˜¯å�¦ç›¸ç­‰ã€‚ ```java public boolean isPalindrome(ListNode head) { @@ -3721,11 +3722,11 @@ public boolean isPalindrome(ListNode head) { fast = fast.next.next; } - if(fast != null){ // żÊý½Úµã£¬Èà slow Ö¸ÏòÏÂÒ»¸ö½Úµã + if(fast != null){ // å�¶æ•°èŠ‚ç‚¹ï¼Œè®© slow 指å�‘下一个节点 slow = slow.next; } - cut(head, slow); // ÇгÉÁ½¸öÁ´±í + cut(head, slow); // 切æˆ�两个链表 ListNode l1 = head, l2 = slow; l2 = reverse(l2); return isEqual(l1, l2); @@ -3757,18 +3758,18 @@ private boolean isEqual(ListNode l1, ListNode l2){ } ``` -**´ÓÁ´±íÖÐɾ³ý½Úµã** +**从链表中删除节点** -[±à³ÌÖ®ÃÀ£º3.4]() +[编程之美:3.4]() -![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/2c968ec5-0967-49ce-ac06-f8f5c9ab33bc.jpg) +![](https://github.com/CyC2018/InterviewNotes/blob/master/pics//2c968ec5-0967-49ce-ac06-f8f5c9ab33bc.jpg) ```java B.val = C.val; B.next = C.next; ``` -**Á´±íÔªËØ°´ÆæÅ¼¾Û¼¯** +**链表元素按奇å�¶è�šé›†** [Leetcode : 328. Odd Even Linked List (Medium)](https://leetcode.com/problems/odd-even-linked-list/description/) @@ -3789,13 +3790,13 @@ public ListNode oddEvenList(ListNode head) { } ``` -## Ê÷ +## æ ‘ -### µÝ¹é +### 递归 -Ò»¿ÃÊ÷ҪôÊÇ¿ÕÊ÷£¬ÒªÃ´ÓÐÁ½¸öÖ¸Õ룬ÿ¸öÖ¸ÕëÖ¸ÏòÒ»¿ÃÊ÷¡£Ê÷ÊÇÒ»Öֵݹé½á¹¹£¬ºÜ¶àÊ÷µÄÎÊÌâ¿ÉÒÔʹÓõݹéÀ´´¦Àí¡£ +一棵树è¦�么是空树,è¦�么有两个指针,æ¯�个指针指å�‘一棵树。树是一ç§�递归结构,很多树的问题å�¯ä»¥ä½¿ç”¨é€’å½’æ�¥å¤„ç�†ã€‚ -**Ê÷µÄ¸ß¶È** +**树的高度** [Leetcode : 104. Maximum Depth of Binary Tree (Easy)](https://leetcode.com/problems/maximum-depth-of-binary-tree/description/) @@ -3806,21 +3807,21 @@ public int maxDepth(TreeNode root) { } ``` -**·­×ªÊ÷** +**翻转树** [Leetcode : 226. Invert Binary Tree (Easy)](https://leetcode.com/problems/invert-binary-tree/description/) ```java public TreeNode invertTree(TreeNode root) { if(root == null) return null; - TreeNode left = root.left; // ºóÃæµÄ²Ù×÷»á¸Ä±ä left Ö¸Õ룬Òò´ËÏȱ£´æÏÂÀ´ + TreeNode left = root.left; // å�Žé�¢çš„æ“�作会改å�˜ left 指针,因此先ä¿�存下æ�¥ root.left = invertTree(root.right); root.right = invertTree(left); return root; } ``` -**¹é²¢Á½¿ÃÊ÷** +**归并两棵树** [Leetcode : 617. Merge Two Binary Trees (Easy)](https://leetcode.com/problems/merge-two-binary-trees/description/) @@ -3836,11 +3837,11 @@ public TreeNode mergeTrees(TreeNode t1, TreeNode t2) { } ``` -**ÅжÏ·¾¶ºÍÊÇ·ñµÈÓÚÒ»¸öÊý** +**判断路径和是å�¦ç­‰äºŽä¸€ä¸ªæ•°** [Leetcdoe : 112. Path Sum (Easy)](https://leetcode.com/problems/path-sum/description/) -ÌâÄ¿ÃèÊö£ºÂ·¾¶ºÍ¶¨ÒåΪ´Ó root µ½ leaf µÄËùÓнڵãµÄºÍ +题目æ��述:路径和定义为从 root 到 leaf 的所有节点的和 ```java public boolean hasPathSum(TreeNode root, int sum) { @@ -3850,13 +3851,13 @@ public boolean hasPathSum(TreeNode root, int sum) { } ``` -**ͳ¼ÆÂ·¾¶ºÍµÈÓÚÒ»¸öÊýµÄ·¾¶ÊýÁ¿** +**统计路径和等于一个数的路径数é‡�** [Leetcode : 437. Path Sum III (Easy)](https://leetcode.com/problems/path-sum-iii/description/) -ÌâÄ¿ÃèÊö£ºÂ·¾¶²»Ò»¶¨ÒÔ root ¿ªÍ·²¢ÒÔ leaf ½á⣬µ«ÊDZØÐëÁ¬Ðø +题目æ��述:路径ä¸�一定以 root 开头并以 leaf 结尾,但是必须连续 -pathSumStartWithRoot() ·½·¨Í³¼ÆÒÔij¸ö½Úµã¿ªÍ·µÄ·¾¶¸öÊý¡£ +pathSumStartWithRoot() 方法统计以æŸ�个节点开头的路径个数。 ```java public int pathSum(TreeNode root, int sum) { @@ -3874,7 +3875,7 @@ private int pathSumStartWithRoot(TreeNode root, int sum){ } ``` -**Ê÷µÄ¶Ô³Æ** +**树的对称** [Leetcode : 101. Symmetric Tree (Easy)](https://leetcode.com/problems/symmetric-tree/description/) @@ -3892,11 +3893,11 @@ private boolean isSymmetric(TreeNode t1, TreeNode t2){ } ``` -**ƽºâÊ÷** +**平衡树** [Leetcode : 110. Balanced Binary Tree (Easy)](https://leetcode.com/problems/balanced-binary-tree/description/) -ÌâÄ¿ÃèÊö£º×óÓÒ×ÓÊ÷¸ß¶È²îÊÇ·ñ¶¼Ð¡ÓÚµÈÓÚ 1 +题目æ��述:左å�³å­�树高度差是å�¦éƒ½å°�于等于 1 ```java private boolean result = true; @@ -3915,11 +3916,11 @@ public int maxDepth(TreeNode root) { } ``` -**×îС·¾¶** +**最å°�路径** [Leetcode : 111. Minimum Depth of Binary Tree (Easy)](https://leetcode.com/problems/minimum-depth-of-binary-tree/description/) -ÌâÄ¿ÃèÊö£ºÊ÷µÄ¸ù½Úµãµ½Ò¶×Ó½ÚµãµÄ×îС³¤¶È +题目æ��述:树的根节点到å�¶å­�节点的最å°�长度 ```java public int minDepth(TreeNode root) { @@ -3931,7 +3932,7 @@ public int minDepth(TreeNode root) { } ``` -**ͳ¼Æ×óÒ¶×Ó½ÚµãµÄºÍ** +**统计左å�¶å­�节点的和** [Leetcode : 404. Sum of Left Leaves (Easy)](https://leetcode.com/problems/sum-of-left-leaves/description/) @@ -3948,11 +3949,11 @@ private boolean isLeaf(TreeNode node){ } ``` -**ÐÞ¼ôÒ»¿ÃÊ÷** +**修剪一棵树** [Leetcode : 669. Trim a Binary Search Tree (Easy)](https://leetcode.com/problems/trim-a-binary-search-tree/description/) -ÌâÄ¿ÃèÊö£ºÖ»±£ÁôÖµÔÚ L \~ R Ö®¼äµÄ½Úµã +题目æ��述:å�ªä¿�留值在 L \~ R 之间的节点 ```java public TreeNode trimBST(TreeNode root, int L, int R) { @@ -3965,7 +3966,7 @@ public TreeNode trimBST(TreeNode root, int L, int R) { } ``` -**×ÓÊ÷** +**å­�æ ‘** [Leetcode : 572. Subtree of Another Tree (Easy)](https://leetcode.com/problems/subtree-of-another-tree/description/) @@ -3985,11 +3986,11 @@ private boolean isSame(TreeNode s, TreeNode t){ } ``` -**´ÓÓÐÐòÊý×éÖй¹Ôì¶þ²æ²éÕÒÊ÷** +**从有åº�数组中构造二å�‰æŸ¥æ‰¾æ ‘** [Leetcode : 108. Convert Sorted Array to Binary Search Tree (Easy)](https://leetcode.com/problems/convert-sorted-array-to-binary-search-tree/description/) -¶þ²æ²éÕÒÊ÷£¨BST£©£º¸ù½Úµã´óÓÚµÈÓÚ×ó×ÓÊ÷ËùÓнڵ㣬СÓÚµÈÓÚÓÒ×ÓÊ÷ËùÓнڵ㡣 +二å�‰æŸ¥æ‰¾æ ‘(BST):根节点大于等于左å­�树所有节点,å°�于等于å�³å­�树所有节点。 ```java public TreeNode sortedArrayToBST(int[] nums) { @@ -4006,7 +4007,7 @@ private TreeNode toBST(int[] nums, int sIdx, int eIdx){ } ``` -**Á½½ÚµãµÄ×·¾¶** +**两节点的最长路径** ```html 1 @@ -4037,7 +4038,7 @@ private int depth(TreeNode root) { } ``` -**ÕÒ³ö¶þ²æÊ÷ÖеڶþСµÄ½Úµã** +**找出二å�‰æ ‘中第二å°�的节点** [Leetcode : 671. Second Minimum Node In a Binary Tree (Easy)](https://leetcode.com/problems/second-minimum-node-in-a-binary-tree/description/) @@ -4052,7 +4053,7 @@ Input: Output: 5 ``` -Ò»¸ö½ÚµãҪô¾ßÓÐ 0 ¸ö»ò 2 ¸ö×ӽڵ㣬Èç¹ûÓÐ×ӽڵ㣬ÄÇô¸ù½ÚµãÊÇ×îСµÄ½Úµã¡£ +一个节点è¦�么具有 0 个或 2 个å­�节点,如果有å­�节点,那么根节点是最å°�的节点。 ```java public int findSecondMinimumValue(TreeNode root) { @@ -4068,7 +4069,7 @@ public int findSecondMinimumValue(TreeNode root) { } ``` -**ѰÕÒÁ½¸ö½ÚµãµÄ×î½ü¹«¹²×æÏÈ** +**寻找两个节点的最近公共祖先** [Leetcode : 235. Lowest Common Ancestor of a Binary Search Tree (Easy)](https://leetcode.com/problems/lowest-common-ancestor-of-a-binary-search-tree/description/) @@ -4080,7 +4081,7 @@ public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) { } ``` -**×î½ü¹«¹²×æÏÈ** +**最近公共祖先** [Leetcode : 236. Lowest Common Ancestor of a Binary Tree (Medium) ](https://leetcode.com/problems/lowest-common-ancestor-of-a-binary-tree/description/) @@ -4093,7 +4094,7 @@ public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) { } ``` -**×î´óÏàͬ½ÚµãÖµµÄ·¾¶³¤¶È** +**最大相å�ŒèŠ‚ç‚¹å€¼çš„è·¯å¾„é•¿åº¦** [Leetcode : 687. Longest Univalue Path (Easy)](https://pomotodo.com/app/) @@ -4125,7 +4126,7 @@ private int dfs(TreeNode root){ } ``` -**¼ä¸ô±éÀú** +**é—´éš”é��历** [Leetcode : 337. House Robber III (Medium)](https://leetcode.com/problems/house-robber-iii/description/) @@ -4144,11 +4145,11 @@ public int rob(TreeNode root) { } ``` -### ²ã´Î±éÀú +### 层次é��历 -ʹÓà BFS£¬²»ÐèҪʹÓÃÁ½¸ö¶ÓÁÐÀ´·Ö±ð´æ´¢µ±Ç°²ãµÄ½ÚµãºÍÏÂÒ»²ãµÄ½Úµã£¬ ÒòΪÔÚ¿ªÊ¼±éÀúÒ»²ãµÄ½Úµãʱ£¬µ±Ç°¶ÓÁÐÖеĽڵãÊý¾ÍÊǵ±Ç°²ãµÄ½ÚµãÊý£¬Ö»Òª¿ØÖƱéÀúÕâô¶à½ÚµãÊý£¬¾ÍÄܱ£Ö¤Õâ´Î±éÀúµÄ¶¼Êǵ±Ç°²ãµÄ½Úµã¡£ +使用 BFS,ä¸�需è¦�使用两个队列æ�¥åˆ†åˆ«å­˜å‚¨å½“å‰�层的节点和下一层的节点, 因为在开始é��历一层的节点时,当å‰�队列中的节点数就是当å‰�层的节点数,å�ªè¦�控制é��历这么多节点数,就能ä¿�è¯�这次é��历的都是当å‰�层的节点。 -**¼ÆËãÒ»¿ÃÊ÷ÿ²ã½ÚµãµÄƽ¾ùÊý** +**计算一棵树æ¯�层节点的平å�‡æ•°** [637. Average of Levels in Binary Tree (Easy)](https://leetcode.com/problems/average-of-levels-in-binary-tree/description/) @@ -4173,7 +4174,7 @@ public List averageOfLevels(TreeNode root) { } ``` -**µÃµ½×óϽǵĽڵã** +**得到左下角的节点** [Leetcode : 513. Find Bottom Left Tree Value (Easy)](https://leetcode.com/problems/find-bottom-left-tree-value/description/) @@ -4190,7 +4191,7 @@ public int findBottomLeftValue(TreeNode root) { } ``` -### ǰÖкóÐò±éÀú +### å‰�中å�Žåº�é��历 ```html 1 @@ -4200,16 +4201,16 @@ public int findBottomLeftValue(TreeNode root) { 4 5 6 ``` -²ã´Î±éÀú˳Ðò£º[1 2 3 4 5 6] -ǰÐò±éÀú˳Ðò£º[1 2 4 5 3 6] -ÖÐÐò±éÀú˳Ðò£º[4 2 5 1 3 6] -ºóÐò±éÀú˳Ðò£º[4 5 2 6 3 1] +层次é��历顺åº�:[1 2 3 4 5 6] +å‰�åº�é��历顺åº�:[1 2 4 5 3 6] +中åº�é��历顺åº�:[4 2 5 1 3 6] +å�Žåº�é��历顺åº�:[4 5 2 6 3 1] -²ã´Î±éÀúʹÓà BFS ʵÏÖ£¬ÀûÓõľÍÊÇ BFS Ò»²ãÒ»²ã±éÀúµÄÌØÐÔ£»¶øÇ°Ðò¡¢ÖÐÐò¡¢ºóÐò±éÀúÀûÓÃÁË DFS ʵÏÖ¡£ +层次é��历使用 BFS 实现,利用的就是 BFS 一层一层é��历的特性;而å‰�åº�ã€�中åº�ã€�å�Žåº�é��历利用了 DFS 实现。 -ǰÐò¡¢ÖÐÐò¡¢ºóÐò±éÖ»ÊÇÔÚ¶Ô½Úµã·ÃÎʵÄ˳ÐòÓÐÒ»µã²»Í¬£¬ÆäËü¶¼Ïàͬ¡£ +å‰�åº�ã€�中åº�ã€�å�Žåº�é��å�ªæ˜¯åœ¨å¯¹èŠ‚ç‚¹è®¿é—®çš„é¡ºåº�有一点ä¸�å�Œï¼Œå…¶å®ƒéƒ½ç›¸å�Œã€‚ -¢Ù ǰÐò +â‘  å‰�åº� ```java void dfs(TreeNode root){ @@ -4219,7 +4220,7 @@ void dfs(TreeNode root){ } ``` -¢Ú ÖÐÐò +â‘¡ 中åº� ```java void dfs(TreeNode root){ @@ -4229,7 +4230,7 @@ void dfs(TreeNode root){ } ``` -¢Û ºóÐò +â‘¢ å�Žåº� ```java void dfs(TreeNode root){ @@ -4239,7 +4240,7 @@ void dfs(TreeNode root){ } ``` -**·ÇµÝ¹éʵÏÖ¶þ²æÊ÷µÄǰÐò±éÀú** +**é�žé€’归实现二å�‰æ ‘çš„å‰�åº�é��历** [Leetcode : 144. Binary Tree Preorder Traversal (Medium)](https://leetcode.com/problems/binary-tree-preorder-traversal/description/) @@ -4253,17 +4254,17 @@ public List preorderTraversal(TreeNode root) { TreeNode node = stack.pop(); ret.add(node.val); if (node.right != null) stack.push(node.right); - if (node.left != null) stack.push(node.left); // ÏÈÌí¼ÓÓÒ×ÓÊ÷ÔÙÌí¼Ó×ó×ÓÊ÷£¬ÕâÑùÊÇΪÁËÈÃ×ó×ÓÊ÷ÔÚÕ»¶¥ + if (node.left != null) stack.push(node.left); // 先添加å�³å­�æ ‘å†�添加左å­�树,这样是为了让左å­�树在栈顶 } return ret; } ``` -**·ÇµÝ¹éʵÏÖ¶þ²æÊ÷µÄºóÐø±éÀú** +**é�žé€’归实现二å�‰æ ‘çš„å�Žç»­é��历** [Leetcode : ### 145. Binary Tree Postorder Traversal (Medium)](https://leetcode.com/problems/binary-tree-postorder-traversal/description/) -ǰÐò±éÀúΪ root -> left -> right£¬ºóÐò±éÀúΪ left -> right -> root£¬¿ÉÒÔÐÞ¸ÄǰÐò±éÀú³ÉΪ root -> right -> left£¬ÄÇôÕâ¸ö˳Ðò¾ÍºÍºóÐò±éÀúÕýºÃÏà·´¡£ +å‰�åº�é��历为 root -> left -> right,å�Žåº�é��历为 left -> right -> root,å�¯ä»¥ä¿®æ”¹å‰�åº�é��历æˆ�为 root -> right -> left,那么这个顺åº�就和å�Žåº�é��历正好相å��。 ```java public List postorderTraversal(TreeNode root) { @@ -4282,7 +4283,7 @@ public List postorderTraversal(TreeNode root) { } ``` -**·ÇµÝ¹éʵÏÖ¶þ²æÊ÷µÄÖÐÐò±éÀú** +**é�žé€’归实现二å�‰æ ‘的中åº�é��历** [Leetcode : 94. Binary Tree Inorder Traversal (Medium)](https://leetcode.com/problems/binary-tree-inorder-traversal/description/) @@ -4292,7 +4293,7 @@ public List inorderTraversal(TreeNode root) { Stack stack = new Stack<>(); TreeNode cur = root; while(cur != null || !stack.isEmpty()) { - while(cur != null) { // Ä£ÄâµÝ¹éÕ»µÄ²»¶ÏÉîÈë + while(cur != null) { // 模拟递归栈的ä¸�断深入 stack.add(cur); cur = cur.left; } @@ -4304,19 +4305,19 @@ public List inorderTraversal(TreeNode root) { } ``` -**ʹÓÃÖÐÐò±éÀúºÍǰÐò±éÀúÐòÁÐÖØ½¨¶þ²æÊ÷** //TODO +**使用中åº�é��历和å‰�åº�é��历åº�列é‡�建二å�‰æ ‘** //TODO ### BST -Ö÷ÒªÀûÓà BST ÖÐÐò±éÀúÓÐÐòµÄÌØµã¡£ +主è¦�利用 BST 中åº�é��历有åº�的特点。 -**ÔÚ BST ÖÐѰÕÒÁ½¸ö½Úµã£¬Ê¹ËüÃǵĺÍΪһ¸ö¸ø¶¨Öµ¡£** +**在 BST 中寻找两个节点,使它们的和为一个给定值。** [653. Two Sum IV - Input is a BST](https://leetcode.com/problems/two-sum-iv-input-is-a-bst/description/) -ʹÓÃÖÐÐò±éÀúµÃµ½ÓÐÐòÊý×éÖ®ºó£¬ÔÙÀûÓÃ˫ָÕë¶ÔÊý×é½øÐвéÕÒ¡£ +使用中åº�é��历得到有åº�数组之å�Žï¼Œå†�利用å�ŒæŒ‡é’ˆå¯¹æ•°ç»„进行查找。 -Ó¦¸Ã×¢Òâµ½£¬ÕâÒ»Ìâ²»ÄÜÓ÷ֱðÔÚ×óÓÒ×ÓÊ÷Á½²¿·ÖÀ´´¦ÀíÕâÖÖ˼Ï룬ÒòΪÁ½¸ö´ýÇóµÄ½Úµã¿ÉÄÜ·Ö±ðÔÚ×óÓÒ×ÓÊ÷ÖС£ +应该注æ„�到,这一题ä¸�能用分别在左å�³å­�树两部分æ�¥å¤„ç�†è¿™ç§�æ€�想,因为两个待求的节点å�¯èƒ½åˆ†åˆ«åœ¨å·¦å�³å­�树中。 ```java public boolean findTarget(TreeNode root, int k) { @@ -4340,11 +4341,11 @@ private void inOrder(TreeNode root, List nums){ } ``` -**ÔÚ BST ÖвéÕÒ×îСµÄÁ½¸ö½ÚµãÖ®²îµÄ¾ø¶ÔÖµ** +**在 BST 中查找最å°�的两个节点之差的ç»�对值** [Leetcode : 530. Minimum Absolute Difference in BST (Easy)](https://leetcode.com/problems/minimum-absolute-difference-in-bst/description/) -ÀûÓà BST µÄÖÐÐò±éÀúΪÓÐÐòµÄÐÔÖÊ£¬¼ÆËãÖÐÐò±éÀúÖÐÁÙ½üµÄÁ½¸ö½ÚµãÖ®²îµÄ¾ø¶ÔÖµ£¬È¡×îСֵ¡£ +利用 BST 的中åº�é��历为有åº�的性质,计算中åº�é��历中临近的两个节点之差的ç»�对值,å�–最å°�值。 ```java private int minDiff = Integer.MAX_VALUE; @@ -4364,11 +4365,11 @@ private void inorder(TreeNode node){ } ``` -**°Ñ BST ÿ¸ö½ÚµãµÄÖµ¶¼¼ÓÉϱÈËü´óµÄ½ÚµãµÄÖµ** +**把 BST æ¯�个节点的值都加上比它大的节点的值** [Leetcode : Convert BST to Greater Tree (Easy)](https://leetcode.com/problems/convert-bst-to-greater-tree/description/) -ÏȱéÀúÓÒ×ÓÊ÷¡£ +å…ˆé��历å�³å­�树。 ```java private int sum = 0; @@ -4393,7 +4394,7 @@ private void traver(TreeNode root) { } ``` -**ѰÕÒ BST ÖгöÏÖ´ÎÊý×î¶àµÄ½Úµã** +**寻找 BST 中出现次数最多的节点** ```java private int cnt = 1; @@ -4431,11 +4432,11 @@ private void inorder(TreeNode node){ } ``` -**ѰÕÒ BST µÄµÚ k ¸öÔªËØ** +**寻找 BST 的第 k 个元素** [Leetcode : 230. Kth Smallest Element in a BST (Medium)](https://leetcode.com/problems/kth-smallest-element-in-a-bst/description/) -µÝ¹é½â·¨£º +递归解法: ```java public int kthSmallest(TreeNode root, int k) { @@ -4451,7 +4452,7 @@ private int count(TreeNode node) { } ``` -ÖÐÐò±éÀú½â·¨£º +中åº�é��历解法: ```java private int cnt = 0; @@ -4477,11 +4478,11 @@ private void inorder(TreeNode node, int k) { ### Trie -![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/5c638d59-d4ae-4ba4-ad44-80bdc30f38dd.jpg) +![](https://github.com/CyC2018/InterviewNotes/blob/master/pics//5c638d59-d4ae-4ba4-ad44-80bdc30f38dd.jpg) -Trie£¬ÓÖ³ÆÇ°×ºÊ÷»ò×ÖµäÊ÷£¬ÓÃÓÚÅжÏ×Ö·û´®ÊÇ·ñ´æÔÚ»òÕßÊÇ·ñ¾ßÓÐijÖÖ×Ö·û´®Ç°×º¡£ +Trie,å�ˆç§°å‰�缀树或字典树,用于判断字符串是å�¦å­˜åœ¨æˆ–者是å�¦å…·æœ‰æŸ�ç§�字符串å‰�缀。 -**ʵÏÖÒ»¸ö Trie** +**实现一个 Trie** [Leetcode : 208. Implement Trie (Prefix Tree) (Medium)](https://leetcode.com/problems/implement-trie-prefix-tree/description/) @@ -4541,7 +4542,7 @@ class Trie { } ``` -**ʵÏÖÒ»¸ö Trie£¬ÓÃÀ´Çóǰ׺ºÍ** +**实现一个 Trie,用æ�¥æ±‚å‰�缀和** [Leetcode : 677. Map Sum Pairs (Medium)](https://leetcode.com/problems/map-sum-pairs/description/) @@ -4598,47 +4599,47 @@ class MapSum { } ``` -## ͼ +## 图 -## λÔËËã +## ä½�è¿�ç®— -**1. »ù±¾Ô­Àí** +**1. 基本原ç�†** -0s ±íʾ Ò»´® 0 £¬1s ±íʾһ´® 1¡£ +0s 表示 一串 0 ,1s 表示一串 1。 ``` x ^ 0s = x x & 0s = 0 x | 0s = x -x ^ 1s = \~x x & 1s = x x | 1s = 1s +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 Óë mask £º00111100 ½øÐÐλÓë²Ù×÷£¬Ö»±£Áô num ÖÐÓë mask µÄ 1 ²¿·ÖÏà¶ÔÓ¦µÄλ£» -¢Û ÀûÓà x | 0s = x ºÍ x | 1s = 1s µÄÌØµã£¬¿ÉÒÔʵÏÖÉèÖòÙ×÷¡£Ò»¸öÊý num Óë mask£º00111100 ½øÐÐλ»ò²Ù×÷£¬½« num ÖÐÓë mask µÄ 1 ²¿·ÖÏà¶ÔÓ¦µÄλ¶¼ÉèÖÃΪ 1 ¡£ +â‘  利用 x ^ 1s = \~x 的特点,å�¯ä»¥å°†ä½�级表示翻转;利用 x ^ x = 0 的特点,å�¯ä»¥å°†ä¸‰ä¸ªæ•°ä¸­é‡�å¤�的两个数去除,å�ªç•™ä¸‹å�¦ä¸€ä¸ªæ•°ï¼› +â‘¡ 利用 x & 0s = 0 å’Œ x & 1s = x 的特点,å�¯ä»¥å®žçŽ°æŽ©ç �æ“�作。一个数 num 与 mask :00111100 进行ä½�与æ“�作,å�ªä¿�ç•™ num 中与 mask çš„ 1 部分相对应的ä½�ï¼› +â‘¢ 利用 x | 0s = x å’Œ x | 1s = 1s 的特点,å�¯ä»¥å®žçŽ°è®¾ç½®æ“�作。一个数 num 与 mask:00111100 进行ä½�或æ“�作,将 num 中与 mask çš„ 1 部分相对应的ä½�都设置为 1 。 -\>\> n ΪËãÊõÓÒÒÆ£¬Ï൱ÓÚ³ýÒÔ 2n£» -\>\>\> n ΪÎÞ·ûºÅÓÒÒÆ£¬×ó±ß»á²¹ÉÏ 0¡£ -<< n ΪËãÊõ×óÒÆ£¬Ï൱ÓÚ³ËÒÔ 2n¡£ +\>\> n 为算术å�³ç§»ï¼Œç›¸å½“于除以 2nï¼› +\>\>\> n 为无符å�·å�³ç§»ï¼Œå·¦è¾¹ä¼šè¡¥ä¸Š 0。 +<< n 为算术左移,相当于乘以 2n。 -n&(n-1) ¸ÃλÔËËãÊÇÈ¥³ý n µÄλ¼¶±íʾÖÐ×îµÍµÄÄÇһλ¡£ÀýÈç¶ÔÓÚ¶þ½øÖƱíʾ 10110**100**£¬¼õÈ¥ 1 µÃµ½ 10110**011**£¬ÕâÁ½¸öÊýÏàÓëµÃµ½ 10110**000**¡£ +n&(n-1) 该ä½�è¿�算是去除 n çš„ä½�级表示中最低的那一ä½�。例如对于二进制表示 10110**100**,å‡�去 1 得到 10110**011**,这两个数相与得到 10110**000**。 -n-n&(\~n+1) ¸ÅÔËËãÊÇÈ¥³ý n µÄλ¼¶±íʾÖÐ×î¸ßµÄÄÇһλ¡£ +n-n&(\~n+1) 概è¿�算是去除 n çš„ä½�级表示中最高的那一ä½�。 -n&(-n) ¸ÃÔËËãµÃµ½ n µÄλ¼¶±íʾÖÐ×îµÍµÄÄÇһλ¡£-n µÃµ½ n µÄ·´Âë¼Ó 1£¬¶ÔÓÚ¶þ½øÖƱíʾ 10110**100**£¬-n µÃµ½ 01001**100**£¬ÏàÓëµÃµ½ 00000**100** +n&(-n) 该è¿�算得到 n çš„ä½�级表示中最低的那一ä½�。-n 得到 n çš„å��ç �加 1,对于二进制表示 10110**100**,-n 得到 01001**100**,相与得到 00000**100** -**2. mask ¼ÆËã** +**2. mask 计算** -Òª»ñÈ¡ 111111111£¬½« 0 È¡·´¼´¿É£¬\~0¡£ +è¦�获å�– 111111111,将 0 å�–å��å�³å�¯ï¼Œ\~0。 -ÒªµÃµ½Ö»ÓÐµÚ i λΪ 1 µÄ mask£¬½« 1 Ïò×óÒÆ¶¯ i λ¼´¿É£¬1<<i ¡£ÀýÈç 1<<5 µÃµ½Ö»ÓÐµÚ 5 λΪ 1 µÄ mask £º00010000¡£ +è¦�得到å�ªæœ‰ç¬¬ i ä½�为 1 çš„ mask,将 1 å�‘左移动 i ä½�å�³å�¯ï¼Œ1<<i 。例如 1<<5 得到å�ªæœ‰ç¬¬ 5 ä½�为 1 çš„ mask :00010000。 -ÒªµÃµ½ 1 µ½ i λΪ 1 µÄ mask£¬1<<(i+1)-1 ¼´¿É£¬ÀýÈ罫 1<<(4+1)-1 = 00010000-1 = 00001111¡£ +è¦�得到 1 到 i ä½�为 1 çš„ mask,1<<(i+1)-1 å�³å�¯ï¼Œä¾‹å¦‚å°† 1<<(4+1)-1 = 00010000-1 = 00001111。 -ÒªµÃµ½ 1 µ½ i λΪ 0 µÄ mask£¬Ö»Ð轫 1 µ½ i λΪ 1 µÄ mask È¡·´£¬¼´ \~(1<<(i+1)-1)¡£ +è¦�得到 1 到 i ä½�为 0 çš„ mask,å�ªéœ€å°† 1 到 i ä½�为 1 çš„ mask å�–å��,å�³ \~(1<<(i+1)-1)。 -**3. λ²Ù×÷¾ÙÀý** +**3. ä½�æ“�作举例** -¢Ù »ñÈ¡µÚ i λ +â‘  获å�–第 i ä½� num & 00010000 != 0 @@ -4646,7 +4647,7 @@ num & 00010000 != 0 (num & (1 << i)) != 0; ``` -¢Ú ½«µÚ i λÉèÖÃΪ 1 +â‘¡ 将第 i ä½�设置为 1 num | 00010000 @@ -4654,15 +4655,15 @@ num | 00010000 num | (1 << i); ``` -¢Û ½«µÚ i λÇå³ýΪ 0 +â‘¢ 将第 i ä½�清除为 0 num & 11101111 ```java -num & (\~(1 << i)) +num & (~(1 << i)) ``` -¢Ü ½«×î¸ßλµ½µÚ i λÇå³ýΪ 0 +â‘£ 将最高ä½�到第 i ä½�清除为 0 num & 00001111 @@ -4670,35 +4671,35 @@ num & 00001111 num & ((1 << i) - 1); ``` -¢Ý ½«µÚ 0 λµ½µÚ i λÇå³ýΪ 0 +⑤ 将第 0 ä½�到第 i ä½�清除为 0 num & 11110000 ```java -num & (\~((1 << (i+1)) - 1)); +num & (~((1 << (i+1)) - 1)); ``` -¢Þ ½«µÚ i λÉèÖÃΪ 0 »òÕß 1 +â‘¥ 将第 i ä½�设置为 0 或者 1 -ÏȽ«µÚ i λÇåÁ㣬Ȼºó½« v ×óÒÆ i λ£¬Ö´ÐС°Î»»ò¡±ÔËËã¡£ +先将第 i ä½�清零,然å�Žå°† v 左移 i ä½�,执行“ä½�或â€�è¿�算。 ```java (num & (1 << i)) | (v << i); ``` -**4. Java ÖеÄλ²Ù×÷** +**4. Java 中的ä½�æ“�作** ```html -static int Integer.bitCount() // ͳ¼Æ 1 µÄÊýÁ¿ -static int Integer.highestOneBit() // »ñµÃ×î¸ßλ -static String toBinaryString(int i) // ת»»Î»¶þ½øÖƱíʾµÄ×Ö·û´® +static int Integer.bitCount() // 统计 1 的数é‡� +static int Integer.highestOneBit() // 获得最高ä½� +static String toBinaryString(int i) // 转æ�¢ä½�二进制表示的字符串 ``` -**ͳ¼ÆÁ½¸öÊýµÄ¶þ½øÖƱíʾÓжàÉÙλ²»Í¬** +**统计两个数的二进制表示有多少ä½�ä¸�å�Œ** [Leetcode : 461. Hamming Distance (Easy)](https://leetcode.com/problems/hamming-distance/) -¶ÔÁ½¸öÊý½øÐÐÒì»ò²Ù×÷£¬²»Í¬µÄÄÇһλ½á¹ûΪ 1 £¬Í³¼ÆÓжàÉÙ¸ö 1 ¼´¿É¡£ +对两个数进行异或æ“�作,ä¸�å�Œçš„那一ä½�结果为 1 ,统计有多少个 1 å�³å�¯ã€‚ ```java public int hammingDistance(int x, int y) { @@ -4712,7 +4713,7 @@ public int hammingDistance(int x, int y) { } ``` -¿ÉÒÔʹÓà Integer.bitcount() À´Í³¼Æ 1 ¸öµÄ¸öÊý¡£ +å�¯ä»¥ä½¿ç”¨ Integer.bitcount() æ�¥ç»Ÿè®¡ 1 个的个数。 ```java public int hammingDistance(int x, int y) { @@ -4720,7 +4721,7 @@ public int hammingDistance(int x, int y) { } ``` -**·­×ªÒ»¸öÊýµÄ±ÈÌØÎ»** +**翻转一个数的比特ä½�** [Leetcode : 190. Reverse Bits (Easy)](https://leetcode.com/problems/reverse-bits/description/) @@ -4736,9 +4737,9 @@ public int reverseBits(int n) { } ``` -**²»ÓöîÍâ±äÁ¿½»»»Á½¸öÕûÊý** +**ä¸�用é¢�外å�˜é‡�交æ�¢ä¸¤ä¸ªæ•´æ•°** -[³ÌÐòÔ±´úÂëÃæÊÔÖ¸ÄÏ £ºP317](#) +[程åº�员代ç �é�¢è¯•指å�— :P317](#) ```java a = a ^ b; @@ -4746,13 +4747,13 @@ b = a ^ b; a = a ^ b; ``` -½« c = a ^ b£¬ÄÇô b ^ c = b ^ b ^ a = a£¬a ^ c = a ^ a ^ b = b¡£ +å°† c = a ^ b,那么 b ^ c = b ^ b ^ a = a,a ^ c = a ^ a ^ b = b。 -**ÅжÏÒ»¸öÊýÊDz»ÊÇ 4 µÄ n ´Î·½** +**判断一个数是ä¸�是 4 çš„ n 次方** [Leetcode : 342. Power of Four (Easy)](https://leetcode.com/problems/power-of-four/) -¸ÃÊý¶þ½øÖƱíʾÓÐÇÒÖ»ÓÐÒ»¸öÆæÊýλΪ 1 £¬ÆäÓàµÄ¶¼Îª 0 £¬ÀýÈç 16 £º 10000¡£¿ÉÒÔÿ´Î°Ñ 1 Ïò×óÒÆ¶¯ 2 룬¾ÍÄܹ¹Ôì³öÕâÖÖÊý×Ö£¬È»ºó±È½Ï¹¹Ôì³öÀ´µÄÊýÓëÒªÅжϵÄÊýÊÇ·ñÏàͬ¡£ +该数二进制表示有且å�ªæœ‰ä¸€ä¸ªå¥‡æ•°ä½�为 1 ,其余的都为 0 ,例如 16 : 10000。å�¯ä»¥æ¯�次把 1 å�‘左移动 2 ä½�,就能构造出这ç§�数字,然å�Žæ¯”较构造出æ�¥çš„æ•°ä¸Žè¦�判断的数是å�¦ç›¸å�Œã€‚ ```java public boolean isPowerOfFour(int num) { @@ -4765,7 +4766,7 @@ public boolean isPowerOfFour(int num) { } ``` -Ò²¿ÉÒÔÓà Java µÄ Integer.toString() ·½·¨½«¸ÃÊýת»»Îª 4 ½øÖÆÐÎʽµÄ×Ö·û´®£¬È»ºóÅжÏ×Ö·û´®ÊÇ·ñÒÔ 1 ¿ªÍ·¡£ +也å�¯ä»¥ç”¨ Java çš„ Integer.toString() 方法将该数转æ�¢ä¸º 4 进制形å¼�的字符串,然å�Žåˆ¤æ–­å­—符串是å�¦ä»¥ 1 开头。 ```java public boolean isPowerOfFour(int num) { @@ -4773,11 +4774,11 @@ public boolean isPowerOfFour(int num) { } ``` -**ÅжÏÒ»¸öÊýÊDz»ÊÇ 2 µÄ n ´Î·½** +**判断一个数是ä¸�是 2 çš„ n 次方** [Leetcode : 231. Power of Two (Easy)](https://leetcode.com/problems/power-of-two/description/) -ͬÑù¿ÉÒÔÓà Power of Four µÄ·½·¨£¬µ«ÊÇ 2 µÄ n ´Î·½¸üÌØÊ⣬ËüµÄ¶þ½øÖƱíʾֻÓÐÒ»¸ö 1 ´æÔÚ¡£ +å�Œæ ·å�¯ä»¥ç”¨ Power of Four 的方法,但是 2 çš„ n 次方更特殊,它的二进制表示å�ªæœ‰ä¸€ä¸ª 1 存在。 ```java public boolean isPowerOfTwo(int n) { @@ -4785,7 +4786,7 @@ public boolean isPowerOfTwo(int n) { } ``` -ÀûÓà 1000 & 0111 == 0 ÕâÖÖÐÔÖÊ£¬µÃµ½ÒÔϽⷨ£º +利用 1000 & 0111 == 0 è¿™ç§�性质,得到以下解法: ```java public boolean isPowerOfTwo(int n) { @@ -4793,13 +4794,13 @@ public boolean isPowerOfTwo(int n) { } ``` -**Êý×éÖÐΨһһ¸ö²»Öظ´µÄÔªËØ** +**数组中唯一一个ä¸�é‡�å¤�的元素** [Leetcode : 136. Single Number (Easy)](https://leetcode.com/problems/single-number/description/) -Á½¸öÏàͬµÄÊýÒì»òµÄ½á¹ûΪ 0£¬¶ÔËùÓÐÊý½øÐÐÒì»ò²Ù×÷£¬×îºóµÄ½á¹û¾ÍÊǵ¥¶À³öÏÖµÄÄǸöÊý¡£ +两个相å�Œçš„æ•°å¼‚或的结果为 0,对所有数进行异或æ“�作,最å�Žçš„结果就是å�•独出现的那个数。 -ÀàËÆµÄÓУº[Leetcode : 389. Find the Difference (Easy)](https://leetcode.com/problems/find-the-difference/description/)£¬Á½¸ö×Ö·û´®½öÓÐÒ»¸ö×Ö·û²»Ïàͬ£¬Ê¹ÓÃÒì»ò²Ù×÷¿ÉÒÔÒÔ O(1) µÄ¿Õ¼ä¸´ÔÓ¶ÈÀ´Çó½â£¬¶ø²»ÐèҪʹÓà HashSet¡£ +类似的有:[Leetcode : 389. Find the Difference (Easy)](https://leetcode.com/problems/find-the-difference/description/),两个字符串仅有一个字符ä¸�相å�Œï¼Œä½¿ç”¨å¼‚或æ“�作å�¯ä»¥ä»¥ O(1) 的空间å¤�æ�‚度æ�¥æ±‚解,而ä¸�需è¦�使用 HashSet。 ```java public int singleNumber(int[] nums) { @@ -4809,22 +4810,22 @@ public int singleNumber(int[] nums) { } ``` -**Êý×éÖв»Öظ´µÄÁ½¸öÔªËØ** +**数组中ä¸�é‡�å¤�的两个元素** [Leetcode : 260. Single Number III (Medium)](https://leetcode.com/problems/single-number-iii/description/) -Á½¸ö²»ÏàµÈµÄÔªËØÔÚλ¼¶±íʾÉϱض¨»áÓÐһλ´æÔÚ²»Í¬¡£ +两个ä¸�相等的元素在ä½�级表示上必定会有一ä½�存在ä¸�å�Œã€‚ -½«Êý×éµÄËùÓÐÔªËØÒì»òµÃµ½µÄ½á¹ûΪ²»´æÔÚÖØ¸´µÄÁ½¸öÔªËØÒì»òµÄ½á¹û¡£ +将数组的所有元素异或得到的结果为ä¸�存在é‡�å¤�的两个元素异或的结果。 -diff &= -diff µÃµ½³ö diff ×îÓҲ಻Ϊ 0 µÄ룬Ҳ¾ÍÊDz»´æÔÚÖØ¸´µÄÁ½¸öÔªËØÔÚλ¼¶±íʾÉÏ×îÓҲ಻ͬµÄÄÇһ룬ÀûÓÃÕâһλ¾Í¿ÉÒÔ½«Á½¸öÔªËØÇø·Ö¿ªÀ´¡£ +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) { @@ -4835,11 +4836,11 @@ public int[] singleNumber(int[] nums) { } ``` -**ÅжÏÒ»¸öÊýµÄλ¼¶±íʾÊÇ·ñ²»»á³öÏÖÁ¬ÐøµÄ 0 ºÍ 1** +**判断一个数的ä½�级表示是å�¦ä¸�会出现连续的 0 å’Œ 1** [Leetcode : 693. Binary Number with Alternating Bits (Easy)](https://leetcode.com/problems/binary-number-with-alternating-bits/description/) -¶ÔÓÚ 10101 ÕâÖÖλ¼¶±íʾµÄÊý£¬°ÑËüÏòÓÒÒÆ¶¯ 1 λµÃµ½ 1010 £¬ÕâÁ½¸öÊýÿ¸öλ¶¼²»Í¬£¬Òò´ËÒì»òµÃµ½µÄ½á¹ûΪ 11111¡£ +对于 10101 è¿™ç§�ä½�级表示的数,把它å�‘å�³ç§»åЍ 1 ä½�得到 1010 ,这两个数æ¯�个ä½�都ä¸�å�Œï¼Œå› æ­¤å¼‚或得到的结果为 11111。 ```java public boolean hasAlternatingBits(int n) { @@ -4848,13 +4849,13 @@ public boolean hasAlternatingBits(int n) { } ``` -**ÇóÒ»¸öÊýµÄ²¹Âë** +**求一个数的补ç �** [Leetcode : 476. Number Complement (Easy)](https://leetcode.com/problems/number-complement/description/) -²»¿¼ÂǶþ½øÖƱíʾÖеÄÊ× 0 ²¿·Ö +ä¸�考虑二进制表示中的首 0 部分 -¶ÔÓÚ 00000101£¬ÒªÇó²¹Âë¿ÉÒÔ½«ËüÓë 00000111 ½øÐÐÒì»ò²Ù×÷¡£ÄÇôÎÊÌâ¾Íת»»ÎªÇóÑÚÂë 00000111¡£ +对于 00000101,è¦�求补ç �å�¯ä»¥å°†å®ƒä¸Ž 00000111 进行异或æ“�作。那么问题就转æ�¢ä¸ºæ±‚掩ç � 00000111。 ```java public int findComplement(int num) { @@ -4866,7 +4867,7 @@ public int findComplement(int num) { } ``` -¿ÉÒÔÀûÓà Java µÄ Integer.highestOneBit() ·½·¨À´»ñµÃº¬ÓÐÊ× 1 µÄÊý¡£ +å�¯ä»¥åˆ©ç”¨ Java çš„ Integer.highestOneBit() 方法æ�¥èŽ·å¾—å�«æœ‰é¦– 1 的数。 ```java public int findComplement(int num) { @@ -4877,7 +4878,7 @@ public int findComplement(int num) { } ``` -¶ÔÓÚ 10000000 ÕâÑùµÄÊýÒªÀ©Õ¹³É 11111111£¬¿ÉÒÔÀûÓÃÒÔÏ·½·¨£º +对于 10000000 这样的数è¦�扩展æˆ� 11111111,å�¯ä»¥åˆ©ç”¨ä»¥ä¸‹æ–¹æ³•: ```html mask |= mask >> 1 11000000 @@ -4897,11 +4898,11 @@ public int findComplement(int num) { } ``` -**ʵÏÖÕûÊýµÄ¼Ó·¨** +**实现整数的加法** [Leetcode : 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£¬µÝ¹éÖÕÖ¹¡£ +a ^ b 表示没有考虑进ä½�的情况下两数的和,(a & b) << 1 就是进ä½�。递归会终止的原因是 (a & b) << 1 最å�³è¾¹ä¼šå¤šä¸€ä¸ª 0,那么继续递归,进ä½�最å�³è¾¹çš„ 0 会慢慢增多,最å�Žè¿›ä½�会å�˜ä¸º 0,递归终止。 ```java public int getSum(int a, int b) { @@ -4909,13 +4910,13 @@ public int getSum(int a, int b) { } ``` -**×Ö·û´®Êý×é×î´ó³Ë»ý** +**字符串数组最大乘积** [Leetcode : 318. Maximum Product of Word Lengths (Medium)](https://leetcode.com/problems/maximum-product-of-word-lengths/description/) -ÌâÄ¿ÃèÊö£º×Ö·û´®Êý×éµÄ×Ö·û´®Ö»º¬ÓÐСд×Ö·û¡£Çó½â×Ö·û´®Êý×éÖÐÁ½¸ö×Ö·û´®³¤¶ÈµÄ×î´ó³Ë»ý£¬ÒªÇóÕâÁ½¸ö×Ö·û´®²»Äܺ¬ÓÐÏàͬ×Ö·û¡£ +题目æ��述:字符串数组的字符串å�ªå�«æœ‰å°�写字符。求解字符串数组中两个字符串长度的最大乘积,è¦�求这两个字符串ä¸�能å�«æœ‰ç›¸å�Œå­—符。 -½âÌâ˼·£º±¾ÌâÖ÷ÒªÎÊÌâÊÇÅжÏÁ½¸ö×Ö·û´®ÊÇ·ñº¬Ïàͬ×Ö·û£¬ÓÉÓÚ×Ö·û´®Ö»º¬ÓÐСд×Ö·û£¬×ܹ² 26 룬Òò´Ë¿ÉÒÔÓÃÒ»¸ö 32 λµÄÕûÊýÀ´´æ´¢Ã¿¸ö×Ö·ûÊÇ·ñ³öÏÖ¹ý¡£ +解题æ€�路:本题主è¦�问题是判断两个字符串是å�¦å�«ç›¸å�Œå­—符,由于字符串å�ªå�«æœ‰å°�写字符,总共 26 ä½�,因此å�¯ä»¥ç”¨ä¸€ä¸ª 32 ä½�的整数æ�¥å­˜å‚¨æ¯�个字符是å�¦å‡ºçŽ°è¿‡ã€‚ ```java public int maxProduct(String[] words) { @@ -4939,12 +4940,12 @@ public int maxProduct(String[] words) { } ``` -# ²Î¿¼×ÊÁÏ +# å�‚考资料 - [Leetcode](https://leetcode.com/problemset/algorithms/?status=Todo) -- Weiss M A, ·ëË´çô. Êý¾Ý½á¹¹ÓëËã·¨·ÖÎö¡ª¡ªC ÓïÑÔÃèÊö[J]. 2004. +- Weiss M A, 冯舜玺. æ•°æ�®ç»“构与算法分æž�——C 语言æ��è¿°[J]. 2004. - Sedgewick R. Algorithms[M]. Pearson Education India, 1988. -- ºÎº£ÌÎ, Èí¼þ¹¤³Ìʦ. ½£Ö¸ Offer: ÃûÆóÃæÊÔ¹Ù¾«½²µäÐͱà³ÌÌâ[M]. µç×Ó¹¤Òµ³ö°æÉç, 2014. -- ¡¶±à³ÌÖ®ÃÀ¡·Ð¡×é. ±à³ÌÖ®ÃÀ[M]. µç×Ó¹¤Òµ³ö°æÉç, 2008. -- ×ó³ÌÔÆ. ³ÌÐòÔ±´úÂëÃæÊÔÖ¸ÄÏ[M]. µç×Ó¹¤Òµ³ö°æÉç, 2015. +- 何海涛, 软件工程师. 剑指 Offer: å��ä¼�é�¢è¯•官精讲典型编程题[M]. 电å­�工业出版社, 2014. +- 《编程之美》å°�组. 编程之美[M]. 电å­�工业出版社, 2008. +- 左程云. 程åº�员代ç �é�¢è¯•指å�—[M]. 电å­�工业出版社, 2015. diff --git a/notes/Linux.md b/notes/Linux.md index 60773fda..2981c0cd 100644 --- a/notes/Linux.md +++ b/notes/Linux.md @@ -1,41 +1,41 @@ -* [³£ÓòÙ×÷ÒÔ¼°¸ÅÄî](#³£ÓòÙ×÷ÒÔ¼°¸ÅÄî) - * [ÇóÖú](#ÇóÖú) - * [¹Ø»ú](#¹Ø»ú) - * [²é¿´½ø³Ì](#²é¿´½ø³Ì) - * [²é¿´¶Ë¿Ú](#²é¿´¶Ë¿Ú) +* [常用æ“�作以å�Šæ¦‚念](#常用æ“�作以å�Šæ¦‚念) + * [求助](#求助) + * [关机](#关机) + * [查看进程](#查看进程) + * [查看端å�£](#查看端å�£) * [PATH](#path) - * [ÔËÐеȼ¶](#ÔËÐеȼ¶) + * [è¿�行等级](#è¿�行等级) * [sudo](#sudo) * [GNU](#gnu) - * [°ü¹ÜÀí¹¤¾ß](#°ü¹ÜÀí¹¤¾ß) - * [³£¼û·¢Ðа汾](#³£¼û·¢Ðа汾) -* [·ÖÇø](#·ÖÇø) - * [´ÅÅ̵ÄÎļþÃû](#´ÅÅ̵ÄÎļþÃû) - * [·ÖÇø±í](#·ÖÇø±í) + * [包管ç�†å·¥å…·](#包管ç�†å·¥å…·) + * [常è§�å�‘行版本](#常è§�å�‘行版本) +* [分区](#分区) + * [ç£�盘的文件å��](#ç£�盘的文件å��) + * [分区表](#分区表) * [1. MBR](#1-mbr) * [2. GPT](#2-gpt) - * [¿ª»ú¼ì²â³ÌÐò](#¿ª»ú¼ì²â³ÌÐò) + * [开机检测程åº�](#开机检测程åº�) * [1. BIOS](#1-bios) * [2. UEFI](#2-uefi) - * [¹ÒÔØ](#¹ÒÔØ) -* [ÎļþȨÏÞÓëĿ¼ÅäÖÃ](#ÎļþȨÏÞÓëĿ¼ÅäÖÃ) - * [ÎļþȨÏÞ¸ÅÄî](#ÎļþȨÏÞ¸ÅÄî) - * [ÎļþÊôÐÔÒÔ¼°È¨ÏÞµÄÐÞ¸Ä](#ÎļþÊôÐÔÒÔ¼°È¨ÏÞµÄÐÞ¸Ä) - * [1. ÐÞ¸ÄÎļþËùÊôȺ×é](#1-ÐÞ¸ÄÎļþËùÊôȺ×é) - * [2. ÐÞ¸ÄÎļþÓµÓÐÕß](#2-ÐÞ¸ÄÎļþÓµÓÐÕß) - * [3. ÐÞ¸ÄȨÏÞ](#3-ÐÞ¸ÄȨÏÞ) - * [Ŀ¼µÄȨÏÞ](#Ŀ¼µÄȨÏÞ) - * [ÎļþĬÈÏȨÏÞ](#ÎļþĬÈÏȨÏÞ) - * [Ŀ¼ÅäÖÃ](#Ŀ¼ÅäÖÃ) -* [ÎļþÓëĿ¼](#ÎļþÓëĿ¼) - * [Îļþʱ¼ä](#Îļþʱ¼ä) - * [ÎļþÓëĿ¼µÄ»ù±¾²Ù×÷](#ÎļþÓëĿ¼µÄ»ù±¾²Ù×÷) + * [挂载](#挂载) +* [文件æ�ƒé™�与目录é…�ç½®](#文件æ�ƒé™�与目录é…�ç½®) + * [文件æ�ƒé™�概念](#文件æ�ƒé™�概念) + * [文件属性以å�Šæ�ƒé™�的修改](#文件属性以å�Šæ�ƒé™�的修改) + * [1. 修改文件所属群组](#1-修改文件所属群组) + * [2. 修改文件拥有者](#2-修改文件拥有者) + * [3. 修改æ�ƒé™�](#3-修改æ�ƒé™�) + * [目录的æ�ƒé™�](#目录的æ�ƒé™�) + * [文件默认æ�ƒé™�](#文件默认æ�ƒé™�) + * [目录é…�ç½®](#目录é…�ç½®) +* [文件与目录](#文件与目录) + * [文件时间](#文件时间) + * [文件与目录的基本æ“�作](#文件与目录的基本æ“�作) * [1. ls](#1-ls) * [2. cp](#2-cp) * [3. rm](#3-rm) * [4. mv](#4-mv) - * [»ñÈ¡ÎļþÄÚÈÝ](#»ñÈ¡ÎļþÄÚÈÝ) + * [获å�–文件内容](#获å�–文件内容) * [1. cat](#1-cat) * [2. tac](#2-tac) * [3. more](#3-more) @@ -44,97 +44,98 @@ * [6. tail](#6-tail) * [7. od](#7-od) * [8. touch](#8-touch) - * [Ö¸ÁîÓëÎļþËÑË÷](#Ö¸ÁîÓëÎļþËÑË÷) + * [指令与文件æ�œç´¢](#指令与文件æ�œç´¢) * [1. which](#1-which) * [2. whereis](#2-whereis) * [3. locate](#3-locate) * [4. find](#4-find) - * [4.1 Óëʱ¼äÓйصÄÑ¡Ïî](#41-Óëʱ¼äÓйصÄÑ¡Ïî) - * [4.2 ÓëÎļþÓµÓÐÕߺÍËùÊôȺ×éÓйصÄÑ¡Ïî](#42-ÓëÎļþÓµÓÐÕߺÍËùÊôȺ×éÓйصÄÑ¡Ïî) - * [4.3 ÓëÎļþȨÏÞºÍÃû³ÆÓйصÄÑ¡Ïî](#43-ÓëÎļþȨÏÞºÍÃû³ÆÓйصÄÑ¡Ïî) -* [´ÅÅÌÓëÎļþϵͳ](#´ÅÅÌÓëÎļþϵͳ) - * [ÎļþϵͳµÄ×é³É](#ÎļþϵͳµÄ×é³É) + * [4.1 与时间有关的选项](#41-与时间有关的选项) + * [4.2 与文件拥有者和所属群组有关的选项](#42-与文件拥有者和所属群组有关的选项) + * [4.3 与文件æ�ƒé™�å’Œå��称有关的选项](#43-与文件æ�ƒé™�å’Œå��称有关的选项) +* [ç£�盘与文件系统](#ç£�盘与文件系统) + * [文件系统的组æˆ�](#文件系统的组æˆ�) * [inode](#inode) - * [Ŀ¼µÄ inode Óë block](#Ŀ¼µÄ-inode-Óë-block) - * [ʵÌåÁ´½ÓÓë·ûºÅÁ´½Ó](#ʵÌåÁ´½ÓÓë·ûºÅÁ´½Ó) - * [1. ʵÌåÁ´½Ó](#1-ʵÌåÁ´½Ó) - * [2. ·ûºÅÁ´½Ó](#2-·ûºÅÁ´½Ó) -* [ѹËõÓë´ò°ü](#ѹËõÓë´ò°ü) - * [ѹËõ](#ѹËõ) + * [目录的 inode 与 block](#目录的-inode-与-block) + * [实体链接与符å�·é“¾æŽ¥](#实体链接与符å�·é“¾æŽ¥) + * [1. 实体链接](#1-实体链接) + * [2. 符å�·é“¾æŽ¥](#2-符å�·é“¾æŽ¥) +* [压缩与打包](#压缩与打包) + * [压缩](#压缩) * [1. gzip](#1-gzip) * [2. bzip2](#2-bzip2) * [3. xz](#3-xz) - * [´ò°ü](#´ò°ü) + * [打包](#打包) * [Bash](#bash) - * [Bash ÌØÐÔ](#bash-ÌØÐÔ) - * [±äÁ¿²Ù×÷](#±äÁ¿²Ù×÷) - * [Ö¸ÁîËÑË÷˳Ðò](#Ö¸ÁîËÑË÷˳Ðò) - * [Êý¾ÝÁ÷ÖØ¶¨Ïò](#Êý¾ÝÁ÷ÖØ¶¨Ïò) - * [¹ÜÏßÖ¸Áî](#¹ÜÏßÖ¸Áî) - * [1. ÌáȡָÁcut](#1-ÌáȡָÁîcut) - * [2. ÅÅÐòÃüÁsort¡¢uniq](#2-ÅÅÐòÃüÁîsortuniq) - * [3. Ë«ÏòÊä³öÖØ¶¨Ïò£ºtee](#3-Ë«ÏòÊä³öÖØ¶¨Ïòtee) - * [4. ×Ö·ûת»»Ö¸Átr¡¢col¡¢expand¡¢join¡¢paste](#4-×Ö·ûת»»Ö¸Áîtrcolexpandjoinpaste) - * [5. ·ÖÇøÖ¸Ásplit](#5-·ÖÇøÖ¸Áîsplit) -* [Õý¹æ±íʾ·¨ÓëÎļþ¸ñʽ»¯´¦Àí](#Õý¹æ±íʾ·¨ÓëÎļþ¸ñʽ»¯´¦Àí) + * [Bash 特性](#bash-特性) + * [å�˜é‡�æ“�作](#å�˜é‡�æ“�作) + * [指令æ�œç´¢é¡ºåº�](#指令æ�œç´¢é¡ºåº�) + * [æ•°æ�®æµ�é‡�定å�‘](#æ•°æ�®æµ�é‡�定å�‘) + * [管线指令](#管线指令) + * [1. æ��å�–指令:cut](#1-æ��å�–指令cut) + * [2. 排åº�命令:sortã€�uniq](#2-排åº�命令sortuniq) + * [3. å�Œå�‘输出é‡�定å�‘:tee](#3-å�Œå�‘输出é‡�定å�‘tee) + * [4. 字符转æ�¢æŒ‡ä»¤ï¼štrã€�colã€�expandã€�joinã€�paste](#4-字符转æ�¢æŒ‡ä»¤trcolexpandjoinpaste) + * [5. 分区指令:split](#5-分区指令split) +* [正规表示法与文件格å¼�化处ç�†](#正规表示法与文件格å¼�化处ç�†) * [grep](#grep) * [printf](#printf) * [awk](#awk) -* [vim Èý¸öģʽ](#vim-Èý¸öģʽ) -* [²Î¿¼×ÊÁÏ](#²Î¿¼×ÊÁÏ) +* [vim 三个模å¼�](#vim-三个模å¼�) +* [å�‚考资料](#å�‚考资料) -# ³£ÓòÙ×÷ÒÔ¼°¸ÅÄî -## ÇóÖú +# 常用æ“�作以å�Šæ¦‚念 + +## 求助 **1. --help** -Ö¸ÁîµÄ»ù±¾Ó÷¨ÓëÑ¡Ïî½éÉÜ¡£ +指令的基本用法与选项介ç»�。 **2. man** -man ÊÇ manual µÄËõд£¬½«Ö¸ÁîµÄ¾ßÌåÐÅÏ¢ÏÔʾ³öÀ´¡£ +man 是 manual 的缩写,将指令的具体信æ�¯æ˜¾ç¤ºå‡ºæ�¥ã€‚ -µ±Ö´ÐÐ man date ʱ£¬ÓÐ DATE(1) ³öÏÖ£¬ÆäÖеÄÊý×Ö´ú±íÖ¸ÁîµÄÀàÐÍ£¬³£ÓõÄÊý×Ö¼°ÆäÀàÐÍÈçÏ£º +当执行 man date 时,有 DATE(1) 出现,其中的数字代表指令的类型,常用的数字å�Šå…¶ç±»åž‹å¦‚下: -| ´úºÅ | ÀàÐÍ | +| 代å�· | 类型 | | -- | -- | -| 1 | Óû§ÔÚ shell »·¾³ÖпÉÒÔ²Ù×÷µÄÖ¸Áî»òÕß¿ÉÖ´ÐÐÎļþ | -| 5 | ÅäÖÃÎļþ | -| 8 | ϵͳ¹ÜÀíÔ±¿ÉÒÔʹÓõĹÜÀíÖ¸Áî | +| 1 | 用户在 shell 环境中å�¯ä»¥æ“�作的指令或者å�¯æ‰§è¡Œæ–‡ä»¶ | +| 5 | é…�置文件 | +| 8 | 系统管ç�†å‘˜å�¯ä»¥ä½¿ç”¨çš„管ç�†æŒ‡ä»¤ | **3. info** -info Óë man ÀàËÆ£¬µ«ÊÇ info ½«Îĵµ·Ö³ÉÒ»¸ö¸öÒ³Ãæ£¬Ã¿¸öÒ³Ãæ¿ÉÒÔ½øÐÐÌø×ª¡£ +info 与 man 类似,但是 info 将文档分æˆ�一个个页é�¢ï¼Œæ¯�个页é�¢å�¯ä»¥è¿›è¡Œè·³è½¬ã€‚ -## ¹Ø»ú +## 关机 **1. sync** -ΪÁ˼ӿì¶Ô´ÅÅÌÉÏÎļþµÄ¶ÁдËÙ¶È£¬Î»ÓÚÄÚ´æÖеÄÎļþÊý¾Ý²»»áÁ¢¼´Í¬²½µ½´ÅÅÌÉÏ£¬Òò´Ë¹Ø»ú֮ǰÐèÒªÏȽøÐÐ sync ͬ²½²Ù×÷¡£ +为了加快对ç£�盘上文件的读写速度,ä½�于内存中的文件数æ�®ä¸�会立å�³å�Œæ­¥åˆ°ç£�盘上,因此关机之å‰�需è¦�先进行 sync å�Œæ­¥æ“�作。 **2. shutdown** ```html -# /sbin/shutdown [-krhc] [ʱ¼ä] [¾¯¸æÑ¶Ï¢] --k £º ²»»á¹Ø»ú£¬Ö»ÊÇ·¢Ë;¯¸æÑ¶Ï¢£¬Í¨ÖªËùÓÐÔÚÏßµÄÓû§ --r £º ½«ÏµÍ³µÄ·þÎñÍ£µôºó¾ÍÖØÐÂÆô¶¯ --h £º ½«ÏµÍ³µÄ·þÎñÍ£µôºó¾ÍÁ¢¼´¹Ø»ú --c £º È¡ÏûÒѾ­ÔÚ½øÐÐµÄ shutdown Ö¸ÁîÄÚÈÝ +# /sbin/shutdown [-krhc] [æ—¶é—´] [警告讯æ�¯] +-k : ä¸�会关机,å�ªæ˜¯å�‘é€�警告讯æ�¯ï¼Œé€šçŸ¥æ‰€æœ‰åœ¨çº¿çš„用户 +-r : 将系统的æœ�务å�œæŽ‰å�Žå°±é‡�æ–°å�¯åЍ +-h : 将系统的æœ�务å�œæŽ‰å�Žå°±ç«‹å�³å…³æœº +-c : å�–消已ç»�在进行的 shutdown 指令内容 ``` -**3. ÆäËü¹Ø»úÖ¸Áî** +**3. 其它关机指令** -reboot¡¢halt¡¢poweroff¡£ +rebootã€�haltã€�poweroff。 -## ²é¿´½ø³Ì +## 查看进程 ```html ps aux | grep threadx ``` -## ²é¿´¶Ë¿Ú +## 查看端å�£ ```html @@ -143,329 +144,329 @@ netstat -anp | grep 80 ## PATH -¿ÉÒÔÔÚ»·¾³±äÁ¿ PATH ÖÐÉùÃ÷¿ÉÖ´ÐÐÎļþµÄ·¾¶£¬Â·¾¶Ö®¼äÓà : ·Ö¸ô¡£ +å�¯ä»¥åœ¨çŽ¯å¢ƒå�˜é‡� PATH 中声明å�¯æ‰§è¡Œæ–‡ä»¶çš„路径,路径之间用 : 分隔。 ```html /usr/local/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/home/dmtsai/.local/bin:/home/dmtsai/bin ``` -## ÔËÐеȼ¶ +## è¿�行等级 -- 0£º¹Ø»úģʽ -- 1£ºµ¥Óû§Ä£Ê½£¨¿ÉÓÃÓÚÆÆ½ârootÃÜÂ룩 -- 2£ºÎÞÍøÂçÖ§³ÖµÄ¶àÓû§Ä£Ê½ -- 3£ºÓÐÍøÂçÖ§³ÖµÄ¶àÓû§Ä£Ê½£¨Îı¾Ä£Ê½£¬¹¤×÷ÖÐ×î³£ÓõÄģʽ£© -- 4£º±£Áô£¬Î´Ê¹Óà -- 5£ºÓÐÍøÂçÖ§³ÖµÄ X-windows ¶àÓû§Ä£Ê½£¨×ÀÃæ£© -- 6£ºÖØÐÂÒýµ¼ÏµÍ³£¬¼´ÖØÆô +- 0:关机模å¼� +- 1:å�•用户模å¼�(å�¯ç”¨äºŽç ´è§£root密ç �) +- 2:无网络支æŒ�的多用户模å¼� +- 3:有网络支æŒ�的多用户模å¼�(文本模å¼�,工作中最常用的模å¼�) +- 4:ä¿�留,未使用 +- 5:有网络支æŒ�çš„ X-windows 多用户模å¼�(桌é�¢ï¼‰ +- 6:é‡�新引导系统,å�³é‡�å�¯ ## sudo -ʹÓà sudo ÔÊÐíÒ»°ãÓû§Ê¹Óà root ¿ÉÖ´ÐеÄÃüÁֻÓÐÔÚ /etc/sudoers ÅäÖÃÎļþÖÐÌí¼ÓµÄÓû§²ÅÄÜʹÓøÃÖ¸Áî¡£ +使用 sudo å…�许一般用户使用 root å�¯æ‰§è¡Œçš„命令,å�ªæœ‰åœ¨ /etc/sudoers é…�置文件中添加的用户æ‰�能使用该指令。 ## GNU -GNU ¼Æ»®£¬ÓÖÒëΪ¸ïÅ«¼Æ»®£¬ËüµÄÄ¿±êÊÇ´´½¨Ò»Ì×ÍêÈ«×ÔÓɵIJÙ×÷ϵͳ£¬³ÆÎª GNU£¬ÆäÄÚÈÝÈí¼þÍêÈ«ÒÔ GPL ·½Ê½·¢²¼¡£ÆäÖÐ GPL È«³ÆÎª GNU ͨÓù«¹²Ðí¿ÉЭÒ飬°üº¬ÁËÒÔÏÂÄÚÈÝ£º +GNU 计划,å�ˆè¯‘为é�©å¥´è®¡åˆ’,它的目标是创建一套完全自由的æ“�作系统,称为 GNU,其内容软件完全以 GPL æ–¹å¼�å�‘布。其中 GPL 全称为 GNU 通用公共许å�¯å��议,包å�«äº†ä»¥ä¸‹å†…容: -- ÒÔÈκÎÄ¿µÄÔËÐд˳ÌÐòµÄ×ÔÓÉ£» -- ÔÙ¸´ÖƵÄ×ÔÓÉ£» -- ¸Ä½ø´Ë³ÌÐò£¬²¢¹«¿ª·¢²¼¸Ä½øµÄ×ÔÓÉ¡£ +- 以任何目的è¿�行此程åº�的自由; +- å†�å¤�制的自由; +- 改进此程åº�,并公开å�‘布改进的自由。 -## °ü¹ÜÀí¹¤¾ß +## 包管ç�†å·¥å…· -RPM ºÍ DPKG Ϊ×î³£¼ûµÄÁ½ÀàÈí¼þ°ü¹ÜÀí¹¤¾ß¡£RPM È«³ÆÎª Redhat Package Manager£¬×îÔçÓÉ Red Hat ¹«Ë¾Öƶ¨ÊµÊ©£¬Ëæºó±» GNU ¿ªÔ´²Ù×÷ϵͳ½ÓÊܲ¢³ÉΪºÜ¶à Linux ϵͳ (RHEL) µÄ¼È¶¨Èí¼þ±ê×¼¡£Óë RPM ½øÐоºÕùµÄÊÇ»ùÓÚ Debian ²Ù×÷ϵͳ (UBUNTU) µÄ DEB Èí¼þ°ü¹ÜÀí¹¤¾ß£­ DPKG£¬È«³ÆÎª Debian Package£¬¹¦ÄÜ·½ÃæÓë RPM ÏàËÆ¡£ +RPM å’Œ DPKG 为最常è§�的两类软件包管ç�†å·¥å…·ã€‚RPM 全称为 Redhat Package Manager,最早由 Red Hat å…¬å�¸åˆ¶å®šå®žæ–½ï¼Œéš�å�Žè¢« GNU å¼€æº�æ“�作系统接å�—å¹¶æˆ�为很多 Linux 系统 (RHEL) 的既定软件标准。与 RPM 进行竞争的是基于 Debian æ“�作系统 (UBUNTU) çš„ DEB 软件包管ç�†å·¥å…·ï¼� DPKG,全称为 Debian Package,功能方é�¢ä¸Ž RPM 相似。 -YUM »ùÓÚ RPM °ü¹ÜÀí¹¤¾ß£¬¾ßÓÐÒÀÀµ¹ÜÀí¹¦ÄÜ£¬²¢¾ßÓÐÈí¼þÉý¼¶µÄ¹¦ÄÜ¡£ +YUM 基于 RPM 包管ç�†å·¥å…·ï¼Œå…·æœ‰ä¾�赖管ç�†åŠŸèƒ½ï¼Œå¹¶å…·æœ‰è½¯ä»¶å�‡çº§çš„功能。 -## ³£¼û·¢Ðа汾 +## 常è§�å�‘行版本 -Linux ·¢ÐаæÊÇ Linux Äں˼°¸÷ÖÖÓ¦ÓÃÈí¼þµÄ¼¯³É°æ±¾¡£ +Linux å�‘行版是 Linux 内核å�Šå�„ç§�应用软件的集æˆ�版本。 -| »ùÓڵİü¹ÜÀí¹¤¾ß | ÉÌÒµ·¢Ðаæ | ÉçÇø·¢Ðаæ | +| 基于的包管ç�†å·¥å…· | 商业å�‘行版 | 社区å�‘行版 | | --- | --- | --- | | DPKG | Ubuntu | Debian | | RPM | Red Hat | Fedora / CentOS | -# ·ÖÇø +# 分区 -## ´ÅÅ̵ÄÎļþÃû +## ç£�盘的文件å�� -Linux ÖÐÿ¸öÓ²¼þ¶¼±»µ±×öÒ»¸öÎļþ¡£ +Linux 中æ¯�个硬件都被当å�šä¸€ä¸ªæ–‡ä»¶ã€‚ -³£¼û´ÅÅ̵ÄÎļþÃû£º +常è§�ç£�盘的文件å��: -- SCSI/SATA/USB ´ÅÅÌ£º/dev/sd[a-p] -- IDE ´ÅÅÌ£º/dev/hd[a-d] +- SCSI/SATA/USB ç£�盘:/dev/sd[a-p] +- IDE ç£�盘:/dev/hd[a-d] -ÆäÖÐÎļþÃûºóÃæµÄÐòºÅµÄÈ·¶¨Óë´ÅÅ̲åÈëµÄ˳ÐòÓйأ¬¶øÓë´ÅÅÌËù²åÈëµÄ²å²ÛλÖÃÎ޹ء£ +其中文件å��å�Žé�¢çš„åº�å�·çš„确定与ç£�盘æ�’入的顺åº�有关,而与ç£�盘所æ�’入的æ�’æ§½ä½�置无关。 -## ·ÖÇø±í +## 分区表 -´ÅÅÌ·ÖÇø±íÖ÷ÒªÓÐÁ½ÖÖ¸ñʽ£¬Ò»ÖÖÊÇÏÞÖÆ½Ï¶àµÄ MBR ·ÖÇø±í£¬Ò»ÖÖÊǽÏÐÂÇÒÏÞÖÆ½ÏÉÙµÄ GPT ·ÖÇø±í¡£ +ç£�盘分区表主è¦�有两ç§�æ ¼å¼�,一ç§�是é™�制较多的 MBR 分区表,一ç§�是较新且é™�制较少的 GPT 分区表。 ### 1. MBR -MBR ÖУ¬µÚÒ»¸öÉÈÇø×îÖØÒª£¬ÀïÃæÓУºÖ÷Òª¿ª»ú¼Ç¼£¨Master boot record, MBR£©¼°·ÖÇø±í£¨partition table£©£¬ÆäÖÐ MBR Õ¼ 446 bytes£¬partition table Õ¼ 64 bytes¡£ +MBR 中,第一个扇区最é‡�è¦�,里é�¢æœ‰ï¼šä¸»è¦�开机记录(Master boot record, MBR)å�Šåˆ†åŒºè¡¨ï¼ˆpartition table),其中 MBR å�  446 bytes,partition table å�  64 bytes。 -·ÖÇø±íÖ»ÓÐ 64 bytes£¬×î¶àÖ»ÄÜ´æ´¢ 4 ¸ö·ÖÇø£¬Õâ 4 ¸ö·ÖÇøÎªÖ÷·ÖÇø£¨Primary£©ºÍÀ©Õ¹·ÖÇø£¨Extended£©¡£ÆäÖÐÀ©Õ¹·ÖÇøÖ»ÓÐÒ»¸ö£¬Ëü½«ÆäËü¿Õ¼äÓÃÀ´¼Ç¼·ÖÇø±í£¬¿ÉÒԼǼ¸ü¶àµÄ·ÖÇø£¬Òò´Ëͨ¹ýÀ©Õ¹·ÖÇø¿ÉÒÔ·Ö³ö¸ü¶àÇø·Ö£¬ÕâЩ·ÖÇø³ÆÎªÂß¼­·ÖÇø¡£ +分区表å�ªæœ‰ 64 bytes,最多å�ªèƒ½å­˜å‚¨ 4 个分区,这 4 个分区为主分区(Primary)和扩展分区(Extended)。其中扩展分区å�ªæœ‰ä¸€ä¸ªï¼Œå®ƒå°†å…¶å®ƒç©ºé—´ç”¨æ�¥è®°å½•分区表,å�¯ä»¥è®°å½•更多的分区,因此通过扩展分区å�¯ä»¥åˆ†å‡ºæ›´å¤šåŒºåˆ†ï¼Œè¿™äº›åˆ†åŒºç§°ä¸ºé€»è¾‘分区。 -Linux Ò²°Ñ·ÖÇøµ±³ÉÎļþ£¬·ÖÇøÎļþµÄÃüÃû·½Ê½Îª£º´ÅÅÌÎļþÃû+±àºÅ£¬ÀýÈç /dev/sda1¡£×¢Ò⣬Âß¼­·ÖÇøµÄ±àºÅ´Ó 5 ¿ªÊ¼¡£ +Linux 也把分区当æˆ�文件,分区文件的命å��æ–¹å¼�为:ç£�盘文件å��+ç¼–å�·ï¼Œä¾‹å¦‚ /dev/sda1。注æ„�,逻辑分区的编å�·ä»Ž 5 开始。 ### 2. GPT -²»Í¬µÄ´ÅÅÌÓв»Í¬µÄÉÈÇø´óС£¬ÀýÈç 512 bytes ºÍ×îдÅÅÌµÄ 4k¡£GPT ΪÁ˼æÈÝËùÓдÅÅÌ£¬ÔÚ¶¨ÒåÉÈÇøÉÏʹÓÃÂß¼­Çø¿éµØÖ·£¨Logical Block Address, LBA£©¡£ +ä¸�å�Œçš„ç£�盘有ä¸�å�Œçš„æ‰‡åŒºå¤§å°�,例如 512 bytes 和最新ç£�盘的 4k。GPT 为了兼容所有ç£�盘,在定义扇区上使用逻辑区å�—地å�€ï¼ˆLogical Block Address, LBA)。 -GPT µÚ 1 ¸öÇø¿é¼Ç¼ÁË MBR£¬½ô½Ó×ÅÊÇ 33 ¸öÇø¿é¼Ç¼·ÖÇøÐÅÏ¢£¬²¢°Ñ×îºóµÄ 33 ¸öÇø¿éÓÃÓÚ¶Ô·ÖÇøÐÅÏ¢½øÐб¸·Ý¡£ +GPT 第 1 个区å�—记录了 MBR,紧接ç�€æ˜¯ 33 个区å�—记录分区信æ�¯ï¼Œå¹¶æŠŠæœ€å�Žçš„ 33 个区å�—用于对分区信æ�¯è¿›è¡Œå¤‡ä»½ã€‚ -GPT ûÓÐÀ©Õ¹·ÖÇø¸ÅÄ¶¼ÊÇÖ÷·ÖÇø£¬×î¶à¿ÉÒÔ·Ö 128 ¸ö·ÖÇø¡£ +GPT 没有扩展分区概念,都是主分区,最多å�¯ä»¥åˆ† 128 个分区。 -![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/a5c25452-6fa5-49e7-9322-823077442775.jpg) +![](https://github.com/CyC2018/InterviewNotes/blob/master/pics//a5c25452-6fa5-49e7-9322-823077442775.jpg) -## ¿ª»ú¼ì²â³ÌÐò +## 开机检测程åº� ### 1. BIOS -BIOS ÊÇ¿ª»úµÄʱºò¼ÆËã»úÖ´ÐеĵÚÒ»¸ö³ÌÐò£¬Õâ¸ö³ÌÐòÖªµÀ¿ÉÒÔ¿ª»úµÄ´ÅÅÌ£¬²¢¶ÁÈ¡´ÅÅ̵ÚÒ»¸öÉÈÇøµÄ MBR£¬ÓÉ MBR Ö´ÐÐÆäÖеĿª»ú¹ÜÀí³ÌÐò£¬Õâ¸ö¿ª»ú¹ÜÀí³ÌÐòµÄ»á¼ÓÔØ²Ù×÷ϵͳµÄºËÐÄÎļþ¡£ +BIOS 是开机的时候计算机执行的第一个程åº�,这个程åº�知é�“å�¯ä»¥å¼€æœºçš„ç£�盘,并读å�–ç£�盘第一个扇区的 MBR,由 MBR 执行其中的开机管ç�†ç¨‹åº�,这个开机管ç�†ç¨‹åº�的会加载æ“�作系统的核心文件。 -MBR ÖеĿª»ú¹ÜÀí³ÌÐòÌṩÒÔϹ¦ÄÜ£ºÑ¡µ¥¡¢ÔØÈëºËÐÄÎļþÒÔ¼°×ª½»ÆäËü¿ª»ú¹ÜÀí³ÌÐò¡£×ª½»Õâ¸ö¹¦ÄÜ¿ÉÒÔÓÃÀ´ÊµÏÖÁ˶àÖØÒýµ¼£¬Ö»ÐèÒª½«ÁíÒ»¸ö²Ù×÷ϵͳµÄ¿ª»ú¹ÜÀí³ÌÐò°²×°ÔÚÆäËü·ÖÇøµÄÆô¶¯ÉÈÇøÉÏ£¬ÔÚÆô¶¯ MBR ÖеĿª»ú¹ÜÀí³ÌÐòʱ£¬¾Í¿ÉÒÔÑ¡ÔñÆô¶¯µ±Ç°µÄ²Ù×÷ϵͳ»òÕßת½»¸øÆäËü¿ª»ú¹ÜÀí³ÌÐò´Ó¶øÆô¶¯ÁíÒ»¸ö²Ù×÷ϵͳ¡£ +MBR 中的开机管ç�†ç¨‹åº�æ��供以下功能:选å�•ã€�载入核心文件以å�Šè½¬äº¤å…¶å®ƒå¼€æœºç®¡ç�†ç¨‹åº�。转交这个功能å�¯ä»¥ç”¨æ�¥å®žçŽ°äº†å¤šé‡�引导,å�ªéœ€è¦�å°†å�¦ä¸€ä¸ªæ“�作系统的开机管ç�†ç¨‹åº�安装在其它分区的å�¯åŠ¨æ‰‡åŒºä¸Šï¼Œåœ¨å�¯åЍ MBR 中的开机管ç�†ç¨‹åº�时,就å�¯ä»¥é€‰æ‹©å�¯åЍ当å‰�çš„æ“�作系统或者转交给其它开机管ç�†ç¨‹åº�从而å�¯åЍå�¦ä¸€ä¸ªæ“�作系统。 -![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/f900f266-a323-42b2-bc43-218fdb8811a8.jpg) +![](https://github.com/CyC2018/InterviewNotes/blob/master/pics//f900f266-a323-42b2-bc43-218fdb8811a8.jpg) -°²×°¶àÖØÒýµ¼£¬×îºÃÏȰ²×° Windows ÔÙ°²×° Linux¡£ÒòΪ°²×° Windows ʱ»á¸²¸Çµô MBR£¬¶ø Linux ¿ÉÒÔÑ¡Ôñ½«¿ª»ú¹ÜÀí³ÌÐò°²×°ÔÚ MBR »òÕ߯äËü·ÖÇøµÄÆô¶¯ÉÈÇø£¬²¢ÇÒ¿ÉÒÔÉèÖÿª»ú¹ÜÀí³ÌÐòµÄÑ¡µ¥¡£ +安装多é‡�引导,最好先安装 Windows å†�安装 Linux。因为安装 Windows 时会覆盖掉 MBR,而 Linux å�¯ä»¥é€‰æ‹©å°†å¼€æœºç®¡ç�†ç¨‹åº�安装在 MBR 或者其它分区的å�¯åŠ¨æ‰‡åŒºï¼Œå¹¶ä¸”å�¯ä»¥è®¾ç½®å¼€æœºç®¡ç�†ç¨‹åº�的选å�•。 ### 2. UEFI -UEFI Ïà±ÈÓÚ BIOS À´Ëµ¹¦ÄܸüÎªÈ«Ãæ£¬Ò²¸üΪ°²È«¡£ +UEFI 相比于 BIOS æ�¥è¯´åŠŸèƒ½æ›´ä¸ºå…¨é�¢ï¼Œä¹Ÿæ›´ä¸ºå®‰å…¨ã€‚ -## ¹ÒÔØ +## 挂载 -¹ÒÔØÀûÓÃĿ¼×÷Ϊ·ÖÇøµÄ½øÈëµã£¬Ò²¾ÍÊÇ˵£¬½øÈëĿ¼֮ºó¾Í¿ÉÒÔ¶ÁÈ¡·ÖÇøµÄÊý¾Ý¡£ +挂载利用目录作为分区的进入点,也就是说,进入目录之å�Žå°±å�¯ä»¥è¯»å�–分区的数æ�®ã€‚ -![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/249f3bb1-feee-4805-a259-a72699d638ca.jpg) +![](https://github.com/CyC2018/InterviewNotes/blob/master/pics//249f3bb1-feee-4805-a259-a72699d638ca.jpg) -# ÎļþȨÏÞÓëĿ¼ÅäÖà +# 文件æ�ƒé™�与目录é…�ç½® -## ÎļþȨÏÞ¸ÅÄî +## 文件æ�ƒé™�概念 -°ÑÓû§·ÖΪÈýÖÖ£ºÎļþÓµÓÐÕß¡¢Èº×éÒÔ¼°ÆäËüÈË£¬¶Ô²»Í¬µÄÓû§Óв»Í¬µÄÎļþȨÏÞ¡£ +把用户分为三ç§�:文件拥有者ã€�群组以å�Šå…¶å®ƒäººï¼Œå¯¹ä¸�å�Œçš„用户有ä¸�å�Œçš„æ–‡ä»¶æ�ƒé™�。 -ʹÓà ls ²é¿´Ò»¸öÎļþʱ£¬»áÏÔʾһ¸öÎļþµÄÐÅÏ¢£¬ÀýÈç drwxr-xr-x. 3 root root 17 May 6 00:14 .config£¬¶ÔÕâ¸öÐÅÏ¢µÄ½âÊÍÈçÏ£º +使用 ls 查看一个文件时,会显示一个文件的信æ�¯ï¼Œä¾‹å¦‚ drwxr-xr-x. 3 root root 17 May 6 00:14 .config,对这个信æ�¯çš„解释如下: -- drwxr-xr-x£ºÎļþÀàÐÍÒÔ¼°È¨ÏÞ£¬µÚ 1 λΪÎļþÀàÐÍ×ֶΣ¬ºó 9 λΪÎļþȨÏÞ×ֶΡ£ -- 3£ºÁ´½ÓÊý£» -- root£ºÎļþÓµÓÐÕߣ» -- root£ºËùÊôȺ×飻 -- 17£ºÎļþ´óС£» -- May 6 00:14£ºÎļþ×îºó±»Ð޸ĵÄʱ¼ä£» -- .config£ºÎļþÃû¡£ +- drwxr-xr-x:文件类型以å�Šæ�ƒé™�,第 1 ä½�为文件类型字段,å�Ž 9 ä½�为文件æ�ƒé™�字段。 +- 3:链接数; +- root:文件拥有者; +- root:所属群组; +- 17:文件大å°�ï¼› +- May 6 00:14:文件最å�Žè¢«ä¿®æ”¹çš„æ—¶é—´ï¼› +- .config:文件å��。 -³£¼ûµÄÎļþÀàÐͼ°Æäº¬ÒåÓУº +常è§�的文件类型å�Šå…¶å�«ä¹‰æœ‰ï¼š -- d£ºÄ¿Â¼£» -- -£ºÎļþ£» -- l£ºÁ´½ÓÎļþ£» +- d:目录; +- -:文件; +- l:链接文件; -9 λµÄÎļþȨÏÞ×Ö¶ÎÖУ¬Ã¿ 3 ¸öΪһ×飬¹² 3 ×飬ÿһ×é·Ö±ð´ú±í¶ÔÎļþÓµÓÐÕß¡¢ËùÊôȺ×éÒÔ¼°ÆäËüÈ˵ÄÎļþȨÏÞ¡£Ò»×éȨÏÞÖÐµÄ 3 λ·Ö±ðΪ r¡¢w¡¢x ȨÏÞ£¬±íʾ¿É¶Á¡¢¿Éд¡¢¿ÉÖ´ÐС£ +9 ä½�的文件æ�ƒé™�字段中,æ¯� 3 个为一组,共 3 组,æ¯�一组分别代表对文件拥有者ã€�所属群组以å�Šå…¶å®ƒäººçš„æ–‡ä»¶æ�ƒé™�。一组æ�ƒé™�中的 3 ä½�分别为 rã€�wã€�x æ�ƒé™�,表示å�¯è¯»ã€�å�¯å†™ã€�å�¯æ‰§è¡Œã€‚ -## ÎļþÊôÐÔÒÔ¼°È¨ÏÞµÄÐÞ¸Ä +## 文件属性以å�Šæ�ƒé™�的修改 -### 1. ÐÞ¸ÄÎļþËùÊôȺ×é +### 1. 修改文件所属群组 ```html # chgrp [-R] groupname dirname/filename --R£ºµÝ¹éÐÞ¸Ä +-R:递归修改 ``` -### 2. ÐÞ¸ÄÎļþÓµÓÐÕß +### 2. 修改文件拥有者 -²»½ö¿ÉÒÔÐÞ¸ÄÎļþÓµÓÐÕߣ¬Ò²¿ÉÒÔÐÞ¸ÄÎļþËùÊôȺ×é¡£ +ä¸�ä»…å�¯ä»¥ä¿®æ”¹æ–‡ä»¶æ‹¥æœ‰è€…,也å�¯ä»¥ä¿®æ”¹æ–‡ä»¶æ‰€å±žç¾¤ç»„。 ```html -# chown [-R] Óû§Ãû:Ⱥ×éÃû dirname/filename +# chown [-R] 用户å��:群组å�� dirname/filename ``` -### 3. ÐÞ¸ÄȨÏÞ +### 3. 修改æ�ƒé™� -¿ÉÒÔ½«Ò»×éȨÏÞÓÃÊý×ÖÀ´±íʾ£¬´Ëʱһ×éȨÏÞµÄ 3 ¸öλµ±×ö¶þ½øÖÆÊý×ÖµÄ룬´Ó×óµ½ÓÒÿ¸öλµÄȨֵΪ 4¡¢2¡¢1£¬¼´Ã¿¸öȨÏÞ¶ÔÓ¦µÄÊý×ÖȨֵΪ r£º4¡¢w£º2¡¢x£º1¡£ +å�¯ä»¥å°†ä¸€ç»„æ�ƒé™�用数字æ�¥è¡¨ç¤ºï¼Œæ­¤æ—¶ä¸€ç»„æ�ƒé™�çš„ 3 个ä½�当å�šäºŒè¿›åˆ¶æ•°å­—çš„ä½�,从左到å�³æ¯�个ä½�çš„æ�ƒå€¼ä¸º 4ã€�2ã€�1,å�³æ¯�个æ�ƒé™�对应的数字æ�ƒå€¼ä¸º r:4ã€�w:2ã€�x:1。 ```html # chmod [-R] xyz dirname/filename ``` -·¶Àý£º½« .bashrc ÎļþµÄȨÏÞÐÞ¸ÄΪ -rwxr-xr--¡£ +范例:将 .bashrc 文件的æ�ƒé™�修改为 -rwxr-xr--。 ```html # chmod 754 .bashrc ``` -Ò²¿ÉÒÔʹÓ÷ûºÅÀ´É趨ȨÏÞ¡£ +也å�¯ä»¥ä½¿ç”¨ç¬¦å�·æ�¥è®¾å®šæ�ƒé™�。 ```html # chmod [ugoa] [+-=] [rwx] dirname/filename -- u£ºÓµÓÐÕß -- g£ºËùÊôȺ×é -- o£ºÆäËûÈË -- a£ºËùÓÐÈË -- +£ºÌí¼ÓȨÏÞ -- -£ºÒƳýȨÏÞ -- =£ºÉ趨ȨÏÞ +- u:拥有者 +- g:所属群组 +- o:其他人 +- a:所有人 +- +:添加æ�ƒé™� +- -:移除æ�ƒé™� +- =:设定æ�ƒé™� ``` -·¶Àý£ºÎª .bashrc ÎļþµÄËùÓÐÓû§Ìí¼ÓдȨÏÞ¡£ +范例:为 .bashrc 文件的所有用户添加写æ�ƒé™�。 ```html # chmod a+w .bashrc ``` -## Ŀ¼µÄȨÏÞ +## 目录的æ�ƒé™� -ÎļþÃû²»ÊÇ´æ´¢ÔÚÒ»¸öÎļþµÄÄÚÈÝÖУ¬¶øÊÇ´æ´¢ÔÚÒ»¸öÎļþËùÔÚµÄĿ¼ÖС£Òò´Ë£¬ÓµÓÐÎļþµÄ w ȨÏÞ²¢²»ÄܶÔÎļþÃû½øÐÐÐ޸ġ£ +文件å��ä¸�是存储在一个文件的内容中,而是存储在一个文件所在的目录中。因此,拥有文件的 w æ�ƒé™�å¹¶ä¸�能对文件å��进行修改。 -Ŀ¼´æ´¢ÎļþÁÐ±í£¬Ò»¸öĿ¼µÄȨÏÞÒ²¾ÍÊÇ¶ÔÆäÎļþÁбíµÄȨÏÞ¡£Òò´Ë£¬Ä¿Â¼µÄ r ȨÏÞ±íʾ¿ÉÒÔ¶ÁÈ¡ÎļþÁÐ±í£»w ȨÏÞ±íʾ¿ÉÒÔÐÞ¸ÄÎļþÁÐ±í£¬¾ßÌåÀ´Ëµ£¬¾ÍÊÇÌí¼Óɾ³ýÎļþ£¬¶ÔÎļþÃû½øÐÐÐ޸ģ»x ȨÏÞ¿ÉÒÔÈøÃĿ¼³ÉΪ¹¤×÷Ŀ¼£¬x ȨÏÞÊÇ r ºÍ w ȨÏ޵Ļù´¡£¬Èç¹û²»ÄÜʹһ¸öĿ¼³ÉΪ¹¤×÷Ŀ¼£¬Ò²¾Íû°ì·¨¶ÁÈ¡ÎļþÁбíÒÔ¼°¶ÔÎļþÁÐ±í½øÐÐÐÞ¸ÄÁË¡£ +目录存储文件列表,一个目录的æ�ƒé™�也就是对其文件列表的æ�ƒé™�。因此,目录的 r æ�ƒé™�表示å�¯ä»¥è¯»å�–文件列表;w æ�ƒé™�表示å�¯ä»¥ä¿®æ”¹æ–‡ä»¶åˆ—表,具体æ�¥è¯´ï¼Œå°±æ˜¯æ·»åŠ åˆ é™¤æ–‡ä»¶ï¼Œå¯¹æ–‡ä»¶å��进行修改;x æ�ƒé™�å�¯ä»¥è®©è¯¥ç›®å½•æˆ�为工作目录,x æ�ƒé™�是 r å’Œ w æ�ƒé™�的基础,如果ä¸�能使一个目录æˆ�为工作目录,也就没办法读å�–文件列表以å�Šå¯¹æ–‡ä»¶åˆ—表进行修改了。 -## ÎļþĬÈÏȨÏÞ +## 文件默认æ�ƒé™� -ÎļþĬÈÏȨÏÞ£ºÎļþĬÈÏûÓпÉÖ´ÐÐȨÏÞ£¬Òò´ËΪ 666£¬Ò²¾ÍÊÇ -rw-rw-rw- ¡£ -Ŀ¼ĬÈÏȨÏÞ£ºÄ¿Â¼±ØÐëÒªÄܹ»½øÈ룬Ҳ¾ÍÊDZØÐëÓµÓпÉÖ´ÐÐȨÏÞ£¬Òò´ËΪ 777 £¬Ò²¾ÍÊÇ drwxrwxrwx¡£ +文件默认æ�ƒé™�:文件默认没有å�¯æ‰§è¡Œæ�ƒé™�,因此为 666,也就是 -rw-rw-rw- 。 +目录默认æ�ƒé™�:目录必须è¦�能够进入,也就是必须拥有å�¯æ‰§è¡Œæ�ƒé™�,因此为 777 ,也就是 drwxrwxrwx。 -¿ÉÒÔͨ¹ý umask ÉèÖûòÕ߲鿴ÎļþµÄĬÈÏȨÏÞ£¬Í¨³£ÒÔÑÚÂëµÄÐÎʽÀ´±íʾ£¬ÀýÈç 002 ±íʾÆäËüÓû§µÄȨÏÞÈ¥³ýÁËÒ»¸ö 2 µÄȨÏÞ£¬Ò²¾ÍÊÇдȨÏÞ£¬Òò´Ë½¨Á¢ÐÂÎļþʱĬÈϵÄȨÏÞΪ -rw-rw-r-- ¡£ +å�¯ä»¥é€šè¿‡ umask 设置或者查看文件的默认æ�ƒé™�,通常以掩ç �的形å¼�æ�¥è¡¨ç¤ºï¼Œä¾‹å¦‚ 002 表示其它用户的æ�ƒé™�去除了一个 2 çš„æ�ƒé™�,也就是写æ�ƒé™�,因此建立新文件时默认的æ�ƒé™�为 -rw-rw-r-- 。 -## Ŀ¼ÅäÖà +## 目录é…�ç½® -ΪÁËʹ²»Í¬ Linux ·¢Ðа汾µÄĿ¼½á¹¹±£³ÖÒ»ÖÂÐÔ£¬Filesystem Hierarchy Standard (FHS) ¹æ¶¨ÁË Linux µÄĿ¼½á¹¹¡£×î»ù´¡µÄÈý¸öĿ¼ÈçÏ£º +为了使ä¸�å�Œ Linux å�‘行版本的目录结构ä¿�æŒ�一致性,Filesystem Hierarchy Standard (FHS) 规定了 Linux 的目录结构。最基础的三个目录如下: -- / (root, ¸ùĿ¼) -- /usr (unix software resource)£ºËùÓÐϵͳĬÈÏÈí¼þ¶¼»á°²×°µ½Õâ¸öĿ¼£» -- /var (variable)£º´æ·Åϵͳ»ò³ÌÐòÔËÐйý³ÌÖеÄÊý¾ÝÎļþ¡£ +- / (root, 根目录) +- /usr (unix software resource):所有系统默认软件都会安装到这个目录; +- /var (variable):存放系统或程åº�è¿�行过程中的数æ�®æ–‡ä»¶ã€‚ -ÍêÕûµÄĿ¼Ê÷ÈçÏ£º +完整的目录树如下: -![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/27ace615-558f-4dfb-8ad4-7ac769c10118.jpg) +![](https://github.com/CyC2018/InterviewNotes/blob/master/pics//27ace615-558f-4dfb-8ad4-7ac769c10118.jpg) -# ÎļþÓëĿ¼ +# 文件与目录 -## Îļþʱ¼ä +## 文件时间 -1. modification time (mtime)£ºÎļþµÄÄÚÈݸüоͻá¸üУ» -2. status time (ctime)£ºÎļþµÄ״̬£¨È¨ÏÞ¡¢ÊôÐÔ£©¸üоͻá¸üУ» -3. access time (atime)£º¶ÁÈ¡Îļþʱ¾Í»á¸üС£ +1. modification time (mtime):文件的内容更新就会更新; +2. status time (ctime):文件的状æ€�(æ�ƒé™�ã€�属性)更新就会更新; +3. access time (atime):读å�–文件时就会更新。 -## ÎļþÓëĿ¼µÄ»ù±¾²Ù×÷ +## 文件与目录的基本æ“�作 ### 1. ls -ÁгöÎļþ»òÕßĿ¼µÄÐÅÏ¢£¬Ä¿Â¼µÄÐÅÏ¢¾ÍÊÇÆäÖаüº¬µÄÎļþ¡£ +列出文件或者目录的信æ�¯ï¼Œç›®å½•的信æ�¯å°±æ˜¯å…¶ä¸­åŒ…å�«çš„æ–‡ä»¶ã€‚ ```html # ls [-aAdfFhilnrRSt] file|dir --a £ºÁгöÈ«²¿µÄÎļþ --d £º½öÁгöĿ¼±¾Éí --l £ºÒÔ³¤Êý¾Ý´®ÐÐÁгö£¬°üº¬ÎļþµÄÊôÐÔÓëȨÏ޵ȵÈÊý¾Ý +-a :列出全部的文件 +-d :仅列出目录本身 +-l :以长数æ�®ä¸²è¡Œåˆ—出,包å�«æ–‡ä»¶çš„属性与æ�ƒé™�等等数æ�® ``` ### 2. cp -¸´ÖƲÙ×÷¡£ +å¤�制æ“�作。 -Èç¹ûÔ´ÎļþÓÐÁ½¸öÒÔÉÏ£¬ÔòÄ¿µÄÎļþÒ»¶¨ÒªÊÇĿ¼²ÅÐС£ +如果æº�文件有两个以上,则目的文件一定è¦�是目录æ‰�行。 ```html cp [-adfilprsu] source destination --a £ºÏ൱ÓÚ -dr --preserve=all µÄÒâ˼£¬ÖÁÓÚ dr Çë²Î¿¼ÏÂÁÐ˵Ã÷ --d £ºÈôÀ´Ô´ÎļþΪÁ´½ÓÎļþ£¬Ôò¸´ÖÆÁ´½ÓÎļþÊôÐÔ¶ø·ÇÎļþ±¾Éí --i £ºÈôÄ¿±êÎļþÒѾ­´æÔÚʱ£¬ÔÚ¸²¸Çǰ»áÏÈѯÎÊ --p £ºÁ¬Í¬ÎļþµÄÊôÐÔÒ»Æð¸´ÖƹýÈ¥ --r £ºµÝ¹é³ÖÐø¸´ÖÆ --u £ºdestination ±È source ¾É²Å¸üРdestination£¬»ò destination ²»´æÔÚµÄÇé¿öϲŸ´ÖÆ ---preserve=all £º³ýÁË -p µÄȨÏÞÏà¹Ø²ÎÊýÍ⣬»¹¼ÓÈë SELinux µÄÊôÐÔ, links, xattr µÈÒ²¸´ÖÆÁË +-a :相当于 -dr --preserve=all çš„æ„�æ€�,至于 dr 请å�‚考下列说明 +-d :若æ�¥æº�文件为链接文件,则å¤�制链接文件属性而é�žæ–‡ä»¶æœ¬èº« +-i :若目标文件已ç»�存在时,在覆盖å‰�会先询问 +-p :连å�Œæ–‡ä»¶çš„属性一起å¤�制过去 +-r :递归æŒ�ç»­å¤�制 +-u :destination 比 source æ—§æ‰�æ›´æ–° destination,或 destination ä¸�存在的情况下æ‰�å¤�制 +--preserve=all :除了 -p çš„æ�ƒé™�相关å�‚数外,还加入 SELinux 的属性, links, xattr 等也å¤�制了 ``` ### 3. rm -ÒÆ³ý²Ù×÷¡£ +移除æ“�作。 ```html -# rm [-fir] Îļþ»òĿ¼ --r £ºµÝ¹éɾ³ý +# rm [-fir] 文件或目录 +-r :递归删除 ``` ### 4. mv -ÒÆ¶¯²Ù×÷¡£ +移动æ“�作。 ```html # mv [-fiu] source destination # mv [options] source1 source2 source3 .... directory --f £º force Ç¿ÖÆµÄÒâ˼£¬Èç¹ûÄ¿±êÎļþÒѾ­´æÔÚ£¬²»»áѯÎʶøÖ±½Ó¸²¸Ç +-f : force 强制的æ„�æ€�,如果目标文件已ç»�存在,ä¸�会询问而直接覆盖 ``` -## »ñÈ¡ÎļþÄÚÈÝ +## 获å�–文件内容 ### 1. cat -È¡µÃÎļþÄÚÈÝ¡£ +å�–得文件内容。 ```html # cat [-AbEnTv] filename --n £º´òÓ¡³öÐкţ¬Á¬Í¬¿Õ°×ÐÐÒ²»áÓÐÐкţ¬-b ²»»á +-n :打å�°å‡ºè¡Œå�·ï¼Œè¿žå�Œç©ºç™½è¡Œä¹Ÿä¼šæœ‰è¡Œå�·ï¼Œ-b ä¸�会 ``` ### 2. tac -ÊÇ cat µÄ·´Ïò²Ù×÷£¬´Ó×îºóÒ»ÐпªÊ¼´òÓ¡¡£ +是 cat çš„å��å�‘æ“�作,从最å�Žä¸€è¡Œå¼€å§‹æ‰“å�°ã€‚ ### 3. more -¿ÉÒÔÒ»Ò³Ò»Ò³²é¿´ÎļþÄÚÈÝ£¬ºÍÎı¾±à¼­Æ÷ÀàËÆ¡£ +å�¯ä»¥ä¸€é¡µä¸€é¡µæŸ¥çœ‹æ–‡ä»¶å†…容,和文本编辑器类似。 ### 4. less -ºÍ more ÀàËÆ¡£ +å’Œ more 类似。 ### 5. head -¿ÉÒÔÈ¡µÃÎļþǰ¼¸ÐС£ +å�¯ä»¥å�–得文件å‰�几行。 ```html # head [-n number] filename --n £ººóÃæ½ÓÊý×Ö£¬´ú±íÏÔʾ¼¸ÐеÄÒâ˼ +-n :å�Žé�¢æŽ¥æ•°å­—,代表显示几行的æ„�æ€� ``` ### 6. tail -ÊÇ head µÄ·´Ïò²Ù×÷£¬Ö»ÊÇÈ¡µÃÊǺó¼¸ÐС£ +是 head çš„å��å�‘æ“�作,å�ªæ˜¯å�–得是å�Žå‡ è¡Œã€‚ ### 7. od -¿ÉÒÔÒÔ×Ö·û»òÕßÊ®Áù½øÖƵÄÐÎʽÏÔʾ¶þ½øÖÆÎļþ¡£ +å�¯ä»¥ä»¥å­—符或者å��六进制的形å¼�显示二进制文件。 ### 8. touch -ÐÞ¸ÄÎļþʱ¼ä»òÕß½¨Á¢ÐÂÎļþ¡£ +修改文件时间或者建立新文件。 ```html # touch [-acdmt] filename --a £º ¸üРatime --c £º ¸üРctime£¬Èô¸ÃÎļþ²»´æÔÚÔò²»½¨Á¢ÐÂÎļþ --m £º ¸üРmtime --d £º ºóÃæ¿ÉÒÔ½ÓÓû¸üеÄÈÕÆÚ¶ø²»Óõ±Ç°µÄÈÕÆÚ£¬Ò²¿ÉÒÔʹÓà --date="ÈÕÆÚ»òʱ¼ä" --t £ººóÃæ¿ÉÒÔ½ÓÓû¸üеÄʱ¼ä¶ø²»Óõ±Ç°µÄʱ¼ä£¬¸ñʽΪ[YYYYMMDDhhmm] +-a : æ›´æ–° atime +-c : æ›´æ–° ctime,若该文件ä¸�存在则ä¸�建立新文件 +-m : æ›´æ–° mtime +-d : å�Žé�¢å�¯ä»¥æŽ¥æ¬²æ›´æ–°çš„æ—¥æœŸè€Œä¸�用当å‰�的日期,也å�¯ä»¥ä½¿ç”¨ --date="日期或时间" +-t :å�Žé�¢å�¯ä»¥æŽ¥æ¬²æ›´æ–°çš„æ—¶é—´è€Œä¸�用当å‰�的时间,格å¼�为[YYYYMMDDhhmm] ``` -## Ö¸ÁîÓëÎļþËÑË÷ +## 指令与文件æ�œç´¢ ### 1. which -Ö¸ÁîËÑË÷¡£ +指令æ�œç´¢ã€‚ ```html # which [-a] command --a £º½«ËùÓÐÖ¸ÁîÁгö£¬¶ø²»ÊÇÖ»ÁеÚÒ»¸ö +-a :将所有指令列出,而ä¸�是å�ªåˆ—第一个 ``` ### 2. whereis -whereis ËÑË÷ÎļþµÄËٶȱȽϿ죬ÒòΪËüÖ»ËÑË÷¼¸¸öÌØ¶¨µÄĿ¼¡£ +whereis æ�œç´¢æ–‡ä»¶çš„速度比较快,因为它å�ªæ�œç´¢å‡ ä¸ªç‰¹å®šçš„目录。 ```html # whereis [-bmsu] dirname/filename @@ -473,114 +474,114 @@ whereis ### 3. locate -locate ¿ÉÒÔÓùؼü×Ö»òÕßÕýÔò±í´ïʽ½øÐÐËÑË÷¡£ +locate å�¯ä»¥ç”¨å…³é”®å­—或者正则表达å¼�进行æ�œç´¢ã€‚ -locate ʹÓà /var/lib/mlocate/ Õâ¸öÊý¾Ý¿âÀ´½øÐÐËÑË÷£¬Ëü´æ´¢ÔÚÄÚ´æÖУ¬²¢ÇÒÿÌì¸üÐÂÒ»´Î£¬ËùÒÔÎÞ·¨Óà locate ËÑË÷н¨µÄÎļþ¡£¿ÉÒÔʹÓà updatedb À´Á¢¼´¸üÐÂÊý¾Ý¿â¡£ +locate 使用 /var/lib/mlocate/ 这个数æ�®åº“æ�¥è¿›è¡Œæ�œç´¢ï¼Œå®ƒå­˜å‚¨åœ¨å†…存中,并且æ¯�天更新一次,所以无法用 locate æ�œç´¢æ–°å»ºçš„æ–‡ä»¶ã€‚å�¯ä»¥ä½¿ç”¨ updatedb æ�¥ç«‹å�³æ›´æ–°æ•°æ�®åº“。 ```html # locate [-ir] keyword --r£º½ÓÕýÔò±í´ïʽ +-r:接正则表达å¼� ``` ### 4. find -find ¿ÉÒÔʹÓÃÎļþµÄÊôÐÔºÍȨÏÞ½øÐÐËÑË÷¡£ +find å�¯ä»¥ä½¿ç”¨æ–‡ä»¶çš„属性和æ�ƒé™�进行æ�œç´¢ã€‚ ```html # find filename [option] ``` -#### 4.1 Óëʱ¼äÓйصÄÑ¡Ïî +#### 4.1 与时间有关的选项 ```html --mtime n £ºÁгöÔÚ n ÌìǰµÄÄÇÒ»ÌìÐ޸ĹýÄÚÈݵÄÎļþ --mtime +n £ºÁгöÔÚ n Ìì֮ǰ(²»º¬ n Ìì±¾Éí)Ð޸ĹýÄÚÈݵÄÎļþ --mtime -n £ºÁгöÔÚ n ÌìÖ®ÄÚ(º¬ n Ìì±¾Éí)Ð޸ĹýÄÚÈݵÄÎļþ --newer file £º Áгö±È file ¸üеÄÎļþ +-mtime n :列出在 n 天å‰�的那一天修改过内容的文件 +-mtime +n :列出在 n 天之å‰�(ä¸�å�« n 天本身)修改过内容的文件 +-mtime -n :列出在 n 天之内(å�« n 天本身)修改过内容的文件 +-newer file : 列出比 file 更新的文件 ``` -+4¡¢4 ºÍ -4 µÄָʾµÄʱ¼ä·¶Î§ÈçÏ£º ++4ã€�4 å’Œ -4 的指示的时间范围如下: -![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/658fc5e7-79c0-4247-9445-d69bf194c539.png) +![](https://github.com/CyC2018/InterviewNotes/blob/master/pics//658fc5e7-79c0-4247-9445-d69bf194c539.png) -#### 4.2 ÓëÎļþÓµÓÐÕߺÍËùÊôȺ×éÓйصÄÑ¡Ïî +#### 4.2 与文件拥有者和所属群组有关的选项 ```html -uid n -gid n -user name -group name --nouser £ºËÑË÷ÓµÓÐÕß²»´æÔÚ /etc/passwd µÄÎļþ --nogroup£ºËÑË÷ËùÊôȺ×é²»´æÔÚÓÚ /etc/group µÄÎļþ +-nouser :æ�œç´¢æ‹¥æœ‰è€…ä¸�存在 /etc/passwd 的文件 +-nogroup:æ�œç´¢æ‰€å±žç¾¤ç»„ä¸�存在于 /etc/group 的文件 ``` -#### 4.3 ÓëÎļþȨÏÞºÍÃû³ÆÓйصÄÑ¡Ïî +#### 4.3 与文件æ�ƒé™�å’Œå��称有关的选项 ```html -name filename --size [+-]SIZE£ºËÑѰ±È SIZE »¹Òª´ó(+)»òС(-)µÄÎļþ¡£Õâ¸ö SIZE µÄ¹æ¸ñÓУºc: ´ú±í byte£¬k: ´ú±í 1024bytes¡£ËùÒÔ£¬ÒªÕÒ±È 50KB »¹Òª´óµÄÎļþ£¬¾ÍÊÇ -size +50k +-size [+-]SIZE:æ�œå¯»æ¯” SIZE 还è¦�大(+)或å°�(-)的文件。这个 SIZE 的规格有:c: 代表 byte,k: 代表 1024bytes。所以,è¦�找比 50KB 还è¦�大的文件,就是 -size +50k -type TYPE --perm mode £ºËÑË÷ȨÏÞµÈÓÚ mode µÄÎļþ --perm -mode £ºËÑË÷ȨÏÞ°üº¬ mode µÄÎļþ --perm /mode £ºËÑË÷ȨÏÞ°üº¬ÈÎÒ» mode µÄÎļþ +-perm mode :æ�œç´¢æ�ƒé™�等于 mode 的文件 +-perm -mode :æ�œç´¢æ�ƒé™�包å�« mode 的文件 +-perm /mode :æ�œç´¢æ�ƒé™�包å�«ä»»ä¸€ mode 的文件 ``` -# ´ÅÅÌÓëÎļþϵͳ +# ç£�盘与文件系统 -## ÎļþϵͳµÄ×é³É +## 文件系统的组æˆ� -¶Ô·ÖÇø½øÐиñʽ»¯ÊÇΪÁËÔÚ·ÖÇøÉϽ¨Á¢Îļþϵͳ¡£Ò»¸ö·ÖÇøÍ¨³£Ö»Äܸñʽ»¯ÎªÒ»¸öÎļþϵͳ£¬µ«ÊÇ´ÅÅÌÕóÁеȼ¼Êõ¿ÉÒÔ½«Ò»¸ö·ÖÇø¸ñʽ»¯Îª¶à¸öÎļþϵͳ£¬Òò´ËÖ»ÓÐÎļþϵͳÄܱ»¹ÒÔØ£¬¶ø·ÖÇø²»Äܱ»¹ÒÔØ¡£ +对分区进行格å¼�化是为了在分区上建立文件系统。一个分区通常å�ªèƒ½æ ¼å¼�化为一个文件系统,但是ç£�盘阵列等技术å�¯ä»¥å°†ä¸€ä¸ªåˆ†åŒºæ ¼å¼�化为多个文件系统,因此å�ªæœ‰æ–‡ä»¶ç³»ç»Ÿèƒ½è¢«æŒ‚载,而分区ä¸�能被挂载。 -ÎļþϵͳÓÐÒÔÏÂÈý¸ö½á¹¹£º +文件系统有以下三个结构: -1. superblock£º¼Ç¼ÎļþϵͳµÄÕûÌåÐÅÏ¢£¬°üÀ¨ inode ºÍ block µÄ×ÜÁ¿¡¢Ê¹ÓÃÁ¿¡¢Ê£ÓàÁ¿£¬ÒÔ¼°ÎļþϵͳµÄ¸ñʽÓëÏà¹ØÐÅÏ¢µÈ£» -2. inode£ºÒ»¸öÎļþÕ¼ÓÃÒ»¸ö inode£¬¼Ç¼ÎļþµÄÊôÐÔ£¬Í¬Ê±¼Ç¼´ËÎļþµÄÄÚÈÝËùÔÚµÄ block ºÅÂ룻 -3. block£º¼Ç¼ÎļþµÄÄÚÈÝ£¬ÎļþÌ«´óʱ£¬»áÕ¼Óöà¸ö block¡£ +1. superblock:记录文件系统的整体信æ�¯ï¼ŒåŒ…括 inode å’Œ block 的总é‡�ã€�使用é‡�ã€�剩余é‡�,以å�Šæ–‡ä»¶ç³»ç»Ÿçš„æ ¼å¼�与相关信æ�¯ç­‰ï¼› +2. inode:一个文件å� ç”¨ä¸€ä¸ª inode,记录文件的属性,å�Œæ—¶è®°å½•此文件的内容所在的 block å�·ç �ï¼› +3. block:记录文件的内容,文件太大时,会å� ç”¨å¤šä¸ª block。 -µ±Òª¶Áȡһ¸öÎļþµÄÄÚÈÝʱ£¬ÏÈÔÚ inode ÖÐÈ¥²éÕÒÎļþÄÚÈÝËùÔÚµÄËùÓÐ block£¬È»ºó°ÑËùÓÐ block µÄÄÚÈݶÁ³öÀ´¡£ +当è¦�读å�–一个文件的内容时,先在 inode 中去查找文件内容所在的所有 block,然å�ŽæŠŠæ‰€æœ‰ block 的内容读出æ�¥ã€‚ -´ÅÅÌË鯬ÊÇÖ¸Ò»¸öÎļþÄÚÈÝËùÔÚµÄ block ¹ýÓÚ·ÖÉ¢¡£ +ç£�盘碎片是指一个文件内容所在的 block 过于分散。 -Ext2 ÎļþϵͳʹÓÃÁËÉÏÊöµÄÎļþ½á¹¹£¬²¢ÔÚ´ËÖ®ÉϼÓÈëÁË block Ⱥ×éµÄ¸ÅÄҲ¾ÍÊǽ«Ò»¸öÎļþϵͳ»®·ÖΪ¶à¸ö block Ⱥ×飬·½±ã¹ÜÀí¡£ +Ext2 文件系统使用了上述的文件结构,并在此之上加入了 block 群组的概念,也就是将一个文件系统划分为多个 block 群组,方便管ç�†ã€‚ -![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/1974a836-aa6b-4fb8-bce1-6eb11969284a.jpg) +![](https://github.com/CyC2018/InterviewNotes/blob/master/pics//1974a836-aa6b-4fb8-bce1-6eb11969284a.jpg) ## inode -Ext2 Îļþϵͳ֧³ÖµÄ block ´óСÓÐ 1k¡¢2k ºÍ 4k ÈýÖÖ£¬²»Í¬µÄ block ´óСÏÞÖÆÁ˵¥Ò»ÎļþµÄ´óС¡£¶øÃ¿¸ö inode ´óСÊǹ̶¨Îª 128 bytes¡£ +Ext2 文件系统支æŒ�çš„ block 大å°�有 1kã€�2k å’Œ 4k 三ç§�,ä¸�å�Œçš„ block 大å°�é™�制了å�•一文件的大å°�。而æ¯�个 inode 大å°�是固定为 128 bytes。 -inode ÖмǼÁËÎļþÄÚÈÝËùÔÚµÄ block£¬µ«ÊÇÿ¸ö block ·Ç³£Ð¡£¬Ò»¸ö´óÎļþËæ±ã¶¼ÐèÒª¼¸Ê®ÍòµÄ block£¬¶øÒ»¸ö inode ´óСÓÐÏÞ£¬ÎÞ·¨Ö±½ÓÒýÓÃÕâô¶à block¡£Òò´ËÒýÈëÁ˼ä½Ó¡¢Ë«¼ä½Ó¡¢Èý¼ä½ÓÒýÓ᣼ä½ÓÒýÓÃÊÇÖ¸£¬Èà inode ¼Ç¼µÄÒýÓà block ¿éµ±³É inode ÓÃÀ´¼Ç¼ÒýÓÃÐÅÏ¢¡£ +inode 中记录了文件内容所在的 block,但是æ¯�个 block é�žå¸¸å°�,一个大文件éš�便都需è¦�几å��万的 block,而一个 inode 大å°�有é™�,无法直接引用这么多 block。因此引入了间接ã€�å�Œé—´æŽ¥ã€�三间接引用。间接引用是指,让 inode 记录的引用 block å�—当æˆ� inode 用æ�¥è®°å½•引用信æ�¯ã€‚ -![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/89091427-7b2b-4923-aff6-44681319a8aa.jpg) +![](https://github.com/CyC2018/InterviewNotes/blob/master/pics//89091427-7b2b-4923-aff6-44681319a8aa.jpg) -inode ¾ßÌå°üº¬ÒÔÏÂÐÅÏ¢£º +inode 具体包å�«ä»¥ä¸‹ä¿¡æ�¯ï¼š -- ¸ÃÎļþµÄ´æÈ¡Ä£Ê½(read/write/excute)£» -- ¸ÃÎļþµÄÓµÓÐÕßÓëȺ×é(owner/group)£» -- ¸ÃÎļþµÄÈÝÁ¿£» -- ¸ÃÎļþ½¨Á¢»ò״̬¸Ä±äµÄʱ¼ä(ctime)£» -- ×î½üÒ»´ÎµÄ¶Áȡʱ¼ä(atime)£» -- ×î½üÐ޸ĵÄʱ¼ä(mtime)£» -- ¶¨ÒåÎļþÌØÐÔµÄÆì±ê(flag)£¬Èç SetUID...£» -- ¸ÃÎļþÕæÕýÄÚÈݵÄÖ¸Ïò (pointer)¡£ +- 该文件的存å�–模å¼�(read/write/excute)ï¼› +- 该文件的拥有者与群组(owner/group)ï¼› +- 该文件的容é‡�ï¼› +- 该文件建立或状æ€�改å�˜çš„æ—¶é—´(ctime)ï¼› +- 最近一次的读å�–æ—¶é—´(atime)ï¼› +- 最近修改的时间(mtime)ï¼› +- 定义文件特性的旗标(flag),如 SetUID...ï¼› +- 该文件真正内容的指å�‘ (pointer)。 -## Ŀ¼µÄ inode Óë block +## 目录的 inode 与 block -½¨Á¢Ò»¸öĿ¼ʱ£¬»á·ÖÅäÒ»¸ö inode ÓëÖÁÉÙÒ»¸ö block¡£block ¼Ç¼µÄÄÚÈÝÊÇĿ¼ÏÂËùÓÐÎļþµÄ inode ±àºÅÒÔ¼°ÎļþÃû¡£¿ÉÒÔ¿´³öÎļþµÄ inode ±¾Éí²»¼Ç¼ÎļþÃû£¬ÎļþÃû¼Ç¼ÔÚĿ¼ÖУ¬Òò´ËÐÂÔöÎļþ¡¢É¾³ýÎļþ¡¢¸ü¸ÄÎļþÃûÕâЩ²Ù×÷ÓëĿ¼µÄ w ȨÏÞÓйء£ +建立一个目录时,会分é…�一个 inode 与至少一个 block。block 记录的内容是目录下所有文件的 inode ç¼–å�·ä»¥å�Šæ–‡ä»¶å��。å�¯ä»¥çœ‹å‡ºæ–‡ä»¶çš„ inode 本身ä¸�记录文件å��,文件å��记录在目录中,因此新增文件ã€�删除文件ã€�更改文件å��这些æ“�作与目录的 w æ�ƒé™�有关。 -## ʵÌåÁ´½ÓÓë·ûºÅÁ´½Ó +## 实体链接与符å�·é“¾æŽ¥ ```html # ln [-sf] source_filename dist_filename --s £ºÄ¬ÈÏÊÇ hard link£¬¼Ó -s Ϊ symbolic link --f £ºÈç¹ûÄ¿±êÎļþ´æÔÚʱ£¬ÏÈɾ³ýÄ¿±êÎļþ +-s :默认是 hard link,加 -s 为 symbolic link +-f :如果目标文件存在时,先删除目标文件 ``` -### 1. ʵÌåÁ´½Ó +### 1. 实体链接 -hard link Ö»ÊÇÔÚij¸öĿ¼ÏÂÐÂÔöÒ»¸öÌõÄ¿£¬Ê¹µÃÐÂÔöµÄÌõÄ¿Á´½Óµ½ÎļþµÄ inode ÉÏ¡£É¾³ýÈÎÒâÒ»¸öÌõÄ¿£¬Îļþ»¹ÊÇ´æÔÚ£¬Ö»ÒªÒýÓÃÊýÁ¿²»Îª 0¡£ +hard link å�ªæ˜¯åœ¨æŸ�个目录下新增一个æ�¡ç›®ï¼Œä½¿å¾—新增的æ�¡ç›®é“¾æŽ¥åˆ°æ–‡ä»¶çš„ inode 上。删除任æ„�一个æ�¡ç›®ï¼Œæ–‡ä»¶è¿˜æ˜¯å­˜åœ¨ï¼Œå�ªè¦�引用数é‡�ä¸�为 0。 -ÓÐÒÔÏÂÏÞÖÆ£º²»ÄÜ¿çÔ½ File System£»²»ÄܶÔĿ¼½øÐÐÁ´½Ó¡£ +有以下é™�制:ä¸�能跨越 File Systemï¼›ä¸�能对目录进行链接。 ```html # ln /etc/crontab . @@ -589,11 +590,11 @@ hard link Ö» 34474855 -rw-r--r--. 2 root root 451 Jun 10 2014 /etc/crontab ``` -### 2. ·ûºÅÁ´½Ó +### 2. 符å�·é“¾æŽ¥ -symbolic link ¿ÉÒÔÀí½âΪ Windows µÄ¿ì½Ý·½Ê½£¬Í¨¹ý½¨Á¢Ò»¸ö¶ÀÁ¢µÄÎļþ£¬Õâ¸öÎļþµÄÊý¾ÝµÄ¶ÁȡָÏòÁ´½ÓµÄÄǸöÎļþ¡£µ±Ô´Îļþ±»É¾³ýÁË£¬Á´½ÓÎļþ¾Í´ò²»¿ªÁË¡£ +symbolic link å�¯ä»¥ç�†è§£ä¸º Windows 的快æ�·æ–¹å¼�,通过建立一个独立的文件,这个文件的数æ�®çš„读å�–指å�‘链接的那个文件。当æº�文件被删除了,链接文件就打ä¸�开了。 -symbolic link ¿ÉÒÔΪĿ¼½¨Á¢Á´½Ó¡£ +symbolic link å�¯ä»¥ä¸ºç›®å½•建立链接。 ```html # ll -i /etc/crontab /root/crontab2 @@ -601,121 +602,121 @@ symbolic link 53745909 lrwxrwxrwx. 1 root root 12 Jun 23 22:31 /root/crontab2 -> /etc/crontab ``` -# ѹËõÓë´ò°ü +# 压缩与打包 -## ѹËõ +## 压缩 -Linux µ×ÏÂÓкܶàѹËõÎļþµÄÀ©Õ¹Ãû£¬³£¼ûµÄÈçÏ£º +Linux 底下有很多压缩文件的扩展å��,常è§�的如下: -| À©Õ¹Ãû | ѹËõ³ÌÐò | +| 扩展å�� | 压缩程åº� | | -- | -- | | \*.Z | compress | |\*.zip | zip | |\*.gz | gzip| |\*.bz2 | bzip2 | |\*.xz | xz | -|\*.tar | tar ³ÌÐò´ò°üµÄÊý¾Ý£¬Ã»Óо­¹ýѹËõ | -|\*.tar.gz | tar ³ÌÐò´ò°üµÄÎļþ£¬¾­¹ý gzip µÄѹËõ | -|\*.tar.bz2 | tar ³ÌÐò´ò°üµÄÎļþ£¬¾­¹ý bzip2 µÄѹËõ | -|\*.tar.xz | tar ³ÌÐò´ò°üµÄÎļþ£¬¾­¹ý xz µÄѹËõ | +|\*.tar | tar 程åº�打包的数æ�®ï¼Œæ²¡æœ‰ç»�过压缩 | +|\*.tar.gz | tar 程åº�打包的文件,ç»�过 gzip 的压缩 | +|\*.tar.bz2 | tar 程åº�打包的文件,ç»�过 bzip2 的压缩 | +|\*.tar.xz | tar 程åº�打包的文件,ç»�过 xz 的压缩 | ### 1. gzip -gzip ÊÇ Linux ʹÓÃ×î¹ãµÄѹËõÖ¸Á¿ÉÒԽ⿪ compress¡¢zip Óë gzip ËùѹËõµÄÎļþ¡£ +gzip 是 Linux 使用最广的压缩指令,å�¯ä»¥è§£å¼€ compressã€�zip 与 gzip 所压缩的文件。 -¾­¹ý gzip ѹËõ¹ý£¬Ô´Îļþ¾Í²»´æÔÚÁË¡£ +ç»�过 gzip 压缩过,æº�文件就ä¸�存在了。 -ÓÐ 9 ¸ö²»Í¬µÄѹËõµÈ¼¶¿ÉÒÔʹÓᣠ+有 9 个ä¸�å�Œçš„压缩等级å�¯ä»¥ä½¿ç”¨ã€‚ -¿ÉÒÔʹÓà zcat¡¢zmore¡¢zless À´¶ÁȡѹËõÎļþµÄÄÚÈÝ¡£ +å�¯ä»¥ä½¿ç”¨ zcatã€�zmoreã€�zless æ�¥è¯»å�–压缩文件的内容。 ```html $ gzip [-cdtv#] filename --c £º½«Ñ¹ËõµÄÊý¾ÝÊä³öµ½ÆÁÄ»ÉÏ --d £º½âѹËõ --t £º¼ìÑéѹËõÎļþÊÇ·ñ³ö´í --v £ºÏÔʾѹËõ±ÈµÈÐÅÏ¢ --# £º # ΪÊý×ÖµÄÒâ˼£¬´ú±íѹËõµÈ¼¶£¬Êý×ÖÔ½´óѹËõ±ÈÔ½¸ß£¬Ä¬ÈÏΪ6 +-c :将压缩的数æ�®è¾“出到å±�幕上 +-d :解压缩 +-t :检验压缩文件是å�¦å‡ºé”™ +-v :显示压缩比等信æ�¯ +-# : # 为数字的æ„�æ€�,代表压缩等级,数字越大压缩比越高,默认为6 ``` ### 2. bzip2 -Ìṩ±È gzip ¸ü¸ßµÄѹËõ±È¡£ +æ��供比 gzip 更高的压缩比。 -²é¿´ÃüÁbzcat¡¢bzmore¡¢bzless¡¢bzgrep¡£ +查看命令:bzcatã€�bzmoreã€�bzlessã€�bzgrep。 ```html $ bzip2 [-cdkzv#] filename --k £º±£ÁôÔ´Îļþ +-k :ä¿�ç•™æº�文件 ``` ### 3. xz -Ìṩ±È bzip2 ¸ü¼ÑµÄѹËõ±È¡£ +æ��供比 bzip2 更佳的压缩比。 -¿ÉÒÔ¿´µ½£¬gzip¡¢bzip2¡¢xz µÄѹËõ±È²»¶ÏÓÅ»¯¡£²»¹ýҪעÒ⣬ѹËõ±ÈÔ½¸ß£¬Ñ¹ËõµÄʱ¼äÒ²Ô½³¤¡£ +å�¯ä»¥çœ‹åˆ°ï¼Œgzipã€�bzip2ã€�xz 的压缩比ä¸�断优化。ä¸�过è¦�注æ„�,压缩比越高,压缩的时间也越长。 -²é¿´ÃüÁxzcat¡¢xzmore¡¢xzless¡¢xzgrep¡£ +查看命令:xzcatã€�xzmoreã€�xzlessã€�xzgrep。 ```html $ xz [-dtlkc#] filename ``` -## ´ò°ü +## 打包 -ѹËõÖ¸ÁîÖ»ÄܶÔÒ»¸öÎļþ½øÐÐѹËõ£¬¶ø´ò°üÄܹ»½«¶à¸öÎļþ´ò°ü³ÉÒ»¸ö´óÎļþ¡£tar ²»½ö¿ÉÒÔÓÃÓÚ´ò°ü£¬Ò²¿ÉÒÔʹÓà gip¡¢bzip2¡¢xz ½«´ò°üÎļþ½øÐÐѹËõ¡£ +压缩指令å�ªèƒ½å¯¹ä¸€ä¸ªæ–‡ä»¶è¿›è¡ŒåŽ‹ç¼©ï¼Œè€Œæ‰“åŒ…èƒ½å¤Ÿå°†å¤šä¸ªæ–‡ä»¶æ‰“åŒ…æˆ�一个大文件。tar ä¸�ä»…å�¯ä»¥ç”¨äºŽæ‰“包,也å�¯ä»¥ä½¿ç”¨ gipã€�bzip2ã€�xz 将打包文件进行压缩。 ```html -$ tar [-z|-j|-J] [cv] [-f н¨µÄtarÎļþ] filename... ==´ò°üѹËõ -$ tar [-z|-j|-J] [tv] [-f ÒÑÓеÄtarÎļþ] ==²é¿´ -$ tar [-z|-j|-J] [xv] [-f ÒÑÓеÄtarÎļþ] [-C Ŀ¼] ==½âѹËõ --z £ºÊ¹ÓÃzip£» --j £ºÊ¹ÓÃbzip2£» --J £ºÊ¹ÓÃxz£» --c £ºÐ½¨´ò°üÎļþ£» --t £º²é¿´´ò°üÎļþÀïÃæÓÐÄÄЩÎļþ£» --x £º½â´ò°ü»ò½âѹËõµÄ¹¦ÄÜ£» --v £ºÔÚѹËõ/½âѹËõµÄ¹ý³ÌÖУ¬ÏÔʾÕýÔÚ´¦ÀíµÄÎļþÃû£» --f : filename£ºÒª´¦ÀíµÄÎļþ£» --C Ŀ¼ £º ÔÚÌØ¶¨Ä¿Â¼½âѹËõ¡£ +$ tar [-z|-j|-J] [cv] [-f 新建的tar文件] filename... ==打包压缩 +$ tar [-z|-j|-J] [tv] [-f 已有的tar文件] ==查看 +$ tar [-z|-j|-J] [xv] [-f 已有的tar文件] [-C 目录] ==解压缩 +-z :使用zipï¼› +-j :使用bzip2ï¼› +-J :使用xzï¼› +-c :新建打包文件; +-t :查看打包文件里é�¢æœ‰å“ªäº›æ–‡ä»¶ï¼› +-x :解打包或解压缩的功能; +-v :在压缩/解压缩的过程中,显示正在处ç�†çš„æ–‡ä»¶å��ï¼› +-f : filename:è¦�处ç�†çš„æ–‡ä»¶ï¼› +-C 目录 : 在特定目录解压缩。 ``` -| ʹÓ÷½Ê½ | ÃüÁî | +| 使用方å¼� | 命令 | | --- | --- | -| ´ò°üѹËõ | tar -jcv -f filename.tar.bz2 Òª±»Ñ¹ËõµÄÎļþ»òĿ¼Ãû³Æ | -| ²é ¿´ | tar -jtv -f filename.tar.bz2 | -| ½âѹËõ | tar -jxv -f filename.tar.bz2 -C Òª½âѹËõµÄĿ¼ | +| 打包压缩 | tar -jcv -f filename.tar.bz2 è¦�被压缩的文件或目录å��ç§° | +| 查 看 | tar -jtv -f filename.tar.bz2 | +| 解压缩 | tar -jxv -f filename.tar.bz2 -C è¦�解压缩的目录 | # Bash -¿ÉÒÔͨ¹ý Shell ÇëÇóÄÚºËÌṩ·þÎñ£¬Bash ÕýÊÇ Shell µÄÒ»ÖÖ¡£ +å�¯ä»¥é€šè¿‡ Shell 请求内核æ��ä¾›æœ�务,Bash 正是 Shell 的一ç§�。 -## Bash ÌØÐÔ +## Bash 特性 -**1. ÃüÁîÀúÊ·** +**1. 命令历å�²** -¼Ç¼ʹÓùýµÄÃüÁî¡£±¾´ÎµÇ¼ËùÖ´ÐеÄÃüÁî¶¼»áÔÝʱ´æ·Åµ½ÄÚ´æÖУ¬ \~/.bash_history ÎļþÖмǼµÄÊÇǰһ´ÎµÇ¼ËùÖ´ÐйýµÄÃüÁî¡£ +记录使用过的命令。本次登录所执行的命令都会暂时存放到内存中, \~/.bash_history 文件中记录的是å‰�一次登录所执行过的命令。 -**2. ÃüÁîÓëÎļþ²¹È«** +**2. 命令与文件补全** -¿ì½Ý¼ü£ºtab +å¿«æ�·é”®ï¼štab -**3. ÃüÃû±ðÃû** +**3. 命å��别å��** -ÀýÈç lm ÊÇ ls -al µÄ±ðÃû¡£ +例如 lm 是 ls -al 的别å��。 **4. shell scripts** -**5. ͨÅä·û** +**5. 通é…�符** -ÀýÈç ls -l /usr/bin/X\* Áгö /usr/bin ÏÂÃæËùÓÐÒÔ X ¿ªÍ·µÄÎļþ¡£ +例如 ls -l /usr/bin/X\* 列出 /usr/bin 下é�¢æ‰€æœ‰ä»¥ X 开头的文件。 -## ±äÁ¿²Ù×÷ +## å�˜é‡�æ“�作 -- ¶ÔÒ»¸ö±äÁ¿¸³ÖµÖ±½ÓʹÓà = £» -- ¶Ô±äÁ¿È¡ÓÃÐèÒªÔÚ±äÁ¿Ç°¼ÓÉÏ \$ £¬Ò²¿ÉÒÔÓà \${} µÄÐÎʽ£» -- Êä³ö±äÁ¿Ê¹Óà echo ÃüÁî¡£ +- 对一个å�˜é‡�赋值直接使用 = ï¼› +- 对å�˜é‡�å�–用需è¦�在å�˜é‡�å‰�加上 \{} 的形å¼�ï¼› +- 输出å�˜é‡�使用 echo 命令。 ```bash $ var=abc @@ -723,24 +724,24 @@ $ echo $var $ echo ${var} ``` -±äÁ¿ÄÚÈÝÈç¹ûÓпոñ£¬ÐèҪʹÓÃË«ÒýºÅ»òÕßµ¥ÒýºÅ¡£Ë«ÒýºÅÄÚµÄÌØÊâ×Ö·û¿ÉÒÔ±£ÁôÔ­±¾ÌØÐÔ£¬ÀýÈçvar="lang is \$LANG"£¬Ôò var µÄֵΪ lang is zh_TW.UTF-8£»¶øµ¥ÒýºÅÄÚµÄÌØÊâ×Ö·û¾ÍÊÇÌØÊâ×Ö·û±¾Éí£¬ÀýÈç var='lang is \$LANG'£¬Ôò var µÄֵΪ lang is \$LANG¡£ +å�˜é‡�内容如果有空格,需è¦�使用å�Œå¼•å�·æˆ–者å�•引å�·ã€‚å�Œå¼•å�·å†…的特殊字符å�¯ä»¥ä¿�留原本特性,例如var="lang is \(uname -r),则 version 的值为 3.10.0-229.el7.x86_64。 -¿ÉÒÔʹÓà export ÃüÁ×Ô¶¨Òå±äÁ¿×ª³É»·¾³±äÁ¿£¬»·¾³±äÁ¿¿ÉÒÔÔÚ×Ó³ÌÐòÖÐʹÓã¬Ëùν×Ó³ÌÐò¾ÍÊÇÓɵ±Ç° Bash ¶ø²úÉúµÄ×Ó Bash¡£ +å�¯ä»¥ä½¿ç”¨ export 命令将自定义å�˜é‡�转æˆ�环境å�˜é‡�,环境å�˜é‡�å�¯ä»¥åœ¨å­�程åº�中使用,所谓å­�程åº�就是由当å‰� Bash 而产生的å­� Bash。 -Bash µÄ±äÁ¿¿ÉÒÔÉùÃ÷ΪÊý×éºÍÕûÊýÊý×Ö¡£×¢ÒâÊý×ÖÀàÐÍûÓи¡µãÊý¡£Èç¹û²»½øÐÐÉùÃ÷£¬Ä¬ÈÏÊÇ×Ö·û´®ÀàÐÍ¡£±äÁ¿µÄÉùÃ÷ʹÓà declare ÃüÁ +Bash çš„å�˜é‡�å�¯ä»¥å£°æ˜Žä¸ºæ•°ç»„和整数数字。注æ„�数字类型没有浮点数。如果ä¸�进行声明,默认是字符串类型。å�˜é‡�的声明使用 declare 命令: ```html $ declare [-aixr] variable --a £º ¶¨ÒåΪÊý×éÀàÐÍ --i £º ¶¨ÒåΪÕûÊýÀàÐÍ --x £º ¶¨ÒåΪ»·¾³±äÁ¿ --r £º ¶¨ÒåΪreadonlyÀàÐÍ +-a : 定义为数组类型 +-i : 定义为整数类型 +-x : 定义为环境å�˜é‡� +-r : 定义为readonly类型 ``` -ʹÓà [ ] À´¶ÔÊý×é½øÐвÙ×÷£º +使用 [ ] æ�¥å¯¹æ•°ç»„进行æ“�作: ```bash $ array[1]=a @@ -748,54 +749,54 @@ $ array[2]=b $ echo ${array[1]} ``` -## Ö¸ÁîËÑË÷˳Ðò +## 指令æ�œç´¢é¡ºåº� -1. ÒÔ¾ø¶Ô»òÏà¶Ô·¾¶À´Ö´ÐÐÖ¸ÁÀýÈç /bin/ls »òÕß ./ls £» -2. ÓɱðÃûÕÒµ½¸ÃÖ¸ÁîÀ´Ö´ÐУ» -3. ÓÉ Bash ÄÚ½¨µÄÖ¸ÁîÀ´Ö´ÐУ» -4. °´ \$PATH ±äÁ¿Ö¸¶¨µÄËÑË÷·¾¶µÄ˳ÐòÕÒµ½µÚÒ»¸öÖ¸ÁîÀ´Ö´ÐС£ +1. 以ç»�对或相对路径æ�¥æ‰§è¡ŒæŒ‡ä»¤ï¼Œä¾‹å¦‚ /bin/ls 或者 ./ls ï¼› +2. 由别å��找到该指令æ�¥æ‰§è¡Œï¼› +3. ç”± Bash 内建的指令æ�¥æ‰§è¡Œï¼› +4. 按 \$PATH å�˜é‡�指定的æ�œç´¢è·¯å¾„的顺åº�找到第一个指令æ�¥æ‰§è¡Œã€‚ -## Êý¾ÝÁ÷ÖØ¶¨Ïò +## æ•°æ�®æµ�é‡�定å�‘ -ÖØ¶¨Ïò¾ÍÊÇʹÓÃÎļþ´úÌæ±ê×¼ÊäÈë¡¢±ê×¼Êä³öºÍ±ê×¼´íÎóÊä³ö¡£ +é‡�定å�‘就是使用文件代替标准输入ã€�标准输出和标准错误输出。 -1. ±ê×¼ÊäÈë(stdin)       £º´úÂëΪ 0 £¬Ê¹Óà < »ò << £» -2. ±ê×¼Êä³ö(stdout)     £º´úÂëΪ 1 £¬Ê¹Óà > »ò >> £» -3. ±ê×¼´íÎóÊä³ö(stderr)£º´úÂëΪ 2 £¬Ê¹Óà 2> »ò 2>> £» +1. 标准输入(stdin)       ï¼šä»£ç �为 0 ,使用 < 或 << ï¼› +2. 标准输出(stdout)     ï¼šä»£ç �为 1 ,使用 > 或 >> ï¼› +3. 标准错误输出(stderr):代ç �为 2 ,使用 2> 或 2>> ï¼› -ÆäÖУ¬ÓÐÒ»¸ö¼ýÍ·µÄ±íʾÒÔ¸²¸ÇµÄ·½Ê½Öض¨Ïò£¬¶øÓÐÁ½¸ö¼ýÍ·µÄ±íʾÒÔ×·¼ÓµÄ·½Ê½Öض¨Ïò¡£ +其中,有一个箭头的表示以覆盖的方å¼�é‡�定å�‘,而有两个箭头的表示以追加的方å¼�é‡�定å�‘。 -¿ÉÒÔ½«²»ÐèÒªµÄ±ê×¼Êä³öÒÔ¼°±ê×¼´íÎóÊä³öÖØ¶¨Ïòµ½ /dev/null£¬Ï൱ÓÚÈÓ½øÀ¬»øÏä¡£ +å�¯ä»¥å°†ä¸�需è¦�的标准输出以å�Šæ ‡å‡†é”™è¯¯è¾“出é‡�定å�‘到 /dev/null,相当于扔进垃圾箱。 -Èç¹ûÐèÒª½«±ê×¼Êä³öÒÔ¼°±ê×¼´íÎóÊä³öÍ¬Ê±ÖØ¶¨Ïòµ½Ò»¸öÎļþ£¬ÐèÒª½«Ä³¸öÊä³öת»»ÎªÁíÒ»¸öÊä³ö£¬ÀýÈç 2>&1 ±íʾ½«±ê×¼´íÎóÊä³öת»»Îª±ê×¼Êä³ö¡£ +如果需è¦�将标准输出以å�Šæ ‡å‡†é”™è¯¯è¾“出å�Œæ—¶é‡�定å�‘到一个文件,需è¦�å°†æŸ�个输出转æ�¢ä¸ºå�¦ä¸€ä¸ªè¾“出,例如 2>&1 表示将标准错误输出转æ�¢ä¸ºæ ‡å‡†è¾“出。 ```bash $ find /home -name .bashrc > list 2>&1 ``` -## ¹ÜÏßÖ¸Áî +## 管线指令 -¹ÜÏßÊǽ«Ò»¸öÃüÁîµÄ±ê×¼Êä³ö×÷ΪÁíÒ»¸öÃüÁîµÄ±ê×¼ÊäÈ룬ÔÚÊý¾ÝÐèÒª¾­¹ý¶à¸ö²½ÖèµÄ´¦ÀíÖ®ºó²ÅÄܵõ½ÎÒÃÇÏëÒªµÄ¸ñʽʱ¾Í¿ÉÒÔʹÓùÜÏß¡£ÔÚÃüÁîÖ®¼äʹÓà | ·Ö¸ô¸÷¸ö¹ÜÏßÃüÁî¡£ +管线是将一个命令的标准输出作为å�¦ä¸€ä¸ªå‘½ä»¤çš„æ ‡å‡†è¾“入,在数æ�®éœ€è¦�ç»�过多个步骤的处ç�†ä¹‹å�Žæ‰�能得到我们想è¦�的格å¼�æ—¶å°±å�¯ä»¥ä½¿ç”¨ç®¡çº¿ã€‚在命令之间使用 | 分隔å�„个管线命令。 ```bash $ ls -al /etc | less ``` -### 1. ÌáȡָÁcut +### 1. æ��å�–指令:cut -ÌáÈ¡¹ý³ÌÒ»ÐÐÒ»ÐеؽøÐС£ +æ��å�–过程一行一行地进行。 -cut ¶ÔÊý¾Ý½øÐÐÇз֣¬È¡³öÏëÒªµÄ²¿·Ö¡£ +cut 对数æ�®è¿›è¡Œåˆ‡åˆ†ï¼Œå�–出想è¦�的部分。 ```html $ cut --d £º·Ö¸ô·û --f £º¾­¹ý -d ·Ö¸ôºó£¬Ê¹Óà -f n È¡³öµÚ n ¸öÇø¼ä --c £ºÒÔ×Ö·ûΪµ¥Î»È¡³öÇø¼ä +-d :分隔符 +-f :ç»�过 -d 分隔å�Žï¼Œä½¿ç”¨ -f n å�–出第 n 个区间 +-c :以字符为å�•ä½�å�–出区间 ``` -·¶Àý 1£ºlast ½«ÏÔʾµÄµÇÈëÕßµÄÐÅÏ¢£¬ÒªÇó½öÏÔʾÓû§Ãû¡£ +范例 1:last 将显示的登入者的信æ�¯ï¼Œè¦�求仅显示用户å��。 ```html $ last @@ -806,7 +807,7 @@ root pts/1 192.168.201.254 Thu Feb 5 22:37 - 23:53 (01:16) $ last | cut -d ' ' -f 1 ``` -·¶Àý 2£º½« export Êä³öµÄѶϢ£¬È¡µÃµÚ 12 ×Ö·ûÒÔºóµÄËùÓÐ×Ö·û´®¡£ +范例 2:将 export 输出的讯æ�¯ï¼Œå�–得第 12 字符以å�Žçš„æ‰€æœ‰å­—符串。 ```html $ export @@ -814,28 +815,28 @@ declare -x HISTCONTROL="ignoredups" declare -x HISTSIZE="1000" declare -x HOME="/home/dmtsai" declare -x HOSTNAME="study.centos.vbird" -.....(ÆäËûÊ¡ÂÔ)..... +.....(å…¶ä»–çœ�ç•¥)..... $ export | cut -c 12 ``` -### 2. ÅÅÐòÃüÁsort¡¢uniq +### 2. 排åº�命令:sortã€�uniq -**sort** ½øÐÐÅÅÐò¡£ +**sort** 进行排åº�。 ```html $ sort [-fbMnrtuk] [file or stdin] --f £ººöÂÔ´óСд --b £ººöÂÔ×îÇ°ÃæµÄ¿Õ¸ñ --M £ºÒÔÔ·ݵÄÃû×ÖÀ´ÅÅÐò£¬ÀýÈç JAN£¬DEC --n £ºÊ¹ÓÃÊý×Ö --r £º·´ÏòÅÅÐò --u £ºÏ൱ÓÚ unique£¬Öظ´µÄÄÚÈÝÖ»³öÏÖÒ»´Î --t £º·Ö¸ô·û£¬Ä¬ÈÏΪ tab --k £ºÖ¸¶¨ÅÅÐòµÄÇø¼ä +-f :忽略大å°�写 +-b :忽略最å‰�é�¢çš„空格 +-M :以月份的å��å­—æ�¥æŽ’åº�,例如 JAN,DEC +-n :使用数字 +-r :å��å�‘排åº� +-u :相当于 unique,é‡�å¤�的内容å�ªå‡ºçŽ°ä¸€æ¬¡ +-t :分隔符,默认为 tab +-k :指定排åº�的区间 ``` -·¶Àý£º/etc/passwd ÄÚÈÝÊÇÒÔ : À´·Ö¸ôµÄ£¬ÒÔµÚÈýÀ¸À´ÅÅÐò¡£ +范例:/etc/passwd 内容是以 : æ�¥åˆ†éš”的,以第三æ �æ�¥æŽ’åº�。 ```html $ cat /etc/passwd | sort -t ':' -k 3 @@ -845,15 +846,15 @@ alex:x:1001:1002::/home/alex:/bin/bash arod:x:1002:1003::/home/arod:/bin/bash ``` -**uniq** ¿ÉÒÔ½«Öظ´µÄÊý¾Ýֻȡһ¸ö¡£ +**uniq** å�¯ä»¥å°†é‡�å¤�的数æ�®å�ªå�–一个。 ```html $ uniq [-ic] --i £ººöÂÔ´óСд --c £º½øÐмÆÊý +-i :忽略大å°�写 +-c :进行计数 ``` -·¶Àý£ºÈ¡µÃÿ¸öÈ˵ĵǼ×Ü´ÎÊý +范例:å�–å¾—æ¯�个人的登录总次数 ```html $ last | cut -d ' ' -f 1 | sort | uniq -c @@ -865,88 +866,88 @@ $ last | cut -d ' ' -f 1 | sort | uniq -c 1 wtmp ``` -### 3. Ë«ÏòÊä³öÖØ¶¨Ïò£ºtee +### 3. å�Œå�‘输出é‡�定å�‘:tee -Êä³öÖØ¶¨Ïò»á½«Êä³öÄÚÈÝÖØ¶¨Ïòµ½ÎļþÖУ¬¶ø **tee** ²»½öÄܹ»Íê³ÉÕâ¸ö¹¦ÄÜ£¬»¹Äܱ£ÁôÆÁÄ»ÉϵÄÊä³ö¡£Ò²¾ÍÊÇ˵£¬Ê¹Óà tee Ö¸Áһ¸öÊä³ö»áͬʱ´«Ë͵½ÎļþºÍÆÁÄ»ÉÏ¡£ +输出é‡�定å�‘会将输出内容é‡�定å�‘到文件中,而 **tee** ä¸�仅能够完æˆ�这个功能,还能ä¿�ç•™å±�幕上的输出。也就是说,使用 tee 指令,一个输出会å�Œæ—¶ä¼ é€�到文件和å±�幕上。 ```html $ tee [-a] file ``` -### 4. ×Ö·ûת»»Ö¸Átr¡¢col¡¢expand¡¢join¡¢paste +### 4. 字符转æ�¢æŒ‡ä»¤ï¼štrã€�colã€�expandã€�joinã€�paste - **tr** ÓÃÀ´É¾³ýÒ»ÐÐÖеÄ×Ö·û£¬»òÕß¶Ô×Ö·û½øÐÐÌæ»»¡£ + **tr** 用æ�¥åˆ é™¤ä¸€è¡Œä¸­çš„字符,或者对字符进行替æ�¢ã€‚ ```html $ tr [-ds] SET1 ... --d £º ɾ³ýÐÐÖÐ SET1 Õâ¸ö×Ö·û´® +-d : 删除行中 SET1 这个字符串 ``` -·¶Àý£¬½« last Êä³öµÄÐÅÏ¢ËùÓÐСдת»»Îª´óд¡£ +范例,将 last 输出的信æ�¯æ‰€æœ‰å°�写转æ�¢ä¸ºå¤§å†™ã€‚ ```html $ last | tr '[a-z]' '[A-Z]' ``` - **col** ½« tab ×Ö·ûתΪ¿Õ¸ñ×Ö·û¡£ + **col** å°† tab 字符转为空格字符。 ```html $ col [-xb] --x £º ½« tab ¼üת»»³É¶ÔµÈµÄ¿Õ¸ñ¼ü +-x : å°† tab 键转æ�¢æˆ�对等的空格键 ``` -**expand** ½« tab ת»»Ò»¶¨ÊýÁ¿µÄ¿Õ¸ñ£¬Ä¬ÈÏÊÇ 8 ¸ö¡£ +**expand** å°† tab 转æ�¢ä¸€å®šæ•°é‡�的空格,默认是 8 个。 ```html $ expand [-t] file --t £ºtab תΪ¿Õ¸ñµÄÊýÁ¿ +-t :tab 转为空格的数é‡� ``` -**join** ½«ÓÐÏàͬÊý¾ÝµÄÄÇÒ»Ðкϲ¢ÔÚÒ»Æð¡£ +**join** 将有相å�Œæ•°æ�®çš„那一行å�ˆå¹¶åœ¨ä¸€èµ·ã€‚ ```html $ join [-ti12] file1 file2 --t £º·Ö¸ô·û£¬Ä¬ÈÏΪ¿Õ¸ñ --i £ººöÂÔ´óСдµÄ²îÒì --1 £ºµÚÒ»¸öÎļþËùÓõıȽÏ×Ö¶Î --2 £ºµÚ¶þ¸öÎļþËùÓõıȽÏ×Ö¶Î +-t :分隔符,默认为空格 +-i :忽略大å°�写的差异 +-1 :第一个文件所用的比较字段 +-2 :第二个文件所用的比较字段 ``` -**paste** Ö±½Ó½«Á½ÐÐÕ³ÌùÔÚÒ»Æð¡£ +**paste** 直接将两行粘贴在一起。 ```html $ paste [-d] file1 file2 --d £º·Ö¸ô·û£¬Ä¬ÈÏΪ tab +-d :分隔符,默认为 tab ``` -### 5. ·ÖÇøÖ¸Ásplit +### 5. 分区指令:split -**split** ½«Ò»¸öÎļþ»®·Ö³É¶à¸öÎļþ¡£ +**split** 将一个文件划分æˆ�多个文件。 ```html $ split [-bl] file PREFIX --b £ºÒÔ´óСÀ´½øÐзÖÇø£¬¿É¼Óµ¥Î»£¬ÀýÈç b, k, m µÈ --l £ºÒÔÐÐÊýÀ´½øÐзÖÇø¡£ -- PREFIX £º·ÖÇøÎļþµÄǰµ¼Ãû³Æ +-b :以大å°�æ�¥è¿›è¡Œåˆ†åŒºï¼Œå�¯åŠ å�•ä½�,例如 b, k, m ç­‰ +-l :以行数æ�¥è¿›è¡Œåˆ†åŒºã€‚ +- PREFIX :分区文件的å‰�导å��ç§° ``` -# Õý¹æ±íʾ·¨ÓëÎļþ¸ñʽ»¯´¦Àí +# 正规表示法与文件格å¼�化处ç�† ## grep -ʹÓÃÕýÔò±íʾʽ°ÑÆ¥ÅäµÄÐÐÌáÈ¡³öÀ´¡£ +使用正则表示å¼�把匹é…�的行æ��å�–出æ�¥ã€‚ ```html -$ grep [-acinv] [--color=auto] ËÑѰ×Ö·û´® filename --a £º ½« binary ÎļþÒÔ text ÎļþµÄ·½Ê½½øÐÐËÑѰ --c £º ¼ÆËãÕÒµ½¸öÊý --i £º ºöÂÔ´óСд --n £º Êä³öÐкŠ--v £º ·´ÏòÑ¡Ôñ£¬Ò༴ÏÔʾ³öûÓÐ ËÑѰ×Ö·û´® ÄÚÈݵÄÄÇÒ»ÐÐ ---color=auto £ºÕÒµ½µÄ¹Ø¼ü×Ö¼ÓÑÕÉ«ÏÔʾ +$ grep [-acinv] [--color=auto] æ�œå¯»å­—符串 filename +-a : å°† binary 文件以 text 文件的方å¼�进行æ�œå¯» +-c : 计算找到个数 +-i : 忽略大å°�写 +-n : 输出行å�· +-v : å��å�‘选择,亦å�³æ˜¾ç¤ºå‡ºæ²¡æœ‰ æ�œå¯»å­—符串 内容的那一行 +--color=auto :找到的关键字加颜色显示 ``` -·¶Àý£º°Ñº¬ÓÐ the ×Ö·û´®µÄÐÐÌáÈ¡³öÀ´£¨×¢ÒâĬÈÏ»áÓÐ --color=auto Ñ¡ÏÒò´ËÒÔÏÂÄÚÈÝÔÚ Linux ÖÐÓÐÑÕÉ«ÏÔʾ the ×Ö·û´®£© +范例:把å�«æœ‰ the 字符串的行æ��å�–出æ�¥ï¼ˆæ³¨æ„�默认会有 --color=auto 选项,因此以下内容在 Linux 中有颜色显示 the 字符串) ```html $ grep -n 'the' regular_express.txt @@ -957,7 +958,7 @@ $ grep -n 'the' regular_express.txt 18:google is the best tools for search keyword ``` -ÒòΪ { Óë } µÄ·ûºÅÔÚ shell ÊÇÓÐÌØÊâÒâÒåµÄ£¬Òò´Ë±ØÐëҪʹÓÃʹÓÃתÒå×Ö·û½øÐÐתÒå¡£ +因为 { 与 } 的符å�·åœ¨ shell 是有特殊æ„�义的,因此必须è¦�使用使用转义字符进行转义。 ```html $ grep -n 'go\{2,5\}g' regular_express.txt @@ -965,9 +966,9 @@ $ grep -n 'go\{2,5\}g' regular_express.txt ## printf -ÓÃÓÚ¸ñʽ»¯Êä³ö¡£ +用于格å¼�化输出。 -Ëü²»ÊôÓڹܵÀÃüÁÔÚ¸ø printf ´«Êý¾ÝʱÐèҪʹÓà $( ) ÐÎʽ¡£ +它ä¸�属于管é�“命令,在给 printf ä¼ æ•°æ�®æ—¶éœ€è¦�使用 $( ) å½¢å¼�。 ```html $ printf '%10s %5i %5i %5i %8.2f \n' $(cat printf.txt) @@ -979,12 +980,12 @@ $ printf '%10s %5i %5i %5i %8.2f \n' $(cat printf.txt) ## awk ```html -$ awk 'Ìõ¼þÀàÐÍ1{¶¯×÷1} Ìõ¼þÀàÐÍ2{¶¯×÷2} ...' filename +$ awk 'æ�¡ä»¶ç±»åž‹1{动作1} æ�¡ä»¶ç±»åž‹2{动作2} ...' filename ``` -awk ÿ´Î´¦ÀíÒ»ÐУ¬´¦ÀíµÄ×îСµ¥Î»ÊÇ×ֶΣ¬Ã¿¸ö×ֶεÄÃüÃû·½Ê½Îª£º\$n£¬n Ϊ×ֶκţ¬´Ó 1 ¿ªÊ¼£¬\$0 ±íʾһÕûÐС£ +awk æ¯�次处ç�†ä¸€è¡Œï¼Œå¤„ç�†çš„æœ€å°�å�•ä½�是字段,æ¯�个字段的命å��æ–¹å¼�为:\0 表示一整行。 -·¶Àý 1£ºÈ¡³öµÇ¼Óû§µÄÓû§ÃûºÍ ip +范例 1:å�–出登录用户的用户å��å’Œ ip ```html $ last -n 5 @@ -997,15 +998,15 @@ dmtsai tty1 Fri May 29 11:55 - 12:11 (00:15) $ last -n 5 | awk '{print $1 "\t" $3} ``` -awk ±äÁ¿£º +awk å�˜é‡�: -| ±äÁ¿Ãû³Æ | ´ú±íÒâÒå | +| å�˜é‡�å��ç§° | 代表æ„�义 | | -- | -- | -| NF | ÿһÐÐÓµÓеÄ×Ö¶Î×ÜÊý | -| NR | ĿǰËù´¦ÀíµÄÊǵڼ¸ÐÐÊý¾Ý | -| FS | ĿǰµÄ·Ö¸ô×Ö·û£¬Ä¬ÈÏÊǿոñ¼ü | +| NF | æ¯�一行拥有的字段总数 | +| NR | ç›®å‰�所处ç�†çš„æ˜¯ç¬¬å‡ è¡Œæ•°æ�® | +| FS | ç›®å‰�的分隔字符,默认是空格键 | -·¶Àý 2£ºÊä³öÕýÔÚ´¦ÀíµÄÐкţ¬²¢ÏÔʾÿһÐÐÓжàÉÙ×Ö¶Î +范例 2:输出正在处ç�†çš„行å�·ï¼Œå¹¶æ˜¾ç¤ºæ¯�一行有多少字段 ```html $ last -n 5 | awk '{print $1 "\t lines: " NR "\t columns: " NF}' @@ -1016,9 +1017,9 @@ dmtsai lines: 4 columns: 10 dmtsai lines: 5 columns: 9 ``` -¿ÉÒÔʹÓôóÓÚµÈÓÚÂß¼­£¬ÆäÖеÈÓÚʹÓà ==¡£ +å�¯ä»¥ä½¿ç”¨å¤§äºŽç­‰äºŽé€»è¾‘,其中等于使用 ==。 -·¶Àý 3£º/etc/passwd ÎļþµÚÈý¸ö×Ö¶ÎΪ UID£¬¶Ô UID СÓÚ 10 µÄÊý¾Ý½øÐд¦Àí¡£ +范例 3:/etc/passwd 文件第三个字段为 UID,对 UID å°�于 10 的数æ�®è¿›è¡Œå¤„ç�†ã€‚ ```text cat /etc/passwd | awk 'BEGIN {FS=":"} $3 < 10 {print $1 "\t " $3}' @@ -1027,24 +1028,24 @@ bin 1 daemon 2 ``` -# vim Èý¸öģʽ +# vim 三个模å¼� -![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/341c632a-1fc1-4068-9b9f-bf7ef68ebb4c.jpg) +![](https://github.com/CyC2018/InterviewNotes/blob/master/pics//341c632a-1fc1-4068-9b9f-bf7ef68ebb4c.jpg) -ÔÚÖ¸ÁîÁÐģʽÏ£¬ÓÐÒÔÏÂÃüÁîÓÃÓÚÀ뿪»òÕß´æ´¢Îļþ¡£ +在指令列模å¼�下,有以下命令用于离开或者存储文件。 -| ÃüÁî | ×÷Óà | +| 命令 | 作用 | | -- | -- | -| :w | дÈë´ÅÅÌ| -| :w! | µ±ÎļþΪֻ¶Áʱ£¬Ç¿ÖÆÐ´Èë´ÅÅÌ¡£µ½µ×Äܲ»ÄÜдÈ룬ÓëÓû§¶Ô¸ÃÎļþµÄȨÏÞÓÐ¹Ø | -| :q | À뿪| -| :q! | Ç¿ÖÆÀ뿪²»±£´æ| -| :wq | дÈë´ÅÅ̺óÀ뿪| -| :wq!| Ç¿ÖÆÐ´Èë´ÅÅ̺óÀ뿪| +| :w | 写入ç£�盘| +| :w! | 当文件为å�ªè¯»æ—¶ï¼Œå¼ºåˆ¶å†™å…¥ç£�盘。到底能ä¸�能写入,与用户对该文件的æ�ƒé™�有关 | +| :q | 离开| +| :q! | 强制离开ä¸�ä¿�å­˜| +| :wq | 写入ç£�盘å�Žç¦»å¼€| +| :wq!| 强制写入ç£�盘å�Žç¦»å¼€| -# ²Î¿¼×ÊÁÏ +# å�‚考资料 -- Äñ¸ç. Äñ ¸ç µÄ Linux ˽ ·¿ ²Ë »ù ´¡ ƪ µÚ Èý °æ[J]. 2009. -- [Linux ƽ̨ÉϵÄÈí¼þ°ü¹ÜÀí](https://www.ibm.com/developerworks/cn/linux/l-cn-rpmdpkg/index.html) +- 鸟哥. 鸟 å“¥ çš„ Linux ç§� 房 è�œ 基 ç¡€ 篇 第 三 版[J]. 2009. +- [Linux å¹³å�°ä¸Šçš„软件包管ç�†](https://www.ibm.com/developerworks/cn/linux/l-cn-rpmdpkg/index.html) diff --git a/notes/MySQL.md b/notes/MySQL.md index 4a86f910..e7feb5e2 100644 --- a/notes/MySQL.md +++ b/notes/MySQL.md @@ -1,226 +1,227 @@ -* [´æ´¢ÒýÇæ](#´æ´¢ÒýÇæ) +* [存储引擎](#存储引擎) * [1. InnoDB](#1-innodb) * [2. MyISAM](#2-myisam) - * [3. InnoDB Óë MyISAM µÄ±È½Ï](#3-innodb-Óë-myisam-µÄ±È½Ï) -* [Êý¾ÝÀàÐÍ](#Êý¾ÝÀàÐÍ) - * [1. ÕûÐÍ](#1-ÕûÐÍ) - * [2. ¸¡µãÊý](#2-¸¡µãÊý) - * [3. ×Ö·û´®](#3-×Ö·û´®) - * [4. ʱ¼äºÍÈÕÆÚ](#4-ʱ¼äºÍÈÕÆÚ) -* [Ë÷Òý](#Ë÷Òý) - * [1. Ë÷Òý·ÖÀà](#1-Ë÷Òý·ÖÀà) - * [1.1 B-Tree Ë÷Òý](#11-b-tree-Ë÷Òý) - * [1.2 ¹þÏ£Ë÷Òý](#12-¹þÏ£Ë÷Òý) - * [1.3. ¿Õ¼äË÷ÒýÊý¾Ý£¨R-Tree£©](#13-¿Õ¼äË÷ÒýÊý¾Ýr-tree) - * [1.4 È«ÎÄË÷Òý](#14-È«ÎÄË÷Òý) - * [2. Ë÷ÒýµÄÓŵã](#2-Ë÷ÒýµÄÓŵã) - * [3. Ë÷ÒýÓÅ»¯](#3-Ë÷ÒýÓÅ»¯) - * [3.1 ¶ÀÁ¢µÄÁÐ](#31-¶ÀÁ¢µÄÁÐ) - * [3.2 ǰ׺Ë÷Òý](#32-ǰ׺Ë÷Òý) - * [3.3 ¶àÁÐË÷Òý](#33-¶àÁÐË÷Òý) - * [3.4 Ë÷ÒýÁеÄ˳Ðò](#34-Ë÷ÒýÁеÄ˳Ðò) - * [3.5 ¾Û´ØË÷Òý](#35-¾Û´ØË÷Òý) - * [3.6 ¸²¸ÇË÷Òý](#36-¸²¸ÇË÷Òý) - * [4. B-Tree ºÍ B+Tree Ô­Àí](#4-b-tree-ºÍ-b+tree-Ô­Àí) + * [3. InnoDB 与 MyISAM 的比较](#3-innodb-与-myisam-的比较) +* [æ•°æ�®ç±»åž‹](#æ•°æ�®ç±»åž‹) + * [1. æ•´åž‹](#1-æ•´åž‹) + * [2. 浮点数](#2-浮点数) + * [3. 字符串](#3-字符串) + * [4. 时间和日期](#4-时间和日期) +* [索引](#索引) + * [1. 索引分类](#1-索引分类) + * [1.1 B-Tree 索引](#11-b-tree-索引) + * [1.2 哈希索引](#12-哈希索引) + * [1.3. 空间索引数æ�®ï¼ˆR-Tree)](#13-空间索引数æ�®r-tree) + * [1.4 全文索引](#14-全文索引) + * [2. 索引的优点](#2-索引的优点) + * [3. 索引优化](#3-索引优化) + * [3.1 独立的列](#31-独立的列) + * [3.2 å‰�缀索引](#32-å‰�缀索引) + * [3.3 多列索引](#33-多列索引) + * [3.4 索引列的顺åº�](#34-索引列的顺åº�) + * [3.5 è�šç°‡ç´¢å¼•](#35-è�šç°‡ç´¢å¼•) + * [3.6 覆盖索引](#36-覆盖索引) + * [4. B-Tree å’Œ B+Tree 原ç�†](#4-b-tree-å’Œ-b+tree-原ç�†) * [4. 1 B-Tree](#4-1-b-tree) * [4.2 B+Tree](#42-b+tree) - * [4.3 ´øÓÐ˳Ðò·ÃÎÊÖ¸ÕëµÄ B+Tree](#43-´øÓÐ˳Ðò·ÃÎÊÖ¸ÕëµÄ-b+tree) - * [4.4 ΪʲôʹÓà B-Tree ºÍ B+Tree](#44-ΪʲôʹÓÃ-b-tree-ºÍ-b+tree) -* [²éѯÐÔÄÜÓÅ»¯](#²éѯÐÔÄÜÓÅ»¯) + * [4.3 带有顺åº�访问指针的 B+Tree](#43-带有顺åº�访问指针的-b+tree) + * [4.4 为什么使用 B-Tree å’Œ B+Tree](#44-为什么使用-b-tree-å’Œ-b+tree) +* [查询性能优化](#查询性能优化) * [1. Explain](#1-explain) - * [2. ¼õÉÙ·µ»ØµÄÁÐ](#2-¼õÉÙ·µ»ØµÄÁÐ) - * [3. ¼õÉÙ·µ»ØµÄÐÐ](#3-¼õÉÙ·µ»ØµÄÐÐ) - * [4. ²ð·Ö´óµÄ DELETE »ò INSERT Óï¾ä](#4-²ð·Ö´óµÄ-delete-»ò-insert-Óï¾ä) -* [·Ö¿âÓë·Ö±í](#·Ö¿âÓë·Ö±í) -* [¹ÊÕÏ×ªÒÆºÍ¹ÊÕϻָ´](#¹ÊÕÏ×ªÒÆºÍ¹ÊÕϻָ´) - * [1. ¹ÊÕÏ×ªÒÆ](#1-¹ÊÕÏ×ªÒÆ) - * [2. ¹ÊÕϻָ´](#2-¹ÊÕϻָ´) -* [²Î¿¼×ÊÁÏ](#²Î¿¼×ÊÁÏ) + * [2. å‡�少返回的列](#2-å‡�少返回的列) + * [3. å‡�少返回的行](#3-å‡�少返回的行) + * [4. 拆分大的 DELETE 或 INSERT 语å�¥](#4-拆分大的-delete-或-insert-语å�¥) +* [分库与分表](#分库与分表) +* [故障转移和故障æ�¢å¤�](#故障转移和故障æ�¢å¤�) + * [1. 故障转移](#1-故障转移) + * [2. æ•…éšœæ�¢å¤�](#2-æ•…éšœæ�¢å¤�) +* [å�‚考资料](#å�‚考资料) -# ´æ´¢ÒýÇæ + +# 存储引擎 ## 1. InnoDB -InnoDB ÊÇ MySQL µÄĬÈÏÊÂÎñÐÍÒýÇæ£¬Ö»ÓÐÔÚÐèÒª InnoDB ²»Ö§³ÖµÄÌØÐÔʱ£¬²Å¿¼ÂÇʹÓÃÆäËü´æ´¢ÒýÇæ¡£ +InnoDB 是 MySQL 的默认事务型引擎,å�ªæœ‰åœ¨éœ€è¦� InnoDB ä¸�支æŒ�的特性时,æ‰�考虑使用其它存储引擎。 -²ÉÓà MVCC À´Ö§³Ö¸ß²¢·¢£¬²¢ÇÒʵÏÖÁËËĸö±ê×¼µÄ¸ôÀë¼¶±ð£¬Ä¬Èϼ¶±ðÊÇ¿ÉÖØ¸´¶Á¡£ +采用 MVCC æ�¥æ”¯æŒ�高并å�‘,并且实现了四个标准的隔离级别,默认级别是å�¯é‡�å¤�读。 -±íÊÇ»ùÓÚ¾Û´ØË÷Òý½¨Á¢µÄ£¬Ëü¶ÔÖ÷¼üµÄ²éѯÐÔÄÜÓкܸߵÄÌáÉý¡£ +表是基于è�šç°‡ç´¢å¼•建立的,它对主键的查询性能有很高的æ��å�‡ã€‚ -ÄÚ²¿×öÁ˺ܶàÓÅ»¯£¬°üÀ¨´Ó´ÅÅ̶ÁÈ¡Êý¾Ýʱ²ÉÓõĿÉÔ¤²âÐÔ¶Á£¬Äܹ»×Ô¶¯ÔÚÄÚ´æÖд´½¨ hash Ë÷ÒýÒÔ¼ÓËÙ¶Á²Ù×÷µÄ×ÔÊÊÓ¦¹þÏ£Ë÷Òý£¬ÒÔ¼°Äܹ»¼ÓËÙ²åÈë²Ù×÷µÄ²åÈ뻺³åÇøµÈ¡£ +内部å�šäº†å¾ˆå¤šä¼˜åŒ–,包括从ç£�盘读å�–æ•°æ�®æ—¶é‡‡ç”¨çš„å�¯é¢„测性读,能够自动在内存中创建 hash 索引以加速读æ“�作的自适应哈希索引,以å�Šèƒ½å¤ŸåŠ é€Ÿæ�’å…¥æ“�作的æ�’入缓冲区等。 -ͨ¹ýһЩ»úÖÆºÍ¹¤¾ßÖ§³ÖÕæÕýµÄÈȱ¸·Ý¡£ +通过一些机制和工具支æŒ�真正的热备份。 ## 2. MyISAM -MyISAM ÌṩÁË´óÁ¿µÄÌØÐÔ£¬°üÀ¨È«ÎÄË÷Òý¡¢Ñ¹Ëõ¡¢¿Õ¼äº¯Êý£¨GIS£©µÈ¡£µ« MyISAM ²»Ö§³ÖÊÂÎñºÍÐм¶Ëø£¬¶øÇÒ±¼À£ºóÎÞ·¨°²È«»Ö¸´¡£ +MyISAM æ��供了大é‡�的特性,包括全文索引ã€�压缩ã€�空间函数(GIS)等。但 MyISAM ä¸�支æŒ�事务和行级é”�,而且奔溃å�Žæ— æ³•安全æ�¢å¤�。 -Ö»ÄܶÔÕûÕűí¼ÓËø£¬¶ø²»ÊÇÕë¶ÔÐС£ +å�ªèƒ½å¯¹æ•´å¼ è¡¨åŠ é”�,而ä¸�是针对行。 -¿ÉÒÔÊÖ¹¤»òÕß×Ô¶¯Ö´Ðмì²éºÍÐÞ¸´²Ù×÷£¬µ«ÊǺÍÊÂÎñ»Ö¸´ÒÔ¼°±¼À£»Ö¸´²»Í¬£¬¿ÉÄܵ¼ÖÂһЩÊý¾Ý¶ªÊ§£¬¶øÇÒÐÞ¸´²Ù×÷ÊǷdz£ÂýµÄ¡£ +å�¯ä»¥æ‰‹å·¥æˆ–者自动执行检查和修å¤�æ“�作,但是和事务æ�¢å¤�以å�Šå¥”溃æ�¢å¤�ä¸�å�Œï¼Œå�¯èƒ½å¯¼è‡´ä¸€äº›æ•°æ�®ä¸¢å¤±ï¼Œè€Œä¸”ä¿®å¤�æ“�作是é�žå¸¸æ…¢çš„。 -¿ÉÒÔ°üº¬¶¯Ì¬»òÕß¾²Ì¬µÄÐС£ +å�¯ä»¥åŒ…å�«åЍæ€�或者é�™æ€�的行。 -Èç¹ûÖ¸¶¨ÁË DELAY_KEY_WRITE Ñ¡ÏÔÚÿ´ÎÐÞ¸ÄÖ´ÐÐÍê³Éʱ£¬²»»áÁ¢¼´½«Ð޸ĵÄË÷ÒýÊý¾ÝдÈë´ÅÅÌ£¬¶øÊÇ»áдµ½ÄÚ´æÖеļü»º³åÇø£¬Ö»ÓÐÔÚÇåÀí¼ü»º³åÇø»òÕ߹رձíµÄʱºò²Å»á½«¶ÔÓ¦µÄË÷Òý¿éдÈë´ÅÅÌ¡£ÕâÖÖ·½Ê½¿ÉÒÔ¼«´óµÄÌáÉýдÈëÐÔÄÜ£¬µ«ÊÇÔÚÊý¾Ý¿â»òÕßÖ÷»ú±¼À£Ê±»áÔì³ÉË÷ÒýË𻵣¬ÐèÒªÖ´ÐÐÐÞ¸´²Ù×÷¡£ +如果指定了 DELAY_KEY_WRITE 选项,在æ¯�次修改执行完æˆ�时,ä¸�会立å�³å°†ä¿®æ”¹çš„索引数æ�®å†™å…¥ç£�盘,而是会写到内存中的键缓冲区,å�ªæœ‰åœ¨æ¸…ç�†é”®ç¼“冲区或者关闭表的时候æ‰�会将对应的索引å�—写入ç£�盘。这ç§�æ–¹å¼�å�¯ä»¥æž�大的æ��å�‡å†™å…¥æ€§èƒ½ï¼Œä½†æ˜¯åœ¨æ•°æ�®åº“或者主机奔溃时会造æˆ�索引æ�Ÿå��,需è¦�执行修å¤�æ“�作。 -Èç¹û±íÔÚ´´½¨²¢µ¼ÈëÊý¾ÝÒԺ󣬲»»áÔÙ½øÐÐÐ޸IJÙ×÷£¬ÄÇôÕâÑùµÄ±íÊʺϲÉÓà MyISAM ѹËõ±í¡£ +如果表在创建并导入数æ�®ä»¥å�Žï¼Œä¸�会å†�进行修改æ“�作,那么这样的表适å�ˆé‡‡ç”¨ MyISAM 压缩表。 -¶ÔÓÚÖ»¶ÁÊý¾Ý£¬»òÕß±í±È½ÏС¡¢¿ÉÒÔÈÝÈÌÐÞ¸´²Ù×÷£¬ÔòÒÀÈ»¿ÉÒÔ¼ÌÐøÊ¹Óà MyISAM¡£ +对于å�ªè¯»æ•°æ�®ï¼Œæˆ–者表比较å°�ã€�å�¯ä»¥å®¹å¿�ä¿®å¤�æ“�作,则ä¾�ç„¶å�¯ä»¥ç»§ç»­ä½¿ç”¨ MyISAM。 -MyISAM Éè¼Æ¼òµ¥£¬Êý¾ÝÒÔ½ôÃܸñʽ´æ´¢£¬ËùÒÔÔÚijЩ³¡¾°ÏÂÐÔÄܺܺᣠ+MyISAM 设计简å�•,数æ�®ä»¥ç´§å¯†æ ¼å¼�存储,所以在æŸ�些场景下性能很好。 -## 3. InnoDB Óë MyISAM µÄ±È½Ï +## 3. InnoDB 与 MyISAM 的比较 -**ÊÂÎñ** +**事务** -InnoDB ÊÇÊÂÎñÐ͵ġ£ +InnoDB 是事务型的。 -**±¸·Ý** +**备份** -InnoDB Ö§³ÖÔÚÏßÈȱ¸·Ý¡£ +InnoDB 支æŒ�在线热备份。 -**±¼À£»Ö¸´** +**奔溃æ�¢å¤�** -MyISAM ±¼À£ºó·¢ÉúË𻵵ĸÅÂÊ±È InnoDB ¸ßºÜ¶à£¬¶øÇÒ»Ö¸´µÄËÙ¶ÈÒ²¸üÂý¡£ +MyISAM 奔溃å�Žå�‘生æ�Ÿå��的概率比 InnoDB 高很多,而且æ�¢å¤�的速度也更慢。 -**²¢·¢** +**å¹¶å�‘** -MyISAM Ö»Ö§³Ö±í¼¶Ëø£¬¶ø InnoDB »¹Ö§³ÖÐм¶Ëø¡£ +MyISAM å�ªæ”¯æŒ�表级é”�,而 InnoDB 还支æŒ�行级é”�。 -**ÆäËüÌØÐÔ** +**其它特性** -MyISAM Ö§³ÖÈ«ÎÄË÷Òý£¬µØÀí¿Õ¼äË÷Òý£» +MyISAM 支æŒ�全文索引,地ç�†ç©ºé—´ç´¢å¼•ï¼› -# Êý¾ÝÀàÐÍ +# æ•°æ�®ç±»åž‹ -## 1. ÕûÐÍ +## 1. æ•´åž‹ -TINYINT, SMALLINT, MEDIUMINT, INT, BIGINT ·Ö±ðʹÓà 8, 16, 24, 64 λ´æ´¢¿Õ¼ä£¬Ò»°ãÇé¿öÏÂԽСµÄÁÐÔ½ºÃ¡£ +TINYINT, SMALLINT, MEDIUMINT, INT, BIGINT 分别使用 8, 16, 24, 64 ä½�存储空间,一般情况下越å°�的列越好。 -INT(11) ÖеÄÊý×ÖÖ»Êǹ涨Á˽»»¥¹¤¾ßÏÔʾ×Ö·ûµÄ¸öÊý£¬¶ÔÓÚ´æ´¢ºÍ¼ÆËãÀ´ËµÊÇûÓÐÒâÒåµÄ¡£ +INT(11) 中的数字å�ªæ˜¯è§„定了交互工具显示字符的个数,对于存储和计算æ�¥è¯´æ˜¯æ²¡æœ‰æ„�义的。 -## 2. ¸¡µãÊý +## 2. 浮点数 -FLOAT ºÍ DOUBLE Ϊ¸¡µãÀàÐÍ£¬DECIMAL Ϊ¸ß¾«¶ÈСÊýÀàÐÍ¡£CPU Ô­ÉúÖ§³Ö¸¡µãÔËË㣬µ«ÊDz»Ö§³Ö DECIMAl ÀàÐ͵ļÆË㣬Òò´Ë DECIMAL µÄ¼ÆËã±È¸¡µãÀàÐÍÐèÒª¸ü¸ßµÄ´ú¼Û¡£ +FLOAT å’Œ DOUBLE 为浮点类型,DECIMAL 为高精度å°�数类型。CPU 原生支æŒ�浮点è¿�算,但是ä¸�支æŒ� DECIMAl 类型的计算,因此 DECIMAL 的计算比浮点类型需è¦�更高的代价。 -FLOAT¡¢DOUBLE ºÍ DECIMAL ¶¼¿ÉÒÔÖ¸¶¨ÁÐ¿í£¬ÀýÈç DECIMAL(18, 9) ±íʾ×ܹ² 18 λ£¬È¡ 9 λ´æ´¢Ð¡Êý²¿·Ö£¬Ê£Ï 9 λ´æ´¢ÕûÊý²¿·Ö¡£ +FLOATã€�DOUBLE å’Œ DECIMAL 都å�¯ä»¥æŒ‡å®šåˆ—宽,例如 DECIMAL(18, 9) 表示总共 18 ä½�,å�– 9 ä½�存储å°�数部分,剩下 9 ä½�存储整数部分。 -## 3. ×Ö·û´® +## 3. 字符串 -Ö÷ÒªÓÐ CHAR ºÍ VARCHAR Á½ÖÖÀàÐÍ£¬Ò»ÖÖÊǶ¨³¤µÄ£¬Ò»ÖÖÊDZ䳤µÄ¡£ +主è¦�有 CHAR å’Œ VARCHAR 两ç§�类型,一ç§�是定长的,一ç§�是å�˜é•¿çš„。 -VARCHAR ÕâÖֱ䳤ÀàÐÍÄܹ»½ÚÊ¡¿Õ¼ä£¬ÒòΪֻÐèÒª´æ´¢±ØÒªµÄÄÚÈÝ¡£µ«ÊÇÔÚÖ´ÐÐ UPDATE ʱ¿ÉÄÜ»áʹÐбäµÃ±ÈÔ­À´³¤£¬µ±³¬³öÒ»¸öÒ³ËùÄÜÈÝÄɵĴóСʱ£¬¾ÍÒªÖ´ÐжîÍâµÄ²Ù×÷£¬MyISAM »á½«Ðвð³É²»Í¬µÄƬ¶Î´æ´¢£¬¶ø InnoDB ÔòÐèÒª·ÖÁÑÒ³À´Ê¹ÐзŽøÒ³ÄÚ¡£ +VARCHAR è¿™ç§�å�˜é•¿ç±»åž‹èƒ½å¤ŸèŠ‚çœ�空间,因为å�ªéœ€è¦�存储必è¦�的内容。但是在执行 UPDATE æ—¶å�¯èƒ½ä¼šä½¿è¡Œå�˜å¾—比原æ�¥é•¿ï¼Œå½“超出一个页所能容纳的大å°�时,就è¦�执行é¢�外的æ“�作,MyISAM 会将行拆æˆ�ä¸�å�Œçš„片段存储,而 InnoDB 则需è¦�分裂页æ�¥ä½¿è¡Œæ”¾è¿›é¡µå†…。 -VARCHAR »á±£Áô×Ö·û´®Ä©Î²µÄ¿Õ¸ñ£¬¶ø CHAR »áɾ³ý¡£ +VARCHAR 会ä¿�留字符串末尾的空格,而 CHAR 会删除。 -## 4. ʱ¼äºÍÈÕÆÚ +## 4. 时间和日期 -MySQL ÌṩÁËÁ½ÖÖÏàËÆµÄÈÕÆÚʱ¼äÀàÐÍ£ºDATATIME ºÍ TIMESTAMP¡£ +MySQL æ��供了两ç§�相似的日期时间类型:DATATIME å’Œ TIMESTAMP。 **DATATIME** -Äܹ»±£´æ´Ó 1001 Äêµ½ 9999 ÄêµÄÈÕÆÚºÍʱ¼ä£¬¾«¶ÈΪÃ룬ʹÓà 8 ×ֽڵĴ洢¿Õ¼ä¡£ +能够ä¿�存从 1001 年到 9999 年的日期和时间,精度为秒,使用 8 字节的存储空间。 -ËüÓëÊ±ÇøÎ޹ء£ +它与时区无关。 -ĬÈÏÇé¿öÏ£¬MySQL ÒÔÒ»ÖÖ¿ÉÅÅÐòµÄ¡¢ÎÞÆçÒåµÄ¸ñʽÏÔʾ DATATIME Öµ£¬ÀýÈç¡°2008-01016 22:37:08¡±£¬ÕâÊÇ ANSI ±ê×¼¶¨ÒåµÄÈÕÆÚºÍʱ¼ä±íʾ·½·¨¡£ +默认情况下,MySQL 以一ç§�å�¯æŽ’åº�çš„ã€�无歧义的格å¼�显示 DATATIME 值,例如“2008-01016 22:37:08â€�,这是 ANSI 标准定义的日期和时间表示方法。 **TIMESTAMP** -ºÍ UNIX ʱ¼ä´ÁÏàͬ£¬±£´æ´Ó 1970 Äê 1 Ô 1 ÈÕÎçÒ¹£¨¸ñÁÖÍþÖÎʱ¼ä£©ÒÔÀ´µÄÃëÊý£¬Ê¹Óà 4 ¸ö×Ö½Ú£¬Ö»Äܱíʾ´Ó 1970 Äê µ½ 2038 Äê¡£ +å’Œ UNIX 时间戳相å�Œï¼Œä¿�存从 1970 å¹´ 1 月 1 æ—¥å�ˆå¤œï¼ˆæ ¼æž—å¨�治时间)以æ�¥çš„秒数,使用 4 个字节,å�ªèƒ½è¡¨ç¤ºä»Ž 1970 å¹´ 到 2038 年。 -ËüºÍÊ±ÇøÓйء£ +它和时区有关。 -MySQL ÌṩÁË FROM_UNIXTIME() º¯Êý°Ñ Unxi ʱ¼ä´Áת»»ÎªÈÕÆÚ£¬²¢ÌṩÁË UNIX_TIMESTAMP() º¯Êý°ÑÈÕÆÚת»»Îª Unix ʱ¼ä´Á¡£ +MySQL æ��供了 FROM_UNIXTIME() 函数把 Unxi 时间戳转æ�¢ä¸ºæ—¥æœŸï¼Œå¹¶æ��供了 UNIX_TIMESTAMP() 函数把日期转æ�¢ä¸º Unix 时间戳。 -ĬÈÏÇé¿öÏ£¬Èç¹û²åÈëʱûÓÐÖ¸¶¨ TIMESTAMP ÁеÄÖµ£¬»á½«Õâ¸öÖµÉèÖÃΪµ±Ç°Ê±¼ä¡£ +默认情况下,如果æ�’入时没有指定 TIMESTAMP 列的值,会将这个值设置为当å‰�时间。 -Ó¦¸Ã¾¡Á¿Ê¹Óà TIMESTAMP£¬ÒòΪËü±È DATETIME ¿Õ¼äЧÂʸü¸ß¡£ +应该尽é‡�使用 TIMESTAMP,因为它比 DATETIME 空间效率更高。 -# Ë÷Òý +# 索引 -Ë÷ÒýÊÇÔÚ´æ´¢ÒýÇæ²ãʵÏֵ쬶ø²»ÊÇÔÚ·þÎñÆ÷²ãʵÏֵģ¬ËùÒÔ²»Í¬´æ´¢ÒýÇæ¾ßÓв»Í¬µÄË÷ÒýÀàÐͺÍʵÏÖ¡£ +索引是在存储引擎层实现的,而ä¸�是在æœ�务器层实现的,所以ä¸�å�Œå­˜å‚¨å¼•擎具有ä¸�å�Œçš„索引类型和实现。 -Ë÷ÒýÄܹ»ÇáÒ×½«²éѯÐÔÄÜÌáÉý¼¸¸öÊýÁ¿¼¶¡£ +索引能够轻易将查询性能æ��å�‡å‡ ä¸ªæ•°é‡�级。 -¶ÔÓڷdz£Ð¡µÄ±í¡¢´ó²¿·ÖÇé¿öϼòµ¥µÄÈ«±íɨÃè±È½¨Á¢Ë÷Òý¸ü¸ßЧ¡£¶ÔÓÚÖе½´óÐÍµÄ±í£¬Ë÷Òý¾Í·Ç³£ÓÐЧ¡£µ«ÊǶÔÓÚÌØ´óÐÍµÄ±í£¬½¨Á¢ºÍʹÓÃË÷ÒýµÄ´ú¼Û½«»áËæÖ®Ôö³¤¡£ÕâÖÖÇé¿öÏ£¬ÐèÒªÓõ½Ò»ÖÖ¼¼Êõ¿ÉÒÔÖ±½ÓÇø·Ö³öÐèÒª²éѯµÄÒ»×éÊý¾Ý£¬¶ø²»ÊÇÒ»Ìõ¼Ç¼һÌõ¼Ç¼µØÆ¥Å䣬ÀýÈç¿ÉÒÔʹÓ÷ÖÇø¼¼Êõ¡£ +对于é�žå¸¸å°�的表ã€�大部分情况下简å�•的全表扫æ��比建立索引更高效。对于中到大型的表,索引就é�žå¸¸æœ‰æ•ˆã€‚但是对于特大型的表,建立和使用索引的代价将会éš�之增长。这ç§�情况下,需è¦�用到一ç§�技术å�¯ä»¥ç›´æŽ¥åŒºåˆ†å‡ºéœ€è¦�查询的一组数æ�®ï¼Œè€Œä¸�是一æ�¡è®°å½•一æ�¡è®°å½•地匹é…�,例如å�¯ä»¥ä½¿ç”¨åˆ†åŒºæŠ€æœ¯ã€‚ -## 1. Ë÷Òý·ÖÀà +## 1. 索引分类 -### 1.1 B-Tree Ë÷Òý +### 1.1 B-Tree 索引 -B-Tree Ë÷ÒýÊÇ´ó¶àÊý MySQL ´æ´¢ÒýÇæµÄĬÈÏË÷ÒýÀàÐÍ¡£ +B-Tree 索引是大多数 MySQL 存储引擎的默认索引类型。 -ÒòΪ²»ÔÙÐèÒª½øÐÐÈ«±íɨÃ裬ֻÐèÒª¶ÔÊ÷½øÐÐËÑË÷¼´¿É£¬Òò´Ë²éÕÒËÙ¶È¿ìºÜ¶à¡£ +因为ä¸�å†�需è¦�进行全表扫æ��,å�ªéœ€è¦�对树进行æ�œç´¢å�³å�¯ï¼Œå› æ­¤æŸ¥æ‰¾é€Ÿåº¦å¿«å¾ˆå¤šã€‚ -¿ÉÒÔÖ¸¶¨¶à¸öÁÐ×÷ΪË÷ÒýÁУ¬¶à¸öË÷ÒýÁй²Í¬×é³É¼ü¡£B-Tree Ë÷ÒýÊÊÓÃÓÚÈ«¼üÖµ¡¢¼üÖµ·¶Î§ºÍ¼üǰ׺²éÕÒ£¬ÆäÖмüǰ׺²éÕÒÖ»ÊÊÓÃÓÚ×î×óǰ׺²éÕÒ¡£ +å�¯ä»¥æŒ‡å®šå¤šä¸ªåˆ—作为索引列,多个索引列共å�Œç»„æˆ�键。B-Tree 索引适用于全键值ã€�键值范围和键å‰�缀查找,其中键å‰�缀查找å�ªé€‚用于最左å‰�缀查找。 -³ýÁËÓÃÓÚ²éÕÒ£¬»¹¿ÉÒÔÓÃÓÚÅÅÐòºÍ·Ö×é¡£ +除了用于查找,还å�¯ä»¥ç”¨äºŽæŽ’åº�和分组。 -Èç¹û²»Êǰ´ÕÕË÷ÒýÁеÄ˳Ðò½øÐвéÕÒ£¬ÔòÎÞ·¨Ê¹ÓÃË÷Òý¡£ +如果ä¸�是按照索引列的顺åº�进行查找,则无法使用索引。 -### 1.2 ¹þÏ£Ë÷Òý +### 1.2 哈希索引 -»ùÓÚ¹þÏ£±íʵÏÖ£¬ÓŵãÊDzéÕҷdz£¿ì¡£ +基于哈希表实现,优点是查找é�žå¸¸å¿«ã€‚ -ÔÚ MySQL ÖÐÖ»ÓÐ Memory ÒýÇæÏÔʽ֧³Ö¹þÏ£Ë÷Òý¡£ +在 MySQL 中å�ªæœ‰ Memory 引擎显å¼�支æŒ�哈希索引。 -InnoDB ÒýÇæÓÐÒ»¸öÌØÊâµÄ¹¦ÄܽС°×ÔÊÊÓ¦¹þÏ£Ë÷Òý¡±£¬µ±Ä³¸öË÷ÒýÖµ±»Ê¹Óõķdz£Æµ·±Ê±£¬»áÔÚ B-Tree Ë÷ÒýÖ®ÉÏÔÙ´´½¨Ò»¸ö¹þÏ£Ë÷Òý£¬ÕâÑù¾ÍÈà B-Tree Ë÷Òý¾ßÓйþÏ£Ë÷ÒýµÄһЩÓŵ㣬±ÈÈç¿ìËٵĹþÏ£²éÕÒ¡£ +InnoDB 引擎有一个特殊的功能å�«â€œè‡ªé€‚应哈希索引â€�,当æŸ�个索引值被使用的é�žå¸¸é¢‘ç¹�时,会在 B-Tree 索引之上å†�创建一个哈希索引,这样就让 B-Tree 索引具有哈希索引的一些优点,比如快速的哈希查找。 -ÏÞÖÆ£º¹þÏ£Ë÷ÒýÖ»°üº¬¹þÏ£ÖµºÍÐÐÖ¸Õ룬¶ø²»´æ´¢×Ö¶ÎÖµ£¬ËùÒÔ²»ÄÜʹÓÃË÷ÒýÖеÄÖµÀ´±ÜÃâ¶ÁÈ¡ÐС£²»¹ý£¬·ÃÎÊÄÚ´æÖеÄÐеÄËٶȺܿ죬ËùÒԴ󲿷ÖÇé¿öÏÂÕâÒ»µã¶ÔÐÔÄÜÓ°Ïì²¢²»Ã÷ÏÔ£»ÎÞ·¨ÓÃÓÚ·Ö×éÓëÅÅÐò£»Ö»Ö§³Ö¾«È·²éÕÒ£¬ÎÞ·¨ÓÃÓÚ²¿·Ö²éÕҺͷ¶Î§²éÕÒ£»Èç¹û¹þÏ£³åÍ»ºÜ¶à£¬²éÕÒËÙ¶È»á±äµÃºÜÂý¡£ +é™�制:哈希索引å�ªåŒ…å�«å“ˆå¸Œå€¼å’Œè¡ŒæŒ‡é’ˆï¼Œè€Œä¸�存储字段值,所以ä¸�能使用索引中的值æ�¥é�¿å…�读å�–行。ä¸�过,访问内存中的行的速度很快,所以大部分情况下这一点对性能影å“�å¹¶ä¸�明显;无法用于分组与排åº�ï¼›å�ªæ”¯æŒ�精确查找,无法用于部分查找和范围查找;如果哈希冲çª�很多,查找速度会å�˜å¾—很慢。 -### 1.3. ¿Õ¼äË÷ÒýÊý¾Ý£¨R-Tree£© +### 1.3. 空间索引数æ�®ï¼ˆR-Tree) -MyISAM ´æ´¢ÒýÇæÖ§³Ö¿Õ¼äË÷Òý£¬¿ÉÒÔÓÃÓÚµØÀíÊý¾Ý´æ´¢¡£ +MyISAM 存储引擎支æŒ�空间索引,å�¯ä»¥ç”¨äºŽåœ°ç�†æ•°æ�®å­˜å‚¨ã€‚ -¿Õ¼äË÷Òý»á´ÓËùÓÐά¶ÈÀ´Ë÷ÒýÊý¾Ý£¬¿ÉÒÔÓÐЧµØÊ¹ÓÃÈÎÒâά¶ÈÀ´½øÐÐ×éºÏ²éѯ¡£ +空间索引会从所有维度æ�¥ç´¢å¼•æ•°æ�®ï¼Œå�¯ä»¥æœ‰æ•ˆåœ°ä½¿ç”¨ä»»æ„�维度æ�¥è¿›è¡Œç»„å�ˆæŸ¥è¯¢ã€‚ -### 1.4 È«ÎÄË÷Òý +### 1.4 全文索引 -MyISAM ´æ´¢ÒýÇæÖ§³ÖÈ«ÎÄË÷Òý£¬ÓÃÓÚ²éÕÒÎı¾ÖеĹؼü´Ê£¬¶ø²»ÊÇÖ±½Ó±È½ÏË÷ÒýÖеÄÖµ¡£ +MyISAM 存储引擎支æŒ�全文索引,用于查找文本中的关键è¯�,而ä¸�是直接比较索引中的值。 -ʹÓà MATCH AGAINST£¬¶ø²»ÊÇÆÕͨµÄ WHERE¡£ +使用 MATCH AGAINST,而ä¸�是普通的 WHERE。 -## 2. Ë÷ÒýµÄÓŵã +## 2. 索引的优点 -- ´ó´ó¼õÉÙÁË·þÎñÆ÷ÐèҪɨÃèµÄÊý¾ÝÁ¿£» +- 大大å‡�少了æœ�务器需è¦�扫æ��的数æ�®é‡�ï¼› -- °ïÖú·þÎñÆ÷±ÜÃâ½øÐÐÅÅÐòºÍ´´½¨ÁÙʱ±í£» +- 帮助æœ�务器é�¿å…�进行排åº�和创建临时表; -- ½«Ëæ»ú I/O ±äΪ˳Ðò I/O¡£ +- å°†éš�机 I/O å�˜ä¸ºé¡ºåº� I/O。 -## 3. Ë÷ÒýÓÅ»¯ +## 3. 索引优化 -### 3.1 ¶ÀÁ¢µÄÁÐ +### 3.1 独立的列 -ÔÚ½øÐвéѯʱ£¬Ë÷ÒýÁв»ÄÜÊDZí´ïʽµÄÒ»²¿·Ö£¬Ò²²»ÄÜÊǺ¯ÊýµÄ²ÎÊý£¬·ñÔòÎÞ·¨Ê¹ÓÃË÷Òý¡£ +在进行查询时,索引列ä¸�能是表达å¼�的一部分,也ä¸�能是函数的å�‚数,å�¦åˆ™æ— æ³•使用索引。 -ÀýÈçÏÂÃæµÄ²éѯ²»ÄÜʹÓà actor_id ÁеÄË÷Òý£º +例如下é�¢çš„æŸ¥è¯¢ä¸�能使用 actor_id 列的索引: ```sql SELECT actor_id FROM sakila.actor WHERE actor_id + 1 = 5; ``` -### 3.2 ǰ׺Ë÷Òý +### 3.2 å‰�缀索引 -¶ÔÓÚ BLOB¡¢TEXT ºÍ VARCHAR ÀàÐ͵ÄÁУ¬±ØÐëʹÓÃǰ׺Ë÷Òý£¬Ö»Ë÷Òý¿ªÊ¼µÄ²¿·Ö×Ö·û¡£ +对于 BLOBã€�TEXT å’Œ VARCHAR 类型的列,必须使用å‰�缀索引,å�ªç´¢å¼•开始的部分字符。 -¶ÔÓÚǰ׺³¤¶ÈµÄѡȡÐèÒª¸ù¾Ý **Ë÷ÒýÑ¡ÔñÐÔ** À´È·¶¨£º²»Öظ´µÄË÷ÒýÖµºÍ¼Ç¼×ÜÊýµÄ±ÈÖµ¡£Ñ¡ÔñÐÔÔ½¸ß£¬²éѯЧÂÊÒ²Ô½¸ß¡£×î´óֵΪ 1 £¬´Ëʱÿ¸ö¼Ç¼¶¼ÓÐΨһµÄË÷ÒýÓëÆä¶ÔÓ¦¡£ +对于å‰�缀长度的选å�–需è¦�æ ¹æ�® **索引选择性** æ�¥ç¡®å®šï¼šä¸�é‡�å¤�的索引值和记录总数的比值。选择性越高,查询效率也越高。最大值为 1 ,此时æ¯�个记录都有唯一的索引与其对应。 -### 3.3 ¶àÁÐË÷Òý +### 3.3 多列索引 -ÔÚÐèҪʹÓöà¸öÁÐ×÷ΪÌõ¼þ½øÐвéѯʱ£¬Ê¹ÓöàÁÐË÷Òý±ÈʹÓöà¸öµ¥ÁÐË÷ÒýÐÔÄܸüºÃ¡£ÀýÈçÏÂÃæµÄÓï¾äÖУ¬×îºÃ°Ñ actor_id ºÍ file_id ÉèÖÃΪ¶àÁÐË÷Òý¡£ +在需è¦�使用多个列作为æ�¡ä»¶è¿›è¡ŒæŸ¥è¯¢æ—¶ï¼Œä½¿ç”¨å¤šåˆ—索引比使用多个å�•列索引性能更好。例如下é�¢çš„语å�¥ä¸­ï¼Œæœ€å¥½æŠŠ actor_id å’Œ file_id 设置为多列索引。 ```sql SELECT file_id, actor_ id FROM sakila.film_actor WhERE actor_id = 1 OR film_id = 1; ``` -### 3.4 Ë÷ÒýÁеÄ˳Ðò +### 3.4 索引列的顺åº� -ÈÃÑ¡ÔñÐÔ×îÇ¿µÄË÷ÒýÁзÅÔÚÇ°Ãæ£¬ÀýÈçÏÂÃæÏÔʾµÄ½á¹ûÖÐ customer_id µÄÑ¡ÔñÐÔ±È staff_id ¸ü¸ß£¬Òò´Ë×îºÃ°Ñ customer_id ÁзÅÔÚ¶àÁÐË÷ÒýµÄÇ°Ãæ¡£ +让选择性最强的索引列放在å‰�é�¢ï¼Œä¾‹å¦‚下é�¢æ˜¾ç¤ºçš„结果中 customer_id 的选择性比 staff_id 更高,因此最好把 customer_id 列放在多列索引的å‰�é�¢ã€‚ ```sql SELECT COUNT(DISTINCT staff_id)/COUNT(*) AS staff_id_selectivity, @@ -235,107 +236,107 @@ customer_id_selectivity: 0.0373 COUNT(*): 16049 ``` -### 3.5 ¾Û´ØË÷Òý +### 3.5 è�šç°‡ç´¢å¼• -![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/b9e9ae8c-e216-4c01-b267-a50dbeb98fa4.jpg) +![](https://github.com/CyC2018/InterviewNotes/blob/master/pics//b9e9ae8c-e216-4c01-b267-a50dbeb98fa4.jpg) -¾Û´ØË÷Òý²¢²»ÊÇÒ»ÖÖË÷ÒýÀàÐÍ£¬¶øÊÇÒ»ÖÖÊý¾Ý´æ´¢·½Ê½¡£ +è�šç°‡ç´¢å¼•å¹¶ä¸�是一ç§�索引类型,而是一ç§�æ•°æ�®å­˜å‚¨æ–¹å¼�。 -ÊõÓï¡°¾Û´Ø¡±±íʾÊý¾ÝÐкÍÏàÁڵļüÖµ½ôÃܵش洢ÔÚÒ»Æð£¬InnoDB µÄ¾Û´ØË÷ÒýµÄÊý¾ÝÐдæ·ÅÔÚ B-Tree µÄÒ¶×ÓÒ³ÖС£ +术语“è�šç°‡â€�表示数æ�®è¡Œå’Œç›¸é‚»çš„键值紧密地存储在一起,InnoDB çš„è�šç°‡ç´¢å¼•的数æ�®è¡Œå­˜æ”¾åœ¨ B-Tree çš„å�¶å­�页中。 -ÒòΪÎÞ·¨°ÑÊý¾ÝÐдæ·ÅÔÚÁ½¸ö²»Í¬µÄµØ·½£¬ËùÒÔÒ»¸ö±íÖ»ÄÜÓÐÒ»¸ö¾Û´ØË÷Òý¡£ +因为无法把数æ�®è¡Œå­˜æ”¾åœ¨ä¸¤ä¸ªä¸�å�Œçš„地方,所以一个表å�ªèƒ½æœ‰ä¸€ä¸ªè�šç°‡ç´¢å¼•。 -**Óŵã** +**优点** -1. ¿ÉÒÔ°ÑÏà¹ØÊý¾Ý±£´æÔÚÒ»Æð£¬¼õÉÙ I/O ²Ù×÷£» -2. ÒòΪÊý¾Ý±£´æÔÚ B-Tree ÖУ¬Òò´ËÊý¾Ý·ÃÎʸü¿ì¡£ +1. å�¯ä»¥æŠŠç›¸å…³æ•°æ�®ä¿�存在一起,å‡�å°‘ I/O æ“�作; +2. 因为数æ�®ä¿�存在 B-Tree 中,因此数æ�®è®¿é—®æ›´å¿«ã€‚ -**ȱµã** +**缺点** -1. ¾Û´ØË÷Òý×î´óÏÞ¶ÈÌá¸ßÁË I/O Ãܼ¯ÐÍÓ¦ÓõÄÐÔÄÜ£¬µ«ÊÇÈç¹ûÊý¾ÝÈ«²¿·ÅÔÚÄڴ棬¾Íû±ØÒªÓþ۴ØË÷Òý¡£ -2. ²åÈëËÙ¶ÈÑÏÖØÒÀÀµÓÚ²åÈë˳Ðò£¬°´Ö÷¼üµÄ˳Ðò²åÈëÊÇ×î¿ìµÄ¡£ -3. ¸üвÙ×÷´ú¼ÛºÜ¸ß£¬ÒòΪÿ¸ö±»¸üеÄÐж¼»áÒÆ¶¯µ½ÐµÄλÖᣠ-4. µ±²åÈ뵽ij¸öÒÑÂúµÄÒ³ÖУ¬´æ´¢ÒýÇæ»á½«¸ÃÒ³·ÖÁѳÉÁ½¸öÒ³ÃæÀ´ÈÝÄɸÃÐУ¬Ò³·ÖÁѻᵼÖ±íÕ¼Óøü¶àµÄ´ÅÅ̿ռ䡣 -5. Èç¹ûÐбȽÏÏ¡Ê裬»òÕßÓÉÓÚÒ³·ÖÁѵ¼ÖÂÊý¾Ý´æ´¢²»Á¬ÐøÊ±£¬¾Û´ØË÷Òý¿ÉÄܵ¼ÖÂÈ«±íɨÃèËٶȱäÂý¡£ +1. è�šç°‡ç´¢å¼•最大é™�度æ��高了 I/O 密集型应用的性能,但是如果数æ�®å…¨éƒ¨æ”¾åœ¨å†…存,就没必è¦�用è�šç°‡ç´¢å¼•。 +2. æ�’入速度严é‡�ä¾�赖于æ�’入顺åº�,按主键的顺åº�æ�’入是最快的。 +3. æ›´æ–°æ“�作代价很高,因为æ¯�个被更新的行都会移动到新的ä½�置。 +4. 当æ�’入到æŸ�个已满的页中,存储引擎会将该页分裂æˆ�两个页é�¢æ�¥å®¹çº³è¯¥è¡Œï¼Œé¡µåˆ†è£‚会导致表å� ç”¨æ›´å¤šçš„ç£�盘空间。 +5. 如果行比较稀ç–�,或者由于页分裂导致数æ�®å­˜å‚¨ä¸�连续时,è�šç°‡ç´¢å¼•å�¯èƒ½å¯¼è‡´å…¨è¡¨æ‰«æ��速度å�˜æ…¢ã€‚ -### 3.6 ¸²¸ÇË÷Òý +### 3.6 覆盖索引 -Ë÷Òý°üº¬ËùÓÐÐèÒª²éѯµÄ×ֶεÄÖµ¡£ +索引包å�«æ‰€æœ‰éœ€è¦�查询的字段的值。 -## 4. B-Tree ºÍ B+Tree Ô­Àí +## 4. B-Tree å’Œ B+Tree 原ç�† ### 4. 1 B-Tree -![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/5ed71283-a070-4b21-85ae-f2cbfd6ba6e1.jpg) +![](https://github.com/CyC2018/InterviewNotes/blob/master/pics//5ed71283-a070-4b21-85ae-f2cbfd6ba6e1.jpg) -ΪÁËÃèÊö B-Tree£¬Ê×Ïȶ¨ÒåÒ»ÌõÊý¾Ý¼Ç¼Ϊһ¸ö¶þÔª×é [key, data]£¬key Ϊ¼Ç¼µÄ¼ü£¬data ΪÊý¾Ý¼Ç¼³ý key ÍâµÄÊý¾Ý¡£ +为了æ��è¿° B-Tree,首先定义一æ�¡æ•°æ�®è®°å½•为一个二元组 [key, data],key 为记录的键,data 为数æ�®è®°å½•除 key 外的数æ�®ã€‚ -B-Tree ÊÇÂú×ãÏÂÁÐÌõ¼þµÄÊý¾Ý½á¹¹£º +B-Tree 是满足下列æ�¡ä»¶çš„æ•°æ�®ç»“构: -- ËùÓÐÒ¶½Úµã¾ßÓÐÏàͬµÄÉî¶È£¬Ò²¾ÍÊÇ˵ B-Tree ÊÇÆ½ºâµÄ£» -- Ò»¸ö½ÚµãÖÐµÄ key ´Ó×óµ½ÓҷǵݼõÅÅÁУ» -- Èç¹ûij¸öÖ¸ÕëµÄ×óÓÒÏàÁÚ key ·Ö±ðÊÇ keyi ºÍ keyi+1£¬ÇÒ²»Îª null£¬Ôò¸ÃÖ¸ÕëÖ¸Ïò½ÚµãµÄËùÓÐ key ´óÓÚ keyi ÇÒСÓÚ keyi+1¡£ +- 所有å�¶èŠ‚ç‚¹å…·æœ‰ç›¸å�Œçš„æ·±åº¦ï¼Œä¹Ÿå°±æ˜¯è¯´ B-Tree 是平衡的; +- 一个节点中的 key 从左到å�³é�žé€’å‡�排列; +- 如果æŸ�个指针的左å�³ç›¸é‚» key 分别是 keyi å’Œ keyi+1,且ä¸�为 null,则该指针指å�‘节点的所有 key 大于 keyi 且å°�于 keyi+1。 -ÔÚ B-Tree Öа´ key ¼ìË÷Êý¾ÝµÄËã·¨·Ç³£Ö±¹Û£ºÊ×ÏÈ´Ó¸ù½Úµã½øÐжþ·Ö²éÕÒ£¬Èç¹ûÕÒµ½Ôò·µ»Ø¶ÔÓ¦½ÚµãµÄ data£¬·ñÔò¶ÔÏàÓ¦Çø¼äµÄÖ¸ÕëÖ¸ÏòµÄ½ÚµãµÝ¹é½øÐвéÕÒ£¬Ö±µ½ÕÒµ½½Úµã»òÕÒµ½ null Ö¸Õ룬ǰÕß²éÕҳɹ¦£¬ºóÕß²éÕÒʧ°Ü¡£ +在 B-Tree 中按 key 检索数æ�®çš„算法é�žå¸¸ç›´è§‚:首先从根节点进行二分查找,如果找到则返回对应节点的 data,å�¦åˆ™å¯¹ç›¸åº”区间的指针指å�‘的节点递归进行查找,直到找到节点或找到 null 指针,å‰�者查找æˆ�功,å�Žè€…查找失败。 -ÓÉÓÚ²åÈëɾ³ýеÄÊý¾Ý¼Ç¼»áÆÆ»µ B-Tree µÄÐÔÖÊ£¬Òò´ËÔÚ²åÈëɾ³ýʱ£¬ÐèÒª¶ÔÊ÷½øÐÐÒ»¸ö·ÖÁÑ¡¢ºÏ²¢¡¢×ªÒƵȲÙ×÷ÒÔ±£³Ö B-Tree ÐÔÖÊ¡£ +由于æ�’入删除新的数æ�®è®°å½•会破å�� B-Tree 的性质,因此在æ�’入删除时,需è¦�对树进行一个分裂ã€�å�ˆå¹¶ã€�转移等æ“�作以ä¿�æŒ� B-Tree 性质。 ### 4.2 B+Tree -![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/63cd5b50-d6d8-4df6-8912-ef4a1dd5ba13.jpg) +![](https://github.com/CyC2018/InterviewNotes/blob/master/pics//63cd5b50-d6d8-4df6-8912-ef4a1dd5ba13.jpg) -Óë B-Tree Ïà±È£¬B+Tree ÓÐÒÔϲ»Í¬µã£º +与 B-Tree 相比,B+Tree 有以下ä¸�å�Œç‚¹ï¼š -- ÿ¸ö½ÚµãµÄÖ¸ÕëÉÏÏÞΪ 2d ¶ø²»ÊÇ 2d+1£» -- Äڽڵ㲻´æ´¢ data£¬Ö»´æ´¢ key£¬Ò¶×ӽڵ㲻´æ´¢Ö¸Õë¡£ +- æ¯�个节点的指针上é™�为 2d 而ä¸�是 2d+1ï¼› +- 内节点ä¸�存储 data,å�ªå­˜å‚¨ key,å�¶å­�节点ä¸�存储指针。 -### 4.3 ´øÓÐ˳Ðò·ÃÎÊÖ¸ÕëµÄ B+Tree +### 4.3 带有顺åº�访问指针的 B+Tree -![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/1ee5f0a5-b8df-43b9-95ab-c516c54ec797.jpg) +![](https://github.com/CyC2018/InterviewNotes/blob/master/pics//1ee5f0a5-b8df-43b9-95ab-c516c54ec797.jpg) -Ò»°ãÔÚÊý¾Ý¿âϵͳ»òÎļþϵͳÖÐʹÓÃµÄ B+Tree ½á¹¹¶¼ÔÚ¾­µä B+Tree »ù´¡ÉϽøÐÐÁËÓÅ»¯£¬ÔÚÒ¶×Ó½ÚµãÔö¼ÓÁË˳Ðò·ÃÎÊÖ¸Õ룬×öÕâ¸öÓÅ»¯µÄÄ¿µÄÊÇΪÁËÌá¸ßÇø¼ä·ÃÎʵÄÐÔÄÜ¡£ +一般在数æ�®åº“系统或文件系统中使用的 B+Tree 结构都在ç»�å…¸ B+Tree 基础上进行了优化,在å�¶å­�节点增加了顺åº�访问指针,å�šè¿™ä¸ªä¼˜åŒ–的目的是为了æ��高区间访问的性能。 -### 4.4 ΪʲôʹÓà B-Tree ºÍ B+Tree +### 4.4 为什么使用 B-Tree å’Œ B+Tree -ºìºÚÊ÷µÈÊý¾Ý½á¹¹Ò²¿ÉÒÔÓÃÀ´ÊµÏÖË÷Òý£¬µ«ÊÇÎļþϵͳ¼°Êý¾Ý¿âϵͳÆÕ±é²ÉÓà B-/+Tree ×÷ΪË÷Òý½á¹¹¡£ +红黑树等数æ�®ç»“构也å�¯ä»¥ç”¨æ�¥å®žçŽ°ç´¢å¼•ï¼Œä½†æ˜¯æ–‡ä»¶ç³»ç»Ÿå�Šæ•°æ�®åº“系统普é��采用 B-/+Tree 作为索引结构。 -Ò³ÊǼÆËã»ú¹ÜÀí´æ´¢Æ÷µÄÂß¼­¿é£¬Ó²¼þ¼°²Ù×÷ϵͳÍùÍù½«Ö÷´æºÍ´ÅÅÌ´æ´¢Çø·Ö¸îΪÁ¬ÐøµÄ´óСÏàµÈµÄ¿é£¬Ã¿¸ö´æ´¢¿é³ÆÎªÒ»Ò³£¨ÔÚÐí¶à²Ù×÷ϵͳÖУ¬Ò³µÃ´óСͨ³£Îª 4k£©£¬Ö÷´æºÍ´ÅÅÌÒÔҳΪµ¥Î»½»»»Êý¾Ý¡£ +页是计算机管ç�†å­˜å‚¨å™¨çš„逻辑å�—,硬件å�Šæ“�作系统往往将主存和ç£�盘存储区分割为连续的大å°�相等的å�—,æ¯�个存储å�—称为一页(在许多æ“�作系统中,页得大å°�通常为 4k),主存和ç£�盘以页为å�•ä½�交æ�¢æ•°æ�®ã€‚ -Ò»°ãÀ´Ëµ£¬Ë÷Òý±¾ÉíÒ²ºÜ´ó£¬²»¿ÉÄÜÈ«²¿´æ´¢ÔÚÄÚ´æÖУ¬Òò´ËË÷ÒýÍùÍùÒÔË÷ÒýÎļþµÄÐÎʽ´æ´¢µÄ´ÅÅÌÉÏ¡£ÎªÁ˼õÉÙ´ÅÅÌ I/O£¬´ÅÅÌÍùÍù²»ÊÇÑϸñ°´Ðè¶ÁÈ¡£¬¶øÊÇÿ´Î¶¼»áÔ¤¶Á¡£ÕâÑù×öµÄÀíÂÛÒÀ¾ÝÊǼÆËã»ú¿ÆÑ§ÖÐÖøÃûµÄ¾Ö²¿ÐÔÔ­Àí£ºµ±Ò»¸öÊý¾Ý±»Óõ½Ê±£¬Æä¸½½üµÄÊý¾ÝҲͨ³£»áÂíÉϱ»Ê¹Óá£Êý¾Ý¿âϵͳµÄÉè¼ÆÕßÇÉÃîÀûÓÃÁË´ÅÅÌÔ¤¶ÁÔ­Àí£¬½«Ò»¸ö½ÚµãµÄ´óСÉèΪµÈÓÚÒ»¸öÒ³£¬ÕâÑùÿ¸ö½ÚµãÖ»ÐèÒªÒ»´Î I/O ¾Í¿ÉÒÔÍêÈ«ÔØÈë¡£B-Tree ÖÐÒ»´Î¼ìË÷×î¶àÐèÒª h-1 ´Î I/O£¨¸ù½Úµã³£×¤Äڴ棩£¬½¥½ø¸´ÔÓ¶ÈΪ O(h)=O(logdN)¡£Ò»°ãʵ¼ÊÓ¦ÓÃÖУ¬³ö¶È d ÊǷdz£´óµÄÊý×Ö£¬Í¨³£³¬¹ý 100£¬Òò´Ë h ·Ç³£Ð¡£¨Í¨³£²»³¬¹ý 3£©¡£¶øºìºÚÊ÷ÕâÖֽṹ£¬h Ã÷ÏÔÒªÉîµÄ¶à¡£²¢ÇÒÓÚÂß¼­ÉϺܽüµÄ½Úµã£¨¸¸×Ó£©ÎïÀíÉÏ¿ÉÄܺÜÔ¶£¬ÎÞ·¨ÀûÓþֲ¿ÐÔ£¬Ð§ÂÊÃ÷ÏÔ±È B-Tree ²îºÜ¶à¡£ +一般æ�¥è¯´ï¼Œç´¢å¼•本身也很大,ä¸�å�¯èƒ½å…¨éƒ¨å­˜å‚¨åœ¨å†…存中,因此索引往往以索引文件的形å¼�存储的ç£�盘上。为了å‡�å°‘ç£�盘 I/O,ç£�盘往往ä¸�是严格按需读å�–,而是æ¯�次都会预读。这样å�šçš„ç�†è®ºä¾�æ�®æ˜¯è®¡ç®—机科学中著å��的局部性原ç�†ï¼šå½“一个数æ�®è¢«ç”¨åˆ°æ—¶ï¼Œå…¶é™„近的数æ�®ä¹Ÿé€šå¸¸ä¼šé©¬ä¸Šè¢«ä½¿ç”¨ã€‚æ•°æ�®åº“系统的设计者巧妙利用了ç£�盘预读原ç�†ï¼Œå°†ä¸€ä¸ªèŠ‚ç‚¹çš„å¤§å°�设为等于一个页,这样æ¯�个节点å�ªéœ€è¦�一次 I/O å°±å�¯ä»¥å®Œå…¨è½½å…¥ã€‚B-Tree 中一次检索最多需è¦� h-1 次 I/O(根节点常驻内存),æ¸�è¿›å¤�æ�‚度为 O(h)=O(logdN)。一般实际应用中,出度 d 是é�žå¸¸å¤§çš„æ•°å­—,通常超过 100,因此 h é�žå¸¸å°�(通常ä¸�超过 3)。而红黑树这ç§�结构,h 明显è¦�深的多。并且于逻辑上很近的节点(父å­�)物ç�†ä¸Šå�¯èƒ½å¾ˆè¿œï¼Œæ— æ³•利用局部性,效率明显比 B-Tree 差很多。 -B+Tree ¸üÊʺÏÍâ´æË÷Òý£¬Ô­ÒòºÍÄÚ½Úµã³ö¶È d Óйء£ÓÉÓÚ B+Tree ÄÚ½ÚµãÈ¥µôÁË data Óò£¬Òò´Ë¿ÉÒÔÓµÓиü´óµÄ³ö¶È£¬ÓµÓиüºÃµÄÐÔÄÜ¡£ +B+Tree 更适å�ˆå¤–存索引,原因和内节点出度 d 有关。由于 B+Tree 内节点去掉了 data 域,因此å�¯ä»¥æ‹¥æœ‰æ›´å¤§çš„出度,拥有更好的性能。 -# ²éѯÐÔÄÜÓÅ»¯ +# 查询性能优化 ## 1. Explain -ÓÃÀ´·ÖÎö SQL Óï¾ä£¬·ÖÎö½á¹ûÖбȽÏÖØÒªµÄ×Ö¶ÎÓУº +用æ�¥åˆ†æž� SQL 语å�¥ï¼Œåˆ†æž�结果中比较é‡�è¦�的字段有: -- select_type : ²éѯÀàÐÍ£¬Óмòµ¥²éѯ¡¢ÁªºÏ²éѯºÍ×Ó²éѯ +- select_type : 查询类型,有简å�•查询ã€�è�”å�ˆæŸ¥è¯¢å’Œå­�查询 -- key : ʹÓõÄË÷Òý +- key : 使用的索引 -- rows : ɨÃèµÄÐÐÊý +- rows : 扫æ��的行数 -## 2. ¼õÉÙ·µ»ØµÄÁÐ +## 2. å‡�少返回的列 -Âý²éѯÖ÷ÒªÊÇÒòΪ·ÃÎÊÁ˹ý¶àÊý¾Ý£¬³ýÁË·ÃÎʹý¶àÐÐÖ®Í⣬Ҳ°üÀ¨·ÃÎʹý¶àÁС£ +慢查询主è¦�是因为访问了过多数æ�®ï¼Œé™¤äº†è®¿é—®è¿‡å¤šè¡Œä¹‹å¤–,也包括访问过多列。 -×îºÃ²»ÒªÊ¹Óà SELECT * Óï¾ä£¬Òª¸ù¾ÝÐèҪѡÔñ²éѯµÄÁС£ +最好ä¸�è¦�使用 SELECT * 语å�¥ï¼Œè¦�æ ¹æ�®éœ€è¦�选择查询的列。 -## 3. ¼õÉÙ·µ»ØµÄÐÐ +## 3. å‡�少返回的行 -×îºÃʹÓà LIMIT Óï¾äÀ´È¡³öÏëÒªµÄÄÇЩÐС£ +最好使用 LIMIT 语å�¥æ�¥å�–出想è¦�的那些行。 -»¹¿ÉÒÔ½¨Á¢Ë÷ÒýÀ´¼õÉÙÌõ¼þÓï¾äµÄÈ«±íɨÃè¡£ÀýÈç¶ÔÓÚÏÂÃæµÄÓï¾ä£¬²»ÊÊÓÃË÷ÒýµÄÇé¿öÏÂÐèÒª½øÐÐÈ«±íɨÃ裬¶øÊ¹ÓÃË÷ÒýÖ»ÐèҪɨÃ輸ÐмǼ¼´¿É£¬Ê¹Óà Explain Óï¾ä¿ÉÒÔͨ¹ý¹Û²ì rows ×Ö¶ÎÀ´¿´³öÕâÖÖ²îÒì¡£ +还å�¯ä»¥å»ºç«‹ç´¢å¼•æ�¥å‡�å°‘æ�¡ä»¶è¯­å�¥çš„全表扫æ��。例如对于下é�¢çš„语å�¥ï¼Œä¸�适用索引的情况下需è¦�进行全表扫æ��,而使用索引å�ªéœ€è¦�扫æ��几行记录å�³å�¯ï¼Œä½¿ç”¨ Explain 语å�¥å�¯ä»¥é€šè¿‡è§‚察 rows 字段æ�¥çœ‹å‡ºè¿™ç§�差异。 ```sql SELECT * FROM sakila.film_actor WHERE film_id = 1; ``` -## 4. ²ð·Ö´óµÄ DELETE »ò INSERT Óï¾ä +## 4. 拆分大的 DELETE 或 INSERT 语å�¥ -Èç¹ûÒ»´ÎÐÔÖ´Ðеϰ£¬¿ÉÄÜÒ»´ÎËø×¡ºÜ¶àÊý¾Ý¡¢Õ¼ÂúÕû¸öÊÂÎñÈÕÖ¾¡¢ºÄ¾¡ÏµÍ³×ÊÔ´¡¢×èÈûºÜ¶àСµÄµ«ÖØÒªµÄ²éѯ¡£ +如果一次性执行的è¯�,å�¯èƒ½ä¸€æ¬¡é”�ä½�很多数æ�®ã€�å� æ»¡æ•´ä¸ªäº‹åŠ¡æ—¥å¿—ã€�耗尽系统资æº�ã€�阻塞很多å°�的但é‡�è¦�的查询。 ```sql DELEFT FROM messages WHERE create < DATE_SUB(NOW(), INTERVAL 3 MONTH); @@ -348,74 +349,74 @@ do { } while rows_affected > 0 ``` -# ·Ö¿âÓë·Ö±í +# 分库与分表 -**1. ·Ö±íÓë·ÖÇøµÄ²»Í¬** +**1. 分表与分区的ä¸�å�Œ** -·Ö±í£¬¾ÍÊǽ²Ò»Õűí·Ö³É¶à¸öС±í£¬ÕâЩС±íÓµÓв»Í¬µÄ±íÃû£»¶ø·ÖÇøÊǽ«Ò»ÕűíµÄÊý¾Ý·ÖΪ¶à¸öÇø¿é£¬ÕâÐ©Çø¿é¿ÉÒÔ´æ´¢ÔÚͬһ¸ö´ÅÅÌÉÏ£¬Ò²¿ÉÒÔ´æ´¢ÔÚ²»Í¬µÄ´ÅÅÌÉÏ£¬ÕâÖÖ·½Ê½Ï±íÈÔȻֻÓÐÒ»¸ö¡£ +分表,就是讲一张表分æˆ�多个å°�表,这些å°�表拥有ä¸�å�Œçš„表å��;而分区是将一张表的数æ�®åˆ†ä¸ºå¤šä¸ªåŒºå�—,这些区å�—å�¯ä»¥å­˜å‚¨åœ¨å�Œä¸€ä¸ªç£�盘上,也å�¯ä»¥å­˜å‚¨åœ¨ä¸�å�Œçš„ç£�盘上,这ç§�æ–¹å¼�下表ä»�ç„¶å�ªæœ‰ä¸€ä¸ªã€‚ -**2. ʹÓ÷ֿâÓë·Ö±íµÄÔ­Òò** +**2. 使用分库与分表的原因** -Ëæ×Åʱ¼äºÍÒµÎñµÄ·¢Õ¹£¬Êý¾Ý¿âÖеıí»áÔ½À´Ô½¶à£¬²¢ÇÒ±íÖеÄÊý¾ÝÁ¿Ò²»áÔ½À´Ô½´ó£¬ÄÇô¶Áд²Ù×÷µÄ¿ªÏúÒ²»áËæ×ÅÔö´ó¡£ +éš�ç�€æ—¶é—´å’Œä¸šåŠ¡çš„å�‘展,数æ�®åº“中的表会越æ�¥è¶Šå¤šï¼Œå¹¶ä¸”表中的数æ�®é‡�也会越æ�¥è¶Šå¤§ï¼Œé‚£ä¹ˆè¯»å†™æ“�作的开销也会éš�ç�€å¢žå¤§ã€‚ -**3. ´¹Ö±ÇзÖ** +**3. 垂直切分** -½«±í°´¹¦ÄÜÄ£¿é¡¢¹ØÏµÃÜÇг̶Ȼ®·Ö³öÀ´£¬²¿Êðµ½²»Í¬µÄ¿âÉÏ¡£ÀýÈ磬ÎÒÃǻὨÁ¢ÉÌÆ·Êý¾Ý¿â payDB¡¢Óû§Êý¾Ý¿â userDB µÈ£¬·Ö±ðÓÃÀ´´æ´¢ÏîÄ¿ÓëÉÌÆ·ÓйصıíºÍÓëÓû§ÓÐ¹ØµÄ±í¡£ +将表按功能模å�—ã€�关系密切程度划分出æ�¥ï¼Œéƒ¨ç½²åˆ°ä¸�å�Œçš„库上。例如,我们会建立商å“�æ•°æ�®åº“ payDBã€�用户数æ�®åº“ userDB 等,分别用æ�¥å­˜å‚¨é¡¹ç›®ä¸Žå•†å“�有关的表和与用户有关的表。 -**4. ˮƽÇзÖ** +**4. 水平切分** -°Ñ±íÖеÄÊý¾Ý°´ÕÕijÖÖ¹æÔò´æ´¢µ½¶à¸ö½á¹¹ÏàͬµÄ±íÖУ¬ÀýÈç°´ id µÄÉ¢ÁÐÖµ¡¢ÐÔ±ðµÈ½øÐл®·Ö£¬ +把表中的数æ�®æŒ‰ç…§æŸ�ç§�规则存储到多个结构相å�Œçš„表中,例如按 id 的散列值ã€�性别等进行划分, -**5. ´¹Ö±ÇзÖÓëˮƽÇзֵÄÑ¡Ôñ** +**5. 垂直切分与水平切分的选择** -Èç¹ûÊý¾Ý¿âÖеıíÌ«¶à£¬²¢ÇÒÏîÄ¿¸÷ÏîÒµÎñÂß¼­ÇåÎú£¬ÄÇô´¹Ö±ÇзÖÊÇÊ×Ñ¡¡£ +如果数æ�®åº“中的表太多,并且项目å�„项业务逻辑清晰,那么垂直切分是首选。 -Èç¹ûÊý¾Ý¿âµÄ±í²»¶à£¬µ«Êǵ¥±íµÄÊý¾ÝÁ¿ºÜ´ó£¬Ó¦¸ÃÑ¡ÔñˮƽÇз֡£ +如果数æ�®åº“的表ä¸�多,但是å�•表的数æ�®é‡�很大,应该选择水平切分。 -**6. ˮƽÇзֵÄʵÏÖ·½Ê½** +**6. 水平切分的实现方å¼�** -×î¼òµ¥µÄÊÇʹÓà merge ´æ´¢ÒýÇæ¡£ +最简å�•的是使用 merge 存储引擎。 -**7. ·Ö¿âÓë·Ö±í´æÔÚµÄÎÊÌâ** +**7. 分库与分表存在的问题** -(1) ÊÂÎñÎÊÌâ +(1) 事务问题 -ÔÚÖ´Ðзֿâ·Ö±íÖ®ºó£¬ÓÉÓÚÊý¾Ý´æ´¢µ½Á˲»Í¬µÄ¿âÉÏ£¬Êý¾Ý¿âÊÂÎñ¹ÜÀí³öÏÖÁËÀ§ÄÑ¡£Èç¹ûÒÀÀµÊý¾Ý¿â±¾ÉíµÄ·Ö²¼Ê½ÊÂÎñ¹ÜÀí¹¦ÄÜÈ¥Ö´ÐÐÊÂÎñ£¬½«¸¶³ö¸ß°ºµÄÐÔÄÜ´ú¼Û£»Èç¹ûÓÉÓ¦ÓóÌÐòȥЭÖú¿ØÖÆ£¬ÐγɳÌÐòÂß¼­ÉϵÄÊÂÎñ£¬ÓÖ»áÔì³É±à³Ì·½ÃæµÄ¸ºµ£¡£ +在执行分库分表之å�Žï¼Œç”±äºŽæ•°æ�®å­˜å‚¨åˆ°äº†ä¸�å�Œçš„库上,数æ�®åº“事务管ç�†å‡ºçŽ°äº†å›°éš¾ã€‚å¦‚æžœä¾�èµ–æ•°æ�®åº“本身的分布å¼�事务管ç�†åŠŸèƒ½åŽ»æ‰§è¡Œäº‹åŠ¡ï¼Œå°†ä»˜å‡ºé«˜æ˜‚çš„æ€§èƒ½ä»£ä»·ï¼›å¦‚æžœç”±åº”ç”¨ç¨‹åº�去å��助控制,形æˆ�程åº�逻辑上的事务,å�ˆä¼šé€ æˆ�编程方é�¢çš„负担。 -(2) ¿ç¿â¿ç±íÁ¬½ÓÎÊÌâ +(2) 跨库跨表连接问题 -ÔÚÖ´ÐÐÁË·Ö¿â·Ö±íÖ®ºó£¬ÄÑÒÔ±ÜÃâ»á½«Ô­±¾Âß¼­¹ØÁªÐÔºÜÇ¿µÄÊý¾Ý»®·Öµ½²»Í¬µÄ±í¡¢²»Í¬µÄ¿âÉÏ¡£Õâʱ£¬±íµÄÁ¬½Ó²Ù×÷½«Êܵ½ÏÞÖÆ£¬ÎÒÃÇÎÞ·¨Á¬½ÓλÓÚ²»Í¬·Ö¿âµÄ±í£¬Ò²ÎÞ·¨Á¬½Ó·Ö±íÁ£¶È²»Í¬µÄ±í£¬µ¼ÖÂÔ­±¾Ö»ÐèÒªÒ»´Î²éѯ¾ÍÄܹ»Íê³ÉµÄÒµÎñÐèÒª½øÐжà´Î²ÅÄÜÍê³É¡£ +在执行了分库分表之å�Žï¼Œéš¾ä»¥é�¿å…�会将原本逻辑关è�”性很强的数æ�®åˆ’分到ä¸�å�Œçš„表ã€�ä¸�å�Œçš„库上。这时,表的连接æ“�作将å�—到é™�制,我们无法连接ä½�于ä¸�å�Œåˆ†åº“的表,也无法连接分表粒度ä¸�å�Œçš„表,导致原本å�ªéœ€è¦�一次查询就能够完æˆ�的业务需è¦�进行多次æ‰�能完æˆ�。 -# ¹ÊÕÏ×ªÒÆºÍ¹ÊÕϻָ´ +# 故障转移和故障æ�¢å¤� -¹ÊÕÏ×ªÒÆÒ²½Ð×öÇл»£¬µ±Ö÷¿â³öÏÖ¹ÊÕÏʱ¾ÍÇл»µ½±¸¿â£¬Ê¹±¸¿â³ÉΪÖ÷¿â¡£¹ÊÕϻָ´¹ËÃû˼Òå¾ÍÊÇ´Ó¹ÊÕÏÖлָ´¹ýÀ´£¬²¢ÇÒ±£Ö¤Êý¾ÝµÄÕýÈ·ÐÔ¡£ +故障转移也å�«å�šåˆ‡æ�¢ï¼Œå½“主库出现故障时就切æ�¢åˆ°å¤‡åº“,使备库æˆ�为主库。故障æ�¢å¤�顾å��æ€�义就是从故障中æ�¢å¤�过æ�¥ï¼Œå¹¶ä¸”ä¿�è¯�æ•°æ�®çš„æ­£ç¡®æ€§ã€‚ -## 1. ¹ÊÕÏ×ªÒÆ +## 1. 故障转移 -**1.1 ÌáÉý±¸¿â»òÇл»½ÇÉ«** +**1.1 æ��å�‡å¤‡åº“或切æ�¢è§’色** -ÌáÉýһ̨±¸¿âΪÖ÷¿â£¬»òÕßÔÚÒ»¸öÖ÷-Ö÷¸´ÖƽṹÖе÷ÕûÖ÷¶¯ºÍ±»¶¯½ÇÉ«¡£ +æ��å�‡ä¸€å�°å¤‡åº“为主库,或者在一个主-主å¤�制结构中调整主动和被动角色。 -**1.2 ÐéÄâ IP µØÖ·ºÍ IP ÍйÜ** +**1.2 虚拟 IP 地å�€å’Œ IP 托管** -Ϊ MySQL ʵÀýÖ¸¶¨Ò»¸öÂß¼­ IP µØÖ·£¬µ± MySQL ʵÀýʧЧʱ£¬¿ÉÒÔ½« IP µØÖ·×ªÒƵ½Áíһ̨ MySQL ·þÎñÆ÷ÉÏ¡£ +为 MySQL 实例指定一个逻辑 IP 地å�€ï¼Œå½“ MySQL 实例失效时,å�¯ä»¥å°† IP 地å�€è½¬ç§»åˆ°å�¦ä¸€å�° MySQL æœ�务器上。 -**1.3 Öмä¼þ½â¾ö·½°¸** +**1.3 中间件解决方案** -ͨ¹ý´úÀí£¬¿ÉÒÔ·ÓÉÁ÷Á¿µ½¿ÉÒÔʹÓõķþÎñÆ÷ÉÏ¡£ +通过代ç�†ï¼Œå�¯ä»¥è·¯ç”±æµ�é‡�到å�¯ä»¥ä½¿ç”¨çš„æœ�务器上。 -![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/fabd5fa0-b75e-48d0-9e2c-31471945ceb9.jpg) +![](https://github.com/CyC2018/InterviewNotes/blob/master/pics//fabd5fa0-b75e-48d0-9e2c-31471945ceb9.jpg) -**1.4 ÔÚÓ¦ÓÃÖд¦Àí¹ÊÕÏ×ªÒÆ** +**1.4 在应用中处ç�†æ•…障转移** -½«¹ÊÕÏ×ªÒÆÕûºÏµ½Ó¦ÓÃÖпÉÄܵ¼ÖÂÓ¦ÓñäµÃÌ«¹ý±¿×¾¡£ +将故障转移整å�ˆåˆ°åº”用中å�¯èƒ½å¯¼è‡´åº”用å�˜å¾—太过笨拙。 -## 2. ¹ÊÕϻָ´ +## 2. æ•…éšœæ�¢å¤� -# ²Î¿¼×ÊÁÏ +# å�‚考资料 -- ¸ßÐÔÄÜ MySQL -- [MySQL Ë÷Òý±³ºóµÄÊý¾Ý½á¹¹¼°Ëã·¨Ô­Àí ](http://blog.codinglabs.org/articles/theory-of-mysql-index.html) -- [MySQL Ë÷ÒýÓÅ»¯È«¹¥ÂÔ ](http://www.runoob.com/w3cnote/mysql-index.html) -- [20+ Ìõ MySQL ÐÔÄÜÓÅ»¯µÄ×î¼Ñ¾­Ñé ](https://www.jfox.info/20-tiao-mysql-xing-nen-you-hua-de-zui-jia-jing-yan.html) +- 高性能 MySQL +- [MySQL 索引背å�Žçš„æ•°æ�®ç»“æž„å�Šç®—法原ç�† ](http://blog.codinglabs.org/articles/theory-of-mysql-index.html) +- [MySQL 索引优化全攻略 ](http://www.runoob.com/w3cnote/mysql-index.html) +- [20+ æ�¡ MySQL 性能优化的最佳ç»�验 ](https://www.jfox.info/20-tiao-mysql-xing-nen-you-hua-de-zui-jia-jing-yan.html) diff --git a/notes/SQL 语法.md b/notes/SQL 语法.md index b128542b..eea75f44 100644 --- a/notes/SQL 语法.md +++ b/notes/SQL 语法.md @@ -1,52 +1,53 @@ -* [»ù´¡](#»ù´¡) -* [²éѯ](#²éѯ) -* [ÅÅÐò](#ÅÅÐò) -* [¹ýÂË](#¹ýÂË) -* [ͨÅä·û](#ͨÅä·û) -* [¼ÆËã×Ö¶Î](#¼ÆËã×Ö¶Î) -* [º¯Êý](#º¯Êý) - * [Îı¾´¦Àí](#Îı¾´¦Àí) - * [ÈÕÆÚºÍʱ¼ä´¦Àí](#ÈÕÆÚºÍʱ¼ä´¦Àí) - * [ÊýÖµ´¦Àí](#ÊýÖµ´¦Àí) - * [»ã×Ü](#»ã×Ü) -* [·Ö×é](#·Ö×é) -* [×Ó²éѯ](#×Ó²éѯ) -* [Á¬½Ó](#Á¬½Ó) - * [ÄÚÁ¬½Ó](#ÄÚÁ¬½Ó) - * [×ÔÁ¬½Ó](#×ÔÁ¬½Ó) - * [×ÔÈ»Á¬½Ó](#×ÔÈ»Á¬½Ó) - * [ÍâÁ¬½Ó](#ÍâÁ¬½Ó) -* [×éºÏ²éѯ](#×éºÏ²éѯ) -* [²åÈë](#²åÈë) -* [¸üÐÂ](#¸üÐÂ) -* [ɾ³ý](#ɾ³ý) -* [´´½¨±í](#´´½¨±í) -* [Ð޸ıí](#Ð޸ıí) -* [ÊÓͼ](#ÊÓͼ) -* [´æ´¢¹ý³Ì](#´æ´¢¹ý³Ì) -* [Óαê](#Óαê) -* [´¥·¢Æ÷](#´¥·¢Æ÷) -* [ÊÂÎñ´¦Àí](#ÊÂÎñ´¦Àí) -* [×Ö·û¼¯](#×Ö·û¼¯) -* [ȨÏÞ¹ÜÀí](#ȨÏÞ¹ÜÀí) +* [基础](#基础) +* [查询](#查询) +* [排åº�](#排åº�) +* [过滤](#过滤) +* [通é…�符](#通é…�符) +* [计算字段](#计算字段) +* [函数](#函数) + * [文本处ç�†](#文本处ç�†) + * [日期和时间处ç�†](#日期和时间处ç�†) + * [数值处ç�†](#数值处ç�†) + * [汇总](#汇总) +* [分组](#分组) +* [å­�查询](#å­�查询) +* [连接](#连接) + * [内连接](#内连接) + * [自连接](#自连接) + * [自然连接](#自然连接) + * [外连接](#外连接) +* [组å�ˆæŸ¥è¯¢](#组å�ˆæŸ¥è¯¢) +* [æ�’å…¥](#æ�’å…¥) +* [æ›´æ–°](#æ›´æ–°) +* [删除](#删除) +* [创建表](#创建表) +* [修改表](#修改表) +* [视图](#视图) +* [存储过程](#存储过程) +* [游标](#游标) +* [触å�‘器](#触å�‘器) +* [事务处ç�†](#事务处ç�†) +* [字符集](#字符集) +* [æ�ƒé™�管ç�†](#æ�ƒé™�管ç�†) -# »ù´¡ -ģʽ£º¶¨ÒåÁËÊý¾ÝÈçºÎ´æ´¢¡¢´æ´¢Ê²Ã´ÑùµÄÊý¾ÝÒÔ¼°Êý¾ÝÈçºÎ·Ö½âµÈÐÅÏ¢£¬Êý¾Ý¿âºÍ±í¶¼ÓÐģʽ¡£ +# 基础 -Ö÷¼üµÄÖµ²»ÔÊÐíÐ޸ģ¬Ò²²»ÔÊÐí¸´Ó㨲»ÄÜʹÓÃÒѾ­É¾³ýµÄÖ÷¼üÖµ¸³¸øÐÂÊý¾ÝÐеÄÖ÷¼ü£©¡£ +模å¼�:定义了数æ�®å¦‚何存储ã€�存储什么样的数æ�®ä»¥å�Šæ•°æ�®å¦‚何分解等信æ�¯ï¼Œæ•°æ�®åº“和表都有模å¼�。 -SQL£¨Structured Query Language)£¬±ê×¼ SQL ÓÉ ANSI ±ê׼ίԱ»á¹ÜÀí£¬´Ó¶ø³ÆÎª ANSI SQL£¬¸÷¸ö DBMS ¶¼ÓÐ×Ô¼ºµÄʵÏÖ£¬Èç PL/SQL¡¢Transact-SQL µÈ¡£ +主键的值ä¸�å…�许修改,也ä¸�å…�许å¤�用(ä¸�能使用已ç»�删除的主键值赋给新数æ�®è¡Œçš„主键)。 -# ²éѯ +SQL(Structured Query Language),标准 SQL ç”± ANSI 标准委员会管ç�†ï¼Œä»Žè€Œç§°ä¸º ANSI SQL,å�„个 DBMS 都有自己的实现,如 PL/SQLã€�Transact-SQL 等。 -SQL Óï¾ä²»Çø·Ö´óСд£¬µ«ÊÇÊý¾Ý¿â±íÃû¡¢ÁÐÃûºÍÖµÊÇ·ñÇø·ÖÒÀÀµÓÚ¾ßÌåµÄ DBMS ÒÔ¼°ÅäÖᣠ+# 查询 + +SQL 语å�¥ä¸�区分大å°�写,但是数æ�®åº“表å��ã€�列å��和值是å�¦åŒºåˆ†ä¾�赖于具体的 DBMS 以å�Šé…�置。 **DISTINCT** -Ïàֵֻͬ»á³öÏÖÒ»´Î¡£Ëü×÷ÓÃÓÚËùÓÐÁУ¬Ò²¾ÍÊÇ˵ËùÓÐÁеÄÖµ¶¼Ïàͬ²ÅËãÏàͬ¡£ +相å�Œå€¼å�ªä¼šå‡ºçŽ°ä¸€æ¬¡ã€‚å®ƒä½œç”¨äºŽæ‰€æœ‰åˆ—ï¼Œä¹Ÿå°±æ˜¯è¯´æ‰€æœ‰åˆ—çš„å€¼éƒ½ç›¸å�Œæ‰�算相å�Œã€‚ ```sql SELECT DISTINCT col1, col2 @@ -55,9 +56,9 @@ FROM mytable; **LIMIT** -ÏÞÖÆ·µ»ØµÄÐÐÊý¡£¿ÉÒÔÓÐÁ½¸ö²ÎÊý£¬µÚÒ»¸ö²ÎÊýΪÆðʼÐУ¬´Ó 0 ¿ªÊ¼£»µÚ¶þ¸ö²ÎÊýΪ·µ»ØµÄ×ÜÐÐÊý¡£ +é™�制返回的行数。å�¯ä»¥æœ‰ä¸¤ä¸ªå�‚数,第一个å�‚数为起始行,从 0 开始;第二个å�‚数为返回的总行数。 -·µ»ØÇ° 5 ÐÐµÄ SQL£º +返回å‰� 5 行的 SQL: ```sql SELECT * @@ -71,7 +72,7 @@ FROM mytable LIMIT 0, 5; ``` -·µ»ØµÚ 3 \~ 5 ÐУº +返回第 3 \~ 5 行: ```sql SELECT * @@ -79,22 +80,22 @@ FROM mytable LIMIT 2, 3; ``` -**×¢ÊÍ** +**注释** ```sql -# ×¢ÊÍ +# 注释 SELECT * -FROM mytable -- ×¢ÊÍ -/* ×¢ÊÍ1 - ×¢ÊÍ2 */ +FROM mytable -- 注释 +/* 注释1 + 注释2 */ ``` -# ÅÅÐò +# 排åº� -**ASC**£ºÉýÐò£¨Ä¬ÈÏ£© -**DESC**£º½µÐò +**ASC**:å�‡åº�(默认) +**DESC**:é™�åº� -¿ÉÒÔ°´¶à¸öÁнøÐÐÅÅÐò£º +å�¯ä»¥æŒ‰å¤šä¸ªåˆ—进行排åº�: ```sql SELECT * @@ -102,9 +103,9 @@ FROM mytable ORDER BY col1 DESC, col2 ASC; ``` -# ¹ýÂË +# 过滤 -ÔÚÓ¦ÓòãÒ²¿ÉÒÔ¹ýÂËÊý¾Ý£¬µ«ÊDz»ÔÚ·þÎñÆ÷¶Ë½øÐйýÂ˵ÄÊý¾Ý·Ç³£´ó£¬µ¼ÖÂͨ¹ýÍøÂç´«ÊäÁ˺ܶà¶àÓàµÄÊý¾Ý£¬´Ó¶øÀË·ÑÁËÍøÂç´ø¿í¡£ +在应用层也å�¯ä»¥è¿‡æ»¤æ•°æ�®ï¼Œä½†æ˜¯ä¸�在æœ�务器端进行过滤的数æ�®é�žå¸¸å¤§ï¼Œå¯¼è‡´é€šè¿‡ç½‘络传输了很多多余的数æ�®ï¼Œä»Žè€Œæµªè´¹äº†ç½‘络带宽。 ```sql SELECT * @@ -112,155 +113,155 @@ FROM mytable WHERE col IS NULL; ``` -ϱíÏÔʾÁË WHERE ×Ó¾ä¿ÉÓõIJÙ×÷·û +下表显示了 WHERE å­�å�¥å�¯ç”¨çš„æ“�作符 -| ²Ù×÷·û | ˵Ã÷ | +| æ“�作符 | 说明 | | ------------ | ------------ | -| = < > | µÈÓÚ Ð¡ÓÚ ´óÓÚ | -| <> != | ²»µÈÓÚ | -| <= !> | СÓÚµÈÓÚ | -| >= !< | ´óÓÚµÈÓÚ | -| BETWEEN | ÔÚÁ½¸öÖµÖ®¼ä | -| IS NULL | ΪNULLÖµ | +| = < > | 等于 å°�于 大于 | +| <> != | ä¸�等于 | +| <= !> | å°�于等于 | +| >= !< | 大于等于 | +| BETWEEN | 在两个值之间 | +| IS NULL | 为NULL值 | -Ó¦¸Ã×¢Òâµ½£¬NULL Óë 0 ¡¢¿Õ×Ö·û´®¶¼²»Í¬¡£ +应该注æ„�到,NULL 与 0 ã€�空字符串都ä¸�å�Œã€‚ -**AND OR** ÓÃÓÚÁ¬½Ó¶à¸ö¹ýÂËÌõ¼þ¡£ÓÅÏÈ´¦Àí AND£¬Òò´Ëµ±Ò»¸ö¹ýÂ˱í´ïÊ½Éæ¼°µ½¶à¸ö AND ºÍ OR ʱ£¬Ó¦µ±Ê¹Óà () À´¾ö¶¨ÓÅÏȼ¶¡£ +**AND OR** 用于连接多个过滤æ�¡ä»¶ã€‚优先处ç�† AND,因此当一个过滤表达å¼�涉å�Šåˆ°å¤šä¸ª AND å’Œ OR 时,应当使用 () æ�¥å†³å®šä¼˜å…ˆçº§ã€‚ -**IN** ²Ù×÷·ûÓÃÓÚÆ¥ÅäÒ»×éÖµ£¬ÆäºóÒ²¿ÉÒÔ½ÓÒ»¸ö SELECT ×Ӿ䣬´Ó¶øÆ¥Åä×Ó²éѯµÃµ½µÄÒ»×éÖµ¡£ +**IN** æ“�作符用于匹é…�一组值,其å�Žä¹Ÿå�¯ä»¥æŽ¥ä¸€ä¸ª SELECT å­�å�¥ï¼Œä»Žè€ŒåŒ¹é…�å­�查询得到的一组值。 -**NOT** ²Ù×÷·ûÓÃÓÚ·ñ¶¨Ò»¸öÌõ¼þ¡£ +**NOT** æ“�作符用于å�¦å®šä¸€ä¸ªæ�¡ä»¶ã€‚ -# ͨÅä·û +# 通é…�符 -ͨÅä·ûÒ²ÊÇÓÃÔÚ¹ýÂËÓï¾äÖУ¬Ö»ÄÜÓÃÓÚÎı¾×ֶΡ£ +通é…�符也是用在过滤语å�¥ä¸­ï¼Œå�ªèƒ½ç”¨äºŽæ–‡æœ¬å­—段。 -- **%** Æ¥Åä >=0 ¸öÈÎÒâ×Ö·û£¬ÀàËÆÓÚ \*£» +- **%** 匹é…� >=0 个任æ„�字符,类似于 \*ï¼› -- **\_** Æ¥Åä ==1 ¸öÈÎÒâ×Ö·û£¬ÀàËÆÓÚ \.£» +- **\_** 匹é…� ==1 个任æ„�字符,类似于 \.ï¼› -- **[ ]** ¿ÉÒÔÆ¥Å伯ºÏÄÚµÄ×Ö·û£¬ÓÃÍÑ×Ö·û ^ ¿ÉÒÔ¶ÔÆä½øÐзñ¶¨ +- **[ ]** å�¯ä»¥åŒ¹é…�集å�ˆå†…的字符,用脱字符 ^ å�¯ä»¥å¯¹å…¶è¿›è¡Œå�¦å®š -ʹÓà Like À´½øÐÐͨÅä·ûÆ¥Åä¡£ +使用 Like æ�¥è¿›è¡Œé€šé…�符匹é…�。 ```sql SELECT * FROM mytable -WHERE col LIKE '[^AB]%' -- ²»ÒÔAB¿ªÍ·µÄÈÎÒâÎı¾ +WHERE col LIKE '[^AB]%' -- ä¸�以AB开头的任æ„�文本 ``` -²»ÒªÀÄÓÃͨÅä·û£¬Í¨Åä·ûλÓÚ¿ªÍ·´¦Æ¥Åä»á·Ç³£Âý¡£ +ä¸�è¦�滥用通é…�符,通é…�符ä½�于开头处匹é…�会é�žå¸¸æ…¢ã€‚ -# ¼ÆËã×Ö¶Î +# 计算字段 -ÔÚÊý¾Ý¿â·þÎñÆ÷ÉÏÍê³ÉÊý¾ÝµÄת»»ºÍ¸ñʽ»¯µÄ¹¤×÷ÍùÍù±È¿Í»§¶ËÉÏ¿ìµÃ¶à£¬²¢ÇÒת»»ºÍ¸ñʽ»¯ºóµÄÊý¾ÝÁ¿¸üÉٵϰ¿ÉÒÔ¼õÉÙÍøÂçͨÐÅÁ¿¡£ +在数æ�®åº“æœ�务器上完æˆ�æ•°æ�®çš„转æ�¢å’Œæ ¼å¼�化的工作往往比客户端上快得多,并且转æ�¢å’Œæ ¼å¼�化å�Žçš„æ•°æ�®é‡�æ›´å°‘çš„è¯�å�¯ä»¥å‡�少网络通信é‡�。 -¼ÆËã×Ö¶Îͨ³£ÐèҪʹÓà **AS** À´È¡±ðÃû£¬·ñÔòÊä³öµÄʱºò×Ö¶ÎÃûΪ¼ÆËã±í´ïʽ¡£ +计算字段通常需è¦�使用 **AS** æ�¥å�–别å��,å�¦åˆ™è¾“出的时候字段å��为计算表达å¼�。 ```sql SELECT col1*col2 AS alias FROM mytable ``` -**Concat()** ÓÃÓÚÁ¬½ÓÁ½¸ö×ֶΡ£Ðí¶àÊý¾Ý¿â»áʹÓÿոñ°ÑÒ»¸öÖµÌî³äΪÁÐ¿í£¬Òò´ËÁ¬½ÓµÄ½á¹û»á³öÏÖһЩ²»±ØÒªµÄ¿Õ¸ñ£¬Ê¹Óà **TRIM()** ¿ÉÒÔÈ¥³ýÊ×β¿Õ¸ñ¡£ +**Concat()** 用于连接两个字段。许多数æ�®åº“会使用空格把一个值填充为列宽,因此连接的结果会出现一些ä¸�å¿…è¦�的空格,使用 **TRIM()** å�¯ä»¥åŽ»é™¤é¦–å°¾ç©ºæ ¼ã€‚ ```sql SELECT Concat(TRIM(col1), ' (', TRIM(col2), ')') FROM mytable ``` -# º¯Êý +# 函数 -¸÷¸ö DBMS µÄº¯Êý¶¼ÊDz»ÏàͬµÄ£¬Òò´Ë²»¿ÉÒÆÖ²¡£ +å�„个 DBMS 的函数都是ä¸�相å�Œçš„,因此ä¸�å�¯ç§»æ¤�。 -## Îı¾´¦Àí +## 文本处ç�† -| º¯Êý | ˵Ã÷ | +| 函数 | 说明 | | ------------ | ------------ | -| LEFT() RIGHT() | ×ó±ß»òÕßÓұߵÄ×Ö·û | -| LOWER() UPPER() | ת»»ÎªÐ¡Ð´»òÕß´óд | -| LTRIM() RTIM() | È¥³ý×ó±ß»òÕßÓұߵĿոñ | -| LENGTH() | ³¤¶È | -| SUNDEX() | ת»»ÎªÓïÒôÖµ | +| LEFT() RIGHT() | 左边或者å�³è¾¹çš„字符 | +| LOWER() UPPER() | 转æ�¢ä¸ºå°�写或者大写 | +| LTRIM() RTIM() | 去除左边或者å�³è¾¹çš„空格 | +| LENGTH() | 长度 | +| SUNDEX() | 转æ�¢ä¸ºè¯­éŸ³å€¼ | -ÆäÖУ¬**SOUNDEX()** Êǽ«Ò»¸ö×Ö·û´®×ª»»ÎªÃèÊöÆäÓïÒô±íʾµÄ×ÖĸÊý×ÖģʽµÄËã·¨£¬ËüÊǸù¾Ý·¢Òô¶ø²»ÊÇ×Öĸ±È½Ï¡£ +其中,**SOUNDEX()** 是将一个字符串转æ�¢ä¸ºæ��述其语音表示的字æ¯�数字模å¼�的算法,它是根æ�®å�‘音而ä¸�是字æ¯�比较。 ```sql SELECT * FROM mytable WHERE SOUNDEX(col1) = SOUNDEX('apple') ``` -## ÈÕÆÚºÍʱ¼ä´¦Àí +## 日期和时间处ç�† -ÈÕÆÚ¸ñʽ£ºYYYY-MM-DD +日期格å¼�:YYYY-MM-DD -ʱ¼ä¸ñʽ£ºHH:MM:SS +æ—¶é—´æ ¼å¼�:HH:MM:SS -|º¯ Êý | ˵ Ã÷| +|函 æ•° | 说 明| | --- | --- | -| AddDate() | Ôö¼ÓÒ»¸öÈÕÆÚ£¨Ìì¡¢Öܵȣ©| -| AddTime() | Ôö¼ÓÒ»¸öʱ¼ä£¨Ê±¡¢·ÖµÈ£©| -| CurDate() | ·µ»Øµ±Ç°ÈÕÆÚ | -| CurTime() | ·µ»Øµ±Ç°Ê±¼ä | -|Date() |·µ»ØÈÕÆÚʱ¼äµÄÈÕÆÚ²¿·Ö| -|DateDiff() |¼ÆËãÁ½¸öÈÕÆÚÖ®²î| -|Date_Add() |¸ß¶ÈÁé»îµÄÈÕÆÚÔËË㺯Êý| -|Date_Format() |·µ»ØÒ»¸ö¸ñʽ»¯µÄÈÕÆÚ»òʱ¼ä´®| -|Day()| ·µ»ØÒ»¸öÈÕÆÚµÄÌìÊý²¿·Ö| -|DayOfWeek() |¶ÔÓÚÒ»¸öÈÕÆÚ£¬·µ»Ø¶ÔÓ¦µÄÐÇÆÚ¼¸| -|Hour() |·µ»ØÒ»¸öʱ¼äµÄСʱ²¿·Ö| -|Minute() |·µ»ØÒ»¸öʱ¼äµÄ·ÖÖÓ²¿·Ö| -|Month() |·µ»ØÒ»¸öÈÕÆÚµÄÔ·ݲ¿·Ö| -|Now() |·µ»Øµ±Ç°ÈÕÆÚºÍʱ¼ä| -|Second() |·µ»ØÒ»¸öʱ¼äµÄÃ벿·Ö| -|Time() |·µ»ØÒ»¸öÈÕÆÚʱ¼äµÄʱ¼ä²¿·Ö| -|Year() |·µ»ØÒ»¸öÈÕÆÚµÄÄê·Ý²¿·Ö| +| AddDate() | 增加一个日期(天ã€�周等)| +| AddTime() | 增加一个时间(时ã€�分等)| +| CurDate() | 返回当å‰�日期 | +| CurTime() | 返回当å‰�æ—¶é—´ | +|Date() |返回日期时间的日期部分| +|DateDiff() |计算两个日期之差| +|Date_Add() |高度ç�µæ´»çš„æ—¥æœŸè¿�算函数| +|Date_Format() |返回一个格å¼�化的日期或时间串| +|Day()| 返回一个日期的天数部分| +|DayOfWeek() |对于一个日期,返回对应的星期几| +|Hour() |返回一个时间的å°�时部分| +|Minute() |返回一个时间的分钟部分| +|Month() |返回一个日期的月份部分| +|Now() |返回当å‰�日期和时间| +|Second() |返回一个时间的秒部分| +|Time() |返回一个日期时间的时间部分| +|Year() |返回一个日期的年份部分| ```sql mysql> SELECT NOW(); -> '2017-06-28 14:01:52' ``` -## ÊýÖµ´¦Àí +## 数值处ç�† -| º¯Êý | ˵Ã÷ | +| 函数 | 说明 | | --- | --- | -| SIN() | ÕýÏÒ | -|COS() | ÓàÏÒ | -| TAN() | ÕýÇÐ | -| ABS() | ¾ø¶ÔÖµ | -| SQRT() | ƽ·½¸ù| -| MOD() | ÓàÊý| -| EXP() | Ö¸Êý| -| PI() | Ô²ÖÜÂÊ| -|RAND() | Ëæ»úÊý| +| SIN() | 正弦 | +|COS() | 余弦 | +| TAN() | 正切 | +| ABS() | ç»�对值 | +| SQRT() | 平方根| +| MOD() | 余数| +| EXP() | 指数| +| PI() | 圆周率| +|RAND() | éš�机数| -## »ã×Ü +## 汇总 -|º¯ Êý |˵ Ã÷| +|函 æ•° |说 明| | --- | --- | -|AVG() |·µ»ØÄ³ÁÐµÄÆ½¾ùÖµ| -|COUNT()| ·µ»ØÄ³ÁеÄÐÐÊý| -|MAX()| ·µ»ØÄ³ÁеÄ×î´óÖµ| -|MIN()| ·µ»ØÄ³ÁеÄ×îСֵ| -|SUM() |·µ»ØÄ³ÁÐÖµÖ®ºÍ| +|AVG() |返回æŸ�列的平å�‡å€¼| +|COUNT()| 返回æŸ�列的行数| +|MAX()| 返回æŸ�列的最大值| +|MIN()| 返回æŸ�列的最å°�值| +|SUM() |返回æŸ�列值之和| -AVG() »áºöÂÔ NULL ÐС£ +AVG() 会忽略 NULL 行。 -DISTINCT ¹Ø¼ü×Ö»áÖ»»ã×ܲ»Í¬µÄÖµ¡£ +DISTINCT 关键字会å�ªæ±‡æ€»ä¸�å�Œçš„值。 ```sql SELECT AVG(DISTINCT col1) AS avg_col FROM mytable ``` -# ·Ö×é +# 分组 -·Ö×é¾ÍÊǰÑÏàͬµÄÊý¾Ý·ÅÔÚͬһ×éÖС£ +分组就是把相å�Œçš„æ•°æ�®æ”¾åœ¨å�Œä¸€ç»„中。 -¿ÉÒÔ¶Ôÿ×éÊý¾ÝʹÓûã×ܺ¯Êý½øÐд¦Àí£¬ÀýÈçÇóÿ×éÊýµÄƽ¾ùÖµµÈ¡£ +å�¯ä»¥å¯¹æ¯�组数æ�®ä½¿ç”¨æ±‡æ€»å‡½æ•°è¿›è¡Œå¤„ç�†ï¼Œä¾‹å¦‚求æ¯�组数的平å�‡å€¼ç­‰ã€‚ -°´ col ÅÅÐò²¢·Ö×éÊý¾Ý£º +按 col 排åº�并分组数æ�®ï¼š ```sql SELECT col, COUNT(*) AS num @@ -268,7 +269,7 @@ FROM mytable GROUP BY col; ``` -WHERE ¹ýÂËÐУ¬HAVING ¹ýÂË·Ö×飬ÐйýÂËÓ¦µ±ÏÈÓë·Ö×é¹ýÂË£» +WHERE 过滤行,HAVING 过滤分组,行过滤应当先与分组过滤; ```sql SELECT col, COUNT(*) AS num @@ -278,7 +279,7 @@ GROUP BY col HAVING COUNT(*) >= 2; ``` -GROUP BY µÄÅÅÐò½á¹ûΪ·Ö×é×ֶΣ¬¶ø ORDER BY Ò²¿ÉÒÔÒÔ¾Û¼¯×Ö¶ÎÀ´½øÐÐÅÅÐò¡£ +GROUP BY 的排åº�结果为分组字段,而 ORDER BY 也å�¯ä»¥ä»¥è�šé›†å­—段æ�¥è¿›è¡ŒæŽ’åº�。 ```sql SELECT col, COUNT(*) AS num @@ -287,18 +288,18 @@ GROUP BY col ORDER BY num; ``` -·Ö×鹿¶¨£º +分组规定: -1. GROUP BY ×Ó¾ä³öÏÖÔÚ WHERE ×Ó¾äÖ®ºó£¬ORDER BY ×Ó¾ä֮ǰ£» -2. ³ýÁË»ã×ܼÆËãÓï¾äÖ®Í⣬SELECT Óï¾äÖеÄÿһÁж¼±ØÐëÔÚ GROUP BY ×Ó¾äÖиø³ö£» -3. NULL µÄÐлᵥ¶À·ÖΪһ×飻 -4. ´ó¶àÊý SQL ʵÏÖ²»Ö§³Ö GROUP BY ÁоßÓпɱ䳤¶ÈµÄÊý¾ÝÀàÐÍ¡£ +1. GROUP BY å­�å�¥å‡ºçŽ°åœ¨ WHERE å­�å�¥ä¹‹å�Žï¼ŒORDER BY å­�å�¥ä¹‹å‰�ï¼› +2. 除了汇总计算语å�¥ä¹‹å¤–,SELECT 语å�¥ä¸­çš„æ¯�一列都必须在 GROUP BY å­�å�¥ä¸­ç»™å‡ºï¼› +3. NULL 的行会å�•独分为一组; +4. 大多数 SQL 实现ä¸�支æŒ� GROUP BY 列具有å�¯å�˜é•¿åº¦çš„æ•°æ�®ç±»åž‹ã€‚ -# ×Ó²éѯ +# å­�查询 -×Ó²éѯÖÐÖ»ÄÜ·µ»ØÒ»¸öÁС£ +å­�查询中å�ªèƒ½è¿”回一个列。 -¿ÉÒÔ½«×Ó²éѯµÄ½á¹û×÷Ϊ WHRER Óï¾äµÄ¹ýÂËÌõ¼þ£º +å�¯ä»¥å°†å­�查询的结果作为 WHRER 语å�¥çš„过滤æ�¡ä»¶ï¼š ``` SELECT * @@ -307,7 +308,7 @@ WHERE col1 IN (SELECT col2 FROM mytable2); ``` -ÏÂÃæµÄÓï¾ä¿ÉÒÔ¼ìË÷³ö¿Í»§µÄ¶©µ¥ÊýÁ¿¡£×Ó²éѯÓï¾ä»á¶Ô¼ìË÷³öµÄÿ¸ö¿Í»§Ö´ÐÐÒ»´Î£º +下é�¢çš„语å�¥å�¯ä»¥æ£€ç´¢å‡ºå®¢æˆ·çš„订å�•æ•°é‡�。å­�查询语å�¥ä¼šå¯¹æ£€ç´¢å‡ºçš„æ¯�个客户执行一次: ```sql SELECT cust_name, (SELECT COUNT(*) @@ -318,17 +319,17 @@ FROM Customers ORDER BY cust_name; ``` -# Á¬½Ó +# 连接 -Á¬½ÓÓÃÓÚÁ¬½Ó¶à¸ö±í£¬Ê¹Óà JOIN ¹Ø¼ü×Ö£¬²¢ÇÒÌõ¼þÓï¾äʹÓà ON¡£ +连接用于连接多个表,使用 JOIN 关键字,并且æ�¡ä»¶è¯­å�¥ä½¿ç”¨ ON。 -Á¬½Ó¿ÉÒÔÌæ»»×Ó²éѯ£¬²¢ÇÒ±È×Ó²éѯµÄЧÂÊÒ»°ã»á¸ü¿ì¡£ +连接å�¯ä»¥æ›¿æ�¢å­�查询,并且比å­�查询的效率一般会更快。 -¿ÉÒÔÓà AS ¸øÁÐÃû¡¢¼ÆËã×ֶκͱíÃûÈ¡±ðÃû£¬¸ø±íÃûÈ¡±ðÃûÊÇΪÁ˼ò»¯ SQL Óï¾äÒÔ¼°Á¬½ÓÏàͬ±í¡£ +å�¯ä»¥ç”¨ AS 给列å��ã€�计算字段和表å��å�–别å��,给表å��å�–别å��是为了简化 SQL 语å�¥ä»¥å�Šè¿žæŽ¥ç›¸å�Œè¡¨ã€‚ -## ÄÚÁ¬½Ó +## 内连接 -ÄÚÁ¬½ÓÓֳƵÈÖµÁ¬½Ó£¬Ê¹Óà INNER JOIN ¹Ø¼ü×Ö¡£ +内连接å�ˆç§°ç­‰å€¼è¿žæŽ¥ï¼Œä½¿ç”¨ INNER JOIN 关键字。 ``` select a, b, c @@ -336,7 +337,7 @@ from A inner join B on A.key = B.key ``` -¿ÉÒÔ²»Ã÷ȷʹÓà INNER JOIN£¬¶øÊ¹ÓÃÆÕͨ²éѯ²¢ÔÚ WHERE Öн«Á½¸ö±íÖÐÒªÁ¬½ÓµÄÁÐÓõÈÖµ·½·¨Á¬½ÓÆðÀ´¡£ +å�¯ä»¥ä¸�明确使用 INNER JOIN,而使用普通查询并在 WHERE 中将两个表中è¦�连接的列用等值方法连接起æ�¥ã€‚ ``` select a, b, c @@ -344,15 +345,15 @@ from A, B where A.key = B.key ``` -ÔÚûÓÐÌõ¼þÓï¾äµÄÇé¿öÏ·µ»ØµÑ¿¨¶û»ý¡£ +在没有æ�¡ä»¶è¯­å�¥çš„æƒ…况下返回笛å�¡å°”积。 -## ×ÔÁ¬½Ó +## 自连接 -×ÔÁ¬½Ó¿ÉÒÔ¿´³ÉÄÚÁ¬½ÓµÄÒ»ÖÖ£¬Ö»ÊÇÁ¬½ÓµÄ±íÊÇ×ÔÉí¶øÒÑ¡£ +自连接å�¯ä»¥çœ‹æˆ�内连接的一ç§�,å�ªæ˜¯è¿žæŽ¥çš„表是自身而已。 -Ò»ÕÅÔ±¹¤±í£¬°üº¬Ô±¹¤ÐÕÃûºÍÔ±¹¤ËùÊô²¿ÃÅ£¬ÒªÕÒ³öÓë Jim ´¦ÔÚͬһ²¿ÃŵÄËùÓÐÔ±¹¤ÐÕÃû¡£ +一张员工表,包å�«å‘˜å·¥å§“å��和员工所属部门,è¦�找出与 Jim 处在å�Œä¸€éƒ¨é—¨çš„æ‰€æœ‰å‘˜å·¥å§“å��。 -**×Ó²éѯ°æ±¾** +**å­�查询版本** ``` select name @@ -363,7 +364,7 @@ where department = ( where name = "Jim"); ``` -**×ÔÁ¬½Ó°æ±¾** +**自连接版本** ``` select name @@ -372,24 +373,24 @@ where e1.department = e2.department and e1.name = "Jim"; ``` -Á¬½ÓÒ»°ã±È×Ó²éѯµÄЧÂʸߡ£ +连接一般比å­�查询的效率高。 -## ×ÔÈ»Á¬½Ó +## 自然连接 -×ÔÈ»Á¬½ÓÊǰÑͬÃûÁÐͨ¹ýµÈÖµ²âÊÔÁ¬½ÓÆðÀ´µÄ£¬Í¬ÃûÁпÉÒÔÓжà¸ö¡£ +自然连接是把å�Œå��列通过等值测试连接起æ�¥çš„,å�Œå��列å�¯ä»¥æœ‰å¤šä¸ªã€‚ -ÄÚÁ¬½ÓºÍ×ÔÈ»Á¬½ÓµÄÇø±ð£ºÄÚÁ¬½ÓÌṩÁ¬½ÓµÄÁУ¬¶ø×ÔÈ»Á¬½Ó×Ô¶¯Á¬½ÓËùÓÐͬÃûÁУ»ÄÚÁ¬½ÓÊôÓÚ×ÔÈ»Á¬½Ó¡£ +内连接和自然连接的区别:内连接æ��供连接的列,而自然连接自动连接所有å�Œå��列;内连接属于自然连接。 ``` select * from employee natural join department; ``` -## ÍâÁ¬½Ó +## 外连接 -ÍâÁ¬½Ó±£ÁôÁËûÓйØÁªµÄÄÇЩÐС£·ÖΪ×óÍâÁ¬½Ó£¬ÓÒÍâÁ¬½ÓÒÔ¼°È«ÍâÁ¬½Ó£¬×óÍâÁ¬½Ó¾ÍÊDZ£Áô×ó±íµÄËùÓÐÐС£ +外连接ä¿�留了没有关è�”的那些行。分为左外连接,å�³å¤–连接以å�Šå…¨å¤–连接,左外连接就是ä¿�留左表的所有行。 -¼ìË÷ËùÓй˿͵Ķ©µ¥ÐÅÏ¢£¬°üÀ¨»¹Ã»Óж©µ¥ÐÅÏ¢µÄ¹Ë¿Í¡£ +检索所有顾客的订å�•ä¿¡æ�¯ï¼ŒåŒ…括还没有订å�•ä¿¡æ�¯çš„顾客。 ``` select Customers.cust_id, Orders.order_num @@ -397,7 +398,7 @@ select Customers.cust_id, Orders.order_num on Customers.cust_id = Orders.curt_id ``` -Èç¹ûÐèҪͳ¼Æ¹Ë¿ÍµÄ¶©µ¥Êý£¬Ê¹Óþۼ¯º¯Êý¡£ +如果需è¦�统计顾客的订å�•数,使用è�šé›†å‡½æ•°ã€‚ ``` select Customers.cust_id, @@ -407,13 +408,13 @@ on Customers.cust_id = Orders.curt_id group by Customers.cust_id ``` -# ×éºÏ²éѯ +# 组å�ˆæŸ¥è¯¢ -ʹÓà **UNION** À´Á¬½ÓÁ½¸ö²éѯ£¬Ã¿¸ö²éѯ±ØÐë°üº¬ÏàͬµÄÁС¢±í´ïʽ»òÕß¾Û¼¯º¯Êý¡£ +使用 **UNION** æ�¥è¿žæŽ¥ä¸¤ä¸ªæŸ¥è¯¢ï¼Œæ¯�个查询必须包å�«ç›¸å�Œçš„列ã€�表达å¼�或者è�šé›†å‡½æ•°ã€‚ -ĬÈÏ»áÈ¥³ýÏàͬÐУ¬Èç¹ûÐèÒª±£ÁôÏàͬÐУ¬Ê¹Óà UNION ALL ¡£ +默认会去除相å�Œè¡Œï¼Œå¦‚果需è¦�ä¿�留相å�Œè¡Œï¼Œä½¿ç”¨ UNION ALL 。 -Ö»Äܰüº¬Ò»¸ö ORDER BY ×Ӿ䣬²¢ÇÒ±ØÐëλÓÚÓï¾äµÄ×îºó¡£ +å�ªèƒ½åŒ…å�«ä¸€ä¸ª ORDER BY å­�å�¥ï¼Œå¹¶ä¸”å¿…é¡»ä½�于语å�¥çš„æœ€å�Žã€‚ ```sql SELECT col @@ -425,16 +426,16 @@ FROM mytable WHERE col =2; ``` -# ²åÈë +# æ�’å…¥ -**ÆÕͨ²åÈë** +**普通æ�’å…¥** ```sql INSERT INTO mytable(col1, col2) VALUES(val1, val2); ``` -**²åÈë¼ìË÷³öÀ´µÄÊý¾Ý** +**æ�’入检索出æ�¥çš„æ•°æ�®** ```sql INSERT INTO mytable1(col1, col2) @@ -442,14 +443,14 @@ SELECT col1, col2 FROM mytable2; ``` -**½«Ò»¸ö±íµÄÄÚÈݸ´ÖƵ½Ò»¸öбí** +**将一个表的内容å¤�制到一个新表** ```sql CREATE TABLE newtable AS SELECT * FROM mytable; ``` -# ¸üР+# æ›´æ–° ```sql UPDATE mytable @@ -457,18 +458,18 @@ SET col = val WHERE id = 1; ``` -# ɾ³ý +# 删除 ```sql DELETE FROM mytable WHERE id = 1; ``` -**TRUNCATE TABLE** ¿ÉÒÔÇå¿Õ±í£¬Ò²¾ÍÊÇɾ³ýËùÓÐÐС£ +**TRUNCATE TABLE** å�¯ä»¥æ¸…空表,也就是删除所有行。 -ʹÓøüкÍɾ³ý²Ù×÷ʱһ¶¨ÒªÓà WHERE ×Ӿ䣬²»È»»á°ÑÕûÕűíµÄÊý¾Ý¶¼ÆÆ»µ¡£¿ÉÒÔÏÈÓà SELECT Óï¾ä½øÐвâÊÔ£¬·ÀÖ¹´íÎóɾ³ý¡£ +使用更新和删除æ“�作时一定è¦�用 WHERE å­�å�¥ï¼Œä¸�然会把整张表的数æ�®éƒ½ç ´å��。å�¯ä»¥å…ˆç”¨ SELECT 语å�¥è¿›è¡Œæµ‹è¯•,防止错误删除。 -# ´´½¨±í +# 创建表 ```sql CREATE TABLE mytable ( @@ -479,38 +480,38 @@ CREATE TABLE mytable ( PRIMARY KEY (`id`)); ``` -# Ð޸ıí +# 修改表 -**Ìí¼ÓÁÐ** +**添加列** ```sql ALTER TABLE mytable ADD col CHAR(20); ``` -**ɾ³ýÁÐ** +**删除列** ```sql ALTER TABLE mytable DROP COLUMN col; ``` -**ɾ³ý±í** +**删除表** ```sql DROP TABLE mytable; ``` -# ÊÓͼ +# 视图 -ÊÓͼÊÇÐéÄâµÄ±í£¬±¾Éí²»°üº¬Êý¾Ý£¬Ò²¾Í²»ÄÜ¶ÔÆä½øÐÐË÷Òý²Ù×÷¡£¶ÔÊÓͼµÄ²Ù×÷ºÍ¶ÔÆÕͨ±íµÄ²Ù×÷Ò»Ñù¡£ +视图是虚拟的表,本身ä¸�包å�«æ•°æ�®ï¼Œä¹Ÿå°±ä¸�能对其进行索引æ“�作。对视图的æ“�作和对普通表的æ“�作一样。 -ÊÓͼ¾ßÓÐÈçϺô¦£º +视图具有如下好处: -1. ¼ò»¯¸´Ô SQL ²Ù×÷£¬±ÈÈ縴ÔÓµÄÁª½á£» -2. ֻʹÓÃʵ¼Ê±íµÄÒ»²¿·ÖÊý¾Ý£» -3. ͨ¹ýÖ»¸øÓû§·ÃÎÊÊÓͼµÄȨÏÞ£¬±£Ö¤Êý¾ÝµÄ°²È«ÐÔ£» -4. ¸ü¸ÄÊý¾Ý¸ñʽºÍ±íʾ¡£ +1. 简化å¤�æ�‚çš„ SQL æ“�作,比如å¤�æ�‚çš„è�”结; +2. å�ªä½¿ç”¨å®žé™…表的一部分数æ�®ï¼› +3. 通过å�ªç»™ç”¨æˆ·è®¿é—®è§†å›¾çš„æ�ƒé™�,ä¿�è¯�æ•°æ�®çš„安全性; +4. 更改数æ�®æ ¼å¼�和表示。 ```sql CREATE VIEW myview AS @@ -519,25 +520,25 @@ FROM mytable WHERE col5 = val; ``` -# ´æ´¢¹ý³Ì +# 存储过程 -´æ´¢¹ý³Ì¿ÉÒÔ¿´³ÉÊǶÔһϵÁÐ SQL ²Ù×÷µÄÅú´¦Àí£» +存储过程å�¯ä»¥çœ‹æˆ�是对一系列 SQL æ“�作的批处ç�†ï¼› -**ʹÓô洢¹ý³ÌµÄºÃ´¦** +**使用存储过程的好处** -1. °ÑʵÏÖ·â×°ÔÚÁË´æ´¢¹ý³ÌÖУ¬²»½ö¼òµ¥£¬Ò²±£Ö¤Á˰²È«ÐÔ£» -2. ¿ÉÒÔ¸´ÓôúÂ룻 -3. ÓÉÓÚÊÇÔ¤ÏȱàÒ룬Òò´Ë¾ßÓкܸߵÄÐÔÄÜ¡£ +1. 把实现å°�装在了存储过程中,ä¸�仅简å�•,也ä¿�è¯�了安全性; +2. å�¯ä»¥å¤�用代ç �ï¼› +3. 由于是预先编译,因此具有很高的性能。 -**´´½¨´æ´¢¹ý³Ì** +**创建存储过程** -ÃüÁîÐÐÖд´½¨´æ´¢¹ý³ÌÐèÒª×Ô¶¨Òå·Ö¸ô·û£¬ÒòΪÃüÁîÐÐÊÇÒÔ ; Ϊ½áÊø·û£¬¶ø´æ´¢¹ý³ÌÖÐÒ²°üº¬Á˷ֺţ¬Òò´Ë»á´íÎó°ÑÕⲿ·Ö·ÖºÅµ±³ÉÊǽáÊø·û£¬Ôì³ÉÓï·¨´íÎó¡£ +命令行中创建存储过程需è¦�自定义分隔符,因为命令行是以 ; 为结æ�Ÿç¬¦ï¼Œè€Œå­˜å‚¨è¿‡ç¨‹ä¸­ä¹ŸåŒ…å�«äº†åˆ†å�·ï¼Œå› æ­¤ä¼šé”™è¯¯æŠŠè¿™éƒ¨åˆ†åˆ†å�·å½“æˆ�是结æ�Ÿç¬¦ï¼Œé€ æˆ�语法错误。 -°üº¬ in¡¢out ºÍ inout ÈýÖÖ²ÎÊý¡£ +包å�« inã€�out å’Œ inout 三ç§�å�‚数。 -¸ø±äÁ¿¸³Öµ¶¼ÐèÒªÓà select into Óï¾ä¡£ +ç»™å�˜é‡�赋值都需è¦�用 select into 语å�¥ã€‚ -ÿ´ÎÖ»ÄܸøÒ»¸ö±äÁ¿¸³Öµ£¬²»Ö§³Ö¼¯ºÏµÄ²Ù×÷¡£ +æ¯�次å�ªèƒ½ç»™ä¸€ä¸ªå�˜é‡�赋值,ä¸�支æŒ�集å�ˆçš„æ“�作。 ```sql delimiter // @@ -558,18 +559,18 @@ call myprocedure(@ret); select @ret; ``` -# Óαê +# 游标 -ÔÚ´æ´¢¹ý³ÌÖÐʹÓÃÓαê¿ÉÒÔ¶ÔÒ»¸ö½á¹û¼¯½øÐÐÒÆ¶¯±éÀú¡£ +在存储过程中使用游标å�¯ä»¥å¯¹ä¸€ä¸ªç»“果集进行移动é��历。 -ÓαêÖ÷ÒªÓÃÓÚ½»»¥Ê½Ó¦Óã¬ÆäÖÐÓû§ÐèÒª¶ÔÊý¾Ý¼¯ÖеÄÈÎÒâÐнøÐÐä¯ÀÀºÍÐ޸ġ£ +游标主è¦�用于交互å¼�应用,其中用户需è¦�对数æ�®é›†ä¸­çš„ä»»æ„�行进行æµ�览和修改。 -**ʹÓÃÓαêµÄËĸö²½Ö裺** +**使用游标的四个步骤:** -1. ÉùÃ÷Óα꣬Õâ¸ö¹ý³ÌûÓÐʵ¼Ê¼ìË÷³öÊý¾Ý£» -2. ´ò¿ªÓαꣻ -3. È¡³öÊý¾Ý£» -4. ¹Ø±ÕÓαꣻ +1. 声明游标,这个过程没有实际检索出数æ�®ï¼› +2. 打开游标; +3. å�–出数æ�®ï¼› +4. 关闭游标; ```sql delimiter // @@ -579,7 +580,7 @@ create procedure myprocedure(out ret int) declare mycursor cursor for select col1 from mytable; - # ¶¨ÒåÁËÒ»¸öcontinue handler£¬µ± sqlstate '02000' Õâ¸öÌõ¼þ³öÏÖʱ£¬»áÖ´ÐÐ set done = 1 + # 定义了一个continue handler,当 sqlstate '02000' 这个æ�¡ä»¶å‡ºçŽ°æ—¶ï¼Œä¼šæ‰§è¡Œ set done = 1 declare continue handler for sqlstate '02000' set done = 1; open mycursor; @@ -594,43 +595,43 @@ create procedure myprocedure(out ret int) delimiter ; ``` -# ´¥·¢Æ÷ +# 触å�‘器 -´¥·¢Æ÷»áÔÚij¸ö±íÖ´ÐÐÒÔÏÂÓï¾äʱ¶ø×Ô¶¯Ö´ÐУºDELETE¡¢INSERT¡¢UPDATE +触å�‘器会在æŸ�个表执行以下语å�¥æ—¶è€Œè‡ªåŠ¨æ‰§è¡Œï¼šDELETEã€�INSERTã€�UPDATE -´¥·¢Æ÷±ØÐëÖ¸¶¨ÔÚÓï¾äÖ´ÐÐ֮ǰ»¹ÊÇÖ®ºó×Ô¶¯Ö´ÐУ¬Ö®Ç°Ö´ÐÐʹÓà BEFORE ¹Ø¼ü×Ö£¬Ö®ºóÖ´ÐÐʹÓà AFTER ¹Ø¼ü×Ö¡£BEFORE ÓÃÓÚÊý¾ÝÑéÖ¤ºÍ¾»»¯¡£ +触å�‘器必须指定在语å�¥æ‰§è¡Œä¹‹å‰�还是之å�Žè‡ªåŠ¨æ‰§è¡Œï¼Œä¹‹å‰�执行使用 BEFORE 关键字,之å�Žæ‰§è¡Œä½¿ç”¨ AFTER 关键字。BEFORE 用于数æ�®éªŒè¯�和净化。 -INSERT ´¥·¢Æ÷°üº¬Ò»¸öÃûΪ NEW µÄÐéÄâ±í¡£ +INSERT 触å�‘器包å�«ä¸€ä¸ªå��为 NEW 的虚拟表。 ```sql CREATE TRIGGER mytrigger AFTER INSERT ON mytable FOR EACH ROW SELECT NEW.col; ``` -DELETE ´¥·¢Æ÷°üº¬Ò»¸öÃûΪ OLD µÄÐéÄâ±í£¬²¢ÇÒÊÇÖ»¶ÁµÄ¡£ +DELETE 触å�‘器包å�«ä¸€ä¸ªå��为 OLD 的虚拟表,并且是å�ªè¯»çš„。 -UPDATE ´¥·¢Æ÷°üº¬Ò»¸öÃûΪ NEW ºÍÒ»¸öÃûΪ OLD µÄÐéÄâ±í£¬ÆäÖÐ NEW ÊÇ¿ÉÒÔ±»Ð޸ĵأ¬¶ø OLD ÊÇÖ»¶ÁµÄ¡£ +UPDATE 触å�‘器包å�«ä¸€ä¸ªå��为 NEW 和一个å��为 OLD 的虚拟表,其中 NEW 是å�¯ä»¥è¢«ä¿®æ”¹åœ°ï¼Œè€Œ OLD 是å�ªè¯»çš„。 -¿ÉÒÔʹÓô¥·¢Æ÷À´½øÐÐÉ󼯏ú×Ù£¬°ÑÐ޸ļǼµ½ÁíÍâÒ»ÕűíÖС£ +å�¯ä»¥ä½¿ç”¨è§¦å�‘器æ�¥è¿›è¡Œå®¡è®¡è·Ÿè¸ªï¼ŒæŠŠä¿®æ”¹è®°å½•到å�¦å¤–一张表中。 -MySQL ²»ÔÊÐíÔÚ´¥·¢Æ÷ÖÐʹÓà CALL Óï¾ä £¬Ò²¾ÍÊDz»Äܵ÷Óô洢¹ý³Ì¡£ +MySQL ä¸�å…�许在触å�‘器中使用 CALL 语å�¥ ,也就是ä¸�能调用存储过程。 -# ÊÂÎñ´¦Àí +# 事务处ç�† -**»ù±¾ÊõÓï** +**基本术语** -1. ÊÂÎñ£¨transaction£©Ö¸Ò»×é SQL Óï¾ä£» -2. »ØÍË£¨rollback£©Ö¸³·ÏúÖ¸¶¨ SQL Óï¾äµÄ¹ý³Ì£» -3. Ìá½»£¨commit£©Ö¸½«Î´´æ´¢µÄ SQL Óï¾ä½á¹ûдÈëÊý¾Ý¿â±í£» -4. ±£Áôµã£¨savepoint£©Ö¸ÊÂÎñ´¦ÀíÖÐÉèÖõÄÁÙʱռλ·û£¨placeholder£©£¬Äã¿ÉÒÔ¶ÔËü·¢²¼»ØÍË£¨Óë»ØÍËÕû¸öÊÂÎñ´¦Àí²»Í¬£©¡£ +1. 事务(transaction)指一组 SQL 语å�¥ï¼› +2. 回退(rollback)指撤销指定 SQL 语å�¥çš„过程; +3. æ��交(commit)指将未存储的 SQL 语å�¥ç»“果写入数æ�®åº“表; +4. ä¿�留点(savepoint)指事务处ç�†ä¸­è®¾ç½®çš„临时å� ä½�符(placeholder),你å�¯ä»¥å¯¹å®ƒå�‘布回退(与回退整个事务处ç�†ä¸�å�Œï¼‰ã€‚ -²»ÄÜ»ØÍË SELECT Óï¾ä£¬»ØÍË SELECT Óï¾äҲûÒâÒ壻Ҳ²»ÄÜ»ØÍË CRETE ºÍ DROP Óï¾ä¡£ +ä¸�能回退 SELECT 语å�¥ï¼Œå›žé€€ SELECT 语å�¥ä¹Ÿæ²¡æ„�义;也ä¸�能回退 CRETE å’Œ DROP 语å�¥ã€‚ -MySQL µÄÊÂÎñÌύĬÈÏÊÇÒþʽÌá½»£¬Ò²¾ÍÊÇÿִÐÐÒ»ÌõÓï¾ä¾Í»áÌá½»Ò»´Î¡£µ±³öÏÖ START TRANSACTION Óï¾äʱ£¬»á¹Ø±ÕÒþʽÌá½»£»µ± COMMIT »ò ROLLBACK Óï¾äÖ´Ðкó£¬ÊÂÎñ»á×Ô¶¯¹Ø±Õ£¬ÖØÐ»ָ´ÒþʽÌá½»¡£ +MySQL 的事务æ��交默认是éš�å¼�æ��交,也就是æ¯�执行一æ�¡è¯­å�¥å°±ä¼šæ��交一次。当出现 START TRANSACTION 语å�¥æ—¶ï¼Œä¼šå…³é—­éš�å¼�æ��交;当 COMMIT 或 ROLLBACK 语å�¥æ‰§è¡Œå�Žï¼Œäº‹åŠ¡ä¼šè‡ªåŠ¨å…³é—­ï¼Œé‡�æ–°æ�¢å¤�éš�å¼�æ��交。 -ͨ¹ýÉèÖà autocommit Ϊ 0 ¿ÉÒÔÈ¡Ïû×Ô¶¯Ìá½»£¬Ö±µ½ autocommit ±»ÉèÖÃΪ 1 ²Å»áÌá½»£»autocommit ±ê¼ÇÊÇÕë¶Ôÿ¸öÁ¬½Ó¶ø²»ÊÇÕë¶Ô·þÎñÆ÷µÄ¡£ +通过设置 autocommit 为 0 å�¯ä»¥å�–消自动æ��交,直到 autocommit 被设置为 1 æ‰�会æ��交;autocommit 标记是针对æ¯�个连接而ä¸�是针对æœ�务器的。 -Èç¹ûûÓÐÉèÖñ£Áôµã£¬ROLLBACK »á»ØÍ˵½ START TRANSACTION Óï¾ä´¦£»Èç¹ûÉèÖÃÁ˱£Áôµã£¬²¢ÇÒÔÚ ROLLBACK ÖÐÖ¸¶¨¸Ã±£Áôµã£¬Ôò»á»ØÍ˵½¸Ã±£Áôµã¡£ +如果没有设置ä¿�留点,ROLLBACK 会回退到 START TRANSACTION 语å�¥å¤„;如果设置了ä¿�留点,并且在 ROLLBACK 中指定该ä¿�留点,则会回退到该ä¿�留点。 ```sql START TRANSACTION @@ -642,15 +643,15 @@ ROLLBACK TO delete1 COMMIT ``` -# ×Ö·û¼¯ +# 字符集 -**»ù±¾ÊõÓï** +**基本术语** -1. ×Ö·û¼¯Îª×ÖĸºÍ·ûºÅµÄ¼¯ºÏ£» -2. ±àÂëΪij¸ö×Ö·û¼¯³ÉÔ±µÄÄÚ²¿±íʾ£» -3. У¶Ô×Ö·ûÖ¸¶¨ÈçºÎ±È½Ï£¬Ö÷ÒªÓÃÓÚÅÅÐòºÍ·Ö×é¡£ +1. 字符集为字æ¯�和符å�·çš„集å�ˆï¼› +2. ç¼–ç �为æŸ�个字符集æˆ�员的内部表示; +3. 校对字符指定如何比较,主è¦�用于排åº�和分组。 -³ýÁ˸ø±íÖ¸¶¨×Ö·û¼¯ºÍУ¶ÔÍ⣬Ҳ¿ÉÒÔ¸øÁÐÖ¸¶¨£º +除了给表指定字符集和校对外,也å�¯ä»¥ç»™åˆ—指定: ```sql CREATE TABLE mytable @@ -658,7 +659,7 @@ CREATE TABLE mytable DEFAULT CHARACTER SET hebrew COLLATE hebrew_general_ci; ``` -¿ÉÒÔÔÚÅÅÐò¡¢·Ö×éʱָ¶¨Ð£¶Ô£º +å�¯ä»¥åœ¨æŽ’åº�ã€�分组时指定校对: ```sql SELECT * @@ -666,67 +667,67 @@ FROM mytable ORDER BY col COLLATE latin1_general_ci; ``` -# ȨÏÞ¹ÜÀí +# æ�ƒé™�管ç�† -MySQL µÄÕË»§ÐÅÏ¢±£´æÔÚ mysql Õâ¸öÊý¾Ý¿âÖС£ +MySQL 的账户信æ�¯ä¿�存在 mysql 这个数æ�®åº“中。 ```sql USE mysql; SELECT user FROM user; ``` -**´´½¨ÕË»§** +**创建账户** ```sql CREATE USER myuser IDENTIFIED BY 'mypassword'; ``` -д´½¨µÄÕË»§Ã»ÓÐÈκÎȨÏÞ¡£ +新创建的账户没有任何æ�ƒé™�。 -**ÐÞ¸ÄÕË»§Ãû** +**修改账户å��** ```sql RENAME myuser TO newuser; ``` -**ɾ³ýÕË»§** +**删除账户** ```sql DROP USER myuser; ``` -**²é¿´È¨ÏÞ** +**查看æ�ƒé™�** ```sql SHOW GRANTS FOR myuser; ``` -![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/c73aa08e-a987-43c9-92be-adea4a884c25.png) +![](https://github.com/CyC2018/InterviewNotes/blob/master/pics//c73aa08e-a987-43c9-92be-adea4a884c25.png) -ÕË»§Óà username@host µÄÐÎʽ¶¨Ò壬username@% ʹÓõÄÊÇĬÈÏÖ÷»úÃû¡£ +账户用 username@host 的形å¼�定义,username@% 使用的是默认主机å��。 -**ÊÚÓèȨÏÞ** +**授予æ�ƒé™�** ```sql GRANT SELECT, INSERT ON mydatabase.* TO myuser; ``` -**ɾ³ýȨÏÞ** +**删除æ�ƒé™�** ```sql REVOKE SELECT, INSERT ON mydatabase.* FROM myuser; ``` -GRANT ºÍ REVOKE ¿ÉÔÚ¼¸¸ö²ã´ÎÉÏ¿ØÖÆ·ÃÎÊȨÏÞ£º +GRANT å’Œ REVOKE å�¯åœ¨å‡ ä¸ªå±‚次上控制访问æ�ƒé™�: -- Õû¸ö·þÎñÆ÷£¬Ê¹Óà GRANT ALLºÍ REVOKE ALL£» -- Õû¸öÊý¾Ý¿â£¬Ê¹Óà ON database.\*£» -- ÌØ¶¨µÄ±í£¬Ê¹Óà ON database.table£» -- ÌØ¶¨µÄÁУ» -- ÌØ¶¨µÄ´æ´¢¹ý³Ì¡£ +- 整个æœ�务器,使用 GRANT ALLå’Œ REVOKE ALLï¼› +- 整个数æ�®åº“,使用 ON database.\*ï¼› +- 特定的表,使用 ON database.tableï¼› +- 特定的列; +- 特定的存储过程。 -**¸ü¸ÄÃÜÂë** +**更改密ç �** -±ØÐëʹÓà Password() º¯Êý +必须使用 Password() 函数 ```sql SET PASSWROD FOR myuser = Password('newpassword'); diff --git a/notes/代ç �å�¯è¯»æ€§.md b/notes/代ç �å�¯è¯»æ€§.md index 2bf6982e..47af4412 100644 --- a/notes/代ç �å�¯è¯»æ€§.md +++ b/notes/代ç �å�¯è¯»æ€§.md @@ -1,90 +1,91 @@ -* [¿É¶ÁÐÔµÄÖØÒªÐÔ](#¿É¶ÁÐÔµÄÖØÒªÐÔ) -* [ÓÃÃû×Ö±í´ï´úÂ뺬Òå](#ÓÃÃû×Ö±í´ï´úÂ뺬Òå) -* [Ãû×Ö²»ÄÜ´øÀ´ÆçÒå](#Ãû×Ö²»ÄÜ´øÀ´ÆçÒå) -* [Á¼ºÃµÄ´úÂë·ç¸ñ](#Á¼ºÃµÄ´úÂë·ç¸ñ) -* [±àдעÊÍ](#±àдעÊÍ) -* [ÈçºÎ±àдעÊÍ](#ÈçºÎ±àдעÊÍ) -* [Ìá¸ß¿ØÖÆÁ÷µÄ¿É¶ÁÐÔ](#Ìá¸ß¿ØÖÆÁ÷µÄ¿É¶ÁÐÔ) -* [²ð·Ö³¤±í´ïʽ](#²ð·Ö³¤±í´ïʽ) -* [±äÁ¿Óë¿É¶ÁÐÔ](#±äÁ¿Óë¿É¶ÁÐÔ) -* [³éÈ¡º¯Êý](#³éÈ¡º¯Êý) -* [Ò»´ÎÖ»×öÒ»¼þÊÂ](#Ò»´ÎÖ»×öÒ»¼þÊÂ) -* [ÓÃ×ÔÈ»ÓïÑÔ±íÊö´úÂë](#ÓÃ×ÔÈ»ÓïÑÔ±íÊö´úÂë) -* [¼õÉÙ´úÂëÁ¿](#¼õÉÙ´úÂëÁ¿) +* [å�¯è¯»æ€§çš„é‡�è¦�性](#å�¯è¯»æ€§çš„é‡�è¦�性) +* [用å��字表达代ç �å�«ä¹‰](#用å��字表达代ç �å�«ä¹‰) +* [å��å­—ä¸�能带æ�¥æ­§ä¹‰](#å��å­—ä¸�能带æ�¥æ­§ä¹‰) +* [良好的代ç �风格](#良好的代ç �风格) +* [编写注释](#编写注释) +* [如何编写注释](#如何编写注释) +* [æ��高控制æµ�çš„å�¯è¯»æ€§](#æ��高控制æµ�çš„å�¯è¯»æ€§) +* [拆分长表达å¼�](#拆分长表达å¼�) +* [å�˜é‡�与å�¯è¯»æ€§](#å�˜é‡�与å�¯è¯»æ€§) +* [抽å�–函数](#抽å�–函数) +* [一次å�ªå�šä¸€ä»¶äº‹](#一次å�ªå�šä¸€ä»¶äº‹) +* [用自然语言表述代ç �](#用自然语言表述代ç �) +* [å‡�少代ç �é‡�](#å‡�少代ç �é‡�) -# ¿É¶ÁÐÔµÄÖØÒªÐÔ -±à³ÌÓкܴóÒ»²¿·Öʱ¼äÊÇÔÚÔĶÁ´úÂ룬²»½öÒªÔĶÁ×Ô¼ºµÄ´úÂ룬¶øÇÒÒªÔĶÁ±ðÈ˵ĴúÂë¡£Òò´Ë£¬¿É¶ÁÐÔÁ¼ºÃµÄ´úÂëÄܹ»´ó´óÌá¸ß±à³ÌЧÂÊ¡£ +# å�¯è¯»æ€§çš„é‡�è¦�性 -¿É¶ÁÐÔÁ¼ºÃµÄ´úÂëÍùÍù»áÈôúÂë¼Ü¹¹¸üºÃ£¬ÒòΪ³ÌÐòÔ±¸üÔ¸ÒâÈ¥ÐÞ¸ÄÕⲿ·Ö´úÂ룬¶øÇÒÒ²¸üÈÝÒ×Ð޸ġ£ +编程有很大一部分时间是在阅读代ç �,ä¸�ä»…è¦�阅读自己的代ç �,而且è¦�阅读别人的代ç �。因此,å�¯è¯»æ€§è‰¯å¥½çš„代ç �能够大大æ��高编程效率。 -Ö»ÓÐÔÚºËÐÄÁìÓòΪÁËЧÂʲſÉÒÔ·ÅÆú¿É¶ÁÐÔ£¬·ñÔò¿É¶ÁÐÔÊǵÚһλ¡£ +å�¯è¯»æ€§è‰¯å¥½çš„代ç �往往会让代ç �架构更好,因为程åº�员更愿æ„�去修改这部分代ç �,而且也更容易修改。 -# ÓÃÃû×Ö±í´ï´úÂ뺬Òå +å�ªæœ‰åœ¨æ ¸å¿ƒé¢†åŸŸä¸ºäº†æ•ˆçއæ‰�å�¯ä»¥æ”¾å¼ƒå�¯è¯»æ€§ï¼Œå�¦åˆ™å�¯è¯»æ€§æ˜¯ç¬¬ä¸€ä½�。 -һЩ±È½ÏÓбí´ïÁ¦µÄµ¥´Ê£º +# 用å��字表达代ç �å�«ä¹‰ -| µ¥´Ê | ¿ÉÌæ´úµ¥´Ê | +一些比较有表达力的å�•è¯�: + +| å�•è¯� | å�¯æ›¿ä»£å�•è¯� | | --- | --- | -| send | deliver¡¢dispatch¡¢announce¡¢distribute¡¢route | -| find | search¡¢extract¡¢locate¡¢recover | -| start| launch¡¢create¡¢begin¡¢open| -| make | create¡¢set up¡¢build¡¢generate¡¢compose¡¢add¡¢new | +| send | deliverã€�dispatchã€�announceã€�distributeã€�route | +| find | searchã€�extractã€�locateã€�recover | +| start| launchã€�createã€�beginã€�open| +| make | createã€�set upã€�buildã€�generateã€�composeã€�addã€�new | -ʹÓà i¡¢j¡¢k ×÷Ϊѭ»·µü´úÆ÷µÄÃû×Ö¹ýÓÚ¼òµ¥£¬user_i¡¢member_i ÕâÖÖÃû×Ö»á¸üÓбí´ïÁ¦¡£ÒòΪѭ»·²ã´ÎÔ½¶à£¬´úÂëÔ½ÄÑÀí½â£¬Óбí´ïÁ¦µÄµü´úÆ÷Ãû×ֿɶÁÐÔ»á¸ü¸ß +使用 iã€�jã€�k 作为循环迭代器的å��字过于简å�•,user_iã€�member_i è¿™ç§�å��字会更有表达力。因为循环层次越多,代ç �è¶Šéš¾ç�†è§£ï¼Œæœ‰è¡¨è¾¾åŠ›çš„è¿­ä»£å™¨å��å­—å�¯è¯»æ€§ä¼šæ›´é«˜ -ΪÃû×ÖÌí¼ÓÐÎÈݴʵÈÐÅÏ¢ÄÜÈÃÃû×Ö¸ü¾ßÓбí´ïÁ¦£¬µ«ÊÇÃû×ÖÒ²»á±ä³¤¡£Ãû×Ö³¤¶ÌµÄ×¼ÔòÊÇ£º×÷ÓÃÓòÔ½´ó£¬Ãû×ÖÔ½³¤¡£Òò´ËÖ»ÓÐÔÚ¶Ì×÷ÓÃÓò²ÅÄÜʹÓÃһЩ¼òµ¥Ãû×Ö¡£ +为å��字添加形容è¯�等信æ�¯èƒ½è®©å��字更具有表达力,但是å��字也会å�˜é•¿ã€‚å��字长短的准则是:作用域越大,å��字越长。因此å�ªæœ‰åœ¨çŸ­ä½œç”¨åŸŸæ‰�能使用一些简å�•å��字。 -# Ãû×Ö²»ÄÜ´øÀ´ÆçÒå +# å��å­—ä¸�能带æ�¥æ­§ä¹‰ -ÆðÍêÃû×ÖҪ˼¿¼Ò»Ï±ðÈË»á¶ÔÕâ¸öÃû×ÖÓкνâ¶Á£¬»á²»»áÎó½âÁËÔ­±¾Ïë±í´ïµÄº¬Òå¡£ +起完å��å­—è¦�æ€�考一下别人会对这个å��字有何解读,会ä¸�会误解了原本想表达的å�«ä¹‰ã€‚ -Óà min¡¢max ±íʾÊýÁ¿·¶Î§£»Óà first¡¢last ±íʾ·ÃÎʿռäµÄ°üº¬·¶Î§£¬begin¡¢end ±íʾ·ÃÎʿռäµÄÅųý·¶Î§£¬¼´ end ²»°üº¬Î²²¿¡£ +用 minã€�max 表示数é‡�范围;用 firstã€�last 表示访问空间的包å�«èŒƒå›´ï¼Œbeginã€�end 表示访问空间的排除范围,å�³ end ä¸�包å�«å°¾éƒ¨ã€‚ -![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/05907ab4-42c5-4b5e-9388-6617f6c97bea.jpg) +![](https://github.com/CyC2018/InterviewNotes/blob/master/pics//05907ab4-42c5-4b5e-9388-6617f6c97bea.jpg) -²¼¶ûÏà¹ØµÄÃüÃû¼ÓÉÏ is¡¢can¡¢should¡¢has µÈǰ׺¡£ +布尔相关的命å��加上 isã€�canã€�shouldã€�has ç­‰å‰�缀。 -# Á¼ºÃµÄ´úÂë·ç¸ñ +# 良好的代ç �风格 -Êʵ±µÄ¿ÕÐкÍËõ½ø¡£ +适当的空行和缩进。 -ÅÅÁÐÕûÆëµÄ×¢ÊÍ£º +排列整é½�的注释: ``` -int a = 1; // ×¢ÊÍ -int b = 11; // ×¢ÊÍ -int c = 111; // ×¢ÊÍ +int a = 1; // 注释 +int b = 11; // 注释 +int c = 111; // 注释 ``` -Óï¾ä˳Ðò²»ÄÜËæÒ⣬±ÈÈçÓë html ±íµ¥Ïà¹ØÁªµÄ±äÁ¿µÄ¸³ÖµÓ¦¸ÃºÍ±íµ¥ÔÚ html ÖеÄ˳ÐòÒ»Ö£» +语å�¥é¡ºåº�ä¸�能éš�æ„�,比如与 html 表å�•相关è�”çš„å�˜é‡�的赋值应该和表å�•在 html 中的顺åº�一致; -°ÑÏà¹ØµÄ´úÂë°´¿é×éÖ¯ÆðÀ´·ÅÔÚÒ»Æð¡£ +把相关的代ç �按å�—组织起æ�¥æ”¾åœ¨ä¸€èµ·ã€‚ -# ±àдעÊÍ +# 编写注释 -ÔĶÁ´úÂëÊ×ÏÈ»á×¢Òâµ½×¢ÊÍ£¬Èç¹û×¢ÊÍû̫´ó×÷Óã¬ÄÇô¾Í»áÀË·Ñ´úÂëÔĶÁµÄʱ¼ä¡£ÄÇЩÄÜÖ±½Ó¿´³öº¬ÒåµÄ´úÂë²»ÐèҪдעÊÍ£¬ÌرðÊDz¢²»ÐèҪΪÿ¸ö·½·¨¶¼¼ÓÉÏ×¢ÊÍ£¬±ÈÈçÄÇЩ¼òµ¥µÄ getter ºÍ setter ·½·¨£¬ÎªÕâЩ·½·¨Ð´×¢ÊÍ·´¶øÈôúÂë¿É¶ÁÐÔ¸ü²î¡£ +阅读代ç �首先会注æ„�到注释,如果注释没太大作用,那么就会浪费代ç �阅读的时间。那些能直接看出å�«ä¹‰çš„代ç �ä¸�需è¦�写注释,特别是并ä¸�需è¦�为æ¯�个方法都加上注释,比如那些简å�•çš„ getter å’Œ setter 方法,为这些方法写注释å��而让代ç �å�¯è¯»æ€§æ›´å·®ã€‚ -²»ÄÜÒòΪÓÐ×¢Ê;ÍËæ±ãÆð¸öÃû×Ö£¬¶øÊÇÕùÈ¡Æð¸öºÃÃû×Ö¶ø²»Ð´×¢ÊÍ¡£ +ä¸�能因为有注释就éš�便起个å��字,而是争å�–起个好å��字而ä¸�写注释。 -¿ÉÒÔÓÃ×¢ÊÍÀ´¼Ç¼²ÉÓõ±Ç°½â¾ö°ì·¨µÄ˼¿¼¹ý³Ì£¬´Ó¶øÈöÁÕ߸üÈÝÒ×Àí½â´úÂë¡£ +å�¯ä»¥ç”¨æ³¨é‡Šæ�¥è®°å½•采用当å‰�解决办法的æ€�考过程,从而让读者更容易ç�†è§£ä»£ç �。 -×¢ÊÍÓÃÀ´ÌáÐÑÒ»Ð©ÌØÊâÇé¿ö¡£ +注释用æ�¥æ��醒一些特殊情况。 -Óà TODO µÈ×ö±ê¼Ç£º +用 TODO ç­‰å�šæ ‡è®°ï¼š -| ±ê¼Ç | Ó÷¨ | +| 标记 | 用法 | |---|---| -|TODO| ´ý×ö | -|FIXME| ´ýÐÞ¸´ | -|HACH| ´Ö²ÚµÄ½â¾ö·½°¸ | -|XXX| ΣÏÕ£¡ÕâÀïÓÐÖØÒªµÄÎÊÌâ | +|TODO| å¾…å�š | +|FIXME| å¾…ä¿®å¤� | +|HACH| 粗糙的解决方案 | +|XXX| å�±é™©ï¼�这里有é‡�è¦�的问题 | -# ÈçºÎ±àдעÊÍ +# 如何编写注释 -¾¡Á¿¼ò½àÃ÷ÁË£º +å°½é‡�简æ´�明了: ``` // The first String is student's name @@ -97,7 +98,7 @@ Map scoreMap = new HashMap<>(); Map scoreMap = new HashMap<>(); ``` -Ìí¼Ó²âÊÔÓÃÀýÀ´ËµÃ÷£º +添加测试用例æ�¥è¯´æ˜Žï¼š ``` //... @@ -107,7 +108,7 @@ int add(int x, int y) { } ``` -Ôںܸ´Ôӵĺ¯Êýµ÷ÓÃÖжÔÿ¸ö²ÎÊý±êÉÏÃû×Ö£º +在很å¤�æ�‚的函数调用中对æ¯�个å�‚数标上å��字: ``` int a = 1; @@ -115,37 +116,37 @@ int b = 2; int num = add(\* x = *\ a, \* y = *\ b); ``` -ʹÓÃרҵÃû´ÊÀ´Ëõ¶Ì¸ÅÄîÉϵĽâÊÍ£¬±ÈÈçÓÃÉè¼ÆÄ£Ê½ÃûÀ´ËµÃ÷´úÂë¡£ +使用专业å��è¯�æ�¥ç¼©çŸ­æ¦‚念上的解释,比如用设计模å¼�å��æ�¥è¯´æ˜Žä»£ç �。 -# Ìá¸ß¿ØÖÆÁ÷µÄ¿É¶ÁÐÔ +# æ��高控制æµ�çš„å�¯è¯»æ€§ -Ìõ¼þ±í´ïʽÖУ¬×ó²àÊDZäÁ¿£¬ÓÒ²àÊdz£Êý¡£±ÈÈçÏÂÃæµÚÒ»¸öÓï¾äÕýÈ·£º +æ�¡ä»¶è¡¨è¾¾å¼�中,左侧是å�˜é‡�,å�³ä¾§æ˜¯å¸¸æ•°ã€‚比如下é�¢ç¬¬ä¸€ä¸ªè¯­å�¥æ­£ç¡®ï¼š ``` if(len < 10) if(10 > len) ``` -if / else Ìõ¼þÓï¾ä£¬Âß¼­µÄ´¦Àí˳ÐòΪ£º¢Ù ÕýÂß¼­£»¢Ú ¹Ø¼üÂß¼­£»¢Û ¼òµ¥Âß¼­¡£ +if / else æ�¡ä»¶è¯­å�¥ï¼Œé€»è¾‘的处ç�†é¡ºåº�为:① 正逻辑;② 关键逻辑;③ 简å�•逻辑。 ``` if(a == b) { - // ÕýÂß¼­ + // 正逻辑 } else{ - // ·´Âß¼­ + // å��逻辑 } ``` -Ö»ÓÐÔÚÂß¼­¼òµ¥µÄÇé¿öÏÂʹÓà ? : ÈýÄ¿ÔËËã·ûÀ´Ê¹´úÂë¸ü½ô´Õ£¬·ñÔòÓ¦¸Ã²ð·Ö³É if / else£» +å�ªæœ‰åœ¨é€»è¾‘简å�•的情况下使用 ? : 三目è¿�算符æ�¥ä½¿ä»£ç �更紧凑,å�¦åˆ™åº”该拆分æˆ� if / elseï¼› -do / while µÄÌõ¼þ·ÅÔÚºóÃæ£¬²»¹»¼òµ¥Ã÷ÁË£¬²¢ÇÒ»áÓÐһЩÃÔ»óµÄµØ·½£¬×îºÃʹÓà while À´´úÌæ¡£ +do / while çš„æ�¡ä»¶æ”¾åœ¨å�Žé�¢ï¼Œä¸�够简å�•明了,并且会有一些迷惑的地方,最好使用 while æ�¥ä»£æ›¿ã€‚ -Èç¹ûÖ»ÓÐÒ»¸ö goto Ä¿±ê£¬ÄÇô goto ÉÐÇÒ»¹ÄܽÓÊÜ£¬µ«ÊǹýÓÚ¸´Ô goto »áÈôúÂë¿É¶ÁÐÔÌØ±ð²î£¬Ó¦¸Ã±ÜÃâʹÓà goto¡£ +如果å�ªæœ‰ä¸€ä¸ª goto 目标,那么 goto 尚且还能接å�—,但是过于å¤�æ�‚çš„ goto 会让代ç �å�¯è¯»æ€§ç‰¹åˆ«å·®ï¼Œåº”该é�¿å…�使用 goto。 -ÔÚǶÌ×µÄÑ­»·ÖУ¬ÓÃһЩ return Óï¾äÍùÍùÄܼõÉÙǶÌ׵IJãÊý¡£ +在嵌套的循环中,用一些 return 语å�¥å¾€å¾€èƒ½å‡�少嵌套的层数。 -# ²ð·Ö³¤±í´ïʽ +# 拆分长表达å¼� -³¤±í´ïʽµÄ¿É¶ÁÐԺܲ¿ÉÒÔÒýÈëһЩ½âÊͱäÁ¿´Ó¶ø²ð·Ö±í´ïʽ£º +长表达å¼�çš„å�¯è¯»æ€§å¾ˆå·®ï¼Œå�¯ä»¥å¼•入一些解释å�˜é‡�从而拆分表达å¼�: ``` if line.split(':')[0].strip() == "root": @@ -157,7 +158,7 @@ if username == "root": ... ``` -ʹÓÃĦ¸ù¶¨Àí¼ò»¯Ò»Ð©Âß¼­±í´ïʽ£º +使用摩根定ç�†ç®€åŒ–一些逻辑表达å¼�: ``` if(!a && !b) { @@ -170,9 +171,9 @@ if(a || b) { } ``` -# ±äÁ¿Óë¿É¶ÁÐÔ +# å�˜é‡�与å�¯è¯»æ€§ -**È¥³ý¿ØÖÆÁ÷±äÁ¿**¡£ÔÚÑ­»·ÖÐͨ¹ýʹÓà break »òÕß return ¿ÉÒÔ¼õÉÙ¿ØÖÆÁ÷±äÁ¿µÄʹÓᣠ+**去除控制æµ�å�˜é‡�**。在循环中通过使用 break 或者 return å�¯ä»¥å‡�少控制æµ�å�˜é‡�的使用。 ``` boolean done = false; @@ -193,9 +194,9 @@ while(/* condition */) { } ``` -**¼õС±äÁ¿×÷ÓÃÓò**¡£×÷ÓÃÓòԽС£¬Ô½ÈÝÒ×¶¨Î»µ½±äÁ¿ËùÓÐʹÓõĵط½¡£ +**å‡�å°�å�˜é‡�作用域**。作用域越å°�,越容易定ä½�到å�˜é‡�所有使用的地方。 -JavaScript ¿ÉÒÔÓñհü¼õС×÷ÓÃÓò¡£ÒÔÏ´úÂëÖÐ submit_form ÊǺ¯Êý±äÁ¿£¬submitted ±äÁ¿¿ØÖƺ¯Êý²»»á±»Ìá½»Á½´Î¡£µÚÒ»¸öʵÏÖÖÐ submitted ÊÇÈ«¾Ö±äÁ¿£¬µÚ¶þ¸öʵÏÖ°Ñ submitted ·Åµ½ÄäÃûº¯ÊýÖУ¬´Ó¶øÏÞÖÆÁËÆð×÷ÓÃÓò·¶Î§¡£ +JavaScript å�¯ä»¥ç”¨é—­åŒ…å‡�å°�作用域。以下代ç �中 submit_form 是函数å�˜é‡�,submitted å�˜é‡�控制函数ä¸�会被æ��交两次。第一个实现中 submitted 是全局å�˜é‡�,第二个实现把 submitted 放到匿å��函数中,从而é™�制了起作用域范围。 ``` submitted = false; @@ -216,16 +217,16 @@ var submit_form = (function() { } submitted = true; } -}()); // () ʹµÃÍâ²ãÄäÃûº¯ÊýÁ¢¼´Ö´ÐÐ +}()); // () 使得外层匿å��函数立å�³æ‰§è¡Œ ``` -JavaScript ÖÐûÓÐÓà var ÉùÃ÷µÄ±äÁ¿¶¼ÊÇÈ«¾Ö±äÁ¿£¬¶øÈ«¾Ö±äÁ¿ºÜÈÝÒ×Ôì³ÉÃÔ»ó£¬Òò´ËÓ¦µ±×ÜÊÇÓà var À´ÉùÃ÷±äÁ¿¡£ +JavaScript 中没有用 var 声明的å�˜é‡�都是全局å�˜é‡�,而全局å�˜é‡�很容易造æˆ�迷惑,因此应当总是用 var æ�¥å£°æ˜Žå�˜é‡�。 -±äÁ¿¶¨ÒåµÄλÖÃÓ¦µ±ÀëËüʹÓõÄλÖÃ×î½ü¡£ +å�˜é‡�定义的ä½�置应当离它使用的ä½�置最近。 -**ʵÀý½âÎö** +**实例解æž�** -ÔÚÒ»¸öÍøÒ³ÖÐÓÐÒÔÏÂÎı¾ÊäÈë×ֶΣº +在一个网页中有以下文本输入字段: ``` @@ -234,7 +235,7 @@ JavaScript ``` -ÏÖÔÚÒª½ÓÊÜÒ»¸ö×Ö·û´®²¢°ÑËü·Åµ½µÚÒ»¸ö¿ÕµÄ input ×Ö¶ÎÖУ¬³õʼʵÏÖÈçÏ£º +现在è¦�接å�—一个字符串并把它放到第一个空的 input 字段中,åˆ�始实现如下: ``` var setFirstEmptyInput = function(new_alue) { @@ -254,11 +255,11 @@ var setFirstEmptyInput = function(new_alue) { } ``` -ÒÔÉÏʵÏÖÓÐÒÔÏÂÎÊÌ⣺ +以上实现有以下问题: -- found ¿ÉÒÔÈ¥³ý£» -- elem ×÷ÓÃÓò¹ý´ó£» -- ¿ÉÒÔÓà for Ñ­»·´úÌæ while Ñ­»·£» +- found å�¯ä»¥åŽ»é™¤ï¼› +- elem 作用域过大; +- å�¯ä»¥ç”¨ for 循环代替 while 循环; ``` var setFirstEmptyInput = function(new_value) { @@ -275,13 +276,13 @@ var setFirstEmptyInput = function(new_value) { }; ``` -# ³éÈ¡º¯Êý +# 抽å�–函数 -¹¤³Ìѧ¾ÍÊǰѴóÎÊÌâ²ð·Ö³ÉСÎÊÌâÔÙ°ÑÕâЩÎÊÌâµÄ½â¾ö·½°¸·Å»ØÒ»Æð¡£ +工程学就是把大问题拆分æˆ�å°�问题å†�把这些问题的解决方案放回一起。 -Ê×ÏÈÓ¦¸ÃÃ÷È·Ò»¸öº¯ÊýµÄ¸ß²ã´ÎÄ¿±ê£¬È»ºó¶ÔÓÚ²»ÊÇÖ±½ÓΪÁËÕâ¸öÄ¿±ê¹¤×÷µÄ´úÂ룬³éÈ¡³öÀ´·Åµ½¶ÀÁ¢µÄº¯ÊýÖС£ +首先应该明确一个函数的高层次目标,然å�Žå¯¹äºŽä¸�是直接为了这个目标工作的代ç �,抽å�–出æ�¥æ”¾åˆ°ç‹¬ç«‹çš„函数中。 -½éÉÜÐԵĴúÂ룺 +介ç»�性的代ç �: ``` int findClostElement(int[] arr) { @@ -302,7 +303,7 @@ int findClostElement(int[] arr) { } ``` -ÒÔÉÏ´úÂëÖÐÑ­»·²¿·ÖÖ÷Òª¼ÆËã¾àÀ룬Õⲿ·Ö²»ÊôÓÚ´úÂë¸ß²ã´ÎÄ¿±ê£¬¸ß²ã´ÎÄ¿±êÊÇѰÕÒ×îС¾àÀëµÄÖµ£¬Òò´Ë¿ÉÒÔ°ÑÕⲿ·Ö´úÌæÌáÈ¡µ½¶ÀÁ¢µÄº¯ÊýÖС£ÕâÑù×öÒ²´øÀ´Ò»¸ö¶îÍâµÄºÃ´¦ÓУº¿ÉÒÔµ¥¶À½øÐвâÊÔ¡¢¿ÉÒÔ¿ìËÙÕÒµ½³ÌÐò´íÎó²¢Ð޸ġ£ +以上代ç �中循环部分主è¦�计算è·�离,这部分ä¸�属于代ç �高层次目标,高层次目标是寻找最å°�è·�离的值,因此å�¯ä»¥æŠŠè¿™éƒ¨åˆ†ä»£æ›¿æ��å�–到独立的函数中。这样å�šä¹Ÿå¸¦æ�¥ä¸€ä¸ªé¢�外的好处有:å�¯ä»¥å�•独进行测试ã€�å�¯ä»¥å¿«é€Ÿæ‰¾åˆ°ç¨‹åº�错误并修改。 ``` public int findClostElement(int[] arr) { @@ -319,22 +320,22 @@ public int findClostElement(int[] arr) { } ``` -²¢²»ÊǺ¯Êý³éÈ¡µÄÔ½¶àÔ½ºÃ£¬Èç¹û³éÈ¡¹ý¶à£¬ÔÚÔĶÁ´úÂëµÄʱºò¿ÉÄÜÐèÒª²»¶ÏÌøÀ´ÌøÈ¥¡£Ö»ÓÐÔÚµ±Ç°º¯Êý²»ÐèҪȥÁ˽âijһ¿é´úÂëϸ½Ú¶øÄܹ»±í´ïÆäÄÚÈÝʱ£¬°ÑÕâ¿é´úÂë³éÈ¡³É×Óº¯Êý²ÅÊǺõġ£ +å¹¶ä¸�是函数抽å�–的越多越好,如果抽å�–过多,在阅读代ç �的时候å�¯èƒ½éœ€è¦�ä¸�æ–­è·³æ�¥è·³åŽ»ã€‚å�ªæœ‰åœ¨å½“å‰�函数ä¸�需è¦�去了解æŸ�一å�—代ç �细节而能够表达其内容时,把这å�—代ç �抽å�–æˆ�å­�函数æ‰�是好的。 -º¯Êý³éȡҲÓÃÓÚ¼õС´úÂëµÄÈßÓà¡£ +函数抽å�–也用于å‡�å°�代ç �的冗余。 -# Ò»´ÎÖ»×öÒ»¼þÊ +# 一次å�ªå�šä¸€ä»¶äº‹ -Ö»×öÒ»¼þʵĴúÂëºÜÈÝÒ×ÈÃÈËÖªµÀÆäÒª×öµÄÊ£» +å�ªå�šä¸€ä»¶äº‹çš„代ç �很容易让人知é�“å…¶è¦�å�šçš„事; -»ù±¾Á÷³Ì£ºÁгö´úÂëËù×öµÄËùÓÐÈÎÎñ£»°Ñÿ¸öÈÎÎñ²ð·Öµ½²»Í¬µÄº¯Êý£¬»òÕß²»Í¬µÄ¶ÎÂä¡£ +基本æµ�程:列出代ç �所å�šçš„æ‰€æœ‰ä»»åŠ¡ï¼›æŠŠæ¯�个任务拆分到ä¸�å�Œçš„函数,或者ä¸�å�Œçš„æ®µè�½ã€‚ -# ÓÃ×ÔÈ»ÓïÑÔ±íÊö´úÂë +# 用自然语言表述代ç � -ÏÈÓÃ×ÔÈ»ÓïÑÔÊéд´úÂëÂß¼­£¬Ò²¾ÍÊÇα´úÂ룬ȻºóÔÙд´úÂ룬ÕâÑù´úÂëÂß¼­»á¸üÇåÎú¡£ +先用自然语言书写代ç �逻辑,也就是伪代ç �,然å�Žå†�写代ç �,这样代ç �逻辑会更清晰。 -# ¼õÉÙ´úÂëÁ¿ +# å‡�少代ç �é‡� -²»Òª¹ý¶ÈÉè¼Æ£¬±àÂë¹ý³Ì»áÓкܶà±ä»¯£¬¹ý¶ÈÉè¼ÆµÄÄÚÈݵ½×îºóÍùÍùÊÇÎÞÓõġ£ +ä¸�è¦�过度设计,编ç �过程会有很多å�˜åŒ–,过度设计的内容到最å�Žå¾€å¾€æ˜¯æ— ç”¨çš„。 -¶àÓñê×¼¿âʵÏÖ¡£ +多用标准库实现。 diff --git a/notes/剑指 offer 题解.md b/notes/剑指 offer 题解.md index 581ba92a..a2fd402c 100644 --- a/notes/剑指 offer 题解.md +++ b/notes/剑指 offer 题解.md @@ -1,97 +1,98 @@ -* [µÚ¶þÕÂ ÃæÊÔÐèÒªµÄ»ù´¡ÖªÊ¶](#µÚ¶þÕÂ-ÃæÊÔÐèÒªµÄ»ù´¡ÖªÊ¶) - * [2. ʵÏÖ Singleton](#2-ʵÏÖ-singleton) - * [3. Êý×éÖÐÖØ¸´µÄÊý×Ö](#3-Êý×éÖÐÖØ¸´µÄÊý×Ö) - * [4. ¶þάÊý×éÖеIJéÕÒ](#4-¶þάÊý×éÖеIJéÕÒ) - * [5. Ìæ»»¿Õ¸ñ](#5-Ìæ»»¿Õ¸ñ) - * [6. ´Óβµ½Í·´òÓ¡Á´±í](#6-´Óβµ½Í·´òÓ¡Á´±í) - * [7. ÖØ½¨¶þ²æÊ÷](#7-ÖØ½¨¶þ²æÊ÷) - * [8. ¶þ²æÊ÷µÄÏÂÒ»¸ö½áµã](#8-¶þ²æÊ÷µÄÏÂÒ»¸ö½áµã) - * [9. ÓÃÁ½¸öջʵÏÖ¶ÓÁÐ](#9-ÓÃÁ½¸öջʵÏÖ¶ÓÁÐ) - * [10.1 ì³²¨ÄÇÆõÊýÁÐ](#101-ì³²¨ÄÇÆõÊýÁÐ) - * [10.2 ÌøÌ¨½×](#102-ÌøÌ¨½×) - * [10.3 ±äÌ¬ÌøÌ¨½×](#103-±äÌ¬ÌøÌ¨½×) - * [10.4 ¾ØÐθ²¸Ç](#104-¾ØÐθ²¸Ç) - * [11. ÐýתÊý×éµÄ×îСÊý×Ö](#11-ÐýתÊý×éµÄ×îСÊý×Ö) - * [12. ¾ØÕóÖеÄ·¾¶](#12-¾ØÕóÖеÄ·¾¶) - * [13. »úÆ÷È˵ÄÔ˶¯·¶Î§](#13-»úÆ÷È˵ÄÔ˶¯·¶Î§) - * [14. ¼ôÉþ×Ó](#14-¼ôÉþ×Ó) - * [15. ¶þ½øÖÆÖÐ 1 µÄ¸öÊý](#15-¶þ½øÖÆÖÐ-1-µÄ¸öÊý) -* [µÚÈýÕ ¸ßÖÊÁ¿µÄ´úÂë](#µÚÈýÕÂ-¸ßÖÊÁ¿µÄ´úÂë) - * [16. ÊýÖµµÄÕûÊý´Î·½](#16-ÊýÖµµÄÕûÊý´Î·½) - * [18.2 ɾ³ýÁ´±íÖÐÖØ¸´µÄ½áµã](#182-ɾ³ýÁ´±íÖÐÖØ¸´µÄ½áµã) - * [19. ÕýÔò±í´ïʽƥÅä](#19-ÕýÔò±í´ïʽƥÅä) - * [20. ±íʾÊýÖµµÄ×Ö·û´®](#20-±íʾÊýÖµµÄ×Ö·û´®) - * [21. µ÷ÕûÊý×é˳ÐòÊ¹ÆæÊýλÓÚżÊýÇ°Ãæ](#21-µ÷ÕûÊý×é˳ÐòÊ¹ÆæÊýλÓÚżÊýÇ°Ãæ) - * [22. Á´±íÖе¹ÊýµÚ k ¸ö½áµã](#22-Á´±íÖе¹ÊýµÚ-k-¸ö½áµã) - * [23. Á´±íÖл·µÄÈë¿Ú½áµã](#23-Á´±íÖл·µÄÈë¿Ú½áµã) - * [24. ·´×ªÁ´±í](#24-·´×ªÁ´±í) - * [25. ºÏ²¢Á½¸öÅÅÐòµÄÁ´±í](#25-ºÏ²¢Á½¸öÅÅÐòµÄÁ´±í) - * [26. Ê÷µÄ×ӽṹ](#26-Ê÷µÄ×ӽṹ) -* [µÚËÄÕ ½â¾öÃæÊÔÌâµÄ˼·](#µÚËÄÕÂ-½â¾öÃæÊÔÌâµÄ˼·) - * [27. ¶þ²æÊ÷µÄ¾µÏñ](#27-¶þ²æÊ÷µÄ¾µÏñ) - * [28.1 ¶Ô³ÆµÄ¶þ²æÊ÷](#281-¶Ô³ÆµÄ¶þ²æÊ÷) - * [28.2 ƽºâ¶þ²æÊ÷](#282-ƽºâ¶þ²æÊ÷) - * [29. ˳ʱÕë´òÓ¡¾ØÕó](#29-˳ʱÕë´òÓ¡¾ØÕó) - * [30. °üº¬ min º¯ÊýµÄÕ»](#30-°üº¬-min-º¯ÊýµÄÕ») - * [31. Õ»µÄѹÈë¡¢µ¯³öÐòÁÐ](#31-Õ»µÄѹÈ뵯³öÐòÁÐ) - * [32.1 ´ÓÉÏÍùÏ´òÓ¡¶þ²æÊ÷](#321-´ÓÉÏÍùÏ´òÓ¡¶þ²æÊ÷) - * [32.3 °Ñ¶þ²æÊ÷´òÓ¡³É¶àÐÐ](#323--°Ñ¶þ²æÊ÷´òÓ¡³É¶àÐÐ) - * [32.3 °´Ö®×ÖÐÎ˳Ðò´òÓ¡¶þ²æÊ÷](#323-°´Ö®×ÖÐÎ˳Ðò´òÓ¡¶þ²æÊ÷) - * [33. ¶þ²æËÑË÷Ê÷µÄºóÐò±éÀúÐòÁÐ](#33-¶þ²æËÑË÷Ê÷µÄºóÐò±éÀúÐòÁÐ) - * [34. ¶þ²æÊ÷ÖкÍΪijһֵµÄ·¾¶](#34-¶þ²æÊ÷ÖкÍΪijһֵµÄ·¾¶) - * [35. ¸´ÔÓÁ´±íµÄ¸´ÖÆ](#35-¸´ÔÓÁ´±íµÄ¸´ÖÆ) - * [36. ¶þ²æËÑË÷Ê÷ÓëË«ÏòÁ´±í](#36-¶þ²æËÑË÷Ê÷ÓëË«ÏòÁ´±í) - * [37. ÐòÁл¯¶þ²æÊ÷](#37-ÐòÁл¯¶þ²æÊ÷) - * [38. ×Ö·û´®µÄÅÅÁÐ](#38-×Ö·û´®µÄÅÅÁÐ) -* [µÚÎåÕ ÓÅ»¯Ê±¼äºÍ¿Õ¼äЧÂÊ](#µÚÎåÕÂ-ÓÅ»¯Ê±¼äºÍ¿Õ¼äЧÂÊ) - * [39. Êý×éÖгöÏÖ´ÎÊý³¬¹ýÒ»°ëµÄÊý×Ö](#39-Êý×éÖгöÏÖ´ÎÊý³¬¹ýÒ»°ëµÄÊý×Ö) - * [40. ×îСµÄ K ¸öÊý](#40-×îСµÄ-k-¸öÊý) - * [41.1 Êý¾ÝÁ÷ÖеÄÖÐλÊý](#411-Êý¾ÝÁ÷ÖеÄÖÐλÊý) - * [14.2 ×Ö·ûÁ÷ÖеÚÒ»¸ö²»Öظ´µÄ×Ö·û](#142-×Ö·ûÁ÷ÖеÚÒ»¸ö²»Öظ´µÄ×Ö·û) - * [42. Á¬Ðø×ÓÊý×éµÄ×î´óºÍ](#42-Á¬Ðø×ÓÊý×éµÄ×î´óºÍ) - * [43. ´Ó 1 µ½ n ÕûÊýÖÐ 1 ³öÏֵĴÎÊý](#43-´Ó-1-µ½-n-ÕûÊýÖÐ-1-³öÏֵĴÎÊý) - * [45. °ÑÊý×éÅųÉ×îСµÄÊý](#45-°ÑÊý×éÅųÉ×îСµÄÊý) - * [49. ³óÊý](#49-³óÊý) - * [50. µÚÒ»¸öÖ»³öÏÖÒ»´ÎµÄ×Ö·ûλÖÃ](#50-µÚÒ»¸öÖ»³öÏÖÒ»´ÎµÄ×Ö·ûλÖÃ) - * [51. Êý×éÖеÄÄæÐò¶Ô](#51-Êý×éÖеÄÄæÐò¶Ô) - * [52. Á½¸öÁ´±íµÄµÚÒ»¸ö¹«¹²½áµã](#52-Á½¸öÁ´±íµÄµÚÒ»¸ö¹«¹²½áµã) -* [µÚÁùÕÂ ÃæÊÔÖеĸ÷ÏîÄÜÁ¦](#µÚÁùÕÂ-ÃæÊÔÖеĸ÷ÏîÄÜÁ¦) - * [53 Êý×ÖÔÚÅÅÐòÊý×éÖгöÏֵĴÎÊý](#53-Êý×ÖÔÚÅÅÐòÊý×éÖгöÏֵĴÎÊý) - * [54. ¶þ²æËÑË÷Ê÷µÄµÚ k ¸ö½áµã](#54-¶þ²æËÑË÷Ê÷µÄµÚ-k-¸ö½áµã) - * [55 ¶þ²æÊ÷µÄÉî¶È](#55-¶þ²æÊ÷µÄÉî¶È) - * [56. Êý×éÖÐÖ»³öÏÖÒ»´ÎµÄÊý×Ö](#56-Êý×éÖÐÖ»³öÏÖÒ»´ÎµÄÊý×Ö) - * [57.1 ºÍΪ S µÄÁ½¸öÊý×Ö](#571-ºÍΪ-s-µÄÁ½¸öÊý×Ö) - * [57.2 ºÍΪ S µÄÁ¬ÐøÕýÊýÐòÁÐ](#572-ºÍΪ-s-µÄÁ¬ÐøÕýÊýÐòÁÐ) - * [58.1 ·­×ªµ¥´Ê˳ÐòÁÐ](#581-·­×ªµ¥´Ê˳ÐòÁÐ) - * [58.2 ×óÐýת×Ö·û´®](#582-×óÐýת×Ö·û´®) - * [59. »¬¶¯´°¿ÚµÄ×î´óÖµ](#59-»¬¶¯´°¿ÚµÄ×î´óÖµ) - * [61. ÆË¿ËÅÆË³×Ó](#61-ÆË¿ËÅÆË³×Ó) - * [62. ԲȦÖÐ×îºóʣϵÄÊý](#62-ԲȦÖÐ×îºóʣϵÄÊý) - * [63. ¹ÉƱµÄ×î´óÀûÈó](#63-¹ÉƱµÄ×î´óÀûÈó) - * [64. Çó 1+2+3+...+n](#64-Çó-1+2+3++n) - * [65. ²»ÓüӼõ³Ë³ý×ö¼Ó·¨](#65-²»ÓüӼõ³Ë³ý×ö¼Ó·¨) - * [66. ¹¹½¨³Ë»ýÊý×é](#66-¹¹½¨³Ë»ýÊý×é) -* [µÚÆßÕ Á½¸öÃæÊÔ°¸Àý](#µÚÆßÕÂ-Á½¸öÃæÊÔ°¸Àý) - * [67. °Ñ×Ö·û´®×ª»»³ÉÕûÊý](#67-°Ñ×Ö·û´®×ª»»³ÉÕûÊý) - * [68. Ê÷ÖÐÁ½¸ö½ÚµãµÄ×îµÍ¹«¹²×æÏÈ](#68-Ê÷ÖÐÁ½¸ö½ÚµãµÄ×îµÍ¹«¹²×æÏÈ) +* [第二章 é�¢è¯•需è¦�的基础知识](#第二章-é�¢è¯•需è¦�的基础知识) + * [2. 实现 Singleton](#2-实现-singleton) + * [3. 数组中é‡�å¤�的数字](#3-数组中é‡�å¤�的数字) + * [4. 二维数组中的查找](#4-二维数组中的查找) + * [5. 替æ�¢ç©ºæ ¼](#5-替æ�¢ç©ºæ ¼) + * [6. 从尾到头打å�°é“¾è¡¨](#6-从尾到头打å�°é“¾è¡¨) + * [7. é‡�建二å�‰æ ‘](#7-é‡�建二å�‰æ ‘) + * [8. 二å�‰æ ‘的下一个结点](#8-二å�‰æ ‘的下一个结点) + * [9. 用两个栈实现队列](#9-用两个栈实现队列) + * [10.1 æ–�波那契数列](#101-æ–�波那契数列) + * [10.2 è·³å�°é˜¶](#102-è·³å�°é˜¶) + * [10.3 å�˜æ€�è·³å�°é˜¶](#103-å�˜æ€�è·³å�°é˜¶) + * [10.4 矩形覆盖](#104-矩形覆盖) + * [11. 旋转数组的最å°�æ•°å­—](#11-旋转数组的最å°�æ•°å­—) + * [12. 矩阵中的路径](#12-矩阵中的路径) + * [13. 机器人的è¿�动范围](#13-机器人的è¿�动范围) + * [14. 剪绳å­�](#14-剪绳å­�) + * [15. 二进制中 1 的个数](#15-二进制中-1-的个数) +* [第三章 高质é‡�的代ç �](#第三章-高质é‡�的代ç �) + * [16. 数值的整数次方](#16-数值的整数次方) + * [18.2 删除链表中é‡�å¤�的结点](#182-删除链表中é‡�å¤�的结点) + * [19. 正则表达å¼�匹é…�](#19-正则表达å¼�匹é…�) + * [20. 表示数值的字符串](#20-表示数值的字符串) + * [21. 调整数组顺åº�使奇数ä½�于å�¶æ•°å‰�é�¢](#21-调整数组顺åº�使奇数ä½�于å�¶æ•°å‰�é�¢) + * [22. 链表中倒数第 k 个结点](#22-链表中倒数第-k-个结点) + * [23. 链表中环的入å�£ç»“点](#23-链表中环的入å�£ç»“点) + * [24. å��转链表](#24-å��转链表) + * [25. å�ˆå¹¶ä¸¤ä¸ªæŽ’åº�的链表](#25-å�ˆå¹¶ä¸¤ä¸ªæŽ’åº�的链表) + * [26. æ ‘çš„å­�结构](#26-æ ‘çš„å­�结构) +* [第四章 解决é�¢è¯•题的æ€�è·¯](#第四章-解决é�¢è¯•题的æ€�è·¯) + * [27. 二å�‰æ ‘的镜åƒ�](#27-二å�‰æ ‘的镜åƒ�) + * [28.1 对称的二å�‰æ ‘](#281-对称的二å�‰æ ‘) + * [28.2 平衡二å�‰æ ‘](#282-平衡二å�‰æ ‘) + * [29. 顺时针打å�°çŸ©é˜µ](#29-顺时针打å�°çŸ©é˜µ) + * [30. 包å�« min 函数的栈](#30-包å�«-min-函数的栈) + * [31. 栈的压入ã€�弹出åº�列](#31-栈的压入弹出åº�列) + * [32.1 从上往下打å�°äºŒå�‰æ ‘](#321-从上往下打å�°äºŒå�‰æ ‘) + * [32.3 把二å�‰æ ‘打å�°æˆ�多行](#323--把二å�‰æ ‘打å�°æˆ�多行) + * [32.3 按之字形顺åº�打å�°äºŒå�‰æ ‘](#323-按之字形顺åº�打å�°äºŒå�‰æ ‘) + * [33. 二å�‰æ�œç´¢æ ‘çš„å�Žåº�é��历åº�列](#33-二å�‰æ�œç´¢æ ‘çš„å�Žåº�é��历åº�列) + * [34. 二å�‰æ ‘中和为æŸ�一值的路径](#34-二å�‰æ ‘中和为æŸ�一值的路径) + * [35. å¤�æ�‚链表的å¤�制](#35-å¤�æ�‚链表的å¤�制) + * [36. 二å�‰æ�œç´¢æ ‘与å�Œå�‘链表](#36-二å�‰æ�œç´¢æ ‘与å�Œå�‘链表) + * [37. åº�列化二å�‰æ ‘](#37-åº�列化二å�‰æ ‘) + * [38. 字符串的排列](#38-字符串的排列) +* [第五章 优化时间和空间效率](#第五章-优化时间和空间效率) + * [39. 数组中出现次数超过一å�Šçš„æ•°å­—](#39-数组中出现次数超过一å�Šçš„æ•°å­—) + * [40. 最å°�çš„ K 个数](#40-最å°�çš„-k-个数) + * [41.1 æ•°æ�®æµ�中的中ä½�æ•°](#411-æ•°æ�®æµ�中的中ä½�æ•°) + * [14.2 字符æµ�中第一个ä¸�é‡�å¤�的字符](#142-字符æµ�中第一个ä¸�é‡�å¤�的字符) + * [42. 连续å­�数组的最大和](#42-连续å­�数组的最大和) + * [43. 从 1 到 n 整数中 1 出现的次数](#43-从-1-到-n-整数中-1-出现的次数) + * [45. 把数组排æˆ�最å°�的数](#45-把数组排æˆ�最å°�的数) + * [49. 丑数](#49-丑数) + * [50. 第一个å�ªå‡ºçŽ°ä¸€æ¬¡çš„å­—ç¬¦ä½�ç½®](#50-第一个å�ªå‡ºçŽ°ä¸€æ¬¡çš„å­—ç¬¦ä½�ç½®) + * [51. 数组中的逆åº�对](#51-数组中的逆åº�对) + * [52. 两个链表的第一个公共结点](#52-两个链表的第一个公共结点) +* [第六章 é�¢è¯•中的å�„项能力](#第六章-é�¢è¯•中的å�„项能力) + * [53 数字在排åº�数组中出现的次数](#53-数字在排åº�数组中出现的次数) + * [54. 二å�‰æ�œç´¢æ ‘的第 k 个结点](#54-二å�‰æ�œç´¢æ ‘的第-k-个结点) + * [55 二å�‰æ ‘的深度](#55-二å�‰æ ‘的深度) + * [56. 数组中å�ªå‡ºçŽ°ä¸€æ¬¡çš„æ•°å­—](#56-数组中å�ªå‡ºçŽ°ä¸€æ¬¡çš„æ•°å­—) + * [57.1 和为 S 的两个数字](#571-和为-s-的两个数字) + * [57.2 和为 S 的连续正数åº�列](#572-和为-s-的连续正数åº�列) + * [58.1 翻转å�•è¯�顺åº�列](#581-翻转å�•è¯�顺åº�列) + * [58.2 左旋转字符串](#582-左旋转字符串) + * [59. 滑动窗å�£çš„æœ€å¤§å€¼](#59-滑动窗å�£çš„æœ€å¤§å€¼) + * [61. 扑克牌顺å­�](#61-扑克牌顺å­�) + * [62. 圆圈中最å�Žå‰©ä¸‹çš„æ•°](#62-圆圈中最å�Žå‰©ä¸‹çš„æ•°) + * [63. 股票的最大利润](#63-股票的最大利润) + * [64. 求 1+2+3+...+n](#64-求-1+2+3++n) + * [65. ä¸�用加å‡�乘除å�šåŠ æ³•](#65-ä¸�用加å‡�乘除å�šåŠ æ³•) + * [66. 构建乘积数组](#66-构建乘积数组) +* [第七章 两个é�¢è¯•案例](#第七章-两个é�¢è¯•案例) + * [67. 把字符串转æ�¢æˆ�æ•´æ•°](#67-把字符串转æ�¢æˆ�æ•´æ•°) + * [68. 树中两个节点的最低公共祖先](#68-树中两个节点的最低公共祖先) -# µÚ¶þÕÂ ÃæÊÔÐèÒªµÄ»ù´¡ÖªÊ¶ -## 2. ʵÏÖ Singleton +# 第二章 é�¢è¯•需è¦�的基础知识 -[µ¥Àýģʽ](https://github.com/CyC2018/InterviewNotes/blob/master/notes/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F.md#%E7%AC%AC-5-%E7%AB%A0-%E5%8D%95%E4%BB%B6%E6%A8%A1%E5%BC%8F) +## 2. 实现 Singleton -## 3. Êý×éÖÐÖØ¸´µÄÊý×Ö +[å�•例模å¼�](https://github.com/CyC2018/InterviewNotes/blob/master/notes/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F.md#%E7%AC%AC-5-%E7%AB%A0-%E5%8D%95%E4%BB%B6%E6%A8%A1%E5%BC%8F) -**ÌâÄ¿ÃèÊö** +## 3. 数组中é‡�å¤�的数字 -ÔÚÒ»¸ö³¤¶ÈΪ n µÄÊý×éÀïµÄËùÓÐÊý×Ö¶¼ÔÚ 0 µ½ n-1 µÄ·¶Î§ÄÚ¡£Êý×éÖÐijЩÊý×ÖÊÇÖØ¸´µÄ£¬µ«²»ÖªµÀÓм¸¸öÊý×ÖÊÇÖØ¸´µÄ¡£Ò²²»ÖªµÀÿ¸öÊý×ÖÖØ¸´¼¸´Î¡£ÇëÕÒ³öÊý×éÖÐÈÎÒâÒ»¸öÖØ¸´µÄÊý×Ö¡£ÀýÈ磬Èç¹ûÊäÈ볤¶ÈΪ 7 µÄÊý×é {2, 3, 1, 0, 2, 5, 3}£¬ÄÇô¶ÔÓ¦µÄÊä³öÊǵÚÒ»¸öÖØ¸´µÄÊý×Ö 2¡£ +**题目æ��è¿°** -**½âÌâ˼·** +在一个长度为 n 的数组里的所有数字都在 0 到 n-1 的范围内。数组中æŸ�些数字是é‡�å¤�的,但ä¸�知é�“有几个数字是é‡�å¤�的。也ä¸�知é�“æ¯�个数字é‡�å¤�几次。请找出数组中任æ„�一个é‡�å¤�的数字。例如,如果输入长度为 7 的数组 {2, 3, 1, 0, 2, 5, 3},那么对应的输出是第一个é‡�å¤�的数字 2。 -ÕâÖÖÊý×éÔªËØÔÚ [0, n-1] ·¶Î§ÄÚµÄÎÊÌ⣬¿ÉÒÔ½«ÖµÎª i µÄÔªËØ·Åµ½µÚ i ¸öλÖÃÉÏ¡£ +**解题æ€�è·¯** + +è¿™ç§�数组元素在 [0, n-1] 范围内的问题,å�¯ä»¥å°†å€¼ä¸º i 的元素放到第 i 个ä½�置上。 ```java public boolean duplicate(int numbers[], int length, int[] duplication) { @@ -115,15 +116,15 @@ private void swap(int[] numbers, int i, int j) { } ``` -## 4. ¶þάÊý×éÖеIJéÕÒ +## 4. 二维数组中的查找 -**ÌâÄ¿ÃèÊö** +**题目æ��è¿°** -ÔÚÒ»¸ö¶þάÊý×éÖУ¬Ã¿Ò»Ðж¼°´ÕÕ´Ó×óµ½ÓÒµÝÔöµÄ˳ÐòÅÅÐò£¬Ã¿Ò»Áж¼°´ÕÕ´ÓÉϵ½ÏµÝÔöµÄ˳ÐòÅÅÐò¡£ÇëÍê³ÉÒ»¸öº¯Êý£¬ÊäÈëÕâÑùµÄÒ»¸ö¶þάÊý×éºÍÒ»¸öÕûÊý£¬ÅжÏÊý×éÖÐÊÇ·ñº¬ÓиÃÕûÊý¡£ +在一个二维数组中,æ¯�一行都按照从左到å�³é€’增的顺åº�排åº�,æ¯�一列都按照从上到下递增的顺åº�排åº�。请完æˆ�一个函数,输入这样的一个二维数组和一个整数,判断数组中是å�¦å�«æœ‰è¯¥æ•´æ•°ã€‚ -**½âÌâ˼·** +**解题æ€�è·¯** -´ÓÓÒÉϽǿªÊ¼²éÕÒ¡£ÒòΪ¾ØÕóÖеÄÒ»¸öÊý£¬Ëü×ó±ßµÄÊý¶¼±ÈËüÀ´µÄС£¬Ï±ߵÄÊý¶¼±ÈËüÀ´µÄ´ó¡£Òò´Ë£¬´ÓÓÒÉϽǿªÊ¼²éÕÒ£¬¾Í¿ÉÒÔ¸ù¾Ý target ºÍµ±Ç°ÔªËصĴóС¹ØÏµÀ´¸Ä±äÐкÍÁеÄϱ꣬´Ó¶øËõС²éÕÒÇø¼ä¡£ +从å�³ä¸Šè§’开始查找。因为矩阵中的一个数,它左边的数都比它æ�¥çš„å°�,下边的数都比它æ�¥çš„大。因此,从å�³ä¸Šè§’开始查找,就å�¯ä»¥æ ¹æ�® target 和当å‰�元素的大å°�关系æ�¥æ”¹å�˜è¡Œå’Œåˆ—的下标,从而缩å°�查找区间。 ```java public boolean Find(int target, int [][] array) { @@ -139,25 +140,25 @@ public boolean Find(int target, int [][] array) { } ``` -## 5. Ìæ»»¿Õ¸ñ +## 5. 替æ�¢ç©ºæ ¼ -**ÌâÄ¿ÃèÊö** +**题目æ��è¿°** -ÇëʵÏÖÒ»¸öº¯Êý£¬½«Ò»¸ö×Ö·û´®ÖеĿոñÌæ»»³É¡°%20¡±¡£ÀýÈ磬µ±×Ö·û´®Îª We Are Happy. Ôò¾­¹ýÌæ»»Ö®ºóµÄ×Ö·û´®Îª We%20Are%20Happy¡£ +请实现一个函数,将一个字符串中的空格替æ�¢æˆ�“%20â€�。例如,当字符串为 We Are Happy. 则ç»�过替æ�¢ä¹‹å�Žçš„字符串为 We%20Are%20Happy。 -**ÌâĿҪÇó** +**题目è¦�求** -ÒÔ O(1) µÄ¿Õ¼ä¸´ÔÓ¶ÈºÍ O(n) µÄ¿Õ¼ä¸´ÔÓ¶ÈÀ´Çó½â¡£ +以 O(1) 的空间å¤�æ�‚度和 O(n) 的空间å¤�æ�‚度æ�¥æ±‚解。 -**½âÌâ˼·** +**解题æ€�è·¯** -´ÓºóÏòǰ¸Ä±ä×Ö·û´®¡£ +从å�Žå�‘å‰�改å�˜å­—符串。 ```java public String replaceSpace(StringBuffer str) { int n = str.length(); for (int i = 0; i < n; i++) { - if (str.charAt(i) == ' ') str.append(" "); // β²¿Ìî³äÁ½¸ö + if (str.charAt(i) == ' ') str.append(" "); // 尾部填充两个 } int idxOfOriginal = n - 1; @@ -176,9 +177,9 @@ public String replaceSpace(StringBuffer str) { } ``` -## 6. ´Óβµ½Í·´òÓ¡Á´±í +## 6. 从尾到头打å�°é“¾è¡¨ -ÕýÏò±éÀúÈ»ºóµ÷Óà Collections.reverse()¡£ +æ­£å�‘é��历然å�Žè°ƒç”¨ Collections.reverse()。 ```java public ArrayList printListFromTailToHead(ListNode listNode) { @@ -192,7 +193,7 @@ public ArrayList printListFromTailToHead(ListNode listNode) { } ``` -ʹÓà Stack +使用 Stack ```java public ArrayList printListFromTailToHead(ListNode listNode) { @@ -209,7 +210,7 @@ public ArrayList printListFromTailToHead(ListNode listNode) { } ``` -µÝ¹é +递归 ```java public ArrayList printListFromTailToHead(ListNode listNode) { @@ -222,11 +223,11 @@ public ArrayList printListFromTailToHead(ListNode listNode) { } ``` -²»Ê¹Óÿ⺯Êý£¬²¢ÇÒ²»Ê¹ÓõݹéµÄµü´úʵÏÖ£¬ÀûÓÃÁ´±íµÄÍ·²å·¨ÎªÄæÐòµÄÌØÐÔ¡£ +ä¸�使用库函数,并且ä¸�使用递归的迭代实现,利用链表的头æ�’法为逆åº�的特性。 ```java public ArrayList printListFromTailToHead(ListNode listNode) { - ListNode head = new ListNode(-1); // Í·½áµã + ListNode head = new ListNode(-1); // 头结点 ListNode cur = listNode; while (cur != null) { ListNode next = cur.next; @@ -244,11 +245,11 @@ public ArrayList printListFromTailToHead(ListNode listNode) { } ``` -## 7. ÖØ½¨¶þ²æÊ÷ +## 7. é‡�建二å�‰æ ‘ -**ÌâÄ¿ÃèÊö** +**题目æ��è¿°** -¸ù¾Ý¶þ²æÊ÷µÄǰÐò±éÀúºÍÖÐÐò±éÀúµÄ½á¹û£¬Öؽ¨³ö¸Ã¶þ²æÊ÷¡£ +æ ¹æ�®äºŒå�‰æ ‘çš„å‰�åº�é��历和中åº�é��历的结果,é‡�建出该二å�‰æ ‘。 ```java public TreeNode reConstructBinaryTree(int[] pre, int[] in) { @@ -268,18 +269,18 @@ private TreeNode reConstructBinaryTree(int[] pre, int preL, int preR, int[] in, } ``` -## 8. ¶þ²æÊ÷µÄÏÂÒ»¸ö½áµã +## 8. 二å�‰æ ‘的下一个结点 -**ÌâÄ¿ÃèÊö** +**题目æ��è¿°** -¸ø¶¨Ò»¸ö¶þ²æÊ÷ºÍÆäÖеÄÒ»¸ö½áµã£¬ÇëÕÒ³öÖÐÐò±éÀú˳ÐòµÄÏÂÒ»¸ö½áµã²¢ÇÒ·µ»Ø¡£×¢Ò⣬Ê÷ÖеĽáµã²»½ö°üº¬×óÓÒ×Ó½áµã£¬Í¬Ê±°üº¬Ö¸Ïò¸¸½áµãµÄÖ¸Õë¡£ +给定一个二å�‰æ ‘和其中的一个结点,请找出中åº�é��历顺åº�的下一个结点并且返回。注æ„�,树中的结点ä¸�仅包å�«å·¦å�³å­�结点,å�Œæ—¶åŒ…å�«æŒ‡å�‘父结点的指针。 -**½âÌâ˼·** +**解题æ€�è·¯** -- Èç¹ûÒ»¸ö½ÚµãÓÐÓÒ×ÓÊ÷²»Îª¿Õ£¬ÄÇô¸Ã½ÚµãµÄÏÂÒ»¸ö½ÚµãÊÇÓÒ×ÓÊ÷µÄ×î×ó½Úµã£» -- ·ñÔò£¬ÏòÉÏÕÒµÚÒ»¸ö×óÁ´½ÓÖ¸ÏòµÄÊ÷°üº¬¸Ã½ÚµãµÄ׿ÏȽڵ㡣 +- 如果一个节点有å�³å­�æ ‘ä¸�为空,那么该节点的下一个节点是å�³å­�树的最左节点; +- å�¦åˆ™ï¼Œå�‘上找第一个左链接指å�‘的树包å�«è¯¥èŠ‚ç‚¹çš„ç¥–å…ˆèŠ‚ç‚¹ã€‚ -![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/6fec7f56-a685-4232-b03e-c92a8dfba486.png) +![](https://github.com/CyC2018/InterviewNotes/blob/master/pics//6fec7f56-a685-4232-b03e-c92a8dfba486.png) ```java public TreeLinkNode GetNext(TreeLinkNode pNode) { @@ -300,11 +301,11 @@ public TreeLinkNode GetNext(TreeLinkNode pNode) { } ``` -## 9. ÓÃÁ½¸öջʵÏÖ¶ÓÁÐ +## 9. 用两个栈实现队列 -**½âÌâ˼·** +**解题æ€�è·¯** -Ìí¼Óµ½Õ»ÖеÄÐòÁÐ˳Ðò»á±»·´×ª£¬Èç¹û½øÐÐÁ½´Î·´×ª£¬ÄÇôµÃµ½µÄÐòÁÐÒÀÈ»ÊÇÕýÏòµÄ¡£Òò´Ë£¬Ìí¼ÓµÄÊý¾ÝÐèҪͬʱѹÈëÁ½¸öÕ»Ö®ºó²ÅÄܳöÕ»£¬ÕâÑù¾ÍÄܱ£Ö¤³öÕ»µÄ˳ÐòΪÏȽøÏȳö¡£ +添加到栈中的åº�列顺åº�会被å��转,如果进行两次å��转,那么得到的åº�列ä¾�然是正å�‘的。因此,添加的数æ�®éœ€è¦�å�Œæ—¶åŽ‹å…¥ä¸¤ä¸ªæ ˆä¹‹å�Žæ‰�能出栈,这样就能ä¿�è¯�出栈的顺åº�为先进先出。 ```java Stack stack1 = new Stack(); @@ -324,7 +325,7 @@ public int pop() { } ``` -## 10.1 ì³²¨ÄÇÆõÊýÁÐ +## 10.1 æ–�波那契数列 ```java private int[] fib = new int[40]; @@ -342,7 +343,7 @@ public int Fibonacci(int n) { } ``` -## 10.2 ÌøÌ¨½× +## 10.2 è·³å�°é˜¶ ```java public int JumpFloor(int target) { @@ -357,7 +358,7 @@ public int JumpFloor(int target) { } ``` -## 10.3 ±äÌ¬ÌøÌ¨½× +## 10.3 å�˜æ€�è·³å�°é˜¶ ```java public int JumpFloorII(int target) { @@ -372,11 +373,11 @@ public int JumpFloorII(int target) { } ``` -## 10.4 ¾ØÐθ²¸Ç +## 10.4 矩形覆盖 -**ÌâÄ¿ÃèÊö** +**题目æ��è¿°** -ÎÒÃÇ¿ÉÒÔÓà 2\*1 µÄС¾ØÐκá×Å»òÕßÊú×ÅÈ¥¸²¸Ç¸ü´óµÄ¾ØÐΡ£ÇëÎÊÓà n ¸ö 2\*1 µÄС¾ØÐÎÎÞÖØµþµØ¸²¸ÇÒ»¸ö 2\*n µÄ´ó¾ØÐΣ¬×ܹ²ÓжàÉÙÖÖ·½·¨£¿ +我们å�¯ä»¥ç”¨ 2\*1 çš„å°�矩形横ç�€æˆ–者竖ç�€åŽ»è¦†ç›–æ›´å¤§çš„çŸ©å½¢ã€‚è¯·é—®ç”¨ n 个 2\*1 çš„å°�矩形无é‡�å� åœ°è¦†ç›–一个 2\*n 的大矩形,总共有多少ç§�方法? ```java public int RectCover(int target) { @@ -385,14 +386,14 @@ public int RectCover(int target) { } ``` -## 11. ÐýתÊý×éµÄ×îСÊý×Ö +## 11. 旋转数组的最å°�æ•°å­— -**ÌâÄ¿ÃèÊö** +**题目æ��è¿°** -°ÑÒ»¸öÊý×é×ʼµÄÈô¸É¸öÔªËØ°áµ½Êý×éµÄĩ⣬ÎÒÃdzÆÖ®ÎªÊý×éµÄÐýת¡£ÊäÈëÒ»¸ö·ÇµÝ¼õÅÅÐòµÄÊý×éµÄÒ»¸öÐýת£¬Êä³öÐýתÊý×éµÄ×îÐ¡ÔªËØ¡£ÀýÈçÊý×é {3, 4, 5, 1, 2} Ϊ {1, 2, 3, 4, 5} µÄÒ»¸öÐýת£¬¸ÃÊý×éµÄ×îСֵΪ 1¡£NOTE£º¸ø³öµÄËùÓÐÔªËØ¶¼´óÓÚ 0£¬ÈôÊý×é´óСΪ 0£¬Çë·µ»Ø 0¡£ +把一个数组最开始的若干个元素æ�¬åˆ°æ•°ç»„的末尾,我们称之为数组的旋转。输入一个é�žé€’å‡�排åº�的数组的一个旋转,输出旋转数组的最å°�元素。例如数组 {3, 4, 5, 1, 2} 为 {1, 2, 3, 4, 5} 的一个旋转,该数组的最å°�值为 1。NOTE:给出的所有元素都大于 0,若数组大å°�为 0,请返回 0。 -O(N) ʱ¼ä¸´ÔӶȽⷨ£º +O(N) æ—¶é—´å¤�æ�‚度解法: ```java public int minNumberInRotateArray(int[] array) { @@ -404,7 +405,7 @@ public int minNumberInRotateArray(int[] array) { } ``` -O(lgN) ʱ¼ä¸´ÔӶȽⷨ£º +O(lgN) æ—¶é—´å¤�æ�‚度解法: ```java public int minNumberInRotateArray(int[] array) { @@ -421,11 +422,11 @@ public int minNumberInRotateArray(int[] array) { } ``` -## 12. ¾ØÕóÖеÄ·¾¶ +## 12. 矩阵中的路径 -**ÌâÄ¿ÃèÊö** +**题目æ��è¿°** -ÇëÉè¼ÆÒ»¸öº¯Êý£¬ÓÃÀ´ÅжÏÔÚÒ»¸ö¾ØÕóÖÐÊÇ·ñ´æÔÚÒ»Ìõ°üº¬Ä³×Ö·û´®ËùÓÐ×Ö·ûµÄ·¾¶¡£Â·¾¶¿ÉÒÔ´Ó¾ØÕóÖеÄÈÎÒâÒ»¸ö¸ñ×Ó¿ªÊ¼£¬Ã¿Ò»²½¿ÉÒÔÔÚ¾ØÕóÖÐÏò×ó£¬ÏòÓÒ£¬ÏòÉÏ£¬ÏòÏÂÒÆ¶¯Ò»¸ö¸ñ×Ó¡£Èç¹ûÒ»Ìõ·¾¶¾­¹ýÁ˾ØÕóÖеÄijһ¸ö¸ñ×Ó£¬Ôò¸Ã·¾¶²»ÄÜÔÙ½øÈë¸Ã¸ñ×Ó¡£ÀýÈç a b c e s f c s a d e e ¾ØÕóÖаüº¬Ò»Ìõ×Ö·û´® "bcced" µÄ·¾¶£¬µ«ÊǾØÕóÖв»°üº¬ "abcb" ·¾¶£¬ÒòΪ×Ö·û´®µÄµÚÒ»¸ö×Ö·û b Õ¼¾ÝÁ˾ØÕóÖеĵÚÒ»Ðеڶþ¸ö¸ñ×ÓÖ®ºó£¬Â·¾¶²»ÄÜÔٴνøÈë¸Ã¸ñ×Ó¡£ +请设计一个函数,用æ�¥åˆ¤æ–­åœ¨ä¸€ä¸ªçŸ©é˜µä¸­æ˜¯å�¦å­˜åœ¨ä¸€æ�¡åŒ…å�«æŸ�字符串所有字符的路径。路径å�¯ä»¥ä»ŽçŸ©é˜µä¸­çš„ä»»æ„�一个格å­�开始,æ¯�一步å�¯ä»¥åœ¨çŸ©é˜µä¸­å�‘左,å�‘å�³ï¼Œå�‘上,å�‘下移动一个格å­�。如果一æ�¡è·¯å¾„ç»�过了矩阵中的æŸ�一个格å­�,则该路径ä¸�能å†�进入该格å­�。例如 a b c e s f c s a d e e 矩阵中包å�«ä¸€æ�¡å­—符串 "bcced" 的路径,但是矩阵中ä¸�包å�« "abcb" 路径,因为字符串的第一个字符 b å� æ�®äº†çŸ©é˜µä¸­çš„第一行第二个格å­�之å�Žï¼Œè·¯å¾„ä¸�能å†�次进入该格å­�。 ```java private int[][] next = {{0, -1}, {0, 1}, {-1, 0}, {1, 0}}; @@ -436,7 +437,7 @@ public boolean hasPath(char[] matrix, int rows, int cols, char[] str) { if (rows == 0 || cols == 0) return false; this.rows = rows; this.cols = cols; - // һάÊý×éÖØ½¨¶þά¾ØÕó + // 一维数组é‡�建二维矩阵 char[][] newMatrix = new char[rows][cols]; for (int i = 0, idx = 0; i < rows; i++) { for (int j = 0; j < cols; j++) { @@ -467,11 +468,11 @@ private boolean backtracking(char[][] matrix, char[] str, boolean[][] used, int ``` -## 13. »úÆ÷È˵ÄÔ˶¯·¶Î§ +## 13. 机器人的è¿�动范围 -**ÌâÄ¿ÃèÊö** +**题目æ��è¿°** -µØÉÏÓÐÒ»¸ö m ÐÐºÍ n Áеķ½¸ñ¡£Ò»¸ö»úÆ÷ÈË´Ó×ø±ê (0,0) µÄ¸ñ×Ó¿ªÊ¼Òƶ¯£¬Ã¿Ò»´ÎÖ»ÄÜÏò×óÓÒÉÏÏÂËĸö·½ÏòÒÆ¶¯Ò»¸ñ£¬µ«ÊDz»ÄܽøÈëÐÐ×ø±êºÍÁÐ×ø±êµÄÊýλ֮ºÍ´óÓÚ k µÄ¸ñ×Ó¡£ÀýÈ磬µ± k Ϊ 18 ʱ£¬»úÆ÷ÈËÄܹ»½øÈë·½¸ñ£¨35,37£©£¬ÒòΪ 3+5+3+7=18¡£µ«ÊÇ£¬Ëü²»ÄܽøÈë·½¸ñ£¨35,38£©£¬ÒòΪ 3+5+3+8=19¡£ÇëÎʸûúÆ÷ÈËÄܹ»´ïµ½¶àÉÙ¸ö¸ñ×Ó£¿ +地上有一个 m 行和 n 列的方格。一个机器人从å��æ ‡ (0,0) 的格å­�开始移动,æ¯�一次å�ªèƒ½å�‘å·¦å�³ä¸Šä¸‹å››ä¸ªæ–¹å�‘移动一格,但是ä¸�能进入行å��标和列å��标的数ä½�之和大于 k 的格å­�。例如,当 k 为 18 时,机器人能够进入方格(35,37),因为 3+5+3+7=18。但是,它ä¸�能进入方格(35,38),因为 3+5+3+8=19。请问该机器人能够达到多少个格å­�? ```java private int cnt = 0; @@ -513,19 +514,19 @@ private void initDigitSum(int rows, int cols) { } ``` -## 14. ¼ôÉþ×Ó +## 14. 剪绳å­� -**ÌâÄ¿ÃèÊö** +**题目æ��è¿°** -°ÑÒ»¸ùÉþ×Ó¼ô³É¶à¶Î£¬²¢ÇÒʹµÃÿ¶ÎµÄ³¤¶È³Ë»ý×î´ó¡£ +把一根绳å­�剪æˆ�多段,并且使得æ¯�段的长度乘积最大。 -**¶¯Ì¬¹æ»®½â·¨** +**动æ€�规划解法** -[·Ö¸îÕûÊý](https://github.com/CyC2018/InterviewNotes/blob/master/notes/Leetcode%20%E9%A2%98%E8%A7%A3.md#%E5%88%86%E5%89%B2%E6%95%B4%E6%95%B0) +[分割整数](https://github.com/CyC2018/InterviewNotes/blob/master/notes/Leetcode%20%E9%A2%98%E8%A7%A3.md#%E5%88%86%E5%89%B2%E6%95%B4%E6%95%B0) -**̰ÐĽⷨ** +**贪心解法** -¾¡¿ÉÄܶàµÃ¼ô³¤¶ÈΪ 3 µÄÉþ×Ó£¬²¢ÇÒ²»ÔÊÐíÓ㤶ÈΪ 1 µÄÉþ×Ó³öÏÖ£¬Èç¹û³öÏÖÁË£¬¾Í´ÓÒѾ­Çкó¤¶ÈΪ 3 µÄÉþ×ÓÖÐÄóöÒ»¶ÎÓ볤¶ÈΪ 1 µÄÉþ×ÓÖØÐÂ×éºÏ£¬°ÑËüÃÇÇгÉÁ½¶Î³¤¶ÈΪ 2 µÄÉþ×Ó¡£ +å°½å�¯èƒ½å¤šå¾—剪长度为 3 的绳å­�,并且ä¸�å…�许有长度为 1 的绳å­�出现,如果出现了,就从已ç»�切好长度为 3 的绳å­�中拿出一段与长度为 1 的绳å­�é‡�新组å�ˆï¼ŒæŠŠå®ƒä»¬åˆ‡æˆ�两段长度为 2 的绳å­�。 ```java int maxProductAfterCuttin(int length) { @@ -539,9 +540,9 @@ int maxProductAfterCuttin(int length) { } ``` -## 15. ¶þ½øÖÆÖÐ 1 µÄ¸öÊý +## 15. 二进制中 1 的个数 -ʹÓÿ⺯Êý£º +使用库函数: ```java public int NumberOf1(int n) { @@ -549,9 +550,9 @@ public int NumberOf1(int n) { } ``` -O(lgM) ʱ¼ä¸´ÔӶȽⷨ£¬ÆäÖÐ M ±íʾ 1 µÄ¸öÊý£º +O(lgM) æ—¶é—´å¤�æ�‚度解法,其中 M 表示 1 的个数: -n&(n-1) ¸ÃλÔËËãÊÇÈ¥³ý n µÄλ¼¶±íʾÖÐ×îµÍµÄÄÇһλ¡£ÀýÈç¶ÔÓÚ¶þ½øÖƱíʾ 10110100£¬¼õÈ¥ 1 µÃµ½ 10110011£¬ÕâÁ½¸öÊýÏàÓëµÃµ½ 10110000¡£ +n&(n-1) 该ä½�è¿�算是去除 n çš„ä½�级表示中最低的那一ä½�。例如对于二进制表示 10110100,å‡�去 1 得到 10110011,这两个数相与得到 10110000。 ```java public int NumberOf1(int n) { @@ -564,9 +565,9 @@ public int NumberOf1(int n) { } ``` -# µÚÈýÕ ¸ßÖÊÁ¿µÄ´úÂë +# 第三章 高质é‡�的代ç � -## 16. ÊýÖµµÄÕûÊý´Î·½ +## 16. 数值的整数次方 ```java public double Power(double base, int exponent) { @@ -583,7 +584,7 @@ public double Power(double base, int exponent) { } ``` -## 18.2 ɾ³ýÁ´±íÖÐÖØ¸´µÄ½áµã +## 18.2 删除链表中é‡�å¤�的结点 ```java public ListNode deleteDuplication(ListNode pHead) { @@ -602,11 +603,11 @@ public ListNode deleteDuplication(ListNode pHead) { } ``` -## 19. ÕýÔò±í´ïʽƥÅä +## 19. 正则表达å¼�匹é…� -**ÌâÄ¿ÃèÊö** +**题目æ��è¿°** -ÇëʵÏÖÒ»¸öº¯ÊýÓÃÀ´Æ¥Åä°üÀ¨ '.' ºÍ '\*' µÄÕýÔò±í´ïʽ¡£Ä£Ê½ÖеÄ×Ö·û '.' ±íʾÈÎÒâÒ»¸ö×Ö·û£¬¶ø '\*' ±íʾËüÇ°ÃæµÄ×Ö·û¿ÉÒÔ³öÏÖÈÎÒâ´Î£¨°üº¬ 0 ´Î£©¡£ ÔÚ±¾ÌâÖУ¬Æ¥ÅäÊÇÖ¸×Ö·û´®µÄËùÓÐ×Ö·ûÆ¥ÅäÕû¸öģʽ¡£ÀýÈ磬×Ö·û´® "aaa" Óëģʽ "a.a" ºÍ "ab\*ac\*a" Æ¥Å䣬µ«ÊÇÓë "aa.a" ºÍ "ab\*a" ¾ù²»Æ¥Åä +请实现一个函数用æ�¥åŒ¹é…�包括 '.' å’Œ '\*' 的正则表达å¼�。模å¼�中的字符 '.' 表示任æ„�一个字符,而 '\*' 表示它å‰�é�¢çš„字符å�¯ä»¥å‡ºçް任æ„�次(包å�« 0 次)。 在本题中,匹é…�是指字符串的所有字符匹é…�整个模å¼�。例如,字符串 "aaa" 与模å¼� "a.a" å’Œ "ab\*ac\*a" 匹é…�,但是与 "aa.a" å’Œ "ab\*a" å�‡ä¸�匹é…� ```java public boolean match(char[] str, char[] pattern) { @@ -629,11 +630,11 @@ public boolean match(char[] str, char[] pattern) { } ``` -## 20. ±íʾÊýÖµµÄ×Ö·û´® +## 20. 表示数值的字符串 -**ÌâÄ¿ÃèÊö** +**题目æ��è¿°** -ÇëʵÏÖÒ»¸öº¯ÊýÓÃÀ´ÅжÏ×Ö·û´®ÊÇ·ñ±íʾÊýÖµ£¨°üÀ¨ÕûÊýºÍСÊý£©¡£ÀýÈ磬×Ö·û´® "+100","5e2","-123","3.1416" ºÍ "-1E-16" ¶¼±íʾÊýÖµ¡£ µ«ÊÇ "12e","1a3.14","1.2.3","+-5" ºÍ "12e+4.3" ¶¼²»ÊÇ¡£ +请实现一个函数用æ�¥åˆ¤æ–­å­—符串是å�¦è¡¨ç¤ºæ•°å€¼ï¼ˆåŒ…括整数和å°�数)。例如,字符串 "+100","5e2","-123","3.1416" å’Œ "-1E-16" 都表示数值。 但是 "12e","1a3.14","1.2.3","+-5" å’Œ "12e+4.3" 都ä¸�是。 ```java public boolean isNumeric(char[] str) { @@ -642,14 +643,14 @@ public boolean isNumeric(char[] str) { } ``` -## 21. µ÷ÕûÊý×é˳ÐòÊ¹ÆæÊýλÓÚżÊýÇ°Ãæ +## 21. 调整数组顺åº�使奇数ä½�于å�¶æ•°å‰�é�¢ -**ÌâĿҪÇó** +**题目è¦�求** -±£Ö¤ÆæÊýºÍÆæÊý£¬Å¼ÊýºÍżÊýÖ®¼äµÄÏà¶ÔλÖò»±ä£¬ÕâºÍÊé±¾²»Ì«Ò»Ñù¡£ +ä¿�è¯�奇数和奇数,å�¶æ•°å’Œå�¶æ•°ä¹‹é—´çš„相对ä½�ç½®ä¸�å�˜ï¼Œè¿™å’Œä¹¦æœ¬ä¸�太一样。 -ʱ¼ä¸´ÔÓ¶È : O(n2) -¿Õ¼ä¸´ÔÓ¶È : O(1) +æ—¶é—´å¤�æ�‚度 : O(n2) +空间å¤�æ�‚度 : O(1) ```java public void reOrderArray(int[] array) { @@ -669,8 +670,8 @@ public void reOrderArray(int[] array) { } ``` -ʱ¼ä¸´ÔÓ¶È : O(n) -¿Õ¼ä¸´ÔÓ¶È : O(n) +æ—¶é—´å¤�æ�‚度 : O(n) +空间å¤�æ�‚度 : O(n) ```java public void reOrderArray(int[] array) { @@ -685,7 +686,7 @@ public void reOrderArray(int[] array) { } ``` -## 22. Á´±íÖе¹ÊýµÚ k ¸ö½áµã +## 22. 链表中倒数第 k 个结点 ```java public ListNode FindKthToTail(ListNode head, int k) { @@ -702,7 +703,7 @@ public ListNode FindKthToTail(ListNode head, int k) { } ``` -## 23. Á´±íÖл·µÄÈë¿Ú½áµã +## 23. 链表中环的入å�£ç»“点 ```java public ListNode EntryNodeOfLoop(ListNode pHead) { @@ -724,7 +725,7 @@ public ListNode EntryNodeOfLoop(ListNode pHead) { } ``` -## 24. ·´×ªÁ´±í +## 24. å��转链表 ```java public ListNode ReverseList(ListNode head) { @@ -739,7 +740,7 @@ public ListNode ReverseList(ListNode head) { } ``` -## 25. ºÏ²¢Á½¸öÅÅÐòµÄÁ´±í +## 25. å�ˆå¹¶ä¸¤ä¸ªæŽ’åº�的链表 ```java public ListNode Merge(ListNode list1, ListNode list2) { @@ -761,7 +762,7 @@ public ListNode Merge(ListNode list1, ListNode list2) { } ``` -## 26. Ê÷µÄ×ӽṹ +## 26. æ ‘çš„å­�结构 ```java public boolean HasSubtree(TreeNode root1, TreeNode root2) { @@ -778,9 +779,9 @@ private boolean isSubtree(TreeNode root1, TreeNode root2) { } ``` -# µÚËÄÕ ½â¾öÃæÊÔÌâµÄ˼· +# 第四章 解决é�¢è¯•题的æ€�è·¯ -## 27. ¶þ²æÊ÷µÄ¾µÏñ +## 27. 二å�‰æ ‘的镜åƒ� ```java public void Mirror(TreeNode root) { @@ -793,7 +794,7 @@ public void Mirror(TreeNode root) { } ``` -## 28.1 ¶Ô³ÆµÄ¶þ²æÊ÷ +## 28.1 对称的二å�‰æ ‘ ```java boolean isSymmetrical(TreeNode pRoot) { @@ -809,7 +810,7 @@ boolean isSymmetrical(TreeNode t1, TreeNode t2) { } ``` -## 28.2 ƽºâ¶þ²æÊ÷ +## 28.2 平衡二å�‰æ ‘ ```java private boolean isBalanced = true; @@ -828,7 +829,7 @@ private int height(TreeNode root) { } ``` -## 29. ˳ʱÕë´òÓ¡¾ØÕó +## 29. 顺时针打å�°çŸ©é˜µ ```java public ArrayList printMatrix(int[][] matrix) { @@ -845,7 +846,7 @@ public ArrayList printMatrix(int[][] matrix) { } ``` -## 30. °üº¬ min º¯ÊýµÄÕ» +## 30. 包å�« min 函数的栈 ```java private Stack stack = new Stack<>(); @@ -873,7 +874,7 @@ public int min() { } ``` -## 31. Õ»µÄѹÈë¡¢µ¯³öÐòÁÐ +## 31. 栈的压入ã€�弹出åº�列 ```java public boolean IsPopOrder(int[] pushA, int[] popA) { @@ -890,7 +891,7 @@ public boolean IsPopOrder(int[] pushA, int[] popA) { } ``` -## 32.1 ´ÓÉÏÍùÏ´òÓ¡¶þ²æÊ÷ +## 32.1 从上往下打å�°äºŒå�‰æ ‘ ```java public ArrayList PrintFromTopToBottom(TreeNode root) { @@ -911,7 +912,7 @@ public ArrayList PrintFromTopToBottom(TreeNode root) { } ``` -## 32.3 °Ñ¶þ²æÊ÷´òÓ¡³É¶àÐÐ +## 32.3 把二å�‰æ ‘打å�°æˆ�多行 ```java ArrayList> Print(TreeNode pRoot) { @@ -934,7 +935,7 @@ ArrayList> Print(TreeNode pRoot) { } ``` -## 32.3 °´Ö®×ÖÐÎ˳Ðò´òÓ¡¶þ²æÊ÷ +## 32.3 按之字形顺åº�打å�°äºŒå�‰æ ‘ ```java public ArrayList> Print(TreeNode pRoot) { @@ -965,7 +966,7 @@ public ArrayList> Print(TreeNode pRoot) { ``` -## 33. ¶þ²æËÑË÷Ê÷µÄºóÐò±éÀúÐòÁÐ +## 33. 二å�‰æ�œç´¢æ ‘çš„å�Žåº�é��历åº�列 ```java public boolean VerifySquenceOfBST(int[] sequence) { @@ -988,7 +989,7 @@ private boolean verify(int[] sequence, int start, int end) { } ``` -## 34. ¶þ²æÊ÷ÖкÍΪijһֵµÄ·¾¶ +## 34. 二å�‰æ ‘中和为æŸ�一值的路径 ```java private ArrayList> ret = new ArrayList<>(); @@ -1012,29 +1013,29 @@ private void dfs(TreeNode node, int target, int curSum, ArrayList path) } ``` -## 35. ¸´ÔÓÁ´±íµÄ¸´ÖÆ +## 35. å¤�æ�‚链表的å¤�制 -**ÌâÄ¿ÃèÊö** +**题目æ��è¿°** -ÊäÈëÒ»¸ö¸´ÔÓÁ´±í£¨Ã¿¸ö½ÚµãÖÐÓнڵãÖµ£¬ÒÔ¼°Á½¸öÖ¸Õ룬һ¸öÖ¸ÏòÏÂÒ»¸ö½Úµã£¬ÁíÒ»¸öÌØÊâÖ¸ÕëÖ¸ÏòÈÎÒâÒ»¸ö½Úµã£©£¬·µ»Ø½á¹ûΪ¸´Öƺó¸´ÔÓÁ´±íµÄ head¡££¨×¢Ò⣬Êä³ö½á¹ûÖÐÇë²»Òª·µ»Ø²ÎÊýÖеĽڵãÒýÓ㬷ñÔòÅÐÌâ³ÌÐò»áÖ±½Ó·µ»Ø¿Õ£© +输入一个å¤�æ�‚链表(æ¯�个节点中有节点值,以å�Šä¸¤ä¸ªæŒ‡é’ˆï¼Œä¸€ä¸ªæŒ‡å�‘下一个节点,å�¦ä¸€ä¸ªç‰¹æ®ŠæŒ‡é’ˆæŒ‡å�‘ä»»æ„�一个节点),返回结果为å¤�制å�Žå¤�æ�‚链表的 head。(注æ„�,输出结果中请ä¸�è¦�返回å�‚数中的节点引用,å�¦åˆ™åˆ¤é¢˜ç¨‹åº�会直接返回空) -µÚÒ»²½£¬ÔÚÿ¸ö½ÚµãµÄºóÃæ²åÈë¸´ÖÆµÄ½Úµã¡£ +第一步,在æ¯�个节点的å�Žé�¢æ�’å…¥å¤�制的节点。 -![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/f8b12555-967b-423d-a84e-bc9eff104b8b.jpg) +![](https://github.com/CyC2018/InterviewNotes/blob/master/pics//f8b12555-967b-423d-a84e-bc9eff104b8b.jpg) -µÚ¶þ²½£¬¶Ô¸´ÖƽڵãµÄ random Á´½Ó½øÐи³Öµ¡£ +第二步,对å¤�制节点的 random 链接进行赋值。 -![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/7b877a2a-8fd1-40d8-a34c-c445827300b8.jpg) +![](https://github.com/CyC2018/InterviewNotes/blob/master/pics//7b877a2a-8fd1-40d8-a34c-c445827300b8.jpg) -µÚÈý²½£¬²ð·Ö¡£ +第三步,拆分。 -![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/b2b6253c-c701-4b30-aff4-bc3c713542a7.jpg) +![](https://github.com/CyC2018/InterviewNotes/blob/master/pics//b2b6253c-c701-4b30-aff4-bc3c713542a7.jpg) ```java public RandomListNode Clone(RandomListNode pHead) { if (pHead == null) return null; - // ²åÈëнڵã + // æ�’入新节点 RandomListNode cur = pHead; while (cur != null) { RandomListNode node = new RandomListNode(cur.label); @@ -1042,7 +1043,7 @@ public RandomListNode Clone(RandomListNode pHead) { cur.next = node; cur = node.next; } - // ½¨Á¢ random Á´½Ó + // 建立 random 链接 cur = pHead; while (cur != null) { RandomListNode clone = cur.next; @@ -1051,7 +1052,7 @@ public RandomListNode Clone(RandomListNode pHead) { } cur = clone.next; } - // ²ð·Ö + // 拆分 RandomListNode pCloneHead = pHead.next; cur = pHead; while (cur.next != null) { @@ -1063,11 +1064,11 @@ public RandomListNode Clone(RandomListNode pHead) { } ``` -## 36. ¶þ²æËÑË÷Ê÷ÓëË«ÏòÁ´±í +## 36. 二å�‰æ�œç´¢æ ‘与å�Œå�‘链表 -**ÌâÄ¿ÃèÊö** +**题目æ��è¿°** -ÊäÈëÒ»¿Ã¶þ²æËÑË÷Ê÷£¬½«¸Ã¶þ²æËÑË÷Ê÷ת»»³ÉÒ»¸öÅÅÐòµÄË«ÏòÁ´±í¡£ÒªÇó²»ÄÜ´´½¨ÈκÎеĽáµã£¬Ö»Äܵ÷ÕûÊ÷ÖнáµãÖ¸ÕëµÄÖ¸Ïò¡£ +输入一棵二å�‰æ�œç´¢æ ‘,将该二å�‰æ�œç´¢æ ‘转æ�¢æˆ�一个排åº�çš„å�Œå�‘链表。è¦�求ä¸�能创建任何新的结点,å�ªèƒ½è°ƒæ•´æ ‘中结点指针的指å�‘。 ```java private TreeNode pre = null; @@ -1088,7 +1089,7 @@ private void inOrder(TreeNode node) { } ``` -## 37. ÐòÁл¯¶þ²æÊ÷ +## 37. åº�列化二å�‰æ ‘ ```java private String serizeString = ""; @@ -1121,11 +1122,11 @@ private TreeNode Deserialize() { } ``` -## 38. ×Ö·û´®µÄÅÅÁÐ +## 38. 字符串的排列 -**ÌâÄ¿ÃèÊö** +**题目æ��è¿°** -ÊäÈëÒ»¸ö×Ö·û´® , °´×ÖµäÐò´òÓ¡³ö¸Ã×Ö·û´®ÖÐ×Ö·ûµÄËùÓÐÅÅÁС£ÀýÈçÊäÈë×Ö·û´® abc, Ôò´òÓ¡³öÓÉ×Ö·û a, b, c ËùÄÜÅÅÁгöÀ´µÄËùÓÐ×Ö·û´® abc, acb, bac, bca, cab ºÍ cba¡£ +输入一个字符串 , 按字典åº�打å�°å‡ºè¯¥å­—符串中字符的所有排列。例如输入字符串 abc, 则打å�°å‡ºç”±å­—符 a, b, c 所能排列出æ�¥çš„æ‰€æœ‰å­—符串 abc, acb, bac, bca, cab å’Œ cba。 ```java private ArrayList ret = new ArrayList<>(); @@ -1145,7 +1146,7 @@ private void backtracking(char[] chars, boolean[] used, String s) { } for (int i = 0; i < chars.length; i++) { if (used[i]) continue; - if (i != 0 && chars[i] == chars[i - 1] && !used[i - 1]) continue; // ±£Ö¤²»Öظ´ + if (i != 0 && chars[i] == chars[i - 1] && !used[i - 1]) continue; // ä¿�è¯�ä¸�é‡�å¤� used[i] = true; backtracking(chars, used, s + chars[i]); used[i] = false; @@ -1153,9 +1154,9 @@ private void backtracking(char[] chars, boolean[] used, String s) { } ``` -# µÚÎåÕ ÓÅ»¯Ê±¼äºÍ¿Õ¼äЧÂÊ +# 第五章 优化时间和空间效率 -## 39. Êý×éÖгöÏÖ´ÎÊý³¬¹ýÒ»°ëµÄÊý×Ö +## 39. 数组中出现次数超过一å�Šçš„æ•°å­— ```java public int MoreThanHalfNum_Solution(int[] array) { @@ -1177,12 +1178,12 @@ public int MoreThanHalfNum_Solution(int[] array) { ``` -## 40. ×îСµÄ K ¸öÊý +## 40. 最å°�çš„ K 个数 -¹¹½¨´óСΪ k µÄС¶¥¶Ñ¡£ +构建大å°�为 k çš„å°�顶堆。 -ʱ¼ä¸´ÔÓ¶È£ºO(nlgk) -¿Õ¼ä¸´ÔÓ¶È£ºO(k) +æ—¶é—´å¤�æ�‚度:O(nlgk) +空间å¤�æ�‚度:O(k) ```java public ArrayList GetLeastNumbers_Solution(int[] input, int k) { @@ -1199,10 +1200,10 @@ public ArrayList GetLeastNumbers_Solution(int[] input, int k) { } ``` -ÀûÓÿìËÙÑ¡Ôñ +利用快速选择 -ʱ¼ä¸´ÔÓ¶È£ºO(n) -¿Õ¼ä¸´ÔÓ¶È£ºO(1) +æ—¶é—´å¤�æ�‚度:O(n) +空间å¤�æ�‚度:O(1) ```java public ArrayList GetLeastNumbers_Solution(int[] input, int k) { @@ -1257,22 +1258,22 @@ private boolean less(int v, int w) { } ``` -## 41.1 Êý¾ÝÁ÷ÖеÄÖÐλÊý +## 41.1 æ•°æ�®æµ�中的中ä½�æ•° -**ÌâÄ¿ÃèÊö** +**题目æ��è¿°** -ÈçºÎµÃµ½Ò»¸öÊý¾ÝÁ÷ÖеÄÖÐλÊý£¿Èç¹û´ÓÊý¾ÝÁ÷ÖжÁ³öÆæÊý¸öÊýÖµ£¬ÄÇôÖÐλÊý¾ÍÊÇËùÓÐÊýÖµÅÅÐòÖ®ºóλÓÚÖмäµÄÊýÖµ¡£Èç¹û´ÓÊý¾ÝÁ÷ÖжÁ³öżÊý¸öÊýÖµ£¬ÄÇôÖÐλÊý¾ÍÊÇËùÓÐÊýÖµÅÅÐòÖ®ºóÖмäÁ½¸öÊýµÄƽ¾ùÖµ¡£ +如何得到一个数æ�®æµ�中的中ä½�数?如果从数æ�®æµ�中读出奇数个数值,那么中ä½�数就是所有数值排åº�之å�Žä½�于中间的数值。如果从数æ�®æµ�中读出å�¶æ•°ä¸ªæ•°å€¼ï¼Œé‚£ä¹ˆä¸­ä½�数就是所有数值排åº�之å�Žä¸­é—´ä¸¤ä¸ªæ•°çš„å¹³å�‡å€¼ã€‚ ```java -private PriorityQueue maxHeap = new PriorityQueue<>((o1, o2) -> o2-o1); // ʵÏÖ×ó±ß²¿·Ö -private PriorityQueue minHeep = new PriorityQueue<>(); // ʵÏÖÓұ߲¿·Ö£¬Óұ߲¿·ÖËùÓÐÔªËØ´óÓÚ×ó±ß²¿·Ö +private PriorityQueue maxHeap = new PriorityQueue<>((o1, o2) -> o2-o1); // 实现左边部分 +private PriorityQueue minHeep = new PriorityQueue<>(); // 实现å�³è¾¹éƒ¨åˆ†ï¼Œå�³è¾¹éƒ¨åˆ†æ‰€æœ‰å…ƒç´ å¤§äºŽå·¦è¾¹éƒ¨åˆ† private int cnt = 0; public void Insert(Integer num) { - // ²åÈëÒª±£Ö¤Á½¸ö¶Ñ´æÓÚÆ½ºâ״̬ + // æ�’å…¥è¦�ä¿�è¯�两个堆存于平衡状æ€� if(cnt % 2 == 0) { - // ΪżÊýµÄÇé¿öϲåÈëµ½×îС¶Ñ£¬ÏȾ­¹ý×î´ó¶Ñɸѡ£¬ÕâÑù¾ÍÄܱ£Ö¤×î´ó¶ÑÖеÄÔªËØ¶¼Ð¡ÓÚ×îС¶ÑÖеÄÔªËØ + // 为å�¶æ•°çš„æƒ…况下æ�’入到最å°�堆,先ç»�过最大堆筛选,这样就能ä¿�è¯�最大堆中的元素都å°�于最å°�堆中的元素 maxHeap.add(num); minHeep.add(maxHeap.poll()); } else { @@ -1291,11 +1292,11 @@ public Double GetMedian() { } ``` -## 14.2 ×Ö·ûÁ÷ÖеÚÒ»¸ö²»Öظ´µÄ×Ö·û +## 14.2 字符æµ�中第一个ä¸�é‡�å¤�的字符 -**ÌâÄ¿ÃèÊö** +**题目æ��è¿°** -ÇëʵÏÖÒ»¸öº¯ÊýÓÃÀ´ÕÒ³ö×Ö·ûÁ÷ÖеÚÒ»¸öÖ»³öÏÖÒ»´ÎµÄ×Ö·û¡£ÀýÈ磬µ±´Ó×Ö·ûÁ÷ÖÐÖ»¶Á³öǰÁ½¸ö×Ö·û "go" ʱ£¬µÚÒ»¸öÖ»³öÏÖÒ»´ÎµÄ×Ö·ûÊÇ "g"¡£µ±´Ó¸Ã×Ö·ûÁ÷ÖжÁ³öǰÁù¸ö×Ö·û¡°google" ʱ£¬µÚÒ»¸öÖ»³öÏÖÒ»´ÎµÄ×Ö·ûÊÇ "l"¡£ +请实现一个函数用æ�¥æ‰¾å‡ºå­—符æµ�中第一个å�ªå‡ºçŽ°ä¸€æ¬¡çš„å­—ç¬¦ã€‚ä¾‹å¦‚ï¼Œå½“ä»Žå­—ç¬¦æµ�中å�ªè¯»å‡ºå‰�两个字符 "go" 时,第一个å�ªå‡ºçŽ°ä¸€æ¬¡çš„å­—ç¬¦æ˜¯ "g"。当从该字符æµ�中读出å‰�六个字符“google" 时,第一个å�ªå‡ºçŽ°ä¸€æ¬¡çš„å­—ç¬¦æ˜¯ "l"。 ```java //Insert one char from stringstream @@ -1318,7 +1319,7 @@ public char FirstAppearingOnce() { ``` -## 42. Á¬Ðø×ÓÊý×éµÄ×î´óºÍ +## 42. 连续å­�数组的最大和 ```java public int FindGreatestSumOfSubArray(int[] array) { @@ -1334,9 +1335,9 @@ public int FindGreatestSumOfSubArray(int[] array) { } ``` -## 43. ´Ó 1 µ½ n ÕûÊýÖÐ 1 ³öÏֵĴÎÊý +## 43. 从 1 到 n 整数中 1 出现的次数 -½âÌâ²Î¿¼£º[Leetcode : 233. Number of Digit One](https://leetcode.com/problems/number-of-digit-one/discuss/64381/4+-lines-O(log-n)-C++JavaPython) +解题å�‚考:[Leetcode : 233. Number of Digit One](https://leetcode.com/problems/number-of-digit-one/discuss/64381/4+-lines-O(log-n)-C++JavaPython) ```java public int NumberOf1Between1AndN_Solution(int n) { @@ -1349,11 +1350,11 @@ public int NumberOf1Between1AndN_Solution(int n) { } ``` -## 45. °ÑÊý×éÅųÉ×îСµÄÊý +## 45. 把数组排æˆ�最å°�的数 -**ÌâÄ¿ÃèÊö** +**题目æ��è¿°** -ÊäÈëÒ»¸öÕýÕûÊýÊý×飬°ÑÊý×éÀïËùÓÐÊý×ÖÆ´½ÓÆðÀ´ÅųÉÒ»¸öÊý£¬´òÓ¡ÄÜÆ´½Ó³öµÄËùÓÐÊý×ÖÖÐ×îСµÄÒ»¸ö¡£ÀýÈçÊäÈëÊý×é {3£¬32£¬321}£¬Ôò´òÓ¡³öÕâÈý¸öÊý×ÖÄÜÅųɵÄ×îСÊý×ÖΪ 321323¡£ +输入一个正整数数组,把数组里所有数字拼接起æ�¥æŽ’æˆ�一个数,打å�°èƒ½æ‹¼æŽ¥å‡ºçš„æ‰€æœ‰æ•°å­—中最å°�的一个。例如输入数组 {3,32,321},则打å�°å‡ºè¿™ä¸‰ä¸ªæ•°å­—能排æˆ�的最å°�数字为 321323。 ```java public String PrintMinNumber(int[] numbers) { @@ -1367,11 +1368,11 @@ public String PrintMinNumber(int[] numbers) { } ``` -## 49. ³óÊý +## 49. 丑数 -**ÌâÄ¿ÃèÊö** +**题目æ��è¿°** -°ÑÖ»°üº¬Òò×Ó 2¡¢3 ºÍ 5 µÄÊý³Æ×÷³óÊý£¨Ugly Number£©¡£ÀýÈç 6¡¢8 ¶¼ÊdzóÊý£¬µ« 14 ²»ÊÇ£¬ÒòΪËü°üº¬Òò×Ó 7¡£ ϰ¹ßÉÏÎÒÃÇ°Ñ 1 µ±×öÊǵÚÒ»¸ö³óÊý¡£Çó°´´ÓСµ½´óµÄ˳ÐòµÄµÚ N ¸ö³óÊý¡£ +把å�ªåŒ…å�«å› å­� 2ã€�3 å’Œ 5 的数称作丑数(Ugly Number)。例如 6ã€�8 都是丑数,但 14 ä¸�是,因为它包å�«å› å­� 7。 习惯上我们把 1 当å�šæ˜¯ç¬¬ä¸€ä¸ªä¸‘æ•°ã€‚æ±‚æŒ‰ä»Žå°�到大的顺åº�的第 N 个丑数。 ```java public int GetUglyNumber_Solution(int index) { @@ -1392,7 +1393,7 @@ public int GetUglyNumber_Solution(int index) { } ``` -## 50. µÚÒ»¸öÖ»³öÏÖÒ»´ÎµÄ×Ö·ûλÖà +## 50. 第一个å�ªå‡ºçŽ°ä¸€æ¬¡çš„å­—ç¬¦ä½�ç½® ```java public int FirstNotRepeatingChar(String str) { @@ -1403,7 +1404,7 @@ public int FirstNotRepeatingChar(String str) { } ``` -## 51. Êý×éÖеÄÄæÐò¶Ô +## 51. 数组中的逆åº�对 ```java private long cnt = 0; @@ -1430,7 +1431,7 @@ private void merge(int[] a, int start, int mid, int end) { else if (a[i] < a[j]) tmp[k] = a[i++]; else { tmp[k] = a[j++]; - this.cnt += mid - i + 1; // a[i] > a[j] £¬ËµÃ÷ a[i...mid] ¶¼´óÓÚ a[j] + this.cnt += mid - i + 1; // a[i] > a[j] ,说明 a[i...mid] 都大于 a[j] } k++; } @@ -1441,7 +1442,7 @@ private void merge(int[] a, int start, int mid, int end) { } ``` -## 52. Á½¸öÁ´±íµÄµÚÒ»¸ö¹«¹²½áµã +## 52. 两个链表的第一个公共结点 ```java public ListNode FindFirstCommonNode(ListNode pHead1, ListNode pHead2) { @@ -1456,9 +1457,9 @@ public ListNode FindFirstCommonNode(ListNode pHead1, ListNode pHead2) { } ``` -# µÚÁùÕÂ ÃæÊÔÖеĸ÷ÏîÄÜÁ¦ +# 第六章 é�¢è¯•中的å�„项能力 -## 53 Êý×ÖÔÚÅÅÐòÊý×éÖгöÏֵĴÎÊý +## 53 数字在排åº�数组中出现的次数 ```java public int GetNumberOfK(int[] array, int k) { @@ -1474,7 +1475,7 @@ public int GetNumberOfK(int[] array, int k) { } ``` -## 54. ¶þ²æËÑË÷Ê÷µÄµÚ k ¸ö½áµã +## 54. 二å�‰æ�œç´¢æ ‘的第 k 个结点 ```java TreeNode ret; @@ -1495,7 +1496,7 @@ private void inorder(TreeNode root, int k) { } ``` -## 55 ¶þ²æÊ÷µÄÉî¶È +## 55 二å�‰æ ‘的深度 ```java public int TreeDepth(TreeNode root) { @@ -1504,25 +1505,25 @@ public int TreeDepth(TreeNode root) { } ``` -## 56. Êý×éÖÐÖ»³öÏÖÒ»´ÎµÄÊý×Ö +## 56. 数组中å�ªå‡ºçŽ°ä¸€æ¬¡çš„æ•°å­— -**ÌâÄ¿ÃèÊö** +**题目æ��è¿°** -Ò»¸öÕûÐÍÊý×éÀï³ýÁËÁ½¸öÊý×ÖÖ®Í⣬ÆäËûµÄÊý×Ö¶¼³öÏÖÁËÁ½´Î£¬ÕÒ³öÕâÁ½¸öÊý¡£ +一个整型数组里除了两个数字之外,其他的数字都出现了两次,找出这两个数。 -**½âÌâ˼·** +**解题æ€�è·¯** -Á½¸ö²»ÏàµÈµÄÔªËØÔÚλ¼¶±íʾÉϱض¨»áÓÐһλ´æÔÚ²»Í¬¡£ +两个ä¸�相等的元素在ä½�级表示上必定会有一ä½�存在ä¸�å�Œã€‚ -½«Êý×éµÄËùÓÐÔªËØÒì»òµÃµ½µÄ½á¹ûΪ²»´æÔÚÖØ¸´µÄÁ½¸öÔªËØÒì»òµÄ½á¹û¡£ +将数组的所有元素异或得到的结果为ä¸�存在é‡�å¤�的两个元素异或的结果。 -diff &= -diff µÃµ½³ö diff ×îÓҲ಻Ϊ 0 µÄ룬Ҳ¾ÍÊDz»´æÔÚÖØ¸´µÄÁ½¸öÔªËØÔÚλ¼¶±íʾÉÏ×îÓҲ಻ͬµÄÄÇһ룬ÀûÓÃÕâһλ¾Í¿ÉÒÔ½«Á½¸öÔªËØÇø·Ö¿ªÀ´¡£ +diff &= -diff 得到出 diff 最å�³ä¾§ä¸�为 0 çš„ä½�,也就是ä¸�存在é‡�å¤�的两个元素在ä½�级表示上最å�³ä¾§ä¸�å�Œçš„那一ä½�,利用这一ä½�å°±å�¯ä»¥å°†ä¸¤ä¸ªå…ƒç´ åŒºåˆ†å¼€æ�¥ã€‚ ```java public void FindNumsAppearOnce(int[] array, int num1[], int num2[]) { int diff = 0; for (int num : array) diff ^= num; - // µÃµ½×îÓÒһλ + // 得到最å�³ä¸€ä½� diff &= -diff; for (int num : array) { if ((num & diff) == 0) num1[0] ^= num; @@ -1531,11 +1532,11 @@ public void FindNumsAppearOnce(int[] array, int num1[], int num2[]) { } ``` -## 57.1 ºÍΪ S µÄÁ½¸öÊý×Ö +## 57.1 和为 S 的两个数字 -**ÌâÄ¿ÃèÊö** +**题目æ��è¿°** -ÊäÈëÒ»¸öµÝÔöÅÅÐòµÄÊý×éºÍÒ»¸öÊý×Ö S£¬ÔÚÊý×éÖвéÕÒÁ½¸öÊý£¬ÊǵÄËûÃǵĺÍÕýºÃÊÇ S£¬Èç¹ûÓжà¶ÔÊý×ֵĺ͵ÈÓÚ S£¬Êä³öÁ½¸öÊýµÄ³Ë»ý×îСµÄ¡£ +输入一个递增排åº�的数组和一个数字 S,在数组中查找两个数,是的他们的和正好是 S,如果有多对数字的和等于 S,输出两个数的乘积最å°�的。 ```java public ArrayList FindNumbersWithSum(int[] array, int sum) { @@ -1550,11 +1551,11 @@ public ArrayList FindNumbersWithSum(int[] array, int sum) { } ``` -## 57.2 ºÍΪ S µÄÁ¬ÐøÕýÊýÐòÁÐ +## 57.2 和为 S 的连续正数åº�列 -**ÌâÄ¿ÃèÊö** +**题目æ��è¿°** -ºÍΪ 100 µÄÁ¬ÐøÐòÁÐÓÐ 18, 19, 20, 21, 22 +和为 100 的连续åº�列有 18, 19, 20, 21, 22 ```java public ArrayList> FindContinuousSequence(int sum) { @@ -1585,13 +1586,13 @@ public ArrayList> FindContinuousSequence(int sum) { } ``` -## 58.1 ·­×ªµ¥´Ê˳ÐòÁÐ +## 58.1 翻转å�•è¯�顺åº�列 -**ÌâÄ¿ÃèÊö** +**题目æ��è¿°** -ÊäÈ룺"I am a student." +输入:"I am a student." -Êä³ö£º"student. a am I" +输出:"student. a am I" ```java public String ReverseSentence(String str) { @@ -1621,11 +1622,11 @@ private void reverse(char[] c, int start, int end) { } ``` -## 58.2 ×óÐýת×Ö·û´® +## 58.2 左旋转字符串 -**ÌâÄ¿ÃèÊö** +**题目æ��è¿°** -¶ÔÓÚÒ»¸ö¸ø¶¨µÄ×Ö·ûÐòÁÐ S£¬ÇëÄã°ÑÆäÑ­»·×óÒÆ K λºóµÄÐòÁÐÊä³ö¡£ÀýÈ磬×Ö·ûÐòÁÐ S=¡±abcXYZdef¡±, ÒªÇóÊä³öÑ­»·×óÒÆ 3 λºóµÄ½á¹û£¬¼´¡°XYZdefabc¡±¡£ +对于一个给定的字符åº�列 S,请你把其循环左移 K ä½�å�Žçš„åº�列输出。例如,字符åº�列 S=â€�abcXYZdefâ€�, è¦�求输出循环左移 3 ä½�å�Žçš„结果,å�³â€œXYZdefabcâ€�。 ```java public String LeftRotateString(String str, int n) { @@ -1648,11 +1649,11 @@ private void reverse(char[] c, int i, int j) { } ``` -## 59. »¬¶¯´°¿ÚµÄ×î´óÖµ +## 59. 滑动窗å�£çš„æœ€å¤§å€¼ -**ÌâÄ¿ÃèÊö** +**题目æ��è¿°** -¸ø¶¨Ò»¸öÊý×éºÍ»¬¶¯´°¿ÚµÄ´óС£¬ÕÒ³öËùÓ묶¯´°¿ÚÀïÊýÖµµÄ×î´óÖµ¡£ÀýÈ磬Èç¹ûÊäÈëÊý×é {2, 3, 4, 2, 6, 2, 5, 1} ¼°»¬¶¯´°¿ÚµÄ´óС 3£¬ÄÇôһ¹²´æÔÚ 6 ¸ö»¬¶¯´°¿Ú£¬ËûÃǵÄ×î´óÖµ·Ö±ðΪ {4, 4, 6, 6, 6, 5}£» +给定一个数组和滑动窗å�£çš„大å°�,找出所有滑动窗å�£é‡Œæ•°å€¼çš„æœ€å¤§å€¼ã€‚例如,如果输入数组 {2, 3, 4, 2, 6, 2, 5, 1} å�Šæ»‘动窗å�£çš„大å°� 3,那么一共存在 6 个滑动窗å�£ï¼Œä»–们的最大值分别为 {4, 4, 6, 6, 6, 5}ï¼› ```java public ArrayList maxInWindows(int[] num, int size) { @@ -1670,11 +1671,11 @@ public ArrayList maxInWindows(int[] num, int size) { } ``` -## 61. ÆË¿ËÅÆË³×Ó +## 61. 扑克牌顺å­� -**ÌâÄ¿ÃèÊö** +**题目æ��è¿°** -ÎåÕÅÅÆ£¬ÆäÖдóС¹íΪñ®×Ó£¬ÅÆÃæ´óСΪ 0¡£ÅжÏÊÇ·ñÄÜ×é³É˳×Ó¡£ +五张牌,其中大å°�鬼为癞å­�,牌é�¢å¤§å°�为 0。判断是å�¦èƒ½ç»„æˆ�顺å­�。 ```java public boolean isContinuous(int[] numbers) { @@ -1692,15 +1693,15 @@ public boolean isContinuous(int[] numbers) { } ``` -## 62. ԲȦÖÐ×îºóʣϵÄÊý +## 62. 圆圈中最å�Žå‰©ä¸‹çš„æ•° -**ÌâÄ¿ÃèÊö** +**题目æ��è¿°** -ÈÃСÅóÓÑÃÇΧ³ÉÒ»¸ö´óȦ¡£È»ºó , ËûËæ»úÖ¸¶¨Ò»¸öÊý m, ÈñàºÅΪ 0 µÄСÅóÓÑ¿ªÊ¼±¨Êý¡£Ã¿´Îº°µ½ m-1 µÄÄǸöСÅóÓÑÒª³öÁгªÊ׸è , È»ºó¿ÉÒÔÔÚÀñÆ·ÏäÖÐÈÎÒâµÄÌôÑ¡ÀñÎï , ²¢ÇÒ²»Ôٻص½È¦ÖÐ , ´ÓËûµÄÏÂÒ»¸öСÅóÓÑ¿ªÊ¼ , ¼ÌÐø 0...m-1 ±¨Êý .... ÕâÑùÏÂÈ¥ .... Ö±µ½Ê£ÏÂ×îºóÒ»¸öСÅóÓÑ , ¿ÉÒÔ²»ÓñíÑÝ¡£ +让å°�朋å�‹ä»¬å›´æˆ�一个大圈。然å�Ž , ä»–éš�机指定一个数 m, 让编å�·ä¸º 0 çš„å°�朋å�‹å¼€å§‹æŠ¥æ•°ã€‚æ¯�次喊到 m-1 的那个å°�朋å�‹è¦�出列唱首歌 , ç„¶å�Žå�¯ä»¥åœ¨ç¤¼å“�箱中任æ„�的挑选礼物 , 并且ä¸�å†�回到圈中 , 从他的下一个å°�朋å�‹å¼€å§‹ , ç»§ç»­ 0...m-1 报数 .... 这样下去 .... 直到剩下最å�Žä¸€ä¸ªå°�朋å�‹ , å�¯ä»¥ä¸�用表演。 -**½âÌâ˼·** +**解题æ€�è·¯** -Լɪ·ò»· +约瑟夫环 ```java public int LastRemaining_Solution(int n, int m) { @@ -1710,11 +1711,11 @@ public int LastRemaining_Solution(int n, int m) { } ``` -## 63. ¹ÉƱµÄ×î´óÀûÈó +## 63. 股票的最大利润 -**ÌâÄ¿ÃèÊö** +**题目æ��è¿°** -¿ÉÒÔÓÐÒ»´ÎÂòÈëºÍÒ»´ÎÂô³ö£¬ÂòÈë±ØÐëÔÚǰ¡£Çó×î´óÊÕÒæ¡£ +å�¯ä»¥æœ‰ä¸€æ¬¡ä¹°å…¥å’Œä¸€æ¬¡å�–出,买入必须在å‰�。求最大收益。 ```java public int maxProfit(int[] prices) { @@ -1730,11 +1731,11 @@ public int maxProfit(int[] prices) { } ``` -## 64. Çó 1+2+3+...+n +## 64. 求 1+2+3+...+n -**ÌâÄ¿ÃèÊö** +**题目æ��è¿°** -Çó 1+2+3+...+n£¬ÒªÇó²»ÄÜʹÓó˳ý·¨¡¢for¡¢while¡¢if¡¢else¡¢switch¡¢case µÈ¹Ø¼ü×Ö¼°Ìõ¼þÅжÏÓï¾ä£¨A?B:C£© +求 1+2+3+...+n,è¦�求ä¸�能使用乘除法ã€�forã€�whileã€�ifã€�elseã€�switchã€�case 等关键字å�Šæ�¡ä»¶åˆ¤æ–­è¯­å�¥ï¼ˆA?B:C) ```java public int Sum_Solution(int n) { @@ -1744,9 +1745,9 @@ public int Sum_Solution(int n) { } ``` -## 65. ²»ÓüӼõ³Ë³ý×ö¼Ó·¨ +## 65. ä¸�用加å‡�乘除å�šåŠ æ³• -a ^ b ±íʾûÓп¼ÂǽøÎ»µÄÇé¿öÏÂÁ½ÊýµÄºÍ£¬(a & b) << 1 ¾ÍÊǽøÎ»¡£µÝ¹é»áÖÕÖ¹µÄÔ­ÒòÊÇ (a & b) << 1 ×îÓұ߻á¶àÒ»¸ö 0£¬ÄÇô¼ÌÐøµÝ¹é£¬½øÎ»×îÓÒ±ßµÄ 0 »áÂýÂýÔö¶à£¬×îºó½øÎ»»á±äΪ 0£¬µÝ¹éÖÕÖ¹¡£ +a ^ b 表示没有考虑进ä½�的情况下两数的和,(a & b) << 1 就是进ä½�。递归会终止的原因是 (a & b) << 1 最å�³è¾¹ä¼šå¤šä¸€ä¸ª 0,那么继续递归,进ä½�最å�³è¾¹çš„ 0 会慢慢增多,最å�Žè¿›ä½�会å�˜ä¸º 0,递归终止。 ```java public int Add(int num1, int num2) { @@ -1755,11 +1756,11 @@ public int Add(int num1, int num2) { } ``` -## 66. ¹¹½¨³Ë»ýÊý×é +## 66. 构建乘积数组 -**ÌâÄ¿ÃèÊö** +**题目æ��è¿°** -¸ø¶¨Ò»¸öÊý×é A[0, 1,..., n-1], Çë¹¹½¨Ò»¸öÊý×é B[0, 1,..., n-1], ÆäÖÐ B ÖеÄÔªËØ B[i]=A[0]\*A[1]\*...\*A[i-1]\*A[i+1]\*...\*A[n-1]¡£²»ÄÜʹÓóý·¨¡£ +给定一个数组 A[0, 1,..., n-1], 请构建一个数组 B[0, 1,..., n-1], 其中 B 中的元素 B[i]=A[0]\*A[1]\*...\*A[i-1]\*A[i+1]\*...\*A[n-1]。ä¸�能使用除法。 ```java public int[] multiply(int[] A) { @@ -1784,9 +1785,9 @@ public int[] multiply(int[] A) { } ``` -# µÚÆßÕ Á½¸öÃæÊÔ°¸Àý +# 第七章 两个é�¢è¯•案例 -## 67. °Ñ×Ö·û´®×ª»»³ÉÕûÊý +## 67. 把字符串转æ�¢æˆ�æ•´æ•° ```java public int StrToInt(String str) { @@ -1803,9 +1804,9 @@ public int StrToInt(String str) { } ``` -## 68. Ê÷ÖÐÁ½¸ö½ÚµãµÄ×îµÍ¹«¹²×æÏÈ +## 68. 树中两个节点的最低公共祖先 -Ê÷ÊǶþ²æ²éÕÒÊ÷µÄ×îµÍ¹«¹²×æÏÈÎÊÌ⣺ +树是二å�‰æŸ¥æ‰¾æ ‘的最低公共祖先问题: ```java public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) { diff --git a/notes/算法.md b/notes/算法.md index 90a01a29..0a3613af 100644 --- a/notes/算法.md +++ b/notes/算法.md @@ -1,96 +1,97 @@ -* [µÚÒ»Õ »ù´¡](#µÚÒ»ÕÂ-»ù´¡) - * [Õ»](#Õ») - * [¶ÓÁÐ](#¶ÓÁÐ) - * [Ëã·¨·ÖÎö](#Ëã·¨·ÖÎö) - * [1. º¯Êýת»»](#1-º¯Êýת»») - * [2. ÊýѧģÐÍ](#2-ÊýѧģÐÍ) +* [第一章 基础](#第一章-基础) + * [æ ˆ](#æ ˆ) + * [队列](#队列) + * [算法分æž�](#算法分æž�) + * [1. 函数转æ�¢](#1-函数转æ�¢) + * [2. 数学模型](#2-数学模型) * [3. ThreeSum](#3-threesum) - * [4. ±¶ÂÊʵÑé](#4-±¶ÂÊʵÑé) - * [5. ×¢ÒâÊÂÏî](#5-×¢ÒâÊÂÏî) + * [4. å€�率实验](#4-å€�率实验) + * [5. 注æ„�事项](#5-注æ„�事项) * [union-find](#union-find) - * [1. quick-find Ëã·¨](#1-quick-find-Ëã·¨) - * [2. quick-union Ëã·¨](#2-quick-union-Ëã·¨) - * [3. ¼ÓȨ quick-union Ëã·¨](#3-¼ÓȨ-quick-union-Ëã·¨) - * [4. ·¾¶Ñ¹ËõµÄ¼ÓȨ quick-union Ëã·¨](#4-·¾¶Ñ¹ËõµÄ¼ÓȨ-quick-union-Ëã·¨) - * [5. ¸÷ÖÖ union-find Ëã·¨µÄ±È½Ï](#5-¸÷ÖÖ-union-find-Ëã·¨µÄ±È½Ï) -* [µÚ¶þÕ ÅÅÐò](#µÚ¶þÕÂ-ÅÅÐò) - * [³õ¼¶ÅÅÐòËã·¨](#³õ¼¶ÅÅÐòËã·¨) - * [1. Ô¼¶¨](#1-Ô¼¶¨) - * [2. Ñ¡ÔñÅÅÐò](#2-Ñ¡ÔñÅÅÐò) - * [3. ²åÈëÅÅÐò](#3-²åÈëÅÅÐò) - * [4. Ñ¡ÔñÅÅÐòºÍ²åÈëÅÅÐòµÄ±È½Ï](#4-Ñ¡ÔñÅÅÐòºÍ²åÈëÅÅÐòµÄ±È½Ï) - * [5. Ï£¶ûÅÅÐò](#5-Ï£¶ûÅÅÐò) - * [¹é²¢ÅÅÐò](#¹é²¢ÅÅÐò) - * [1. ¹é²¢·½·¨](#1-¹é²¢·½·¨) - * [2. ×Ô¶¥ÏòϹ鲢ÅÅÐò](#2-×Ô¶¥ÏòϹ鲢ÅÅÐò) - * [3. ×Ôµ×ÏòÉϹ鲢ÅÅÐò](#3-×Ôµ×ÏòÉϹ鲢ÅÅÐò) - * [¿ìËÙÅÅÐò](#¿ìËÙÅÅÐò) - * [1. »ù±¾Ëã·¨](#1-»ù±¾Ëã·¨) - * [2. ÇзÖ](#2-ÇзÖ) - * [3. ÐÔÄÜ·ÖÎö](#3-ÐÔÄÜ·ÖÎö) - * [4. Ëã·¨¸Ä½ø](#4-Ëã·¨¸Ä½ø) - * [4.1 Çл»µ½²åÈëÅÅÐò](#41-Çл»µ½²åÈëÅÅÐò) - * [4.2 ÈýÈ¡Ñù](#42-ÈýÈ¡Ñù) - * [4.3 ÈýÏòÇзÖ](#43-ÈýÏòÇзÖ) - * [ÓÅÏȶÓÁÐ](#ÓÅÏȶÓÁÐ) - * [1. ¶Ñ](#1-¶Ñ) - * [2. Éϸ¡ºÍϳÁ](#2-Éϸ¡ºÍϳÁ) - * [3. ²åÈëÔªËØ](#3-²åÈëÔªËØ) - * [4. ɾ³ý×î´óÔªËØ](#4-ɾ³ý×î´óÔªËØ) - * [5. ¶ÑÅÅÐò](#5-¶ÑÅÅÐò) - * [6. ·ÖÎö](#6-·ÖÎö) - * [Ó¦ÓÃ](#Ó¦ÓÃ) - * [1. ÅÅÐòËã·¨µÄ±È½Ï](#1-ÅÅÐòËã·¨µÄ±È½Ï) - * [2. Java µÄÅÅÐòË㷨ʵÏÖ](#2-java-µÄÅÅÐòË㷨ʵÏÖ) - * [3. »ùÓÚÇзֵĿìËÙÑ¡ÔñËã·¨](#3-»ùÓÚÇзֵĿìËÙÑ¡ÔñËã·¨) -* [µÚÈýÕ ²éÕÒ](#µÚÈýÕÂ-²éÕÒ) - * [·ûºÅ±í](#·ûºÅ±í) - * [1. ÎÞÐò·ûºÅ±í](#1-ÎÞÐò·ûºÅ±í) - * [2. ÓÐÐò·ûºÅ±í](#2-ÓÐÐò·ûºÅ±í) - * [3. ¶þ·Ö²éÕÒʵÏÖÓÐÐò·ûºÅ±í](#3-¶þ·Ö²éÕÒʵÏÖÓÐÐò·ûºÅ±í) - * [¶þ²æ²éÕÒÊ÷](#¶þ²æ²éÕÒÊ÷) + * [1. quick-find 算法](#1-quick-find-算法) + * [2. quick-union 算法](#2-quick-union-算法) + * [3. 加æ�ƒ quick-union 算法](#3-加æ�ƒ-quick-union-算法) + * [4. 路径压缩的加æ�ƒ quick-union 算法](#4-路径压缩的加æ�ƒ-quick-union-算法) + * [5. å�„ç§� union-find 算法的比较](#5-å�„ç§�-union-find-算法的比较) +* [第二章 排åº�](#第二章-排åº�) + * [åˆ�级排åº�算法](#åˆ�级排åº�算法) + * [1. 约定](#1-约定) + * [2. 选择排åº�](#2-选择排åº�) + * [3. æ�’入排åº�](#3-æ�’入排åº�) + * [4. 选择排åº�å’Œæ�’入排åº�的比较](#4-选择排åº�å’Œæ�’入排åº�的比较) + * [5. 希尔排åº�](#5-希尔排åº�) + * [归并排åº�](#归并排åº�) + * [1. 归并方法](#1-归并方法) + * [2. 自顶å�‘下归并排åº�](#2-自顶å�‘下归并排åº�) + * [3. 自底å�‘上归并排åº�](#3-自底å�‘上归并排åº�) + * [快速排åº�](#快速排åº�) + * [1. 基本算法](#1-基本算法) + * [2. 切分](#2-切分) + * [3. 性能分æž�](#3-性能分æž�) + * [4. 算法改进](#4-算法改进) + * [4.1 切æ�¢åˆ°æ�’入排åº�](#41-切æ�¢åˆ°æ�’入排åº�) + * [4.2 三å�–æ ·](#42-三å�–æ ·) + * [4.3 三å�‘切分](#43-三å�‘切分) + * [优先队列](#优先队列) + * [1. å †](#1-å †) + * [2. 上浮和下沉](#2-上浮和下沉) + * [3. æ�’入元素](#3-æ�’入元素) + * [4. 删除最大元素](#4-删除最大元素) + * [5. 堆排åº�](#5-堆排åº�) + * [6. 分æž�](#6-分æž�) + * [应用](#应用) + * [1. 排åº�算法的比较](#1-排åº�算法的比较) + * [2. Java 的排åº�算法实现](#2-java-的排åº�算法实现) + * [3. 基于切分的快速选择算法](#3-基于切分的快速选择算法) +* [第三章 查找](#第三章-查找) + * [符å�·è¡¨](#符å�·è¡¨) + * [1. æ— åº�符å�·è¡¨](#1-æ— åº�符å�·è¡¨) + * [2. 有åº�符å�·è¡¨](#2-有åº�符å�·è¡¨) + * [3. 二分查找实现有åº�符å�·è¡¨](#3-二分查找实现有åº�符å�·è¡¨) + * [二å�‰æŸ¥æ‰¾æ ‘](#二å�‰æŸ¥æ‰¾æ ‘) * [1. get()](#1-get) * [2. put()](#2-put) - * [3. ·ÖÎö](#3-·ÖÎö) + * [3. 分æž�](#3-分æž�) * [4. floor()](#4-floor) * [5. rank()](#5-rank) * [6. min()](#6-min) * [7. deleteMin()](#7-deletemin) * [8. delete()](#8-delete) * [9. keys()](#9-keys) - * [10. ÐÔÄÜ·ÖÎö](#10-ÐÔÄÜ·ÖÎö) - * [ƽºâ²éÕÒÊ÷](#ƽºâ²éÕÒÊ÷) - * [2-3 ²éÕÒÊ÷](#2-3-²éÕÒÊ÷) - * [1. ²åÈë²Ù×÷](#1-²åÈë²Ù×÷) - * [2. ÐÔÖÊ](#2-ÐÔÖÊ) - * [ºìºÚ¶þ²æ²éÕÒÊ÷](#ºìºÚ¶þ²æ²éÕÒÊ÷) - * [1. ×óÐýת](#1-×óÐýת) - * [2. ÓÒÐýת](#2-ÓÒÐýת) - * [3. ÑÕɫת»»](#3-ÑÕɫת»») - * [4. ²åÈë](#4-²åÈë) - * [5. ɾ³ý×îС¼ü](#5-ɾ³ý×îС¼ü) - * [6. ·ÖÎö](#6-·ÖÎö) - * [É¢Áбí](#É¢Áбí) - * [1. É¢Áк¯Êý](#1-É¢Áк¯Êý) - * [2. »ùÓÚÀ­Á´·¨µÄÉ¢Áбí](#2-»ùÓÚÀ­Á´·¨µÄÉ¢Áбí) - * [3. »ùÓÚÏßÐÔ̽²â·¨µÄÉ¢Áбí](#3-»ùÓÚÏßÐÔ̽²â·¨µÄÉ¢Áбí) - * [3.1 ²éÕÒ](#31-²éÕÒ) - * [3.2 ²åÈë](#32-²åÈë) - * [3.3 ɾ³ý](#33-ɾ³ý) - * [3.4 µ÷ÕûÊý×é´óС](#34-µ÷ÕûÊý×é´óС) - * [Ó¦ÓÃ](#Ó¦ÓÃ) - * [1. ¸÷ÖÖ·ûºÅ±íʵÏֵıȽÏ](#1-¸÷ÖÖ·ûºÅ±íʵÏֵıȽÏ) - * [2. Java µÄ·ûºÅ±íʵÏÖ](#2-java-µÄ·ûºÅ±íʵÏÖ) - * [3. ¼¯ºÏÀàÐÍ](#3-¼¯ºÏÀàÐÍ) - * [4. Ï¡ÊèÏòÁ¿³Ë·¨](#4-Ï¡ÊèÏòÁ¿³Ë·¨) + * [10. 性能分æž�](#10-性能分æž�) + * [平衡查找树](#平衡查找树) + * [2-3 查找树](#2-3-查找树) + * [1. æ�’å…¥æ“�作](#1-æ�’å…¥æ“�作) + * [2. 性质](#2-性质) + * [红黑二å�‰æŸ¥æ‰¾æ ‘](#红黑二å�‰æŸ¥æ‰¾æ ‘) + * [1. 左旋转](#1-左旋转) + * [2. å�³æ—‹è½¬](#2-å�³æ—‹è½¬) + * [3. 颜色转æ�¢](#3-颜色转æ�¢) + * [4. æ�’å…¥](#4-æ�’å…¥) + * [5. 删除最å°�é”®](#5-删除最å°�é”®) + * [6. 分æž�](#6-分æž�) + * [散列表](#散列表) + * [1. 散列函数](#1-散列函数) + * [2. 基于拉链法的散列表](#2-基于拉链法的散列表) + * [3. 基于线性探测法的散列表](#3-基于线性探测法的散列表) + * [3.1 查找](#31-查找) + * [3.2 æ�’å…¥](#32-æ�’å…¥) + * [3.3 删除](#33-删除) + * [3.4 调整数组大å°�](#34-调整数组大å°�) + * [应用](#应用) + * [1. å�„ç§�符å�·è¡¨å®žçŽ°çš„æ¯”è¾ƒ](#1-å�„ç§�符å�·è¡¨å®žçŽ°çš„æ¯”è¾ƒ) + * [2. Java 的符å�·è¡¨å®žçް](#2-java-的符å�·è¡¨å®žçް) + * [3. 集å�ˆç±»åž‹](#3-集å�ˆç±»åž‹) + * [4. 稀ç–�å�‘é‡�乘法](#4-稀ç–�å�‘é‡�乘法) -# µÚÒ»Õ »ù´¡ -## Õ» +# 第一章 基础 -**Êý×éʵÏÖ** +## æ ˆ + +**数组实现** ```java public class ResizeArrayStack implements Iterable { @@ -112,7 +113,7 @@ public class ResizeArrayStack implements Iterable { return item; } - // µ÷ÕûÊý×é´óС£¬Ê¹µÃÕ»¾ßÓÐÉìËõÐÔ + // 调整数组大å°�,使得栈具有伸缩性 private void resize(int size) { Item[] tmp = (Item[]) new Object[size]; for (int i = 0; i < N; i++) { @@ -131,7 +132,7 @@ public class ResizeArrayStack implements Iterable { @Override public Iterator iterator() { - // ÐèÒª·µ»ØÄæÐò±éÀúµÄµü´úÆ÷ + // 需è¦�返回逆åº�é��历的迭代器 return new ReverseArrayIterator(); } @@ -151,15 +152,15 @@ public class ResizeArrayStack implements Iterable { } ``` -ÉÏÃæÊµÏÖʹÓÃÁË·ºÐÍ£¬Java ²»ÄÜÖ±½Ó´´½¨·ºÐÍÊý×飬ֻÄÜʹÓÃתÐÍÀ´´´½¨¡£ +上é�¢å®žçŽ°ä½¿ç”¨äº†æ³›åž‹ï¼ŒJava ä¸�能直接创建泛型数组,å�ªèƒ½ä½¿ç”¨è½¬åž‹æ�¥åˆ›å»ºã€‚ ```java Item[] arr = (Item[]) new Object[N]; ``` -**Á´±íʵÏÖ** +**链表实现** -ÐèҪʹÓÃÁ´±íµÄÍ·²å·¨À´ÊµÏÖ£¬ÒòΪͷ²å·¨ÖÐ×îºóѹÈëÕ»µÄÔªËØÔÚÁ´±íµÄ¿ªÍ·£¬ËüµÄ next Ö¸ÕëÖ¸Ïòǰһ¸öѹÈëÕ»µÄÔªËØ£¬ÔÚµ¯³öÔªËØÊ¹¾Í¿ÉÒÔÈÃǰһ¸öѹÈëÕ»µÄÔªËØ³ÆÎªÕ»¶¥ÔªËØ¡£ +需è¦�使用链表的头æ�’法æ�¥å®žçŽ°ï¼Œå› ä¸ºå¤´æ�’法中最å�ŽåŽ‹å…¥æ ˆçš„å…ƒç´ åœ¨é“¾è¡¨çš„å¼€å¤´ï¼Œå®ƒçš„ next 指针指å�‘å‰�一个压入栈的元素,在弹出元素使就å�¯ä»¥è®©å‰�一个压入栈的元素称为栈顶元素。 ```java public class Stack { @@ -197,11 +198,11 @@ public class Stack { } ``` -## ¶ÓÁÐ +## 队列 -ÏÂÃæÊǶÓÁеÄÁ´±íʵÏÖ£¬ÐèҪά»¤ first ºÍ last ½ÚµãÖ¸Õ룬·Ö±ðÖ¸Ïò¶ÓÊ׺ͶÓβ¡£ +下é�¢æ˜¯é˜Ÿåˆ—的链表实现,需è¦�维护 first å’Œ last 节点指针,分别指å�‘队首和队尾。 -ÕâÀïÐèÒª¿¼ÂÇÈÃÄĸöÖ¸ÕëÖ¸ÕëÁ´±íÍ·²¿½Úµã£¬ÄĸöÖ¸ÕëÖ¸ÏòÁ´±íβ²¿½Úµã¡£ÒòΪ³ö¶ÓÁвÙ×÷ÐèÒªÈöÓÊ×ÔªËØµÄÏÂÒ»¸öÔªËØ³ÉΪ¶ÓÊ×£¬¾ÍÐèÒªÈÝÒ×»ñÈ¡ÏÂÒ»¸öÔªËØ£¬¶øÁ´±íµÄÍ·²¿½ÚµãµÄ next Ö¸ÕëÖ¸ÏòÏÂÒ»¸öÔªËØ£¬Òò´ËÈöÓÊ×Ö¸Õë first Ö¸ÕëÁ´±íµÄ¿ªÍ·¡£ +这里需è¦�考虑让哪个指针指针链表头部节点,哪个指针指å�‘链表尾部节点。因为出队列æ“�作需è¦�让队首元素的下一个元素æˆ�为队首,就需è¦�容易获å�–下一个元素,而链表的头部节点的 next 指针指å�‘下一个元素,因此让队首指针 first 指针链表的开头。 ```java public class Queue { @@ -221,7 +222,7 @@ public class Queue { return N; } - // Èë¶ÓÁÐ + // 入队列 public void enqueue(Item item){ Node newNode = new Node(); newNode.item = item; @@ -236,7 +237,7 @@ public class Queue { N++; } - // ³ö¶ÓÁÐ + // 出队列 public Item dequeue(){ Node node = first; first = first.next; @@ -246,41 +247,41 @@ public class Queue { } ``` -## Ëã·¨·ÖÎö +## 算法分æž� -### 1. º¯Êýת»» +### 1. 函数转æ�¢ -Ö¸Êýº¯Êý¿ÉÒÔת»»ÎªÏßÐÔº¯Êý£¬´Ó¶øÔÚº¯ÊýͼÏñÉÏÏÔʾµÄ¸üÖ±¹Û¡£ +指数函数å�¯ä»¥è½¬æ�¢ä¸ºçº¿æ€§å‡½æ•°ï¼Œä»Žè€Œåœ¨å‡½æ•°å›¾åƒ�上显示的更直观。 -T(N)=aN3 ת»»Îª lg(T(N))=3lgN+lga +T(N)=aN3 转æ�¢ä¸º lg(T(N))=3lgN+lga -![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/5510045a-8f32-487f-a756-463e51a6dab0.png) +![](https://github.com/CyC2018/InterviewNotes/blob/master/pics//5510045a-8f32-487f-a756-463e51a6dab0.png) -### 2. ÊýѧģÐÍ +### 2. 数学模型 -**½üËÆ** +**è¿‘ä¼¼** -ʹÓà \~f(N) À´±íʾËùÓÐËæ×Å N µÄÔö´ó³ýÒÔ f(N) µÄ½á¹ûÇ÷½üÓÚ 1 µÄº¯Êý , ÀýÈç N3/6-N2/2+N/3 \~ N3/6¡£ +使用 \~f(N) æ�¥è¡¨ç¤ºæ‰€æœ‰éš�ç�€ N 的增大除以 f(N) 的结果趋近于 1 的函数 , 例如 N3/6-N2/2+N/3 \~ N3/6。 -![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/ca3a793e-06e5-4ff3-b28e-a9c20540d164.png) +![](https://github.com/CyC2018/InterviewNotes/blob/master/pics//ca3a793e-06e5-4ff3-b28e-a9c20540d164.png) -**Ôö³¤ÊýÁ¿¼¶** +**增长数é‡�级** -Ôö³¤ÊýÁ¿¼¶½«Ëã·¨ÓëËüµÄʵÏÖ¸ôÀ뿪À´£¬Ò»¸öËã·¨µÄÔö³¤ÊýÁ¿¼¶Îª N3 ÓëËüÊÇ·ñÓà Java ʵÏÖ£¬ÊÇ·ñÔËÐÐÓëÌØ¶¨¼ÆËã»úÉÏÎ޹ء£ +增长数é‡�级将算法与它的实现隔离开æ�¥ï¼Œä¸€ä¸ªç®—法的增长数é‡�级为 N3 与它是å�¦ç”¨ Java 实现,是å�¦è¿�行与特定计算机上无关。 -![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/1ea4dc9a-c4dd-46b5-bb11-49f98d57ded1.png) +![](https://github.com/CyC2018/InterviewNotes/blob/master/pics//1ea4dc9a-c4dd-46b5-bb11-49f98d57ded1.png) -**ÄÚÑ­»·** +**内循环** -Ö´ÐÐ×îÆµ·±µÄÖ¸Áî¾ö¶¨Á˳ÌÐòÖ´ÐеÄ×Üʱ¼ä£¬°ÑÕâЩָÁî³ÆÎª³ÌÐòµÄÄÚÑ­»·¡£ +执行最频ç¹�的指令决定了程åº�执行的总时间,把这些指令称为程åº�的内循环。 -**³É±¾Ä£ÐÍ** +**æˆ�本模型** -ʹÓóɱ¾Ä£ÐÍÀ´ÆÀ¹ÀËã·¨£¬ÀýÈçÊý×éµÄ·ÃÎÊ´ÎÊý¾ÍÊÇÒ»Öֳɱ¾Ä£ÐÍ¡£ +使用æˆ�本模型æ�¥è¯„估算法,例如数组的访问次数就是一ç§�æˆ�本模型。 ### 3. ThreeSum -ThreeSum ³ÌÐòÓÃÓÚͳ¼ÆÒ»¸öÊý×éÖÐÈýÔª×éµÄºÍΪ 0 µÄÊýÁ¿¡£ +ThreeSum 程åº�用于统计一个数组中三元组的和为 0 的数é‡�。 ```java public class ThreeSum { @@ -301,13 +302,13 @@ public class ThreeSum { } ``` -¸Ã³ÌÐòµÄÄÚÑ­»·Îª if (a[i] + a[j] + a[k] == 0) Óï¾ä£¬×ܹ²Ö´ÐеĴÎÊýΪ N3/6-N2/2+N/3£¬Òò´ËËüµÄ½üËÆÖ´ÐдÎÊýΪ \~N3/6£¬Ôö³¤ÊýÁ¿¼¶Îª N3¡£ +该程åº�的内循环为 if (a[i] + a[j] + a[k] == 0) 语å�¥ï¼Œæ€»å…±æ‰§è¡Œçš„æ¬¡æ•°ä¸º N3/6-N2/2+N/3,因此它的近似执行次数为 \~N3/6,增长数é‡�级为 N3。 -**¸Ä½ø** +**改进** -ͨ¹ý½«Êý×éÏÈÅÅÐò£¬¶ÔÁ½¸öÔªËØÇóºÍ£¬²¢Óöþ·Ö²éÕÒ·½·¨²éÕÒÊÇ·ñ´æÔڸú͵ÄÏà·´Êý£¬Èç¹û´æÔÚ£¬¾Í˵Ã÷´æÔÚÈýÔª×éµÄºÍΪ 0¡£ +通过将数组先排åº�,对两个元素求和,并用二分查找方法查找是å�¦å­˜åœ¨è¯¥å’Œçš„相å��数,如果存在,就说明存在三元组的和为 0。 -¸Ã·½·¨¿ÉÒÔ½« ThreeSum Ëã·¨Ôö³¤ÊýÁ¿¼¶½µµÍΪ N2logN¡£ +该方法å�¯ä»¥å°† ThreeSum 算法增长数é‡�级é™�低为 N2logN。 ```java public class ThreeSumFast { @@ -318,7 +319,7 @@ public class ThreeSumFast { for (int i = 0; i < N; i++) { for (int j = i + 1; j < N; j++) { for (int k = j + 1; k < N; k++) { - // rank() ·½·¨·µ»ØÔªËØÔÚÊý×éÖеÄϱ꣬Èç¹ûÔªËØ²»´æÔÚ£¬ÕâÀï»á·µ»Ø -1¡£Ó¦¸Ã×¢ÒâÕâÀïµÄÏÂ±ê±ØÐë´óÓÚ j£¬ÕâÑù¾Í²»»áÖØ¸´Í³¼ÆÁË¡£ + // rank() 方法返回元素在数组中的下标,如果元素ä¸�存在,这里会返回 -1。应该注æ„�这里的下标必须大于 j,这样就ä¸�会é‡�å¤�统计了。 if (BinarySearch.rank(-a[i] - a[j], a) > j) { cnt++; } @@ -330,53 +331,53 @@ public class ThreeSumFast { } ``` -### 4. ±¶ÂÊʵÑé +### 4. å€�率实验 -Èç¹û T(N) \~ aNblgN£¬ÄÇô T(2N)/T(N) \~ 2b£¬ÀýÈç¶ÔÓÚ±©Á¦·½·¨µÄ ThreeSum Ëã·¨£¬½üËÆÊ±¼äΪ \~N3/6£¬¶ÔËü½øÐб¶ÂÊʵÑéµÃµ½ÈçϽá¹û£º +如果 T(N) \~ aNblgN,那么 T(2N)/T(N) \~ 2b,例如对于暴力方法的 ThreeSum 算法,近似时间为 \~N3/6,对它进行å€�率实验得到如下结果: -![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/6f5ed46f-86d7-4852-a34f-c1cf1b6343a0.png) +![](https://github.com/CyC2018/InterviewNotes/blob/master/pics//6f5ed46f-86d7-4852-a34f-c1cf1b6343a0.png) -¿É¼û T(2N)/T(N)\~23£¬Ò²¾ÍÊÇ b Ϊ 3¡£ +å�¯è§� T(2N)/T(N)\~23,也就是 b 为 3。 -### 5. ×¢ÒâÊÂÏî +### 5. 注æ„�事项 -**´ó³£Êý** +**大常数** -ÔÚÇó½üËÆÊ±£¬Èç¹ûµÍ¼¶ÏîµÄ³£ÊýϵÊýºÜ´ó£¬ÄÇô½üËÆµÄ½á¹û¾ÍÊÇ´íÎóµÄ¡£ +在求近似时,如果低级项的常数系数很大,那么近似的结果就是错误的。 -**»º´æ** +**缓存** -¼ÆËã»úϵͳ»áʹÓûº´æ¼¼ÊõÀ´×éÖ¯Äڴ棬·ÃÎÊÊý×éÏàÁÚµÄÔªËØ»á±È·ÃÎʲ»ÏàÁÚµÄÔªËØ¿ìºÜ¶à¡£ +计算机系统会使用缓存技术æ�¥ç»„织内存,访问数组相邻的元素会比访问ä¸�相邻的元素快很多。 -**¶Ô×Çé¿öϵÄÐÔÄܵı£Ö¤** +**对最å��情况下的性能的ä¿�è¯�** -Ôں˷´Ó¦¶Ñ¡¢ÐÄÔàÆð²«Æ÷»òÕßɲ³µ¿ØÖÆÆ÷ÖеÄÈí¼þ£¬×Çé¿öϵÄÐÔÄÜÊÇÊ®·ÖÖØÒªµÄ¡£ +在核å��应堆ã€�心è„�èµ·æ��器或者刹车控制器中的软件,最å��情况下的性能是å��分é‡�è¦�的。 -**Ëæ»ú»¯Ëã·¨** +**éš�机化算法** -ͨ¹ý´òÂÒÊäÈ룬ȥ³ýËã·¨¶ÔÊäÈëµÄÒÀÀµ¡£ +通过打乱输入,去除算法对输入的ä¾�赖。 -**¾ù̯·ÖÎö** +**å�‡æ‘Šåˆ†æž�** -½«ËùÓвÙ×÷µÄ×ܳɱ¾ËùÒÔ²Ù×÷×ÜÊýÀ´½«³É±¾¾ù̯¡£ÀýÈç¶ÔÒ»¸ö¿ÕÕ»½øÐÐ N ´ÎÁ¬ÐøµÄ push() µ÷ÓÃÐèÒª·ÃÎÊÊý×éµÄÔªËØÎª N+4+8+16+...+2N=5N-4£¨N ÊÇÏòÊý×éдÈëÔªËØ£¬ÆäÓàµÄ¶¼Êǵ÷ÕûÊý×é´óСʱ½øÐи´ÖÆÐèÒªµÄ·ÃÎÊÊý×é²Ù×÷£©£¬¾ù̯ºóÿ´Î²Ù×÷·ÃÎÊÊý×éµÄƽ¾ù´ÎÊýΪ³£Êý¡£ +将所有æ“�作的总æˆ�本所以æ“�作总数æ�¥å°†æˆ�本å�‡æ‘Šã€‚例如对一个空栈进行 N 次连续的 push() 调用需è¦�访问数组的元素为 N+4+8+16+...+2N=5N-4(N 是å�‘数组写入元素,其余的都是调整数组大å°�时进行å¤�制需è¦�的访问数组æ“�作),å�‡æ‘Šå�Žæ¯�次æ“�作访问数组的平å�‡æ¬¡æ•°ä¸ºå¸¸æ•°ã€‚ ## union-find -**¸ÅÀÀ** +**概览** -ÓÃÓÚ½â¾ö¶¯Ì¬Á¬Í¨ÐÔÎÊÌ⣬Äܶ¯Ì¬Á¬½ÓÁ½¸öµã£¬²¢ÇÒÅжÏÁ½¸öµãÊÇ·ñÁ¬½Ó¡£ +用于解决动æ€�连通性问题,能动æ€�连接两个点,并且判断两个点是å�¦è¿žæŽ¥ã€‚ -![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/5d387d02-6f96-44d6-b5d0-4538349f868e.png) +![](https://github.com/CyC2018/InterviewNotes/blob/master/pics//5d387d02-6f96-44d6-b5d0-4538349f868e.png) **API** -![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/a9b91b7d-65d7-4aa3-8ef6-21876b05ad16.png) +![](https://github.com/CyC2018/InterviewNotes/blob/master/pics//a9b91b7d-65d7-4aa3-8ef6-21876b05ad16.png) -**»ù±¾Êý¾Ý½á¹¹** +**基本数æ�®ç»“æž„** ```java public class UF { - // ʹÓà id Êý×éÀ´±£´æµãµÄÁ¬Í¨ÐÅÏ¢ + // 使用 id 数组æ�¥ä¿�存点的连通信æ�¯ private int[] id; public UF(int N) { @@ -392,11 +393,11 @@ public class UF { } ``` -### 1. quick-find Ëã·¨ +### 1. quick-find 算法 -±£Ö¤ÔÚͬһÁ¬Í¨·ÖÁ¿µÄËùÓд¥µãµÄ id ÖµÏàµÈ¡£ +ä¿�è¯�在å�Œä¸€è¿žé€šåˆ†é‡�的所有触点的 id 值相等。 -ÕâÖÖ·½·¨¿ÉÒÔ¿ìËÙÈ¡µÃÒ»¸ö´¥µãµÄ id Öµ£¬²¢ÇÒÅжÏÁ½¸ö´¥µãÊÇ·ñÁ¬Í¨£¬µ«ÊÇ union µÄ²Ù×÷´ú¼ÛÈ´ºÜ¸ß£¬ÐèÒª½«ÆäÖÐÒ»¸öÁ¬Í¨·ÖÁ¿ÖеÄËùÓнڵã id Öµ¶¼ÐÞ¸ÄΪÁíÒ»¸ö½ÚµãµÄ id Öµ¡£ +è¿™ç§�方法å�¯ä»¥å¿«é€Ÿå�–得一个触点的 id 值,并且判断两个触点是å�¦è¿žé€šï¼Œä½†æ˜¯ union çš„æ“�作代价å�´å¾ˆé«˜ï¼Œéœ€è¦�将其中一个连通分é‡�中的所有节点 id 值都修改为å�¦ä¸€ä¸ªèŠ‚ç‚¹çš„ id 值。 ```java public int find(int p) { @@ -413,11 +414,11 @@ public class UF { } ``` -### 2. quick-union Ëã·¨ +### 2. quick-union 算法 -ÔÚ union ʱֻ½«´¥µãµÄ id ÖµÖ¸ÏòÁíÒ»¸ö´¥µã id Öµ£¬²»Ö±½ÓÓà id À´´æ´¢ËùÊôµÄÁ¬Í¨·ÖÁ¿¡£ÕâÑù¾Í¹¹³ÉÒ»¸öµ¹ÖõÄÊ÷Ðνṹ£¬¸ù½ÚµãÐèÒªÖ¸Ïò×Ô¼º¡£ÔÚ½øÐвéÕÒÒ»¸ö½ÚµãËùÊôµÄÁ¬Í¨·ÖÁ¿Ê±£¬ÒªÒ»Ö±ÏòÉϲéÕÒÖ±µ½¸ù½Úµã£¬²¢Ê¹Óøù½ÚµãµÄ id Öµ×÷Ϊ±¾Á¬Í¨·ÖÁ¿µÄ idÖµ¡£ +在 union æ—¶å�ªå°†è§¦ç‚¹çš„ id 值指å�‘å�¦ä¸€ä¸ªè§¦ç‚¹ id 值,ä¸�直接用 id æ�¥å­˜å‚¨æ‰€å±žçš„连通分é‡�。这样就构æˆ�一个倒置的树形结构,根节点需è¦�指å�‘自己。在进行查找一个节点所属的连通分é‡�时,è¦�一直å�‘上查找直到根节点,并使用根节点的 id 值作为本连通分é‡�çš„ id值。 -![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/9192dc0a-a7cd-4030-8df6-e388600644cf.jpg) +![](https://github.com/CyC2018/InterviewNotes/blob/master/pics//9192dc0a-a7cd-4030-8df6-e388600644cf.jpg) ```java public int find(int p) { @@ -433,22 +434,22 @@ public class UF { } ``` -ÕâÖÖ·½·¨¿ÉÒÔ¿ìËÙ½øÐÐ union ²Ù×÷£¬µ«ÊÇ find ²Ù×÷ºÍÊ÷¸ß³ÉÕý±È£¬×µÄÇé¿öÏÂÊ÷µÄ¸ß¶ÈΪ´¥µãµÄÊýÄ¿¡£ +è¿™ç§�方法å�¯ä»¥å¿«é€Ÿè¿›è¡Œ union æ“�作,但是 find æ“�作和树高æˆ�正比,最å��的情况下树的高度为触点的数目。 -![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/d206d090-d911-4263-a1fe-d6f63f5d1776.png) +![](https://github.com/CyC2018/InterviewNotes/blob/master/pics//d206d090-d911-4263-a1fe-d6f63f5d1776.png) -### 3. ¼ÓȨ quick-union Ëã·¨ +### 3. 加æ�ƒ quick-union 算法 -ΪÁ˽â¾ö quick-union µÄÊ÷ͨ³£»áºÜ¸ßµÄÎÊÌ⣬¼ÓȨ quick-union ÔÚ union ²Ù×÷ʱ»áÈýÏСµÄÊ÷Á¬½Ó½Ï´óµÄÊ÷ÉÏÃæ¡£ +为了解决 quick-union 的树通常会很高的问题,加æ�ƒ quick-union 在 union æ“�作时会让较å°�的树连接较大的树上é�¢ã€‚ -ÀíÂÛÑо¿Ö¤Ã÷£¬¼ÓȨ quick-union Ëã·¨¹¹ÔìµÄÊ÷Éî¶È×î¶à²»³¬¹ý lgN¡£ +ç�†è®ºç ”ç©¶è¯�明,加æ�ƒ quick-union 算法构造的树深度最多ä¸�超过 lgN。 -![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/8d6af5ac-74eb-4e07-99aa-654b9f21f1d3.jpg) +![](https://github.com/CyC2018/InterviewNotes/blob/master/pics//8d6af5ac-74eb-4e07-99aa-654b9f21f1d3.jpg) ```java public class WeightedQuickUnionUF { private int[] id; - // ±£´æ½ÚµãµÄÊýÁ¿ÐÅÏ¢ + // ä¿�存节点的数é‡�ä¿¡æ�¯ private int[] sz; public WeightedQuickUnionUF(int N) { @@ -484,25 +485,25 @@ public class WeightedQuickUnionUF { } ``` -### 4. ·¾¶Ñ¹ËõµÄ¼ÓȨ quick-union Ëã·¨ +### 4. 路径压缩的加æ�ƒ quick-union 算法 -ÔÚ¼ì²é½ÚµãµÄͬʱ½«ËüÃÇÖ±½ÓÁ´½Óµ½¸ù½Úµã£¬Ö»ÐèÒªÔÚ find ÖÐÌí¼ÓÒ»¸öÑ­»·¼´¿É¡£ +在检查节点的å�Œæ—¶å°†å®ƒä»¬ç›´æŽ¥é“¾æŽ¥åˆ°æ ¹èŠ‚ç‚¹ï¼Œå�ªéœ€è¦�在 find 中添加一个循环å�³å�¯ã€‚ -### 5. ¸÷ÖÖ union-find Ëã·¨µÄ±È½Ï +### 5. å�„ç§� union-find 算法的比较 -![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/e5baeb38-0ec9-4ad7-8374-1cdb0dba74a6.jpg) +![](https://github.com/CyC2018/InterviewNotes/blob/master/pics//e5baeb38-0ec9-4ad7-8374-1cdb0dba74a6.jpg) -# µÚ¶þÕ ÅÅÐò +# 第二章 排åº� -## ³õ¼¶ÅÅÐòËã·¨ +## åˆ�级排åº�算法 -### 1. Ô¼¶¨ +### 1. 约定 -´ýÅÅÐòµÄÔªËØÐèҪʵÏÖ Java µÄ Comparable ½Ó¿Ú£¬¸Ã½Ó¿ÚÓÐ compareTo() ·½·¨¡£ +待排åº�的元素需è¦�实现 Java çš„ Comparable 接å�£ï¼Œè¯¥æŽ¥å�£æœ‰ compareTo() 方法。 -Ñо¿ÅÅÐòËã·¨µÄ³É±¾Ä£ÐÍʱ£¬¼ÆËãµÄÊDZȽϺͽ»»»µÄ´ÎÊý¡£ +研究排åº�算法的æˆ�本模型时,计算的是比较和交æ�¢çš„æ¬¡æ•°ã€‚ -ʹÓø¨Öúº¯Êý less() ºÍ exch() À´½øÐбȽϺͽ»»»µÄ²Ù×÷£¬Ê¹µÃ´úÂëµÄ¿É¶ÁÐԺͿÉÒÆÖ²ÐÔ¸üºÃ¡£ +使用辅助函数 less() å’Œ exch() æ�¥è¿›è¡Œæ¯”较和交æ�¢çš„æ“�作,使得代ç �çš„å�¯è¯»æ€§å’Œå�¯ç§»æ¤�性更好。 ```java private boolean less(Comparable v, Comparable w){ @@ -516,11 +517,11 @@ private void exch(Comparable[] a, int i, int j){ } ``` -### 2. Ñ¡ÔñÅÅÐò +### 2. 选择排åº� -ÕÒµ½Êý×éÖеÄ×îÐ¡ÔªËØ£¬È»ºó½«ËüÓëÊý×éµÄµÚÒ»¸öÔªËØ½»»»Î»Öá£È»ºóÔÙ´ÓʣϵÄÔªËØÖÐÕÒµ½×îСµÄÔªËØ£¬½«ËüÓëÊý×éµÄµÚ¶þ¸öÔªËØ½»»»Î»Öᣲ»¶Ï½øÐÐÕâÑùµÄ²Ù×÷£¬Ö±µ½½«Õû¸öÊý×éÅÅÐò¡£ +找到数组中的最å°�元素,然å�Žå°†å®ƒä¸Žæ•°ç»„的第一个元素交æ�¢ä½�置。然å�Žå†�从剩下的元素中找到最å°�的元素,将它与数组的第二个元素交æ�¢ä½�置。ä¸�断进行这样的æ“�作,直到将整个数组排åº�。 -![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/222768a7-914f-4d64-b874-d98f3b926fb6.jpg) +![](https://github.com/CyC2018/InterviewNotes/blob/master/pics//222768a7-914f-4d64-b874-d98f3b926fb6.jpg) ```java public class Selection { @@ -537,13 +538,13 @@ public class Selection { } ``` -Ñ¡ÔñÅÅÐòÐèÒª \~N2/2 ´Î±È½ÏºÍ \~N ´Î½»»»£¬ËüµÄÔËÐÐʱ¼äÓëÊäÈëÎ޹أ¬Õâ¸öÌØµãʹµÃËü¶ÔÒ»¸öÒѾ­ÅÅÐòµÄÊý×éÒ²ÐèÒªÕâô¶àµÄ±È½ÏºÍ½»»»²Ù×÷¡£ +选择排åº�需è¦� \~N2/2 次比较和 \~N 次交æ�¢ï¼Œå®ƒçš„è¿�行时间与输入无关,这个特点使得它对一个已ç»�排åº�的数组也需è¦�这么多的比较和交æ�¢æ“�作。 -### 3. ²åÈëÅÅÐò +### 3. æ�’入排åº� -½«Ò»¸öÔªËØ²åÈëµ½ÒÑÅÅÐòµÄÊý×éÖУ¬Ê¹µÃ²åÈëÖ®ºóµÄÊý×éÒ²ÊÇÓÐÐòµÄ¡£²åÈëÅÅÐò´Ó×óµ½ÓÒ²åÈëÿ¸öÔªËØ£¬Ã¿´Î²åÈëÖ®ºó×󲿵Ä×ÓÊý×éÊÇÓÐÐòµÄ¡£ +将一个元素æ�’入到已排åº�的数组中,使得æ�’入之å�Žçš„æ•°ç»„也是有åº�的。æ�’入排åº�从左到å�³æ�’å…¥æ¯�个元素,æ¯�次æ�’入之å�Žå·¦éƒ¨çš„å­�数组是有åº�的。 -![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/065c3bbb-3ea0-4dbf-8f26-01d0e0ba7db7.png) +![](https://github.com/CyC2018/InterviewNotes/blob/master/pics//065c3bbb-3ea0-4dbf-8f26-01d0e0ba7db7.png) ```java public class Insertion { @@ -558,23 +559,23 @@ public class Insertion { } ``` -²åÈëÅÅÐòµÄ¸´ÔÓ¶ÈÈ¡¾öÓÚÊý×éµÄ³õʼ˳Ðò£¬Èç¹ûÊý×éÒѾ­²¿·ÖÓÐÐòÁË£¬ÄÇô²åÈëÅÅÐò»áºÜ¿ì¡£Æ½¾ùÇé¿öϲåÈëÅÅÐòÐèÒª \~N2/4 ±È½ÏÒÔ¼° \~N2/4 ´Î½»»»£¬×µÄÇé¿öÏÂÐèÒª \~N2/2 ±È½ÏÒÔ¼° \~N2/2 ´Î½»»»£¬×µÄÇé¿öÊÇÊý×éÊÇÄæÐòµÄ£»¶ø×îºÃµÄÇé¿öÏÂÐèÒª N-1 ´Î±È½ÏºÍ 0 ´Î½»»»£¬×îºÃµÄÇé¿ö¾ÍÊÇÊý×éÒѾ­ÓÐÐòÁË¡£ +æ�’入排åº�çš„å¤�æ�‚度å�–决于数组的åˆ�始顺åº�,如果数组已ç»�部分有åº�了,那么æ�’入排åº�会很快。平å�‡æƒ…况下æ�’入排åº�需è¦� \~N2/4 比较以å�Š \~N2/4 次交æ�¢ï¼Œæœ€å��的情况下需è¦� \~N2/2 比较以å�Š \~N2/2 次交æ�¢ï¼Œæœ€å��的情况是数组是逆åº�的;而最好的情况下需è¦� N-1 次比较和 0 次交æ�¢ï¼Œæœ€å¥½çš„æƒ…况就是数组已ç»�有åº�了。 -²åÈëÅÅÐò¶ÔÓÚ²¿·ÖÓÐÐòÊý×éºÍС¹æÄ£Êý×éÌØ±ð¸ßЧ¡£ +æ�’入排åº�对于部分有åº�数组和å°�规模数组特别高效。 -### 4. Ñ¡ÔñÅÅÐòºÍ²åÈëÅÅÐòµÄ±È½Ï +### 4. 选择排åº�å’Œæ�’入排åº�的比较 -¶ÔÓÚËæ»úÅÅÐòµÄÎÞÖØ¸´Ö÷¼üµÄÊý×飬²åÈëÅÅÐòºÍÑ¡ÔñÅÅÐòµÄÔËÐÐʱ¼äÊÇÆ½·½¼¶±ðµÄ£¬Á½ÕßÖ®±ÈÊÇÒ»¸ö½ÏСµÄ³£Êý¡£ +对于éš�机排åº�的无é‡�å¤�主键的数组,æ�’入排åº�和选择排åº�çš„è¿�行时间是平方级别的,两者之比是一个较å°�的常数。 -### 5. Ï£¶ûÅÅÐò +### 5. 希尔排åº� -¶ÔÓÚ´ó¹æÄ£µÄÊý×飬²åÈëÅÅÐòºÜÂý£¬ÒòΪËüÖ»Äܽ»»»ÏàÁÚµÄÔªËØ£¬Èç¹ûÒª°ÑÔªËØ´ÓÒ»¶ËÒÆµ½ÁíÒ»¶Ë£¬¾ÍÐèÒªºÜ¶à´Î²Ù×÷¡£ +对于大规模的数组,æ�’入排åº�很慢,因为它å�ªèƒ½äº¤æ�¢ç›¸é‚»çš„元素,如果è¦�把元素从一端移到å�¦ä¸€ç«¯ï¼Œå°±éœ€è¦�很多次æ“�作。 -Ï£¶ûÅÅÐòµÄ³öÏÖ¾ÍÊÇΪÁ˸Ľø²åÈëÅÅÐòµÄÕâÖÖ¾ÖÏÞÐÔ£¬Ëüͨ¹ý½»»»²»ÏàÁÚµÄÔªËØ£¬Ê¹µÃÔªËØ¸ü¿ìµÄÒÆµ½ÕýÈ·µÄλÖÃÉÏ¡£ +希尔排åº�的出现就是为了改进æ�’入排åº�的这ç§�å±€é™�性,它通过交æ�¢ä¸�相邻的元素,使得元素更快的移到正确的ä½�置上。 -Ï£¶ûÅÅÐòʹÓòåÈëÅÅÐò¶Ô¼ä¸ô h µÄÐòÁнøÐÐÅÅÐò£¬Èç¹û h ºÜ´ó£¬ÄÇÃ´ÔªËØ¾ÍÄܺܿìµÄÒÆµ½ºÜÔ¶µÄµØ·½¡£Í¨¹ý²»¶Ï¼õС h£¬×îºóÁî h=1£¬¾Í¿ÉÒÔʹµÃÕû¸öÊý×éÊÇÓÐÐòµÄ¡£ +希尔排åº�使用æ�’入排åº�对间隔 h çš„åº�列进行排åº�,如果 h 很大,那么元素就能很快的移到很远的地方。通过ä¸�æ–­å‡�å°� h,最å�Žä»¤ h=1,就å�¯ä»¥ä½¿å¾—整个数组是有åº�的。 -![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/8320bad6-3f91-4a15-8e3d-68e8f39649b5.png) +![](https://github.com/CyC2018/InterviewNotes/blob/master/pics//8320bad6-3f91-4a15-8e3d-68e8f39649b5.png) ```java public class Shell { @@ -596,15 +597,15 @@ public class Shell { } ``` -Ï£¶ûÅÅÐòµÄÔËÐÐʱ¼ä´ï²»µ½Æ½·½¼¶±ð£¬Ê¹ÓõÝÔöÐòÁÐ 1, 4, 13, 40, ... µÄÏ£¶ûÅÅÐòËùÐèÒªµÄ±È½Ï´ÎÊý²»»á³¬¹ý N µÄÈô¸É±¶³ËÓÚµÝÔöÐòÁеij¤¶È¡£ºóÃæ½éÉܵĸ߼¶ÅÅÐòËã·¨Ö»»á±ÈÏ£¶ûÅÅÐò¿ìÁ½±¶×óÓÒ¡£ +希尔排åº�çš„è¿�行时间达ä¸�到平方级别,使用递增åº�列 1, 4, 13, 40, ... 的希尔排åº�所需è¦�的比较次数ä¸�会超过 N 的若干å€�乘于递增åº�列的长度。å�Žé�¢ä»‹ç»�的高级排åº�算法å�ªä¼šæ¯”希尔排åº�快两å€�å·¦å�³ã€‚ -## ¹é²¢ÅÅÐò +## 归并排åº� -¹é²¢ÅÅÐòµÄ˼ÏëÊǽ«Êý×é·Ö³ÉÁ½²¿·Ö£¬·Ö±ð½øÐÐÅÅÐò£¬È»ºó¹é²¢ÆðÀ´¡£ +归并排åº�çš„æ€�想是将数组分æˆ�两部分,分别进行排åº�,然å�Žå½’å¹¶èµ·æ�¥ã€‚ -![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/dcf265ad-fe35-424d-b4b7-d149cdf239f4.png) +![](https://github.com/CyC2018/InterviewNotes/blob/master/pics//dcf265ad-fe35-424d-b4b7-d149cdf239f4.png) -### 1. ¹é²¢·½·¨ +### 1. 归并方法 ```java public class MergeSort { @@ -614,20 +615,20 @@ public class MergeSort { int i = lo, j = mid + 1; for (int k = lo; k <= hi; k++) { - aux[k] = a[k]; // ½«Êý¾Ý¸´ÖƵ½¸¨ÖúÊý×é + aux[k] = a[k]; // 将数æ�®å¤�制到辅助数组 } for (int k = lo; k <= hi; k++) { if (i > mid) a[k] = aux[j++]; else if (j > hi) a[k] = aux[i++]; - else if (aux[i].compareTo(a[j]) < 0) a[k] = aux[i++]; // ÏȽøÐÐÕâÒ»²½£¬±£Ö¤Îȶ¨ÐÔ + else if (aux[i].compareTo(a[j]) < 0) a[k] = aux[i++]; // 先进行这一步,ä¿�è¯�稳定性 else a[k] = aux[j++]; } } } ``` -### 2. ×Ô¶¥ÏòϹ鲢ÅÅÐò +### 2. 自顶å�‘下归并排åº� ```java public static void sort(Comparable[] a) { @@ -644,19 +645,19 @@ private static void sort(Comparable[] a, int lo, int hi) { } ``` -![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/6468a541-3a9a-4008-82b6-03a0fe941d2a.png) +![](https://github.com/CyC2018/InterviewNotes/blob/master/pics//6468a541-3a9a-4008-82b6-03a0fe941d2a.png) -![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/c7665f73-c52f-4ce4-aed3-592bbd76265b.png) +![](https://github.com/CyC2018/InterviewNotes/blob/master/pics//c7665f73-c52f-4ce4-aed3-592bbd76265b.png) -ºÜÈÝÒ׿´³ö¸ÃÅÅÐòËã·¨µÄʱ¼ä¸´ÔÓ¶ÈΪ O(NlgN)¡£ +很容易看出该排åº�算法的时间å¤�æ�‚度为 O(NlgN)。 -ÒòΪСÊý×éµÄµÝ¹é²Ù×÷»á¹ýÓÚÆµ·±£¬Òò´ËʹÓòåÈëÅÅÐòÀ´´¦ÀíСÊý×齫»á»ñµÃ¸ü¸ßµÄÐÔÄÜ¡£ +因为å°�数组的递归æ“�作会过于频ç¹�,因此使用æ�’入排åº�æ�¥å¤„ç�†å°�数组将会获得更高的性能。 -### 3. ×Ôµ×ÏòÉϹ鲢ÅÅÐò +### 3. 自底å�‘上归并排åº� -Ïȹ鲢ÄÇЩ΢ÐÍÊý×飬Ȼºó³É¶Ô¹é²¢µÃµ½µÄ×ÓÊý×é¡£ +先归并那些微型数组,然å�Žæˆ�对归并得到的å­�数组。 -![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/c7b9b4c8-83d1-4eb0-8408-ea6576a9ed90.png) +![](https://github.com/CyC2018/InterviewNotes/blob/master/pics//c7b9b4c8-83d1-4eb0-8408-ea6576a9ed90.png) ```java public static void busort(Comparable[] a) { @@ -670,13 +671,13 @@ public static void busort(Comparable[] a) { } ``` -## ¿ìËÙÅÅÐò +## 快速排åº� -### 1. »ù±¾Ëã·¨ +### 1. 基本算法 -¹é²¢ÅÅÐò½«Êý×é·ÖΪÁ½¸ö×ÓÊý×é·Ö±ðÅÅÐò£¬²¢½«ÓÐÐòµÄ×ÓÊý×é¹é²¢Ê¹µÃÕû¸öÊý×éÅÅÐò£»¿ìËÙÅÅÐòͨ¹ýÒ»¸öÇзÖÔªËØ½«Êý×é·ÖΪÁ½¸ö×ÓÊý×飬×ó×ÓÊý×éСÓÚµÈÓÚÇзÖÔªËØ£¬ÓÒ×ÓÊý×é´óÓÚµÈÓÚÇзÖÔªËØ£¬½«ÕâÁ½¸ö×ÓÊý×éÅÅÐòÒ²¾Í½«Õû¸öÊý×éÅÅÐòÁË¡£ +归并排åº�将数组分为两个å­�数组分别排åº�,并将有åº�çš„å­�数组归并使得整个数组排åº�;快速排åº�通过一个切分元素将数组分为两个å­�数组,左å­�数组å°�于等于切分元素,å�³å­�数组大于等于切分元素,将这两个å­�数组排åº�也就将整个数组排åº�了。 -![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/61b4832d-71f3-413c-84b6-237e219b9fdc.png) +![](https://github.com/CyC2018/InterviewNotes/blob/master/pics//61b4832d-71f3-413c-84b6-237e219b9fdc.png) ```java public class QuickSort { @@ -694,11 +695,11 @@ public class QuickSort { } ``` -### 2. ÇÐ·Ö +### 2. 切分 -È¡ a[lo] ×÷ΪÇзÖÔªËØ£¬È»ºó´ÓÊý×éµÄ×ó¶ËÏòÓÒɨÃèÖ±µ½ÕÒµ½µÚÒ»¸ö´óÓÚµÈÓÚËüµÄÔªËØ£¬ÔÙ´ÓÊý×éµÄÓÒ¶ËÏò×óɨÃèÕÒµ½µÚÒ»¸öСÓÚµÈÓÚËüµÄÔªËØ£¬½»»»ÕâÁ½¸öÔªËØ£¬²¢²»¶Ï¼ÌÐøÕâ¸ö¹ý³Ì£¬¾Í¿ÉÒÔ±£Ö¤×óÖ¸ÕëµÄ×ó²àÔªËØ¶¼²»´óÓÚÇзÖÔªËØ£¬ÓÒÖ¸Õë j µÄÓÒ²àÔªËØ¶¼²»Ð¡ÓÚÇзÖÔªËØ¡£µ±Á½¸öÖ¸ÕëÏàÓöʱ£¬½«ÇзÖÔªËØ a[lo] ºÍ×ó×ÓÊý×é×îÓÒ²àµÄÔªËØ a[j] ½»»»È»ºó·µ»Ø j ¼´¿É¡£ +å�– a[lo] 作为切分元素,然å�Žä»Žæ•°ç»„的左端å�‘å�³æ‰«æ��直到找到第一个大于等于它的元素,å†�从数组的å�³ç«¯å�‘左扫æ��找到第一个å°�于等于它的元素,交æ�¢è¿™ä¸¤ä¸ªå…ƒç´ ï¼Œå¹¶ä¸�断继续这个过程,就å�¯ä»¥ä¿�è¯�左指针的左侧元素都ä¸�大于切分元素,å�³æŒ‡é’ˆ j çš„å�³ä¾§å…ƒç´ éƒ½ä¸�å°�于切分元素。当两个指针相é�‡æ—¶ï¼Œå°†åˆ‡åˆ†å…ƒç´  a[lo] 和左å­�数组最å�³ä¾§çš„元素 a[j] 交æ�¢ç„¶å�Žè¿”回 j å�³å�¯ã€‚ -![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/e198c201-f386-4491-8ad6-f7e433bf992d.png) +![](https://github.com/CyC2018/InterviewNotes/blob/master/pics//e198c201-f386-4491-8ad6-f7e433bf992d.png) ```java private static int partition(Comparable[] a, int lo, int hi) { @@ -715,31 +716,31 @@ private static int partition(Comparable[] a, int lo, int hi) { } ``` -### 3. ÐÔÄÜ·ÖÎö +### 3. 性能分æž� -¿ìËÙÅÅÐòÊÇÔ­µØÅÅÐò£¬²»ÐèÒª¸¨ÖúÊý×飬µ«Êǵݹéµ÷ÓÃÐèÒª¸¨ÖúÕ»¡£ +快速排åº�是原地排åº�,ä¸�需è¦�辅助数组,但是递归调用需è¦�辅助栈。 -¿ìËÙÅÅÐò×îºÃµÄÇé¿öÏÂÊÇÿ´Î¶¼ÕýºÃÄܽ«Êý×é¶Ô°ë·Ö£¬ÕâÑùµÝ¹éµ÷ÓôÎÊý²ÅÊÇ×îÉٵġ£ÕâÖÖÇé¿öϱȽϴÎÊýΪ CN=2CN/2+N£¬Ò²¾ÍÊǸ´ÔÓ¶ÈΪ O(NlgN)¡£ +快速排åº�最好的情况下是æ¯�次都正好能将数组对å�Šåˆ†ï¼Œè¿™æ ·é€’归调用次数æ‰�是最少的。这ç§�情况下比较次数为 CN=2CN/2+N,也就是å¤�æ�‚度为 O(NlgN)。 -×µÄÇé¿öÏ£¬µÚÒ»´Î´Ó×îСµÄÔªËØÇз֣¬µÚ¶þ´Î´ÓµÚ¶þСµÄÔªËØÇз֣¬Èç´ËÕâ°ã¡£Òò´Ë×µÄÇé¿öÏÂÐèÒª±È½Ï N2/2¡£ÎªÁË·ÀÖ¹Êý×é×ʼ¾ÍÊÇÓÐÐòµÄ£¬ÔÚ½øÐпìËÙÅÅÐòʱÐèÒªËæ»ú´òÂÒÊý×é¡£ +最å��的情况下,第一次从最å°�的元素切分,第二次从第二å°�的元素切分,如此这般。因此最å��的情况下需è¦�比较 N2/2。为了防止数组最开始就是有åº�的,在进行快速排åº�时需è¦�éš�机打乱数组。 -### 4. Ëã·¨¸Ä½ø +### 4. 算法改进 -#### 4.1 Çл»µ½²åÈëÅÅÐò +#### 4.1 切æ�¢åˆ°æ�’入排åº� -ÒòΪ¿ìËÙÅÅÐòÔÚСÊý×éÖÐÒ²»áµ÷ÓÃ×Ô¼º£¬¶ÔÓÚСÊý×飬²åÈëÅÅÐò±È¿ìËÙÅÅÐòµÄÐÔÄܸüºÃ£¬Òò´ËÔÚСÊý×éÖпÉÒÔÇл»µ½²åÈëÅÅÐò¡£ +因为快速排åº�在å°�数组中也会调用自己,对于å°�数组,æ�’入排åº�比快速排åº�的性能更好,因此在å°�数组中å�¯ä»¥åˆ‡æ�¢åˆ°æ�’入排åº�。 -#### 4.2 ÈýÈ¡Ñù +#### 4.2 三å�–æ · -×îºÃµÄÇé¿öÏÂÊÇÿ´Î¶¼ÄÜÈ¡Êý×éµÄÖÐλÊý×÷ΪÇзÖÔªËØ£¬µ«ÊǼÆËãÖÐλÊýµÄ´ú¼ÛºÜ¸ß¡£ÈËÃÇ·¢ÏÖÈ¡ 3 ¸öÔªËØ²¢½«´óС¾ÓÖеÄÔªËØ×÷ΪÇзÖÔªËØµÄЧ¹û×îºÃ¡£ +最好的情况下是æ¯�次都能å�–数组的中ä½�数作为切分元素,但是计算中ä½�数的代价很高。人们å�‘现å�– 3 个元素并将大å°�居中的元素作为切分元素的效果最好。 -#### 4.3 ÈýÏòÇÐ·Ö +#### 4.3 三å�‘切分 -¶ÔÓÚÓдóÁ¿Öظ´ÔªËصÄÊý×飬¿ÉÒÔ½«Êý×éÇзÖΪÈý²¿·Ö£¬·Ö±ð¶ÔӦСÓÚ¡¢µÈÓںʹóÓÚÇзÖÔªËØ¡£ +对于有大é‡�é‡�å¤�元素的数组,å�¯ä»¥å°†æ•°ç»„切分为三部分,分别对应å°�于ã€�等于和大于切分元素。 -ÈýÏòÇзֿìËÙÅÅÐò¶ÔÓÚÖ»ÓÐÈô¸É²»Í¬Ö÷¼üµÄËæ»úÊý×é¿ÉÒÔÔÚÏßÐÔʱ¼äÄÚÍê³ÉÅÅÐò¡£ +三å�‘切分快速排åº�对于å�ªæœ‰è‹¥å¹²ä¸�å�Œä¸»é”®çš„éš�机数组å�¯ä»¥åœ¨çº¿æ€§æ—¶é—´å†…完æˆ�排åº�。 -![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/9d2226dc-c4a3-40ec-9b3e-a46bf86af499.png) +![](https://github.com/CyC2018/InterviewNotes/blob/master/pics//9d2226dc-c4a3-40ec-9b3e-a46bf86af499.png) ```java public class Quick3Way { @@ -759,17 +760,17 @@ public class Quick3Way { } ``` -## ÓÅÏȶÓÁÐ +## 优先队列 -ÓÅÏȶÓÁÐÖ÷ÒªÓÃÓÚ´¦Àí×î´óÔªËØ¡£ +优先队列主è¦�用于处ç�†æœ€å¤§å…ƒç´ ã€‚ -### 1. ¶Ñ +### 1. å † -¶¨Ò壺һ¿Å¶þ²æÊ÷µÄÿ¸ö½Úµã¶¼´óÓÚµÈÓÚËüµÄÁ½¸ö×ӽڵ㡣 +定义:一颗二å�‰æ ‘çš„æ¯�个节点都大于等于它的两个å­�节点。 -¶Ñ¿ÉÒÔÓÃÊý×éÀ´±íʾ£¬ÒòΪ¶ÑÊÇÒ»ÖÖÍêÈ«¶þ²æÊ÷£¬¶øÍêÈ«¶þ²æÊ÷ºÜÈÝÒ׾ʹ洢ÔÚÊý×éÖС£Î»Öà k µÄ½ÚµãµÄ¸¸½ÚµãλÖÃΪ k/2£¬¶øËüµÄÁ½¸ö×Ó½ÚµãµÄλÖ÷ֱðΪ 2k ºÍ 2k+1¡£ÕâÀïÎÒÃDz»Ê¹ÓÃÊý×éË÷ÒýΪ 0 µÄλÖã¬ÊÇΪÁ˸üÇåÎúµØÀí½â½ÚµãµÄ¹ØÏµ¡£ +å †å�¯ä»¥ç”¨æ•°ç»„æ�¥è¡¨ç¤ºï¼Œå› ä¸ºå †æ˜¯ä¸€ç§�完全二å�‰æ ‘,而完全二å�‰æ ‘很容易就存储在数组中。ä½�ç½® k 的节点的父节点ä½�置为 k/2,而它的两个å­�节点的ä½�置分别为 2k å’Œ 2k+1。这里我们ä¸�使用数组索引为 0 çš„ä½�置,是为了更清晰地ç�†è§£èŠ‚ç‚¹çš„å…³ç³»ã€‚ -![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/a9b6c1db-0f4a-4e91-8ac8-6b19bd106b51.png) +![](https://github.com/CyC2018/InterviewNotes/blob/master/pics//a9b6c1db-0f4a-4e91-8ac8-6b19bd106b51.png) ```java public class MaxPQ { @@ -800,9 +801,9 @@ public class MaxPQ { } ``` -### 2. Éϸ¡ºÍϳÁ +### 2. 上浮和下沉 -ÔÚ¶ÑÖУ¬µ±Ò»¸ö½Úµã±È¸¸½Úµã´ó£¬ÄÇôÐèÒª½»»»Õâ¸öÁ½¸ö½Úµã¡£½»»»ºó»¹¿ÉÄܱÈËüеĸ¸½Úµã´ó£¬Òò´ËÐèÒª²»¶ÏµØ½øÐбȽϺͽ»»»²Ù×÷¡£°ÑÕâÖÖ²Ù×÷³ÆÎªÉϸ¡¡£ +在堆中,当一个节点比父节点大,那么需è¦�交æ�¢è¿™ä¸ªä¸¤ä¸ªèŠ‚ç‚¹ã€‚äº¤æ�¢å�Žè¿˜å�¯èƒ½æ¯”它新的父节点大,因此需è¦�ä¸�断地进行比较和交æ�¢æ“�作。把这ç§�æ“�作称为上浮。 ```java private void swim(int k) { @@ -813,7 +814,7 @@ private void swim(int k) { } ``` -ÀàËÆµØ£¬µ±Ò»¸ö½Úµã±È×Ó½ÚµãÀ´µÃС£¬Ò²ÐèÒª²»¶ÏµÄÏòϱȽϺͽ»»»²Ù×÷£¬°ÑÕâÖÖ²Ù×÷³ÆÎªÏ³Á¡£Ò»¸ö½ÚµãÓÐÁ½¸ö×ӽڵ㣬Ӧµ±ÓëÁ½¸ö×Ó½ÚµãÖÐ×î´óÄÇô½Úµã½øÐн»»»¡£ +类似地,当一个节点比å­�节点æ�¥å¾—å°�,也需è¦�ä¸�æ–­çš„å�‘下比较和交æ�¢æ“�作,把这ç§�æ“�作称为下沉。一个节点有两个å­�节点,应当与两个å­�节点中最大那么节点进行交æ�¢ã€‚ ```java private void sink(int k) { @@ -827,9 +828,9 @@ private void sink(int k) { } ``` -### 3. ²åÈëÔªËØ +### 3. æ�’入元素 -½«ÐÂÔªËØ·Åµ½Êý×éĩβ£¬È»ºóÉϸ¡µ½ºÏÊʵÄλÖᣠ+将新元素放到数组末尾,然å�Žä¸Šæµ®åˆ°å�ˆé€‚çš„ä½�置。 ```java public void insert(Key v) { @@ -838,9 +839,9 @@ public void insert(Key v) { } ``` -### 4. ɾ³ý×î´óÔªËØ +### 4. 删除最大元素 -´ÓÊý×é¶¥¶Ëɾ³ý×î´óµÄÔªËØ£¬²¢½«Êý×éµÄ×îºóÒ»¸öÔªËØ·Åµ½¶¥¶Ë£¬²¢ÈÃÕâ¸öÔªËØÏ³Áµ½ºÏÊʵÄλÖᣠ+从数组顶端删除最大的元素,并将数组的最å�Žä¸€ä¸ªå…ƒç´ æ”¾åˆ°é¡¶ç«¯ï¼Œå¹¶è®©è¿™ä¸ªå…ƒç´ ä¸‹æ²‰åˆ°å�ˆé€‚çš„ä½�置。 ```java public Key delMax() { @@ -852,15 +853,15 @@ public Key delMax() { } ``` -### 5. ¶ÑÅÅÐò +### 5. 堆排åº� -ÓÉÓÚ¶Ñ¿ÉÒÔºÜÈÝÒ׵õ½×î´óµÄÔªËØ²¢É¾³ýËü£¬²»¶ÏµØ½øÐÐÕâÖÖ²Ù×÷¿ÉÒԵõ½Ò»¸öµÝ¼õÐòÁС£Èç¹û°Ñ×î´óÔªËØºÍµ±Ç°¶ÑÖÐÊý×éµÄ×îºóÒ»¸öÔªËØ½»»»Î»Ö㬲¢ÇÒ²»É¾³ýËü£¬ÄÇô¾Í¿ÉÒԵõ½Ò»¸ö´Óβµ½Í·µÄµÝ¼õÐòÁУ¬´ÓÕýÏòÀ´¿´¾ÍÊÇÒ»¸öµÝÔöÐòÁС£Òò´ËºÜÈÝÒ×ʹÓöÑÀ´½øÐÐÅÅÐò£¬²¢ÇÒ¶ÑÅÅÐòÊÇÔ­µØÅÅÐò£¬²»Õ¼ÓöîÍâ¿Õ¼ä¡£ +由于堆å�¯ä»¥å¾ˆå®¹æ˜“得到最大的元素并删除它,ä¸�断地进行这ç§�æ“�作å�¯ä»¥å¾—到一个递å‡�åº�列。如果把最大元素和当å‰�堆中数组的最å�Žä¸€ä¸ªå…ƒç´ äº¤æ�¢ä½�置,并且ä¸�删除它,那么就å�¯ä»¥å¾—到一个从尾到头的递å‡�åº�列,从正å�‘æ�¥çœ‹å°±æ˜¯ä¸€ä¸ªé€’增åº�列。因此很容易使用堆æ�¥è¿›è¡ŒæŽ’åº�,并且堆排åº�是原地排åº�,ä¸�å� ç”¨é¢�外空间。 -¶ÑÅÅÐòÒª·ÖÁ½¸ö½×¶Î£¬µÚÒ»¸ö½×¶ÎÊǰÑÎÞÐòÊý×齨Á¢Ò»¸ö¶Ñ£»µÚ¶þ¸ö½×¶ÎÊǽ»»»×î´óÔªËØºÍµ±Ç°¶ÑµÄÊý×é×îºóÒ»¸öÔªËØ£¬²¢ÇÒ½øÐÐϳÁ²Ù×÷ά³Ö¶ÑµÄÓÐÐò״̬¡£ +堆排åº�è¦�分两个阶段,第一个阶段是把无åº�数组建立一个堆;第二个阶段是交æ�¢æœ€å¤§å…ƒç´ å’Œå½“å‰�堆的数组最å�Žä¸€ä¸ªå…ƒç´ ï¼Œå¹¶ä¸”进行下沉æ“�作维æŒ�堆的有åº�状æ€�。 -ÎÞÐòÊý×齨Á¢¶Ñ×îÖ±½ÓµÄ·½·¨ÊÇ´Ó×óµ½ÓÒ±éÀúÊý×飬Ȼºó½øÐÐÉϸ¡²Ù×÷¡£Ò»¸ö¸ü¸ßЧµÄ·½·¨ÊÇ´ÓÓÒÖÁ×ó½øÐÐϳÁ²Ù×÷£¬Èç¹ûÒ»¸ö½ÚµãµÄÁ½¸ö½Úµã¶¼ÒѾ­ÊǶÑÓÐÐò£¬ÄÇô½øÐÐϳÁ²Ù×÷¿ÉÒÔʹµÃÕâ¸ö½ÚµãΪ¸ù½ÚµãµÄ¶ÑÓÐÐò¡£Ò¶×ӽڵ㲻ÐèÒª½øÐÐϳÁ²Ù×÷£¬Òò´Ë¿ÉÒÔºöÂÔÒ¶×Ó½ÚµãµÄÔªËØ£¬Òò´ËÖ»ÐèÒª±éÀúÒ»°ëµÄÔªËØ¼´¿É¡£ +æ— åº�数组建立堆最直接的方法是从左到å�³é��历数组,然å�Žè¿›è¡Œä¸Šæµ®æ“�作。一个更高效的方法是从å�³è‡³å·¦è¿›è¡Œä¸‹æ²‰æ“�作,如果一个节点的两个节点都已ç»�是堆有åº�,那么进行下沉æ“�作å�¯ä»¥ä½¿å¾—这个节点为根节点的堆有åº�。å�¶å­�节点ä¸�需è¦�进行下沉æ“�作,因此å�¯ä»¥å¿½ç•¥å�¶å­�节点的元素,因此å�ªéœ€è¦�é��历一å�Šçš„元素å�³å�¯ã€‚ -![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/a2670745-a7b1-497b-90a4-dbddc4e2006d.jpg) +![](https://github.com/CyC2018/InterviewNotes/blob/master/pics//a2670745-a7b1-497b-90a4-dbddc4e2006d.jpg) ```java public static void sort(Comparable[] a){ @@ -875,33 +876,33 @@ public static void sort(Comparable[] a){ } ``` -### 6. ·ÖÎö +### 6. 分æž� -Ò»¸ö¶ÑµÄ¸ß¶ÈΪ lgN£¬Òò´ËÔÚ¶ÑÖвåÈëÔªËØºÍɾ³ý×î´óÔªËØµÄ¸´ÔӶȶ¼Îª lgN¡£ +一个堆的高度为 lgN,因此在堆中æ�’入元素和删除最大元素的å¤�æ�‚度都为 lgN。 -¶ÔÓÚ¶ÑÅÅÐò£¬ÓÉÓÚÒª¶Ô N ¸ö½Úµã½øÐÐϳÁ²Ù×÷£¬Òò´Ë¸´ÔÓ¶ÈΪ NlgN¡£ +对于堆排åº�,由于è¦�对 N 个节点进行下沉æ“�作,因此å¤�æ�‚度为 NlgN。 -¶ÑÅÅÐòʱһÖÖÔ­µØÅÅÐò£¬Ã»ÓÐÀûÓöîÍâµÄ¿Õ¼ä¡£ +堆排åº�时一ç§�原地排åº�,没有利用é¢�外的空间。 -ÏÖ´ú²Ù×÷ϵͳºÜÉÙʹÓöÑÅÅÐò£¬ÒòΪËüÎÞ·¨ÀûÓûº´æ£¬Ò²¾ÍÊÇÊý×éÔªËØºÜÉÙºÍÏàÁÚµÄÔªËØ½øÐбȽϡ£ +现代æ“�作系统很少使用堆排åº�,因为它无法利用缓存,也就是数组元素很少和相邻的元素进行比较。 -## Ó¦Óà +## 应用 -### 1. ÅÅÐòËã·¨µÄ±È½Ï +### 1. 排åº�算法的比较 -![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/be53c00b-2534-4dc6-ad03-c55995c47db9.jpg) +![](https://github.com/CyC2018/InterviewNotes/blob/master/pics//be53c00b-2534-4dc6-ad03-c55995c47db9.jpg) -¿ìËÙÅÅÐòʱ×î¿ìµÄͨÓÃÅÅÐòËã·¨£¬ËüµÄÄÚÑ­»·µÄÖ¸ÁîºÜÉÙ£¬¶øÇÒËü»¹ÄÜÀûÓûº´æ£¬ÒòΪËü×ÜÊÇ˳ÐòµØ·ÃÎÊÊý¾Ý¡£ËüµÄÔËÐÐʱ¼äÔö³¤ÊýÁ¿¼¶Îª \~cNlgN£¬ÕâÀïµÄ c ±ÈÆäËûÏßÐÔ¶ÔÊý¼¶±ðµÄÅÅÐòËã·¨¶¼ÒªÐ¡¡£Ê¹ÓÃÈýÏòÇзÖÖ®ºó£¬Êµ¼ÊÓ¦ÓÃÖпÉÄܳöÏÖµÄijЩ·Ö²¼µÄÊäÈëÄܹ»´ïµ½ÏßÐÔ¼¶±ð£¬¶øÆäËüÅÅÐòËã·¨ÈÔÈ»ÐèÒªÏßÐÔ¶ÔÊýʱ¼ä¡£ +快速排åº�时最快的通用排åº�算法,它的内循环的指令很少,而且它还能利用缓存,因为它总是顺åº�地访问数æ�®ã€‚它的è¿�行时间增长数é‡�级为 \~cNlgN,这里的 c 比其他线性对数级别的排åº�算法都è¦�å°�。使用三å�‘切分之å�Žï¼Œå®žé™…应用中å�¯èƒ½å‡ºçŽ°çš„æŸ�些分布的输入能够达到线性级别,而其它排åº�算法ä»�然需è¦�线性对数时间。 -### 2. Java µÄÅÅÐòË㷨ʵÏÖ +### 2. Java 的排åº�算法实现 -Java ϵͳ¿âÖеÄÖ÷ÒªÅÅÐò·½·¨Îª java.util.Arrays.sort()£¬¶ÔÓÚԭʼÊý¾ÝÀàÐÍʹÓÃÈýÏòÇзֵĿìËÙÅÅÐò£¬¶ÔÓÚÒýÓÃÀàÐÍʹÓù鲢ÅÅÐò¡£ +Java 系统库中的主è¦�排åº�方法为 java.util.Arrays.sort(),对于原始数æ�®ç±»åž‹ä½¿ç”¨ä¸‰å�‘切分的快速排åº�,对于引用类型使用归并排åº�。 -### 3. »ùÓÚÇзֵĿìËÙÑ¡ÔñËã·¨ +### 3. 基于切分的快速选择算法 -¿ìËÙÅÅÐòµÄ partition() ·½·¨£¬»á½«Êý×éµÄ a[lo] ÖÁ a[hi] ÖØÐÂÅÅÐò²¢·µ»ØÒ»¸öÕûÊý j ʹµÃ a[lo..j-1] СÓÚµÈÓÚ a[j]£¬ÇÒ a[j+1..hi] ´óÓÚµÈÓÚ a[j]¡£ÄÇôÈç¹û j=k£¬a[j] ¾ÍÊÇµÚ k ¸öÊý¡£ +快速排åº�çš„ partition() 方法,会将数组的 a[lo] 至 a[hi] é‡�新排åº�并返回一个整数 j 使得 a[lo..j-1] å°�于等于 a[j],且 a[j+1..hi] 大于等于 a[j]。那么如果 j=k,a[j] 就是第 k 个数。 -¸ÃËã·¨ÊÇÏßÐÔ¼¶±ðµÄ£¬ÒòΪÿ´ÎÕýºÃ½«Êý×é¶þ·Ö£¬ÄÇô±È½ÏµÄ×Ü´ÎÊýΪ (N+N/2+N/4+..)£¬Ö±µ½ÕÒµ½µÚ k ¸öÔªËØ£¬Õâ¸öºÍÏÔȻСÓÚ 2N¡£ +该算法是线性级别的,因为æ¯�次正好将数组二分,那么比较的总次数为 (N+N/2+N/4+..),直到找到第 k 个元素,这个和显然å°�于 2N。 ```java public static Comparable select(Comparable[] a, int k) { @@ -916,33 +917,33 @@ public static Comparable select(Comparable[] a, int k) { } ``` -# µÚÈýÕ ²éÕÒ +# 第三章 查找 -±¾ÕÂʹÓÃÈýÖÖ¾­µäµÄÊý¾ÝÀàÐÍÀ´ÊµÏÖ¸ßЧµÄ·ûºÅ±í£º¶þ²æ²éÕÒÊ÷¡¢ºìºÚÊ÷ºÍÉ¢ÁÐ±í¡£ +本章使用三ç§�ç»�典的数æ�®ç±»åž‹æ�¥å®žçŽ°é«˜æ•ˆçš„ç¬¦å�·è¡¨ï¼šäºŒå�‰æŸ¥æ‰¾æ ‘ã€�红黑树和散列表。 -## ·ûºÅ±í +## 符å�·è¡¨ -### 1. ÎÞÐò·ûºÅ±í +### 1. æ— åº�符å�·è¡¨ -![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/b69d7184-ab62-4957-ba29-fb4fa25f9b65.jpg) +![](https://github.com/CyC2018/InterviewNotes/blob/master/pics//b69d7184-ab62-4957-ba29-fb4fa25f9b65.jpg) -### 2. ÓÐÐò·ûºÅ±í +### 2. 有åº�符å�·è¡¨ -![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/ba6ae411-82da-4d86-a434-6776d1731e8e.jpg) +![](https://github.com/CyC2018/InterviewNotes/blob/master/pics//ba6ae411-82da-4d86-a434-6776d1731e8e.jpg) -ÓÐÐò·ûºÅ±íµÄ¼üÐèҪʵÏÖ Comparable ½Ó¿Ú¡£ +有åº�符å�·è¡¨çš„键需è¦�实现 Comparable 接å�£ã€‚ -²éÕҵijɱ¾Ä£ÐÍ£º¼üµÄ±È½Ï´ÎÊý£¬ÔÚ²»½øÐбȽÏʱʹÓÃÊý×éµÄ·ÃÎÊ´ÎÊý¡£ +查找的æˆ�本模型:键的比较次数,在ä¸�进行比较时使用数组的访问次数。 -### 3. ¶þ·Ö²éÕÒʵÏÖÓÐÐò·ûºÅ±í +### 3. 二分查找实现有åº�符å�·è¡¨ -ʹÓÃÒ»¶ÔƽÐÐÊý×飬һ¸ö´æ´¢¼üÒ»¸ö´æ´¢Öµ¡£ +使用一对平行数组,一个存储键一个存储值。 -ÐèÒª´´½¨Ò»¸ö Key ÀàÐ굀 Comparable ¶ÔÏóÊý×éºÍÒ»¸ö Value ÀàÐ굀 Object ¶ÔÏóÊý×é¡£ +需è¦�创建一个 Key 类型的 Comparable 对象数组和一个 Value 类型的 Object 对象数组。 -rank() ·½·¨ÖÁ¹ØÖØÒª£¬µ±¼üÔÚ±íÖÐʱ£¬ËüÄܹ»ÖªµÀ¸Ã¼üµÄλÖ㻵±¼ü²»ÔÚ±íÖÐʱ£¬ËüÒ²ÄÜÖªµÀÔں䦲åÈëмü¡£ +rank() 方法至关é‡�è¦�,当键在表中时,它能够知é�“该键的ä½�置;当键ä¸�在表中时,它也能知é�“在何处æ�’入新键。 -¸´ÔÓ¶È£º¶þ·Ö²éÕÒ×î¶àÐèÒª lgN+1 ´Î±È½Ï£¬Ê¹Óöþ·Ö²éÕÒʵÏֵķûºÅ±íµÄ²éÕÒ²Ù×÷ËùÐèÒªµÄʱ¼ä×î¶àÊǶÔÊý¼¶±ðµÄ¡£µ«ÊDzåÈë²Ù×÷ÐèÒªÒÆ¶¯Êý×éÔªËØ£¬ÊÇÏßÐÔ¼¶±ðµÄ¡£ +å¤�æ�‚度:二分查找最多需è¦� lgN+1 次比较,使用二分查找实现的符å�·è¡¨çš„æŸ¥æ‰¾æ“�作所需è¦�的时间最多是对数级别的。但是æ�’å…¥æ“�作需è¦�移动数组元素,是线性级别的。 ```java public class BinarySearchST, Value> { @@ -1001,15 +1002,15 @@ public class BinarySearchST, Value> { } ``` -## ¶þ²æ²éÕÒÊ÷ +## 二å�‰æŸ¥æ‰¾æ ‘ -**¶þ²æÊ÷** ¶¨ÒåΪһ¸ö¿ÕÁ´½Ó£¬»òÕßÊÇÒ»¸öÓÐ×óÓÒÁ½¸öÁ´½ÓµÄ½Úµã£¬Ã¿¸öÁ´½Ó¶¼Ö¸ÏòÒ»¿Å×Ó¶þ²æÊ÷¡£ +**二å�‰æ ‘** 定义为一个空链接,或者是一个有左å�³ä¸¤ä¸ªé“¾æŽ¥çš„节点,æ¯�个链接都指å�‘一颗å­�二å�‰æ ‘。 -**¶þ²æ²éÕÒÊ÷**£¨BST£©ÊÇÒ»¿Å¶þ²æÊ÷£¬²¢ÇÒÿ¸ö½ÚµãµÄ¼ü¶¼´óÓÚÆä×ó×ÓÊ÷ÖеÄÈÎÒâ½ÚµãµÄ¼ü¶øÐ¡ÓÚÓÒ×ÓÊ÷µÄÈÎÒâ½ÚµãµÄ¼ü¡£ +**二å�‰æŸ¥æ‰¾æ ‘**(BST)是一颗二å�‰æ ‘,并且æ¯�个节点的键都大于其左å­�树中的任æ„�节点的键而å°�于å�³å­�树的任æ„�节点的键。 -![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/25226bb2-92cc-40cb-9e7f-c44e79fbb64a.jpg) +![](https://github.com/CyC2018/InterviewNotes/blob/master/pics//25226bb2-92cc-40cb-9e7f-c44e79fbb64a.jpg) -¶þ²æ²éÕÒÊ÷µÄ²éÕÒ²Ù×÷ÿ´Îµü´ú¶¼»áÈÃÇø¼ä¼õÉÙÒ»°ë£¬ºÍ¶þ·Ö²éÕÒÀàËÆ¡£ +二å�‰æŸ¥æ‰¾æ ‘的查找æ“�作æ¯�次迭代都会让区间å‡�少一å�Šï¼Œå’ŒäºŒåˆ†æŸ¥æ‰¾ç±»ä¼¼ã€‚ ```java public class BST, Value> { @@ -1019,7 +1020,7 @@ public class BST, Value> { private Key key; private Value val; private Node left, right; - // ÒԸýڵãΪ¸ùµÄ×ÓÊ÷Öнڵã×ÜÊý + // 以该节点为根的å­�树中节点总数 private int N; public Node(Key key, Value val, int N) { @@ -1042,7 +1043,7 @@ public class BST, Value> { ### 1. get() -Èç¹ûÊ÷Êǿյģ¬Ôò²éÕÒδÃüÖУ»Èç¹û±»²éÕҵļüºÍ¸ù½ÚµãµÄ¼üÏàµÈ£¬²éÕÒÃüÖУ¬·ñÔòµÝ¹éµØÔÚ×ÓÊ÷ÖвéÕÒ£ºÈç¹û±»²éÕҵļü½ÏС¾ÍÔÚ×ó×ÓÊ÷ÖвéÕÒ£¬½Ï´ó¾ÍÔÚÓÒ×ÓÊ÷ÖвéÕÒ¡£ +如果树是空的,则查找未命中;如果被查找的键和根节点的键相等,查找命中,å�¦åˆ™é€’归地在å­�树中查找:如果被查找的键较å°�就在左å­�树中查找,较大就在å�³å­�树中查找。 ```java public Value get(Key key) { @@ -1059,7 +1060,7 @@ private Value get(Node x, Key key) { ### 2. put() -µ±²åÈëµÄ¼ü²»´æÔÚÓÚÊ÷ÖУ¬ÐèÒª´´½¨Ò»¸öнڵ㣬²¢ÇÒ¸üÐÂÉϲã½ÚµãµÄÁ´½ÓʹµÃ¸Ã½ÚµãÕýÈ·Á´½Óµ½Ê÷ÖС£ +当æ�’入的键ä¸�存在于树中,需è¦�创建一个新节点,并且更新上层节点的链接使得该节点正确链接到树中。 ```java public void put(Key key, Value val) { @@ -1076,17 +1077,17 @@ private Node put(Node x, Key key, Value val) { } ``` -### 3. ·ÖÎö +### 3. 分æž� -¶þ²æ²éÕÒÊ÷µÄËã·¨ÔËÐÐʱ¼äÈ¡¾öÓÚÊ÷µÄÐÎ×´£¬¶øÊ÷µÄÐÎ×´ÓÖÈ¡¾öÓÚ¼ü±»²åÈëµÄÏȺó˳Ðò¡£×îºÃµÄÇé¿öÏÂÊ÷ÊÇÍêȫƽºâµÄ£¬Ã¿Ìõ¿ÕÁ´½ÓºÍ¸ù½ÚµãµÄ¾àÀ붼Ϊ lgN¡£ÔÚ×µÄÇé¿öÏ£¬Ê÷µÄ¸ß¶ÈΪ N¡£ +二å�‰æŸ¥æ‰¾æ ‘的算法è¿�行时间å�–决于树的形状,而树的形状å�ˆå�–决于键被æ�’入的先å�Žé¡ºåº�。最好的情况下树是完全平衡的,æ¯�æ�¡ç©ºé“¾æŽ¥å’Œæ ¹èŠ‚ç‚¹çš„è·�离都为 lgN。在最å��的情况下,树的高度为 N。 -![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/73a3983d-dd18-4373-897e-64b706a7e370.jpg) +![](https://github.com/CyC2018/InterviewNotes/blob/master/pics//73a3983d-dd18-4373-897e-64b706a7e370.jpg) -¸´ÔÓ¶È£º²éÕҺͲåÈë²Ù×÷¶¼Îª¶ÔÊý¼¶±ð¡£ +å¤�æ�‚度:查找和æ�’å…¥æ“�作都为对数级别。 ### 4. floor() -Èç¹û key СÓÚ¸ù½ÚµãµÄ key£¬ÄÇôСÓÚµÈÓÚ key µÄ×î´ó¼ü½ÚµãÒ»¶¨ÔÚ×ó×ÓÊ÷ÖУ»Èç¹û key ´óÓÚ¸ù½ÚµãµÄ key£¬Ö»Óе±¸ù½ÚµãÓÒ×ÓÊ÷ÖдæÔÚСÓÚµÈÓÚ key µÄ½Úµã£¬Ð¡ÓÚµÈÓÚ key µÄ×î´ó¼ü½Úµã²ÅÔÚÓÒ×ÓÊ÷ÖУ¬·ñÔò¸ù½Úµã¾ÍÊÇСÓÚµÈÓÚ key µÄ×î´ó¼ü½Úµã¡£ +如果 key å°�于根节点的 key,那么å°�于等于 key 的最大键节点一定在左å­�树中;如果 key 大于根节点的 key,å�ªæœ‰å½“根节点å�³å­�树中存在å°�于等于 key 的节点,å°�于等于 key 的最大键节点æ‰�在å�³å­�树中,å�¦åˆ™æ ¹èŠ‚ç‚¹å°±æ˜¯å°�于等于 key 的最大键节点。 ```java public Key floor(Key key) { @@ -1134,9 +1135,9 @@ private Node min(Node x) { ### 7. deleteMin() -ÁîÖ¸Ïò×îС½ÚµãµÄÁ´½ÓÖ¸Ïò×îС½ÚµãµÄÓÒ×ÓÊ÷¡£ +令指å�‘最å°�节点的链接指å�‘最å°�节点的å�³å­�树。 -![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/6e2cb20a-8d2a-46fe-9ac7-68a2126b7bd5.jpg) +![](https://github.com/CyC2018/InterviewNotes/blob/master/pics//6e2cb20a-8d2a-46fe-9ac7-68a2126b7bd5.jpg) ```java public void deleteMin() { @@ -1152,9 +1153,9 @@ public Node deleteMin(Node x) { ### 8. delete() -Èç¹û´ýɾ³ýµÄ½ÚµãÖ»ÓÐÒ»¸ö×ÓÊ÷£¬ÄÇôֻÐèÒªÈÃÖ¸Ïò´ýɾ³ý½ÚµãµÄÁ´½ÓÖ¸ÏòΨһµÄ×ÓÊ÷¼´¿É£»·ñÔò£¬ÈÃÓÒ×ÓÊ÷µÄ×îС½ÚµãÌæ»»¸Ã½Úµã¡£ +如果待删除的节点å�ªæœ‰ä¸€ä¸ªå­�树,那么å�ªéœ€è¦�让指å�‘待删除节点的链接指å�‘唯一的å­�æ ‘å�³å�¯ï¼›å�¦åˆ™ï¼Œè®©å�³å­�树的最å°�节点替æ�¢è¯¥èŠ‚ç‚¹ã€‚ -![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/b488282d-bfe0-464f-9e91-1f5b83a975bd.jpg) +![](https://github.com/CyC2018/InterviewNotes/blob/master/pics//b488282d-bfe0-464f-9e91-1f5b83a975bd.jpg) ```java public void delete(Key key) { @@ -1180,7 +1181,7 @@ private Node delete(Node x, Key key) { ### 9. keys() -ÀûÓöþ²æ²éÕÒÊ÷ÖÐÐò±éÀúµÄ½á¹ûΪÓÐÐòÐòÁеÄÌØµã¡£ +利用二å�‰æŸ¥æ‰¾æ ‘中åº�é��历的结果为有åº�åº�列的特点。 ```java public Iterable keys(Key lo, Key hi) { @@ -1198,44 +1199,44 @@ private void keys(Node x, Queue queue, Key lo, Key hi) { } ``` -### 10. ÐÔÄÜ·ÖÎö +### 10. 性能分æž� -¸´ÔÓ¶È£º¶þ²æ²éÕÒÊ÷ËùÓвÙ×÷ÔÚ×µÄÇé¿öÏÂËùÐèÒªµÄʱ¼ä¶¼ºÍÊ÷µÄ¸ß¶È³ÉÕý±È¡£ +å¤�æ�‚度:二å�‰æŸ¥æ‰¾æ ‘所有æ“�作在最å��的情况下所需è¦�的时间都和树的高度æˆ�正比。 -## ƽºâ²éÕÒÊ÷ +## 平衡查找树 -### 2-3 ²éÕÒÊ÷ +### 2-3 查找树 -![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/2548f2ec-7b00-4ec7-b286-20fc3022e084.jpg) +![](https://github.com/CyC2018/InterviewNotes/blob/master/pics//2548f2ec-7b00-4ec7-b286-20fc3022e084.jpg) -Ò»¿ÅÍêÃÀƽºâµÄ 2-3 ²éÕÒÊ÷µÄËùÓпÕÁ´½Óµ½¸ù½ÚµãµÄ¾àÀëÓ¦¸ÃÊÇÏàͬµÄ¡£ +一颗完美平衡的 2-3 查找树的所有空链接到根节点的è·�离应该是相å�Œçš„。 -#### 1. ²åÈë²Ù×÷ +#### 1. æ�’å…¥æ“�作 -µ±²åÈëÖ®ºó²úÉúÒ»¸öÁÙʱ 4- ½Úµãʱ£¬ÐèÒª½« 4- ½Úµã·ÖÁÑ³É 3 ¸ö 2- ½Úµã£¬²¢½«ÖмäµÄ 2- ½ÚµãÒÆµ½Éϲã½ÚµãÖС£Èç¹ûÉÏÒÆ²Ù×÷¼ÌÐø²úÉúÁÙʱ 4- ½ÚµãÔòÒ»Ö±½øÐзÖÁÑÉÏÒÆ£¬Ö±µ½²»´æÔÚÁÙʱ 4- ½Úµã¡£ +当æ�’入之å�Žäº§ç”Ÿä¸€ä¸ªä¸´æ—¶ 4- 节点时,需è¦�å°† 4- 节点分裂æˆ� 3 个 2- 节点,并将中间的 2- 节点移到上层节点中。如果上移æ“�作继续产生临时 4- 节点则一直进行分裂上移,直到ä¸�存在临时 4- 节点。 -![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/912174d8-0786-4222-b7ef-a611d36e5db9.jpg) +![](https://github.com/CyC2018/InterviewNotes/blob/master/pics//912174d8-0786-4222-b7ef-a611d36e5db9.jpg) -#### 2. ÐÔÖÊ +#### 2. 性质 -2-3 ²éÕÒÊ÷²åÈë²Ù×÷µÄ±ä»»¶¼ÊǾֲ¿µÄ£¬³ýÁËÏà¹ØµÄ½ÚµãºÍÁ´½ÓÖ®Íâ²»±ØÐ޸ĻòÕß¼ì²éÊ÷µÄÆäËü²¿·Ö£¬¶øÕâЩ¾Ö²¿±ä»»²»»áÓ°ÏìÊ÷µÄÈ«¾ÖÓÐÐòÐÔºÍÆ½ºâÐÔ¡£ +2-3 查找树æ�’å…¥æ“�作的å�˜æ�¢éƒ½æ˜¯å±€éƒ¨çš„,除了相关的节点和链接之外ä¸�必修改或者检查树的其它部分,而这些局部å�˜æ�¢ä¸�会影å“�树的全局有åº�性和平衡性。 -2-3 ²éÕÒÊ÷µÄ²éÕҺͲåÈë²Ù×÷¸´ÔӶȺͲåÈë˳Ðò **ÎÞ¹Ø**£¬ÔÚ×µÄÇé¿öϲéÕҺͲåÈë²Ù×÷·ÃÎÊµÄ½Úµã±ØÈ»²»³¬¹ý logN ¸ö£¬º¬ÓÐ 10 ÒÚ¸ö½ÚµãµÄ 2-3 ²éÕÒÊ÷×î¶àÖ»ÐèÒª·ÃÎÊ 30 ¸ö½Úµã¾ÍÄܽøÐÐÈÎÒâµÄ²éÕҺͲåÈë²Ù×÷¡£ +2-3 查找树的查找和æ�’å…¥æ“�作å¤�æ�‚度和æ�’入顺åº� **æ— å…³**,在最å��的情况下查找和æ�’å…¥æ“�作访问的节点必然ä¸�超过 logN 个,å�«æœ‰ 10 亿个节点的 2-3 查找树最多å�ªéœ€è¦�访问 30 个节点就能进行任æ„�的查找和æ�’å…¥æ“�作。 -### ºìºÚ¶þ²æ²éÕÒÊ÷ +### 红黑二å�‰æŸ¥æ‰¾æ ‘ -2-3 ²éÕÒÊ÷ÐèÒªÓõ½ 2- ½ÚµãºÍ 3- ½Úµã£¬ºìºÚÊ÷ʹÓúìÁ´½ÓÀ´ÊµÏÖ 3- ½Úµã¡£Ö¸ÏòÒ»¸ö½ÚµãµÄÁ´½ÓÑÕÉ«Èç¹ûΪºìÉ«£¬ÄÇôÕâ¸ö½ÚµãºÍÉϲã½Úµã±íʾµÄÊÇÒ»¸ö 3- ½Úµã£¬¶øºÚÉ«ÔòÊÇÆÕͨÁ´½Ó¡£ +2-3 查找树需è¦�用到 2- 节点和 3- 节点,红黑树使用红链接æ�¥å®žçް 3- 节点。指å�‘一个节点的链接颜色如果为红色,那么这个节点和上层节点表示的是一个 3- 节点,而黑色则是普通链接。 -![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/7080a928-06ba-4e10-9792-b8dd190dc8e2.jpg) +![](https://github.com/CyC2018/InterviewNotes/blob/master/pics//7080a928-06ba-4e10-9792-b8dd190dc8e2.jpg) -ºìºÚÊ÷¾ßÓÐÒÔÏÂÐÔÖÊ£º +红黑树具有以下性质: -1. ºìÁ´½Ó¶¼Îª×óÁ´½Ó£» -2. ÍêÃÀºÚɫƽºâ£¬¼´ÈÎÒâ¿ÕÁ´½Óµ½¸ù½ÚµãµÄ·¾¶ÉϵĺÚÁ´½ÓÊýÁ¿Ïàͬ¡£ +1. 红链接都为左链接; +2. 完美黑色平衡,å�³ä»»æ„�空链接到根节点的路径上的黑链接数é‡�相å�Œã€‚ -»­ºìºÚÊ÷ʱ¿ÉÒÔ½«ºìÁ´½Ó»­Æ½¡£ +画红黑树时å�¯ä»¥å°†çº¢é“¾æŽ¥ç”»å¹³ã€‚ -![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/62077f5d-a06d-4129-9b43-78715b82cb03.png) +![](https://github.com/CyC2018/InterviewNotes/blob/master/pics//62077f5d-a06d-4129-9b43-78715b82cb03.png) ```java public class RedBlackBST, Value> { @@ -1265,13 +1266,13 @@ public class RedBlackBST, Value> { } ``` -#### 1. ×óÐýת +#### 1. 左旋转 -ÒòΪºÏ·¨µÄºìÁ´½Ó¶¼Îª×óÁ´½Ó£¬Èç¹û³öÏÖÓÒÁ´½ÓΪºìÁ´½Ó£¬ÄÇô¾ÍÐèÒª½øÐÐ×óÐýת²Ù×÷¡£ +因为å�ˆæ³•的红链接都为左链接,如果出现å�³é“¾æŽ¥ä¸ºçº¢é“¾æŽ¥ï¼Œé‚£ä¹ˆå°±éœ€è¦�进行左旋转æ“�作。 -![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/33a4e822-2dd0-481e-ac89-7f6161034402.jpg) +![](https://github.com/CyC2018/InterviewNotes/blob/master/pics//33a4e822-2dd0-481e-ac89-7f6161034402.jpg) -![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/5e0cef33-4087-4f21-a428-16d5fddda671.jpg) +![](https://github.com/CyC2018/InterviewNotes/blob/master/pics//5e0cef33-4087-4f21-a428-16d5fddda671.jpg) ```java public Node rotateLeft(Node h) { @@ -1286,13 +1287,13 @@ public Node rotateLeft(Node h) { } ``` -#### 2. ÓÒÐýת +#### 2. å�³æ—‹è½¬ -½øÐÐÓÒÐýתÊÇΪÁËת»»Á½¸öÁ¬ÐøµÄ×óºìÁ´½Ó£¬Õâ»áÔÚÖ®ºóµÄ²åÈë¹ý³ÌÖÐ̽ÌÖ¡£ +进行å�³æ—‹è½¬æ˜¯ä¸ºäº†è½¬æ�¢ä¸¤ä¸ªè¿žç»­çš„左红链接,这会在之å�Žçš„æ�’入过程中探讨。 -![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/dfd078b2-aa4f-4c50-8319-232922d822b8.jpg) +![](https://github.com/CyC2018/InterviewNotes/blob/master/pics//dfd078b2-aa4f-4c50-8319-232922d822b8.jpg) -![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/3f8d8c9d-a9a9-4d7a-813c-2de05ee5a97e.jpg) +![](https://github.com/CyC2018/InterviewNotes/blob/master/pics//3f8d8c9d-a9a9-4d7a-813c-2de05ee5a97e.jpg) ```java public Node rotateRight(Node h) { @@ -1306,13 +1307,13 @@ public Node rotateRight(Node h) { } ``` -#### 3. ÑÕɫת»» +#### 3. 颜色转æ�¢ -Ò»¸ö 4- ½ÚµãÔÚºìºÚÊ÷ÖбíÏÖΪһ¸ö½ÚµãµÄ×óÓÒ×ӽڵ㶼ÊǺìÉ«µÄ¡£·ÖÁÑ 4- ½Úµã³ýÁËÐèÒª½«×Ó½ÚµãµÄÑÕÉ«Óɺì±äºÚÖ®Í⣬ͬʱÐèÒª½«¸¸½ÚµãµÄÑÕÉ«Óɺڱäºì£¬´Ó 2-3 Ê÷µÄ½Ç¶È¿´¾ÍÊǽ«Öмä½ÚµãÒÆµ½Éϲã½Úµã¡£ +一个 4- 节点在红黑树中表现为一个节点的左å�³å­�节点都是红色的。分裂 4- 节点除了需è¦�å°†å­�节点的颜色由红å�˜é»‘之外,å�Œæ—¶éœ€è¦�将父节点的颜色由黑å�˜çº¢ï¼Œä»Ž 2-3 树的角度看就是将中间节点移到上层节点。 -![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/de7c5a31-55f5-4e9d-92ec-4ed5b2ec3828.jpg) +![](https://github.com/CyC2018/InterviewNotes/blob/master/pics//de7c5a31-55f5-4e9d-92ec-4ed5b2ec3828.jpg) -![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/e5ad625e-729d-4a8d-923a-7c3df5773e1c.jpg) +![](https://github.com/CyC2018/InterviewNotes/blob/master/pics//e5ad625e-729d-4a8d-923a-7c3df5773e1c.jpg) ```java void flipColors(Node h){ @@ -1322,15 +1323,15 @@ void flipColors(Node h){ } ``` -#### 4. ²åÈë +#### 4. æ�’å…¥ -ÏȽ«Ò»¸ö½Úµã°´¶þ²æ²éÕÒÊ÷µÄ·½·¨²åÈëµ½ÕýȷλÖã¬È»ºóÔÙ½øÐÐÈçÏÂÑÕÉ«²Ù×÷£º +先将一个节点按二å�‰æŸ¥æ‰¾æ ‘的方法æ�’入到正确ä½�置,然å�Žå†�进行如下颜色æ“�作: -- Èç¹ûÓÒ×Ó½ÚµãÊǺìÉ«µÄ¶ø×ó×Ó½ÚµãÊǺÚÉ«µÄ£¬½øÐÐ×óÐýת£» -- Èç¹û×ó×Ó½ÚµãÊǺìÉ«µÄÇÒËüµÄ×ó×Ó½ÚµãÒ²ÊǺìÉ«µÄ£¬½øÐÐÓÒÐýת£» -- Èç¹û×óÓÒ×Ó½Úµã¾ùΪºìÉ«µÄ£¬½øÐÐÑÕɫת»»¡£ +- 如果å�³å­�节点是红色的而左å­�节点是黑色的,进行左旋转; +- 如果左å­�节点是红色的且它的左å­�节点也是红色的,进行å�³æ—‹è½¬ï¼› +- 如果左å�³å­�节点å�‡ä¸ºçº¢è‰²çš„,进行颜色转æ�¢ã€‚ -![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/40639782-5df2-4e96-a4f3-f9dd664d0ca1.jpg) +![](https://github.com/CyC2018/InterviewNotes/blob/master/pics//40639782-5df2-4e96-a4f3-f9dd664d0ca1.jpg) ```java public void put(Key key, Value val) { @@ -1354,55 +1355,55 @@ private Node put(Node x, Key key, Value val) { } ``` -¿ÉÒÔ¿´µ½¸Ã²åÈë²Ù×÷ºÍ BST µÄ²åÈë²Ù×÷ÀàËÆ£¬Ö»ÊÇÔÚ×îºó¼ÓÈëÁËÐýתºÍÑÕÉ«±ä»»²Ù×÷¼´¿É¡£ +å�¯ä»¥çœ‹åˆ°è¯¥æ�’å…¥æ“�作和 BST çš„æ�’å…¥æ“�作类似,å�ªæ˜¯åœ¨æœ€å�ŽåŠ å…¥äº†æ—‹è½¬å’Œé¢œè‰²å�˜æ�¢æ“�作å�³å�¯ã€‚ -¸ù½ÚµãÒ»¶¨ÎªºÚÉ«£¬ÒòΪ¸ù½ÚµãûÓÐÉϲã½Úµã£¬Ò²¾ÍûÓÐÉϲã½ÚµãµÄ×óÁ´½ÓÖ¸Ïò¸ù½Úµã¡£flipColors() ÓпÉÄÜ»áʹµÃ¸ù½ÚµãµÄÑÕÉ«±äΪºìÉ«£¬Ã¿µ±¸ù½ÚµãÓɺìÉ«±ä³ÉºÚɫʱÊ÷µÄºÚÁ´½Ó¸ß¶È¼Ó 1. +根节点一定为黑色,因为根节点没有上层节点,也就没有上层节点的左链接指å�‘根节点。flipColors() 有å�¯èƒ½ä¼šä½¿å¾—根节点的颜色å�˜ä¸ºçº¢è‰²ï¼Œæ¯�当根节点由红色å�˜æˆ�黑色时树的黑链接高度加 1. -#### 5. ɾ³ý×îС¼ü +#### 5. 删除最å°�é”® -Èç¹û×îС¼üÔÚÒ»¸ö 2- ½ÚµãÖУ¬ÄÇôɾ³ý¸Ã¼ü»áÁôÏÂÒ»¸ö¿ÕÁ´½Ó£¬¾ÍÆÆ»µÁËÆ½ºâÐÔ£¬Òò´ËҪȷ±£×îС¼ü²»ÔÚ 2- ½ÚµãÖС£½« 2- ½Úµãת»»³É 3- ½Úµã»òÕß 4- ½ÚµãÓÐÁ½ÖÖ·½·¨£¬Ò»ÖÖÊÇÏòÉϲã½ÚµãÄÃÒ»¸ö key£¬Ò»ÖÖÊÇÏòÐֵܽڵãÄÃÒ»¸ö key¡£Èç¹ûÉϲã½ÚµãÊÇ 2- ½Úµã£¬ÄÇô¾Íû°ì·¨´ÓÉϲã½ÚµãÄà key ÁË£¬Òò´ËÒª±£Ö¤É¾³ý·¾¶ÉϵÄËùÓнڵ㶼²»ÊÇ 2- ½Úµã¡£ÔÚÏòÏÂɾ³ýµÄ¹ý³ÌÖУ¬±£Ö¤ÒÔÏÂÇé¿öÖ®Ò»·¢Éú£º +如果最å°�键在一个 2- 节点中,那么删除该键会留下一个空链接,就破å��了平衡性,因此è¦�ç¡®ä¿�最å°�é”®ä¸�在 2- 节点中。将 2- 节点转æ�¢æˆ� 3- 节点或者 4- 节点有两ç§�方法,一ç§�是å�‘上层节点拿一个 key,一ç§�是å�‘兄弟节点拿一个 key。如果上层节点是 2- 节点,那么就没办法从上层节点拿 key 了,因此è¦�ä¿�è¯�删除路径上的所有节点都ä¸�是 2- 节点。在å�‘下删除的过程中,ä¿�è¯�以下情况之一å�‘生: -1. Èç¹ûµ±Ç°½ÚµãµÄ×ó×ӽڵ㲻ÊÇ 2- ½Úµã£¬Íê³É£» -2. Èç¹ûµ±Ç°½ÚµãµÄ×ó×Ó½ÚµãÊÇ 2- ½Úµã¶øËüµÄÐֵܽڵ㲻ÊÇ 2- ½Úµã£¬ÏòÐֵܽڵãÄÃÒ»¸ö key ¹ýÀ´£» -3. Èç¹ûµ±Ç°½ÚµãµÄ×ó×Ó½ÚµãºÍËüµÄÐֵܽڵ㶼ÊÇ 2- ½Úµã£¬½«×ó×ӽڵ㡢¸¸½ÚµãÖеÄ×îС¼üºÍ×î½üµÄÐֵܽڵãºÏ²¢ÎªÒ»¸ö 4- ½Úµã¡£ +1. 如果当å‰�节点的左å­�节点ä¸�是 2- 节点,完æˆ�ï¼› +2. 如果当å‰�节点的左å­�节点是 2- 节点而它的兄弟节点ä¸�是 2- 节点,å�‘兄弟节点拿一个 key 过æ�¥ï¼› +3. 如果当å‰�节点的左å­�节点和它的兄弟节点都是 2- 节点,将左å­�节点ã€�父节点中的最å°�键和最近的兄弟节点å�ˆå¹¶ä¸ºä¸€ä¸ª 4- 节点。 -![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/b001fa64-307c-49af-b4b2-2043fc26154e.png) +![](https://github.com/CyC2018/InterviewNotes/blob/master/pics//b001fa64-307c-49af-b4b2-2043fc26154e.png) -×îºóµÃµ½Ò»¸öº¬ÓÐ×îС¼üµÄ 3- ½Úµã»òÕß 4- ½Úµã£¬Ö±½Ó´ÓÖÐɾ³ý¡£È»ºóÔÙ´ÓÍ··Ö½âËùÓÐÁÙʱµÄ 4- ½Úµã¡£ +最å�Žå¾—到一个å�«æœ‰æœ€å°�键的 3- 节点或者 4- 节点,直接从中删除。然å�Žå†�从头分解所有临时的 4- 节点。 -![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/70b66757-755c-4e17-a7b7-5ce808023643.png) +![](https://github.com/CyC2018/InterviewNotes/blob/master/pics//70b66757-755c-4e17-a7b7-5ce808023643.png) -#### 6. ·ÖÎö +#### 6. 分æž� -Ò»¿Å´óСΪ N µÄºìºÚÊ÷µÄ¸ß¶È²»»á³¬¹ý 2lgN¡£×µÄÇé¿öÏÂÊÇËüËù¶ÔÓ¦µÄ 2-3 Ê÷Öй¹³É×î×ó±ßµÄ·¾¶½ÚµãÈ«²¿¶¼ÊÇ 3- ½Úµã¶øÆäÓà¶¼ÊÇ 2- ½Úµã¡£ +一颗大å°�为 N 的红黑树的高度ä¸�会超过 2lgN。最å��的情况下是它所对应的 2-3 树中构æˆ�最左边的路径节点全部都是 3- 节点而其余都是 2- 节点。 -ºìºÚÊ÷´ó¶àÊýµÄ²Ù×÷ËùÐèÒªµÄʱ¼ä¶¼ÊǶÔÊý¼¶±ðµÄ¡£ +红黑树大多数的æ“�作所需è¦�的时间都是对数级别的。 -## É¢Áбí +## 散列表 -É¢ÁбíÀàËÆÓÚÊý×飬¿ÉÒÔ°ÑÉ¢ÁбíµÄÉ¢ÁÐÖµ¿´³ÉÊý×éµÄË÷ÒýÖµ¡£·ÃÎÊÉ¢ÁбíºÍ·ÃÎÊÊý×éÔªËØÒ»Ñù¿ìËÙ£¬Ëü¿ÉÒÔÔÚ³£Êýʱ¼äÄÚʵÏÖ²éÕҺͲåÈëµÄ·ûºÅ±í¡£ +散列表类似于数组,å�¯ä»¥æŠŠæ•£åˆ—表的散列值看æˆ�数组的索引值。访问散列表和访问数组元素一样快速,它å�¯ä»¥åœ¨å¸¸æ•°æ—¶é—´å†…实现查找和æ�’入的符å�·è¡¨ã€‚ -ÓÉÓÚÎÞ·¨Í¨¹ýÉ¢ÁÐÖµÖªµÀ¼üµÄ´óС¹ØÏµ£¬Òò´ËÉ¢ÁбíÎÞ·¨ÊµÏÖÓÐÐòÐÔ²Ù×÷¡£ +由于无法通过散列值知é�“键的大å°�关系,因此散列表无法实现有åº�性æ“�作。 -### 1. É¢Áк¯Êý +### 1. 散列函数 -¶ÔÓÚÒ»¸ö´óСΪ M µÄÉ¢ÁÐ±í£¬É¢Áк¯ÊýÄܹ»°ÑÈÎÒâ¼üת»»Îª [0, M-1] ÄÚµÄÕýÕûÊý£¬¸ÃÕýÕûÊý¼´Îª hash Öµ¡£ +对于一个大å°�为 M 的散列表,散列函数能够把任æ„�键转æ�¢ä¸º [0, M-1] 内的正整数,该正整数å�³ä¸º hash 值。 -É¢ÁбíÓгåÍ»µÄ´æÔÚ£¬Ò²¾ÍÊÇÁ½¸ö²»Í¬µÄ¼ü¿ÉÄÜÓÐÏàͬµÄ hash Öµ¡£ +散列表有冲çª�的存在,也就是两个ä¸�å�Œçš„é”®å�¯èƒ½æœ‰ç›¸å�Œçš„ hash 值。 -É¢Áк¯ÊýÓ¦¸ÃÂú×ãÒÔÏÂÈý¸öÌõ¼þ£º +散列函数应该满足以下三个æ�¡ä»¶ï¼š -1. Ò»ÖÂÐÔ£ºÏàµÈµÄ¼üÓ¦µ±ÓÐÏàµÈµÄ hash Öµ¡£ -2. ¸ßЧÐÔ£º¼ÆËãÓ¦µ±¼ò±ã£¬ÓбØÒªµÄ»°¿ÉÒÔ°Ñ hash Öµ»º´æÆðÀ´£¬ÔÚµ÷Óà hash º¯Êýʱֱ½Ó·µ»Ø¡£ -3. ¾ùÔÈÐÔ£ºËùÓмüµÄ hash ÖµÓ¦µ±¾ùÔȵطֲ¼µ½ [0, M-1] Ö®¼ä£¬Õâ¸öÌõ¼þÖÁ¹ØÖØÒª£¬Ö±½ÓÓ°Ï쵽ɢÁбíµÄÐÔÄÜ¡£ +1. 一致性:相等的键应当有相等的 hash 值。 +2. 高效性:计算应当简便,有必è¦�çš„è¯�å�¯ä»¥æŠŠ hash 值缓存起æ�¥ï¼Œåœ¨è°ƒç”¨ hash 函数时直接返回。 +3. å�‡åŒ€æ€§ï¼šæ‰€æœ‰é”®çš„ hash 值应当å�‡åŒ€åœ°åˆ†å¸ƒåˆ° [0, M-1] 之间,这个æ�¡ä»¶è‡³å…³é‡�è¦�,直接影å“�到散列表的性能。 -³ýÁôÓàÊý·¨¿ÉÒÔ½«ÕûÊýÉ¢Áе½ [0, M-1] Ö®¼ä£¬ÀýÈçÒ»¸öÕýÕûÊý k£¬¼ÆËã k%M ¼È¿ÉµÃµ½Ò»¸ö [0, M-1] Ö®¼äµÄ hash Öµ¡£×¢Òâ M ±ØÐëÊÇÒ»¸öËØÊý£¬·ñÔòÎÞ·¨ÀûÓüü°üº¬µÄËùÓÐÐÅÏ¢¡£ÀýÈç M Ϊ 10k£¬ÄÇôֻÄÜÀûÓüüµÄºó k λ¡£ +除留余数法å�¯ä»¥å°†æ•´æ•°æ•£åˆ—到 [0, M-1] 之间,例如一个正整数 k,计算 k%M æ—¢å�¯å¾—到一个 [0, M-1] 之间的 hash 值。注æ„� M 必须是一个素数,å�¦åˆ™æ— æ³•利用键包å�«çš„æ‰€æœ‰ä¿¡æ�¯ã€‚例如 M 为 10k,那么å�ªèƒ½åˆ©ç”¨é”®çš„å�Ž k ä½�。 -¶ÔÓÚÆäËüÊý£¬¿ÉÒÔ½«Æäת»»³ÉÕûÊýµÄÐÎʽ£¬È»ºóÀûÓóýÁôÓàÊý·¨¡£ÀýÈç¶ÔÓÚ¸¡µãÊý£¬¿ÉÒÔ½«Æä±íʾ³É¶þ½øÖÆÐÎʽ£¬È»ºóʹÓöþ½øÖÆÐÎʽµÄÕûÊýÖµ½øÐгýÁôÓàÊý·¨¡£ +对于其它数,å�¯ä»¥å°†å…¶è½¬æ�¢æˆ�整数的形å¼�,然å�Žåˆ©ç”¨é™¤ç•™ä½™æ•°æ³•。例如对于浮点数,å�¯ä»¥å°†å…¶è¡¨ç¤ºæˆ�二进制形å¼�,然å�Žä½¿ç”¨äºŒè¿›åˆ¶å½¢å¼�的整数值进行除留余数法。 -¶ÔÓÚÓжಿ·Ö×éºÏµÄ¼ü£¬Ã¿²¿·Ö¶¼ÐèÒª¼ÆËã hash Öµ£¬²¢ÇÒ×îºóºÏ²¢Ê±ÐèÒªÈÃÿ²¿·Ö hash Öµ¶¼¾ßÓÐͬµÈÖØÒªµÄµØÎ»¡£¿ÉÒÔ½«¸Ã¼ü¿´³É R ½øÖƵÄÕûÊý£¬¼üÖÐÿ²¿·Ö¶¼¾ßÓв»Í¬µÄȨֵ¡£ +对于有多部分组å�ˆçš„键,æ¯�部分都需è¦�计算 hash 值,并且最å�Žå�ˆå¹¶æ—¶éœ€è¦�让æ¯�部分 hash 值都具有å�Œç­‰é‡�è¦�的地ä½�。å�¯ä»¥å°†è¯¥é”®çœ‹æˆ� R 进制的整数,键中æ¯�部分都具有ä¸�å�Œçš„æ�ƒå€¼ã€‚ -ÀýÈ磬×Ö·û´®µÄÉ¢Áк¯ÊýʵÏÖÈçÏ +例如,字符串的散列函数实现如下 ```java int hash = 0; @@ -1410,21 +1411,21 @@ for(int i = 0; i < s.length(); i++) hash = (R * hash + s.charAt(i)) % M; ``` -ÔÙ±ÈÈ磬ӵÓжà¸ö³ÉÔ±µÄ×Ô¶¨ÒåÀàµÄ¹þÏ£º¯ÊýÈçÏ +å†�比如,拥有多个æˆ�员的自定义类的哈希函数如下 ```java int hash = (((day * R + month) % M) * R + year) % M; ``` -R µÄÖµ²»ÊǺÜÖØÒª£¬Í¨³£È¡ 31¡£ +R 的值ä¸�是很é‡�è¦�,通常å�– 31。 -Java ÖÐµÄ hashCode() ʵÏÖÁË hash º¯Êý£¬µ«ÊÇĬÈÏʹÓöÔÏóµÄÄÚ´æµØÖ·Öµ¡£ÔÚʹÓà hashCode() º¯Êýʱ£¬Ó¦µ±½áºÏ³ýÁôÓàÊý·¨À´Ê¹Óá£ÒòΪÄÚ´æµØÖ·ÊÇ 32 λÕûÊý£¬ÎÒÃÇÖ»ÐèÒª 31 λµÄ·Ç¸ºÕûÊý£¬Òò´ËÓ¦µ±ÆÁ±Î·ûºÅλ֮ºóÔÙʹÓóýÁôÓàÊý·¨¡£ +Java 中的 hashCode() 实现了 hash 函数,但是默认使用对象的内存地å�€å€¼ã€‚在使用 hashCode() 函数时,应当结å�ˆé™¤ç•™ä½™æ•°æ³•æ�¥ä½¿ç”¨ã€‚因为内存地å�€æ˜¯ 32 ä½�整数,我们å�ªéœ€è¦� 31 ä½�çš„é�žè´Ÿæ•´æ•°ï¼Œå› æ­¤åº”当å±�蔽符å�·ä½�之å�Žå†�使用除留余数法。 ```java int hash = (x.hashCode() & 0x7fffffff) % M; ``` -ʹÓà Java ×Ô´øµÄ HashMap µÈ×Ô´øµÄ¹þÏ£±íʵÏÖʱ£¬Ö»ÐèҪȥʵÏÖ Key ÀàÐ굀 hashCode() º¯Êý¼´¿É¡£Java ¹æ¶¨ hashCode() Äܹ»½«¼ü¾ùÔÈ·Ö²¼ÓÚËùÓÐµÄ 32 λÕûÊý£¬Java ÖÐµÄ String¡¢Integer µÈ¶ÔÏóµÄ hashCode() ¶¼ÄÜʵÏÖÕâÒ»µã¡£ÒÔÏÂչʾÁË×Ô¶¨ÒåÀàÐÍÈçºÎʵÏÖ hashCode()¡£ +使用 Java 自带的 HashMap 等自带的哈希表实现时,å�ªéœ€è¦�去实现 Key 类型的 hashCode() 函数å�³å�¯ã€‚Java 规定 hashCode() 能够将键å�‡åŒ€åˆ†å¸ƒäºŽæ‰€æœ‰çš„ 32 ä½�整数,Java 中的 Stringã€�Integer 等对象的 hashCode() 都能实现这一点。以下展示了自定义类型如何实现 hashCode()。 ```java public class Transaction{ @@ -1442,19 +1443,19 @@ public class Transaction{ } ``` -### 2. »ùÓÚÀ­Á´·¨µÄÉ¢Áбí +### 2. 基于拉链法的散列表 -À­Á´·¨Ê¹ÓÃÁ´±íÀ´´æ´¢ hash ÖµÏàͬµÄ¼ü£¬´Ó¶ø½â¾ö³åÍ»¡£´Ëʱ²éÕÒÐèÒª·ÖÁ½²½£¬Ê×ÏȲéÕÒ Key ËùÔÚµÄÁ´±í£¬È»ºóÔÚÁ´±íÖÐ˳Ðò²éÕÒ¡£ +拉链法使用链表æ�¥å­˜å‚¨ hash 值相å�Œçš„键,从而解决冲çª�。此时查找需è¦�分两步,首先查找 Key 所在的链表,然å�Žåœ¨é“¾è¡¨ä¸­é¡ºåº�查找。 -![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/540133af-aaaf-4208-8f7f-33cb89ac9621.png) +![](https://github.com/CyC2018/InterviewNotes/blob/master/pics//540133af-aaaf-4208-8f7f-33cb89ac9621.png) -¶ÔÓÚ N ¸ö¼ü£¬M ÌõÁ´±í (N>M)£¬Èç¹û¹þÏ£º¯ÊýÄܹ»Âú×ã¾ùÔÈÐÔµÄÌõ¼þ£¬Ã¿ÌõÁ´±íµÄ´óСÇ÷ÏòÓÚ N/M£¬Òò´ËδÃüÖеIJéÕҺͲåÈë²Ù×÷ËùÐèÒªµÄ±È½Ï´ÎÊýΪ \~N/M¡£ +对于 N 个键,M æ�¡é“¾è¡¨ (N>M),如果哈希函数能够满足å�‡åŒ€æ€§çš„æ�¡ä»¶ï¼Œæ¯�æ�¡é“¾è¡¨çš„大å°�è¶‹å�‘于 N/M,因此未命中的查找和æ�’å…¥æ“�作所需è¦�的比较次数为 \~N/M。 -### 3. »ùÓÚÏßÐÔ̽²â·¨µÄÉ¢Áбí +### 3. 基于线性探测法的散列表 -ÏßÐÔ̽²â·¨Ê¹ÓÿÕλÀ´½â¾ö³åÍ»£¬µ±³åÍ»·¢Éúʱ£¬Ïòǰ̽²âÒ»¸ö¿ÕλÀ´´æ´¢³åÍ»µÄ¼ü¡£Ê¹ÓÃÏß³Ì̽²â·¨£¬Êý×éµÄ´óС M Ó¦µ±´óÓÚ¼üµÄ¸öÊý N£¨M>N)¡£ +线性探测法使用空ä½�æ�¥è§£å†³å†²çª�,当冲çª�å�‘生时,å�‘å‰�探测一个空ä½�æ�¥å­˜å‚¨å†²çª�的键。使用线程探测法,数组的大å°� M 应当大于键的个数 N(M>N)。 -![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/2b3410f1-9559-4dd1-bc3d-e3e572247be2.png) +![](https://github.com/CyC2018/InterviewNotes/blob/master/pics//2b3410f1-9559-4dd1-bc3d-e3e572247be2.png) ```java public class LinearProbingHashST { @@ -1483,7 +1484,7 @@ public class LinearProbingHashST { } ``` -#### 3.1 ²éÕÒ +#### 3.1 查找 ```java public Value get(Key key) { @@ -1496,7 +1497,7 @@ public Value get(Key key) { } ``` -#### 3.2 ²åÈë +#### 3.2 æ�’å…¥ ```java public void put(Key key, Value val) { @@ -1514,9 +1515,9 @@ public void put(Key key, Value val) { } ``` -#### 3.3 ɾ³ý +#### 3.3 删除 -ɾ³ý²Ù×÷Ó¦µ±½«ÓÒ²àËùÓÐÏàÁڵļüÖµÖØÐ²åÈëÉ¢ÁбíÖС£ +删除æ“�作应当将å�³ä¾§æ‰€æœ‰ç›¸é‚»çš„键值é‡�æ–°æ�’入散列表中。 ```java public void delete(Key key) { @@ -1542,15 +1543,15 @@ public void delete(Key key) { } ``` -#### 3.4 µ÷ÕûÊý×é´óС +#### 3.4 调整数组大å°� -ÏßÐÔ̽²â·¨µÄ³É±¾È¡¾öÓÚÁ¬ÐøÌõÄ¿µÄ³¤¶È£¬Á¬ÐøÌõĿҲ½Ð¾Û´Ø¡£µ±¾Û´ØºÜ³¤Ê±£¬ÔÚ²éÕҺͲåÈëʱҲÐèÒª½øÐкܶà´Î̽²â¡£ +线性探测法的æˆ�本å�–决于连续æ�¡ç›®çš„长度,连续æ�¡ç›®ä¹Ÿå�«è�šç°‡ã€‚当è�šç°‡å¾ˆé•¿æ—¶ï¼Œåœ¨æŸ¥æ‰¾å’Œæ�’入时也需è¦�进行很多次探测。 -¦Á = N/M£¬°Ñ ¦Á ³ÆÎªÀûÓÃÂÊ¡£ÀíÂÛÖ¤Ã÷£¬µ± ¦Á СÓÚ 1/2 ʱ̽²âµÄÔ¤¼Æ´ÎÊýÖ»ÔÚ 1.5 µ½ 2.5 Ö®¼ä¡£ +α = N/M,把 α 称为利用率。ç�†è®ºè¯�明,当 α å°�于 1/2 时探测的预计次数å�ªåœ¨ 1.5 到 2.5 之间。 -![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/0ddebc5c-7c24-46b1-98db-4fa5e54db16b.png) +![](https://github.com/CyC2018/InterviewNotes/blob/master/pics//0ddebc5c-7c24-46b1-98db-4fa5e54db16b.png) -ΪÁ˱£Ö¤É¢ÁбíµÄÐÔÄÜ£¬Ó¦µ±µ÷ÕûÊý×éµÄ´óС£¬Ê¹µÃ ¦Á ÔÚ [1/4, 1/2] Ö®¼ä¡£ +为了ä¿�è¯�散列表的性能,应当调整数组的大å°�,使得 α 在 [1/4, 1/2] 之间。 ```java private void resize() { @@ -1571,29 +1572,29 @@ private void resize(int cap) { } ``` -ËäȻÿ´ÎÖØÐµ÷ÕûÊý×é¶¼ÐèÒªÖØÐ°Ñÿ¸ö¼üÖµ¶Ô²åÈ뵽ɢÁÐ±í£¬µ«ÊÇ´Ó̯»¹·ÖÎöµÄ½Ç¶ÈÀ´¿´£¬ËùÐèÒªµÄ´ú¼ÛÈ´ÊǺÜСµÄ¡£´ÓÏÂͼ¿ÉÒÔ¿´³ö£¬Ã¿´ÎÊý×鳤¶È¼Ó±¶ºó£¬ÀÛ¼ÆÆ½¾ùÖµ¶¼»áÔö¼Ó 1£¬ÒòΪ±íÖÐÿ¸ö¼ü¶¼ÐèÒªÖØÐ¼ÆËãÉ¢ÁÐÖµ£¬µ«ÊÇËæºóƽ¾ùÖµ»áϽµ¡£ +虽然æ¯�次é‡�新调整数组都需è¦�é‡�新把æ¯�个键值对æ�’入到散列表,但是从摊还分æž�的角度æ�¥çœ‹ï¼Œæ‰€éœ€è¦�的代价å�´æ˜¯å¾ˆå°�的。从下图å�¯ä»¥çœ‹å‡ºï¼Œæ¯�次数组长度加å€�å�Žï¼Œç´¯è®¡å¹³å�‡å€¼éƒ½ä¼šå¢žåŠ  1,因为表中æ¯�个键都需è¦�é‡�新计算散列值,但是éš�å�Žå¹³å�‡å€¼ä¼šä¸‹é™�。 -![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/01658047-0d86-4a7a-a8ca-7ea20fa1fdde.png) +![](https://github.com/CyC2018/InterviewNotes/blob/master/pics//01658047-0d86-4a7a-a8ca-7ea20fa1fdde.png) -## Ó¦Óà +## 应用 -### 1. ¸÷ÖÖ·ûºÅ±íʵÏÖµÄ±È½Ï +### 1. å�„ç§�符å�·è¡¨å®žçŽ°çš„æ¯”è¾ƒ -![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/9ee83c8c-1165-476c-85a6-e6e434e5307a.jpg) +![](https://github.com/CyC2018/InterviewNotes/blob/master/pics//9ee83c8c-1165-476c-85a6-e6e434e5307a.jpg) -Ó¦µ±ÓÅÏÈ¿¼ÂÇÉ¢ÁÐ±í£¬µ±ÐèÒªÓÐÐòÐÔ²Ù×÷ʱʹÓúìºÚÊ÷¡£ +应当优先考虑散列表,当需è¦�有åº�性æ“�作时使用红黑树。 -### 2. Java µÄ·ûºÅ±íʵÏÖ +### 2. Java 的符å�·è¡¨å®žçް -Java µÄ java.util.TreeMap ºÍ java.util.HashMap ·Ö±ðÊÇ»ùÓÚºìºÚÊ÷ºÍÀ­Á´·¨µÄÉ¢ÁбíµÄ·ûºÅ±íʵÏÖ¡£ +Java çš„ java.util.TreeMap å’Œ java.util.HashMap 分别是基于红黑树和拉链法的散列表的符å�·è¡¨å®žçŽ°ã€‚ -### 3. ¼¯ºÏÀàÐÍ +### 3. 集å�ˆç±»åž‹ -³ýÁË·ûºÅ±í£¬¼¯ºÏÀàÐÍÒ²¾­³£Ê¹Óã¬ËüÖ»ÓмüûÓÐÖµ£¬¿ÉÒÔÓü¯ºÏÀàÐÍÀ´´æ´¢Ò»ÏµÁеļüÈ»ºóÅжÏÒ»¸ö¼üÊÇ·ñÔÚ¼¯ºÏÖС£ +除了符å�·è¡¨ï¼Œé›†å�ˆç±»åž‹ä¹Ÿç»�常使用,它å�ªæœ‰é”®æ²¡æœ‰å€¼ï¼Œå�¯ä»¥ç”¨é›†å�ˆç±»åž‹æ�¥å­˜å‚¨ä¸€ç³»åˆ—的键然å�Žåˆ¤æ–­ä¸€ä¸ªé”®æ˜¯å�¦åœ¨é›†å�ˆä¸­ã€‚ -### 4. Ï¡ÊèÏòÁ¿³Ë·¨ +### 4. 稀ç–�å�‘é‡�乘法 -µ±ÏòÁ¿ÎªÏ¡ÊèÏòÁ¿Ê±£¬¿ÉÒÔʹÓ÷ûºÅ±íÀ´´æ´¢ÏòÁ¿ÖÐµÄ·Ç 0 Ë÷ÒýºÍÖµ£¬Ê¹µÃ³Ë·¨ÔËËãÖ»ÐèÒª¶ÔÄÇЩ·Ç 0 ÔªËØ½øÐм´¿É¡£ +当å�‘é‡�为稀ç–�å�‘é‡�时,å�¯ä»¥ä½¿ç”¨ç¬¦å�·è¡¨æ�¥å­˜å‚¨å�‘é‡�中的é�ž 0 索引和值,使得乘法è¿�ç®—å�ªéœ€è¦�对那些é�ž 0 元素进行å�³å�¯ã€‚ ```java import java.util.HashMap; diff --git a/notes/计算机æ“�作系统.md b/notes/计算机æ“�作系统.md index 2bbd65c1..19820759 100644 --- a/notes/计算机æ“�作系统.md +++ b/notes/计算机æ“�作系统.md @@ -1,248 +1,249 @@ -* [µÚÒ»Õ ¸ÅÊö](#µÚÒ»ÕÂ-¸ÅÊö) - * [²Ù×÷ϵͳ»ù±¾ÌØÕ÷](#²Ù×÷ϵͳ»ù±¾ÌØÕ÷) - * [1. ²¢·¢](#1-²¢·¢) - * [2. ¹²Ïí](#2-¹²Ïí) - * [3. ÐéÄâ](#3-ÐéÄâ) - * [4. Òì²½](#4-Òì²½) - * [ϵͳµ÷ÓÃ](#ϵͳµ÷ÓÃ) - * [ÖжϷÖÀà](#ÖжϷÖÀà) - * [1. ÍâÖжÏ](#1-ÍâÖжÏ) - * [2. Òì³£](#2-Òì³£) - * [3. ÏÝÈë](#3-ÏÝÈë) - * [´óÄں˺Í΢ÄÚºË](#´óÄں˺Í΢ÄÚºË) - * [1. ´óÄÚºË](#1-´óÄÚºË) - * [2. ΢ÄÚºË](#2-΢ÄÚºË) -* [µÚ¶þÕ ½ø³Ì¹ÜÀí](#µÚ¶þÕÂ-½ø³Ì¹ÜÀí) - * [½ø³ÌÓëÏß³Ì](#½ø³ÌÓëÏß³Ì) - * [1. ½ø³Ì](#1-½ø³Ì) - * [2. Ïß³Ì](#2-Ïß³Ì) - * [3. Çø±ð](#3-Çø±ð) - * [½ø³Ì״̬µÄÇл»](#½ø³Ì״̬µÄÇл») - * [µ÷¶ÈËã·¨](#µ÷¶ÈËã·¨) - * [1. Åú´¦ÀíϵͳÖеĵ÷¶È](#1-Åú´¦ÀíϵͳÖеĵ÷¶È) - * [1.1 ÏÈÀ´ÏÈ·þÎñ](#11-ÏÈÀ´ÏÈ·þÎñ) - * [1.2 ¶Ì×÷ÒµÓÅÏÈ](#12-¶Ì×÷ÒµÓÅÏÈ) - * [1.3 ×î¶ÌÊ£Óàʱ¼äÓÅÏÈ](#13-×î¶ÌÊ£Óàʱ¼äÓÅÏÈ) - * [2. ½»»¥Ê½ÏµÍ³Öеĵ÷¶È](#2-½»»¥Ê½ÏµÍ³Öеĵ÷¶È) - * [2.1 ÓÅÏÈȨÓÅÏÈ](#21-ÓÅÏÈȨÓÅÏÈ) - * [2.2 ʱ¼äƬÂÖת](#22-ʱ¼äƬÂÖת) - * [2.3 ¶à¼¶·´À¡¶ÓÁÐ](#23-¶à¼¶·´À¡¶ÓÁÐ) - * [2.4 ¶Ì½ø³ÌÓÅÏÈ](#24-¶Ì½ø³ÌÓÅÏÈ) - * [3. ʵʱϵͳÖеĵ÷¶È](#3-ʵʱϵͳÖеĵ÷¶È) - * [½ø³Ìͬ²½](#½ø³Ìͬ²½) - * [1. ÁÙ½çÇø](#1-ÁÙ½çÇø) - * [2. ͬ²½Ó뻥³â](#2-ͬ²½Ó뻥³â) - * [3. ÐźÅÁ¿](#3-ÐźÅÁ¿) - * [4. ¹Ü³Ì](#4-¹Ü³Ì) - * [½ø³ÌͨÐÅ](#½ø³ÌͨÐÅ) - * [1. ¹ÜµÀ](#1-¹ÜµÀ) - * [2. ÐźÅÁ¿](#2-ÐźÅÁ¿) - * [3. ÏûÏ¢¶ÓÁÐ](#3-ÏûÏ¢¶ÓÁÐ) - * [4. ÐźÅ](#4-ÐźÅ) - * [5. ¹²ÏíÄÚ´æ](#5-¹²ÏíÄÚ´æ) - * [6. Ì×½Ó×Ö](#6-Ì×½Ó×Ö) - * [¾­µäͬ²½ÎÊÌâ](#¾­µäͬ²½ÎÊÌâ) - * [1. ¶ÁÕß-дÕßÎÊÌâ](#1-¶ÁÕß-дÕßÎÊÌâ) - * [2. ÕÜѧ¼Ò½ø²ÍÎÊÌâ](#2-ÕÜѧ¼Ò½ø²ÍÎÊÌâ) -* [µÚÈýÕ ËÀËø](#µÚÈýÕÂ-ËÀËø) - * [ËÀËøµÄÌõ¼þ](#ËÀËøµÄÌõ¼þ) - * [ËÀËøµÄ´¦Àí·½·¨](#ËÀËøµÄ´¦Àí·½·¨) - * [1. ÍÒÄñ²ßÂÔ](#1-ÍÒÄñ²ßÂÔ) - * [2. ËÀËøÔ¤·À](#2-ËÀËøÔ¤·À) - * [2.1 ÆÆ»µ»¥³âÌõ¼þ](#21-ÆÆ»µ»¥³âÌõ¼þ) - * [2.2 ÆÆ»µÇëÇóÓë±£³ÖÌõ¼þ](#22-ÆÆ»µÇëÇóÓë±£³ÖÌõ¼þ) - * [2.3 ÆÆ»µ²»¿ÉÇÀÕ¼Ìõ¼þ](#23-ÆÆ»µ²»¿ÉÇÀÕ¼Ìõ¼þ) - * [2.4 ÆÆ»µ»·Â·µÈ´ý](#24-ÆÆ»µ»·Â·µÈ´ý) - * [3. ËÀËø±ÜÃâ](#3-ËÀËø±ÜÃâ) - * [3.1 °²È«×´Ì¬](#31-°²È«×´Ì¬) - * [3.2 µ¥¸ö×ÊÔ´µÄÒøÐмÒËã·¨](#32-µ¥¸ö×ÊÔ´µÄÒøÐмÒËã·¨) - * [3.3 ¶à¸ö×ÊÔ´µÄÒøÐмÒËã·¨](#33-¶à¸ö×ÊÔ´µÄÒøÐмÒËã·¨) - * [4. ËÀËø¼ì²âÓëËÀËø»Ö¸´](#4-ËÀËø¼ì²âÓëËÀËø»Ö¸´) - * [4.1 ËÀËø¼ì²âËã·¨](#41-ËÀËø¼ì²âËã·¨) - * [4.2 ËÀËø»Ö¸´](#42-ËÀËø»Ö¸´) -* [µÚËÄÕ ´æ´¢Æ÷¹ÜÀí](#µÚËÄÕÂ-´æ´¢Æ÷¹ÜÀí) - * [ÐéÄâÄÚ´æ](#ÐéÄâÄÚ´æ) - * [·ÖÒ³Óë·Ö¶Î](#·ÖÒ³Óë·Ö¶Î) - * [1. ·ÖÒ³](#1-·ÖÒ³) - * [2. ·Ö¶Î](#2-·Ö¶Î) - * [3. ¶Îҳʽ](#3-¶Îҳʽ) - * [4. ·ÖÒ³Óë·Ö¶ÎÇø±ð](#4-·ÖÒ³Óë·Ö¶ÎÇø±ð) - * [Ò³ÃæÖû»Ëã·¨](#Ò³ÃæÖû»Ëã·¨) - * [1. ×î¼Ñ£¨Optimal£©](#1-×î¼Ñoptimal) - * [2. ÏȽøÏȳö£¨FIFO£©](#2-ÏȽøÏȳöfifo) - * [3. ×î½ü×î¾ÃδʹÓã¨LRU, Least Recently Used£©](#3-×î½ü×î¾ÃδʹÓÃlru,-least-recently-used) - * [4. ʱÖÓ£¨Clock£©](#4-ʱÖÓclock) -* [µÚÎåÕ É豸¹ÜÀí](#µÚÎåÕÂ-É豸¹ÜÀí) - * [´ÅÅ̵÷¶ÈËã·¨](#´ÅÅ̵÷¶ÈËã·¨) - * [1. ÏÈÀ´ÏÈ·þÎñ£¨FCFS, First Come First Serverd£©](#1-ÏÈÀ´ÏÈ·þÎñfcfs,-first-come-first-serverd) - * [2. ×î¶ÌѰµÀʱ¼äÓÅÏÈ£¨SSTF, Shortest Seek Time First£©](#2-×î¶ÌѰµÀʱ¼äÓÅÏÈsstf,-shortest-seek-time-first) - * [3. ɨÃèËã·¨£¨SCAN£©](#3-ɨÃèËã·¨scan) - * [4. Ñ­»·É¨ÃèËã·¨£¨CSCAN£©](#4-Ñ­»·É¨ÃèËã·¨cscan) -* [²Î¿¼×ÊÁÏ](#²Î¿¼×ÊÁÏ) +* [第一章 概述](#第一章-概述) + * [æ“�作系统基本特å¾�](#æ“�作系统基本特å¾�) + * [1. å¹¶å�‘](#1-å¹¶å�‘) + * [2. 共享](#2-共享) + * [3. 虚拟](#3-虚拟) + * [4. 异步](#4-异步) + * [系统调用](#系统调用) + * [中断分类](#中断分类) + * [1. 外中断](#1-外中断) + * [2. 异常](#2-异常) + * [3. é™·å…¥](#3-é™·å…¥) + * [大内核和微内核](#大内核和微内核) + * [1. 大内核](#1-大内核) + * [2. 微内核](#2-微内核) +* [第二章 进程管ç�†](#第二章-进程管ç�†) + * [进程与线程](#进程与线程) + * [1. 进程](#1-进程) + * [2. 线程](#2-线程) + * [3. 区别](#3-区别) + * [进程状æ€�的切æ�¢](#进程状æ€�的切æ�¢) + * [调度算法](#调度算法) + * [1. 批处ç�†ç³»ç»Ÿä¸­çš„调度](#1-批处ç�†ç³»ç»Ÿä¸­çš„调度) + * [1.1 å…ˆæ�¥å…ˆæœ�务](#11-å…ˆæ�¥å…ˆæœ�务) + * [1.2 短作业优先](#12-短作业优先) + * [1.3 最短剩余时间优先](#13-最短剩余时间优先) + * [2. 交互å¼�系统中的调度](#2-交互å¼�系统中的调度) + * [2.1 优先æ�ƒä¼˜å…ˆ](#21-优先æ�ƒä¼˜å…ˆ) + * [2.2 时间片轮转](#22-时间片轮转) + * [2.3 多级å��馈队列](#23-多级å��馈队列) + * [2.4 短进程优先](#24-短进程优先) + * [3. 实时系统中的调度](#3-实时系统中的调度) + * [进程å�Œæ­¥](#进程å�Œæ­¥) + * [1. 临界区](#1-临界区) + * [2. å�Œæ­¥ä¸Žäº’æ–¥](#2-å�Œæ­¥ä¸Žäº’æ–¥) + * [3. ä¿¡å�·é‡�](#3-ä¿¡å�·é‡�) + * [4. 管程](#4-管程) + * [进程通信](#进程通信) + * [1. 管é�“](#1-管é�“) + * [2. ä¿¡å�·é‡�](#2-ä¿¡å�·é‡�) + * [3. 消æ�¯é˜Ÿåˆ—](#3-消æ�¯é˜Ÿåˆ—) + * [4. ä¿¡å�·](#4-ä¿¡å�·) + * [5. 共享内存](#5-共享内存) + * [6. 套接字](#6-套接字) + * [ç»�å…¸å�Œæ­¥é—®é¢˜](#ç»�å…¸å�Œæ­¥é—®é¢˜) + * [1. 读者-写者问题](#1-读者-写者问题) + * [2. 哲学家进é¤�问题](#2-哲学家进é¤�问题) +* [第三章 æ­»é”�](#第三章-æ­»é”�) + * [æ­»é”�çš„æ�¡ä»¶](#æ­»é”�çš„æ�¡ä»¶) + * [æ­»é”�的处ç�†æ–¹æ³•](#æ­»é”�的处ç�†æ–¹æ³•) + * [1. 鸵鸟策略](#1-鸵鸟策略) + * [2. æ­»é”�预防](#2-æ­»é”�预防) + * [2.1 ç ´å��互斥æ�¡ä»¶](#21-ç ´å��互斥æ�¡ä»¶) + * [2.2 ç ´å��请求与ä¿�æŒ�æ�¡ä»¶](#22-ç ´å��请求与ä¿�æŒ�æ�¡ä»¶) + * [2.3 ç ´å��ä¸�å�¯æŠ¢å� æ�¡ä»¶](#23-ç ´å��ä¸�å�¯æŠ¢å� æ�¡ä»¶) + * [2.4 ç ´å��环路等待](#24-ç ´å��环路等待) + * [3. æ­»é”�é�¿å…�](#3-æ­»é”�é�¿å…�) + * [3.1 安全状æ€�](#31-安全状æ€�) + * [3.2 å�•个资æº�的银行家算法](#32-å�•个资æº�的银行家算法) + * [3.3 多个资æº�的银行家算法](#33-多个资æº�的银行家算法) + * [4. æ­»é”�检测与死é”�æ�¢å¤�](#4-æ­»é”�检测与死é”�æ�¢å¤�) + * [4.1 æ­»é”�检测算法](#41-æ­»é”�检测算法) + * [4.2 æ­»é”�æ�¢å¤�](#42-æ­»é”�æ�¢å¤�) +* [第四章 存储器管ç�†](#第四章-存储器管ç�†) + * [虚拟内存](#虚拟内存) + * [分页与分段](#分页与分段) + * [1. 分页](#1-分页) + * [2. 分段](#2-分段) + * [3. 段页å¼�](#3-段页å¼�) + * [4. 分页与分段区别](#4-分页与分段区别) + * [页é�¢ç½®æ�¢ç®—法](#页é�¢ç½®æ�¢ç®—法) + * [1. 最佳(Optimal)](#1-最佳optimal) + * [2. 先进先出(FIFO)](#2-先进先出fifo) + * [3. 最近最久未使用(LRU, Least Recently Used)](#3-最近最久未使用lru,-least-recently-used) + * [4. 时钟(Clock)](#4-æ—¶é’Ÿclock) +* [第五章 设备管ç�†](#第五章-设备管ç�†) + * [ç£�盘调度算法](#ç£�盘调度算法) + * [1. å…ˆæ�¥å…ˆæœ�务(FCFS, First Come First Serverd)](#1-å…ˆæ�¥å…ˆæœ�务fcfs,-first-come-first-serverd) + * [2. 最短寻é�“时间优先(SSTF, Shortest Seek Time First)](#2-最短寻é�“时间优先sstf,-shortest-seek-time-first) + * [3. 扫æ��算法(SCAN)](#3-扫æ��算法scan) + * [4. 循环扫æ��算法(CSCAN)](#4-循环扫æ��算法cscan) +* [å�‚考资料](#å�‚考资料) -# µÚÒ»Õ ¸ÅÊö -## ²Ù×÷ϵͳ»ù±¾ÌØÕ÷ +# 第一章 概述 -### 1. ²¢·¢ +## æ“�作系统基本特å¾� -²¢·¢ÐÔÊÇÖ¸ºê¹ÛÉÏÔÚÒ»¶Îʱ¼äÄÚÄÜͬʱÔËÐжà¸ö³ÌÐò£¬¶ø²¢ÐÐÐÔÔòָͬһʱ¿ÌÄÜÔËÐжà¸öÖ¸Áî¡£ +### 1. å¹¶å�‘ -²¢ÐÐÐèÒªÓ²¼þÖ§³Ö£¬Èç¶àÁ÷Ë®Ïß»òÕß¶à´¦ÀíÆ÷¡£ +å¹¶å�‘性是指å®�观上在一段时间内能å�Œæ—¶è¿�行多个程åº�,而并行性则指å�Œä¸€æ—¶åˆ»èƒ½è¿�行多个指令。 -²Ù×÷ϵͳͨ¹ýÒýÈë½ø³ÌºÍỊ̈߳¬Ê¹µÃ³ÌÐòÄܹ»²¢·¢ÔËÐС£ +并行需è¦�硬件支æŒ�,如多æµ�水线或者多处ç�†å™¨ã€‚ -### 2. ¹²Ïí +æ“�作系统通过引入进程和线程,使得程åº�能够并å�‘è¿�行。 -¹²ÏíÊÇָϵͳÖеÄ×ÊÔ´¿ÉÒÔ¹©¶à¸ö²¢·¢½ø³Ì¹²Í¬Ê¹Óᣠ+### 2. 共享 -ÓÐÁ½ÖÖ¹²Ïí·½Ê½£º»¥³â¹²ÏíºÍͬʱ¹²Ïí¡£ +共享是指系统中的资æº�å�¯ä»¥ä¾›å¤šä¸ªå¹¶å�‘进程共å�Œä½¿ç”¨ã€‚ -»¥³â¹²ÏíµÄ×ÊÔ´³ÆÎªÁÙ½ç×ÊÔ´£¬ÀýÈç´òÓ¡»úµÈ£¬ÔÚͬһʱ¼äÖ»ÔÊÐíÒ»¸ö½ø³Ì·ÃÎÊ£¬·ñÔò»á³öÏÖ´íÎó£¬ÐèÒªÓÃͬ²½»úÖÆÀ´ÊµÏÖ¶ÔÁÙ½ç×ÊÔ´µÄ·ÃÎÊ¡£ +有两ç§�共享方å¼�:互斥共享和å�Œæ—¶å…±äº«ã€‚ -### 3. ÐéÄâ +互斥共享的资æº�称为临界资æº�,例如打å�°æœºç­‰ï¼Œåœ¨å�Œä¸€æ—¶é—´å�ªå…�许一个进程访问,å�¦åˆ™ä¼šå‡ºçŽ°é”™è¯¯ï¼Œéœ€è¦�用å�Œæ­¥æœºåˆ¶æ�¥å®žçŽ°å¯¹ä¸´ç•Œèµ„æº�的访问。 -ÐéÄâ¼¼Êõ°ÑÒ»¸öÎïÀíʵÌåת»»Îª¶à¸öÂß¼­ÊµÌå¡£Ö÷ÒªÓÐÁ½ÖÖÐéÄâ¼¼Êõ£ºÊ±·Ö¸´Óü¼ÊõºÍ¿Õ·Ö¸´Óü¼Êõ£¬ÀýÈç¶à¸ö½ø³ÌÄÜÔÚͬһ¸ö´¦ÀíÆ÷Éϲ¢·¢Ö´ÐÐʹÓÃÁËʱ·Ö¸´Óü¼Êõ£¬ÈÃÿ¸ö½ø³ÌÂÖÁ÷Õ¼Óд¦ÀíÆ÷£¬Ã¿´ÎÖ»Ö´ÐÐһС¸öʱ¼äƬ²¢¿ìËÙÇл»¡£ +### 3. 虚拟 -### 4. Òì²½ +虚拟技术把一个物ç�†å®žä½“转æ�¢ä¸ºå¤šä¸ªé€»è¾‘实体。主è¦�有两ç§�虚拟技术:时分å¤�用技术和空分å¤�用技术,例如多个进程能在å�Œä¸€ä¸ªå¤„ç�†å™¨ä¸Šå¹¶å�‘执行使用了时分å¤�用技术,让æ¯�个进程轮æµ�å� æœ‰å¤„ç�†å™¨ï¼Œæ¯�次å�ªæ‰§è¡Œä¸€å°�个时间片并快速切æ�¢ã€‚ -Òì²½ÊÇÖ¸½ø³Ì²»ÊÇÒ»´ÎÐÔÖ´ÐÐÍê±Ï£¬¶øÊÇ×ß×ßͣͣ£¬ÒÔ²»¿ÉÖªµÄËÙ¶ÈÏòÇ°ÍÆ½ø¡£ +### 4. 异步 -## ϵͳµ÷Óà +异步是指进程ä¸�是一次性执行完毕,而是走走å�œå�œï¼Œä»¥ä¸�å�¯çŸ¥çš„速度å�‘å‰�推进。 -Èç¹ûÒ»¸ö½ø³ÌÔÚÓû§Ì¬ÐèÒªÓõ½²Ù×÷ϵͳµÄһЩ¹¦ÄÜ£¬¾ÍÐèҪʹÓÃϵͳµ÷ÓôӶøÏÝÈëÄںˣ¬ÓɲÙ×÷ϵͳ´úΪÍê³É¡£ +## 系统调用 -¿ÉÒÔÓÉϵͳµ÷ÓÃÇëÇóµÄ¹¦ÄÜÓÐÉ豸¹ÜÀí¡¢Îļþ¹ÜÀí¡¢½ø³Ì¹ÜÀí¡¢½ø³ÌͨÐÅ¡¢´æ´¢Æ÷¹ÜÀíµÈ¡£ +如果一个进程在用户æ€�需è¦�用到æ“�作系统的一些功能,就需è¦�使用系统调用从而陷入内核,由æ“�作系统代为完æˆ�。 -## ÖжϷÖÀà +å�¯ä»¥ç”±ç³»ç»Ÿè°ƒç”¨è¯·æ±‚的功能有设备管ç�†ã€�文件管ç�†ã€�进程管ç�†ã€�进程通信ã€�存储器管ç�†ç­‰ã€‚ -### 1. ÍâÖÐ¶Ï +## 中断分类 -ÓÉ CPU Ö´ÐÐÖ¸ÁîÒÔÍâµÄʼþÒýÆð£¬Èç I/O ½áÊøÖжϣ¬±íʾÉ豸ÊäÈë/Êä³ö´¦ÀíÒѾ­Íê³É£¬´¦ÀíÆ÷Äܹ»·¢ËÍÏÂÒ»¸öÊäÈë/Êä³öÇëÇó¡£´ËÍ⻹ÓÐʱÖÓÖжϡ¢¿ØÖÆÌ¨Öжϵȡ£ +### 1. 外中断 -### 2. Òì³£ +ç”± CPU 执行指令以外的事件引起,如 I/O 结æ�Ÿä¸­æ–­ï¼Œè¡¨ç¤ºè®¾å¤‡è¾“å…¥/输出处ç�†å·²ç»�完æˆ�,处ç�†å™¨èƒ½å¤Ÿå�‘é€�下一个输入/输出请求。此外还有时钟中断ã€�控制å�°ä¸­æ–­ç­‰ã€‚ -ÓÉ CPU Ö´ÐÐÖ¸ÁîµÄÄÚ²¿Ê¼þÒýÆð£¬Èç·Ç·¨²Ù×÷Âë¡¢µØÖ·Ô½½ç¡¢ËãÊõÒç³öµÈ¡£ +### 2. 异常 -### 3. ÏÝÈë +ç”± CPU 执行指令的内部事件引起,如é�žæ³•æ“�作ç �ã€�地å�€è¶Šç•Œã€�算术溢出等。 -ÔÚÓû§³ÌÐòÖÐʹÓÃϵͳµ÷Óᣠ+### 3. é™·å…¥ -## ´óÄں˺Í΢ÄÚºË +在用户程åº�中使用系统调用。 -### 1. ´óÄÚºË +## 大内核和微内核 -´óÄÚºËÊǽ«²Ù×÷ϵͳ¹¦ÄÜ×÷Ϊһ¸ö½ôÃܽáºÏµÄÕûÌå·Åµ½Äںˣ¬ÓÉÓÚ¸÷Ä£¿é¹²ÏíÐÅÏ¢£¬Òò´ËÓкܸߵÄÐÔÄÜ¡£ +### 1. 大内核 -### 2. ΢ÄÚºË +大内核是将æ“�作系统功能作为一个紧密结å�ˆçš„æ•´ä½“放到内核,由于å�„模å�—共享信æ�¯ï¼Œå› æ­¤æœ‰å¾ˆé«˜çš„æ€§èƒ½ã€‚ -ÓÉÓÚ²Ù×÷ϵͳ²»¶Ï¸´ÔÓ£¬Òò´Ë½«Ò»²¿·Ö²Ù×÷ϵͳ¹¦ÄÜÒÆ³öÄںˣ¬´Ó¶ø½µµÍÄں˵ĸ´ÔÓÐÔ¡£ÒƳöµÄ²¿·Ö¸ù¾Ý·Ö²ãµÄÔ­Ôò»®·Ö³ÉÈô¸É·þÎñ£¬Ï໥¶ÀÁ¢¡£µ«ÊÇÐèҪƵ·±µØÔÚÓû§Ì¬ºÍºËÐÄ̬֮¼ä½øÐÐÇл»£¬»áÓÐÒ»¶¨µÄÐÔÄÜËðʧ¡£ +### 2. 微内核 -# µÚ¶þÕ ½ø³Ì¹ÜÀí +由于æ“�作系统ä¸�æ–­å¤�æ�‚,因此将一部分æ“�作系统功能移出内核,从而é™�低内核的å¤�æ�‚性。移出的部分根æ�®åˆ†å±‚的原则划分æˆ�若干æœ�务,相互独立。但是需è¦�频ç¹�地在用户æ€�和核心æ€�之间进行切æ�¢ï¼Œä¼šæœ‰ä¸€å®šçš„æ€§èƒ½æ�Ÿå¤±ã€‚ -## ½ø³ÌÓëÏß³Ì +# 第二章 进程管ç�† -### 1. ½ø³Ì +## 进程与线程 -½ø³ÌÊDzÙ×÷ϵͳ½øÐÐ×ÊÔ´·ÖÅäµÄ»ù±¾µ¥Î»¡£ +### 1. 进程 -½ø³Ì¿ØÖÆ¿é (Process Control Block, PCB) ÃèÊö½ø³ÌµÄ»ù±¾ÐÅÏ¢ºÍÔËÐÐ״̬£¬ËùνµÄ´´½¨½ø³ÌºÍ³·Ïú½ø³Ì£¬¶¼ÊÇÖ¸¶Ô PCB µÄ²Ù×÷¡£ +进程是æ“�作系统进行资æº�分é…�的基本å�•ä½�。 -### 2. Ïß³Ì +进程控制å�— (Process Control Block, PCB) æ��述进程的基本信æ�¯å’Œè¿�行状æ€�,所谓的创建进程和撤销进程,都是指对 PCB çš„æ“�作。 -Ò»¸ö½ø³ÌÖпÉÒÔÓжà¸öỊ̈߳¬Ïß³ÌÊǶÀÁ¢µ÷¶ÈµÄ»ù±¾µ¥Î»¡£Í¬Ò»¸ö½ø³ÌÖеĶà¸öÏß³ÌÖ®¼ä¿ÉÒÔ²¢·¢Ö´ÐУ¬ËüÃǹ²Ïí½ø³Ì×ÊÔ´¡£ +### 2. 线程 -### 3. Çø±ð +一个进程中å�¯ä»¥æœ‰å¤šä¸ªçº¿ç¨‹ï¼Œçº¿ç¨‹æ˜¯ç‹¬ç«‹è°ƒåº¦çš„基本å�•ä½�。å�Œä¸€ä¸ªè¿›ç¨‹ä¸­çš„多个线程之间å�¯ä»¥å¹¶å�‘执行,它们共享进程资æº�。 -- ÓµÓÐ×ÊÔ´£º½ø³ÌÊÇ×ÊÔ´·ÖÅäµÄ»ù±¾µ¥Î»£¬µ«ÊÇÏ̲߳»ÓµÓÐ×ÊÔ´£¬Ï߳̿ÉÒÔ·ÃÎÊÂÊÊô½ø³ÌµÄ×ÊÔ´¡£ +### 3. 区别 -- µ÷¶È£ºÏß³ÌÊǶÀÁ¢µ÷¶ÈµÄ»ù±¾µ¥Î»£¬ÔÚͬһ½ø³ÌÖУ¬Ï̵߳ÄÇл»²»»áÒýÆð½ø³ÌÇл»£¬´ÓÒ»¸ö½ø³ÌÄÚµÄÏß³ÌÇл»µ½ÁíÒ»¸ö½ø³ÌÖеÄÏß³Ìʱ£¬»áÒýÆð½ø³ÌÇл»¡£ +- 拥有资æº�:进程是资æº�分é…�的基本å�•ä½�,但是线程ä¸�拥有资æº�,线程å�¯ä»¥è®¿é—®çŽ‡å±žè¿›ç¨‹çš„èµ„æº�。 -- ϵͳ¿ªÏú£ºÓÉÓÚ´´½¨»ò³·Ïú½ø³Ìʱ£¬ÏµÍ³¶¼ÒªÎªÖ®·ÖÅä»ò»ØÊÕ×ÊÔ´£¬ÈçÄÚ´æ¿Õ¼ä¡¢I/O É豸µÈ£¬Òò´Ë²Ù×÷ϵͳËù¸¶³öµÄ¿ªÏúÔ¶´óÓÚ´´½¨»ò³·ÏúÏß³ÌʱµÄ¿ªÏú¡£ÀàËÆµØ£¬ÔÚ½øÐнø³ÌÇл»Ê±£¬Éæ¼°µ±Ç°Ö´Ðнø³Ì CPU »·¾³µÄ±£´æ¼°Ðµ÷¶È½ø³Ì CPU »·¾³µÄÉèÖ᣶øÏß³ÌÇл»Ê±Ö»Ðè±£´æºÍÉèÖÃÉÙÁ¿¼Ä´æÆ÷ÄÚÈÝ£¬¿ªÏúºÜС¡£ +- 调度:线程是独立调度的基本å�•ä½�,在å�Œä¸€è¿›ç¨‹ä¸­ï¼Œçº¿ç¨‹çš„切æ�¢ä¸�会引起进程切æ�¢ï¼Œä»Žä¸€ä¸ªè¿›ç¨‹å†…的线程切æ�¢åˆ°å�¦ä¸€ä¸ªè¿›ç¨‹ä¸­çš„线程时,会引起进程切æ�¢ã€‚ -- ͨÐÅ·½Ã棺½ø³Ì¼äͨÐÅ (IPC) ÐèÒª½ø³Ìͬ²½ºÍ»¥³âÊֶεĸ¨Öú£¬ÒÔ±£Ö¤Êý¾ÝµÄÒ»ÖÂÐÔ£¬¶øÏ̼߳ä¿ÉÒÔͨ¹ýÖ±½Ó¶Á/дͬһ½ø³ÌÖеÄÊý¾Ý¶Î£¨ÈçÈ«¾Ö±äÁ¿£©À´½øÐÐͨÐÅ¡£ +- 系统开销:由于创建或撤销进程时,系统都è¦�为之分é…�或回收资æº�,如内存空间ã€�I/O 设备等,因此æ“�作系统所付出的开销远大于创建或撤销线程时的开销。类似地,在进行进程切æ�¢æ—¶ï¼Œæ¶‰å�Šå½“å‰�执行进程 CPU 环境的ä¿�å­˜å�Šæ–°è°ƒåº¦è¿›ç¨‹ CPU 环境的设置。而线程切æ�¢æ—¶å�ªéœ€ä¿�存和设置少é‡�寄存器内容,开销很å°�。 -¾ÙÀý£ºQQ ºÍä¯ÀÀÆ÷ÊÇÁ½¸ö½ø³Ì£¬ä¯ÀÀÆ÷½ø³ÌÀïÃæÓкܶàỊ̈߳¬ÀýÈç HTTP ÇëÇóÏ̡߳¢Ê¼þÏìÓ¦Ï̡߳¢äÖȾÏ̵߳ȵȣ¬Ï̵߳IJ¢·¢Ö´ÐÐʹµÃÔÚä¯ÀÀÆ÷Öеã»÷Ò»¸öÐÂÁ´½Ó´Ó¶ø·¢Æð HTTP ÇëÇóʱ£¬ä¯ÀÀÆ÷»¹¿ÉÒÔÏìÓ¦Óû§µÄÆäËüʼþ¡£ +- 通信方é�¢ï¼šè¿›ç¨‹é—´é€šä¿¡ (IPC) 需è¦�进程å�Œæ­¥å’Œäº’斥手段的辅助,以ä¿�è¯�æ•°æ�®çš„一致性,而线程间å�¯ä»¥é€šè¿‡ç›´æŽ¥è¯»/写å�Œä¸€è¿›ç¨‹ä¸­çš„æ•°æ�®æ®µï¼ˆå¦‚全局å�˜é‡�)æ�¥è¿›è¡Œé€šä¿¡ã€‚ -## ½ø³Ì״̬µÄÇл» +举例:QQ å’Œæµ�览器是两个进程,æµ�览器进程里é�¢æœ‰å¾ˆå¤šçº¿ç¨‹ï¼Œä¾‹å¦‚ HTTP 请求线程ã€�事件å“�应线程ã€�渲染线程等等,线程的并å�‘执行使得在æµ�览器中点击一个新链接从而å�‘èµ· HTTP 请求时,æµ�览器还å�¯ä»¥å“�应用户的其它事件。 -![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/1706ce58-a081-4fed-9b36-c3c0d7e22b3a.jpg) +## 进程状æ€�的切æ�¢ -×èÈû״̬ÊÇȱÉÙÐèÒªµÄ×ÊÔ´´Ó¶øÓÉÔËÐÐ״̬ת»»¶øÀ´£¬µ«ÊǸÃ×ÊÔ´²»°üÀ¨ CPU£¬È±ÉÙ CPU »áÈýø³Ì´ÓÔËÐÐ̬ת»»Îª¾ÍÐ÷̬¡£ +![](https://github.com/CyC2018/InterviewNotes/blob/master/pics//1706ce58-a081-4fed-9b36-c3c0d7e22b3a.jpg) -Ö»ÓоÍÐ÷̬ºÍÔËÐÐ̬¿ÉÒÔÏ໥ת»»£¬ÆäËüµÄ¶¼Êǵ¥Ïòת»»¡£¾ÍÐ÷״̬µÄ½ø³Ìͨ¹ýµ÷¶ÈËã·¨´Ó¶ø»ñµÃ CPU ʱ¼ä£¬×ªÎªÔËÐÐ״̬£»¶øÔËÐÐ״̬µÄ½ø³Ì£¬ÔÚ·ÖÅ䏸ËüµÄ CPU ʱ¼äƬÓÃÍêÖ®ºó¾Í»áתΪ¾ÍÐ÷״̬£¬µÈ´ýÏÂÒ»´Îµ÷¶È¡£ +阻塞状æ€�是缺少需è¦�的资æº�从而由è¿�行状æ€�转æ�¢è€Œæ�¥ï¼Œä½†æ˜¯è¯¥èµ„æº�ä¸�包括 CPU,缺少 CPU 会让进程从è¿�行æ€�转æ�¢ä¸ºå°±ç»ªæ€�。 -## µ÷¶ÈËã·¨ +å�ªæœ‰å°±ç»ªæ€�å’Œè¿�行æ€�å�¯ä»¥ç›¸äº’转æ�¢ï¼Œå…¶å®ƒçš„都是å�•å�‘转æ�¢ã€‚就绪状æ€�的进程通过调度算法从而获得 CPU 时间,转为è¿�行状æ€�;而è¿�行状æ€�的进程,在分é…�给它的 CPU 时间片用完之å�Žå°±ä¼šè½¬ä¸ºå°±ç»ªçжæ€�,等待下一次调度。 -ÐèÒªÕë¶Ô²»Í¬»·¾³À´ÌÖÂÛµ÷¶ÈËã·¨¡£ +## 调度算法 -### 1. Åú´¦ÀíϵͳÖеĵ÷¶È +需è¦�针对ä¸�å�ŒçŽ¯å¢ƒæ�¥è®¨è®ºè°ƒåº¦ç®—法。 -#### 1.1 ÏÈÀ´ÏÈ·þÎñ +### 1. 批处ç�†ç³»ç»Ÿä¸­çš„调度 -first-come first-serverd£¨FCFS£©¡£ +#### 1.1 å…ˆæ�¥å…ˆæœ�务 -µ÷¶È×îÏȽøÈë¾ÍÐ÷¶ÓÁеÄ×÷Òµ¡£ +first-come first-serverd(FCFS)。 -ÓÐÀûÓÚ³¤×÷Òµ£¬µ«²»ÀûÓÚ¶Ì×÷Òµ£¬ÒòΪ¶Ì×÷Òµ±ØÐëÒ»Ö±µÈ´ýÇ°ÃæµÄ³¤×÷ÒµÖ´ÐÐÍê±Ï²ÅÄÜÖ´ÐУ¬¶ø³¤×÷ÒµÓÖÐèÒªÖ´Ðкܳ¤Ê±¼ä£¬Ôì³ÉÁ˶Ì×÷ÒµµÈ´ýʱ¼ä¹ý³¤¡£ +调度最先进入就绪队列的作业。 -#### 1.2 ¶Ì×÷ÒµÓÅÏÈ +有利于长作业,但ä¸�利于短作业,因为短作业必须一直等待å‰�é�¢çš„长作业执行完毕æ‰�能执行,而长作业å�ˆéœ€è¦�执行很长时间,造æˆ�了短作业等待时间过长。 -shortest job first£¨SJF£©¡£ +#### 1.2 短作业优先 -µ÷¶È¹À¼ÆÔËÐÐʱ¼ä×î¶ÌµÄ×÷Òµ¡£ +shortest job first(SJF)。 -³¤×÷ÒµÓпÉÄÜ»á¶öËÀ£¬´¦ÓÚÒ»Ö±µÈ´ý¶Ì×÷ÒµÖ´ÐÐÍê±ÏµÄ״̬¡£Èç¹ûÒ»Ö±ÓжÌ×÷Òµµ½À´£¬ÄÇô³¤×÷ÒµÓÀÔ¶µÃ²»µ½µ÷¶È¡£ +调度估计è¿�行时间最短的作业。 -#### 1.3 ×î¶ÌÊ£Óàʱ¼äÓÅÏÈ +长作业有å�¯èƒ½ä¼šé¥¿æ­»ï¼Œå¤„于一直等待短作业执行完毕的状æ€�。如果一直有短作业到æ�¥ï¼Œé‚£ä¹ˆé•¿ä½œä¸šæ°¸è¿œå¾—ä¸�到调度。 -shortest remaining time next£¨SRTN£©¡£ +#### 1.3 最短剩余时间优先 -### 2. ½»»¥Ê½ÏµÍ³Öеĵ÷¶È +shortest remaining time next(SRTN)。 -#### 2.1 ÓÅÏÈȨÓÅÏÈ +### 2. 交互å¼�系统中的调度 -³ýÁË¿ÉÒÔÊÖ¶¯¸³ÓèÓÅÏÈȨ֮Í⣬»¹¿ÉÒÔ°ÑÏìÓ¦±È×÷ΪÓÅÏÈȨ£¬ÕâÖÖµ÷¶È·½Ê½½Ð×ö¸ßÏìÓ¦±ÈÓÅÏȵ÷¶ÈËã·¨¡£ +#### 2.1 优先æ�ƒä¼˜å…ˆ -ÏìÓ¦±È = (µÈ´ýʱ¼ä + ÒªÇó·þÎñʱ¼ä) / ÒªÇó·þÎñʱ¼ä = ÏìӦʱ¼ä / ÒªÇó·þÎñʱ¼ä +除了å�¯ä»¥æ‰‹åŠ¨èµ‹äºˆä¼˜å…ˆæ�ƒä¹‹å¤–,还å�¯ä»¥æŠŠå“�应比作为优先æ�ƒï¼Œè¿™ç§�调度方å¼�å�«å�šé«˜å“�应比优先调度算法。 -ÕâÖÖµ÷¶ÈËã·¨Ö÷ÒªÊÇΪÁ˽â¾ö SJF Öг¤×÷Òµ¿ÉÄÜ»á¶öËÀµÄÎÊÌ⣬ÒòÎªËæ×ŵȴýʱ¼äµÄÔö³¤£¬ÏìÓ¦±ÈÒ²»áÔ½À´Ô½¸ß¡£ +å“�应比 = (等待时间 + è¦�求æœ�务时间) / è¦�求æœ�务时间 = å“�应时间 / è¦�求æœ�务时间 -#### 2.2 ʱ¼äƬÂÖת +è¿™ç§�调度算法主è¦�是为了解决 SJF 中长作业å�¯èƒ½ä¼šé¥¿æ­»çš„问题,因为éš�ç�€ç­‰å¾…时间的增长,å“�应比也会越æ�¥è¶Šé«˜ã€‚ -½«ËùÓоÍÐ÷½ø³Ì°´ FCFS µÄÔ­ÔòÅųÉÒ»¸ö¶ÓÁУ¬Ã¿´Îµ÷¶Èʱ£¬°Ñ CPU ·ÖÅ䏸¶ÓÊ×½ø³Ì£¬¸Ã½ø³Ì¿ÉÒÔÖ´ÐÐÒ»¸öʱ¼äƬ¡£µ±Ê±¼äƬÓÃÍêʱ£¬ÓɼÆÊ±Æ÷·¢³öʱÖÓÖжϣ¬µ÷¶È³ÌÐò±ãÍ£Ö¹¸Ã½ø³ÌµÄÖ´ÐУ¬²¢½«ËüËÍÍù¾ÍÐ÷¶ÓÁеÄĩβ£¬Í¬Ê±¼ÌÐø°Ñ CPU ·ÖÅ䏸¶ÓÊ׵Ľø³Ì¡£ +#### 2.2 时间片轮转 -ʱ¼äƬÂÖתËã·¨µÄЧÂʺÍʱ¼äƬµÄ´óСÓкܴó¹ØÏµ¡£ÒòΪÿ´Î½ø³ÌÇл»¶¼Òª±£´æ½ø³ÌµÄÐÅÏ¢²¢ÇÒÔØÈëнø³ÌµÄÐÅÏ¢£¬Èç¹ûʱ¼äƬ̫С£¬½ø³ÌÇл»Ì«Æµ·±£¬ÔÚ½ø³ÌÇл»ÉϾͻỨ¹ý¶àʱ¼ä¡£ +将所有就绪进程按 FCFS 的原则排æˆ�一个队列,æ¯�次调度时,把 CPU 分é…�给队首进程,该进程å�¯ä»¥æ‰§è¡Œä¸€ä¸ªæ—¶é—´ç‰‡ã€‚当时间片用完时,由计时器å�‘出时钟中断,调度程åº�便å�œæ­¢è¯¥è¿›ç¨‹çš„æ‰§è¡Œï¼Œå¹¶å°†å®ƒé€�往就绪队列的末尾,å�Œæ—¶ç»§ç»­æŠŠ CPU 分é…�给队首的进程。 -#### 2.3 ¶à¼¶·´À¡¶ÓÁÐ +时间片轮转算法的效率和时间片的大å°�有很大关系。因为æ¯�次进程切æ�¢éƒ½è¦�ä¿�存进程的信æ�¯å¹¶ä¸”载入新进程的信æ�¯ï¼Œå¦‚果时间片太å°�,进程切æ�¢å¤ªé¢‘ç¹�,在进程切æ�¢ä¸Šå°±ä¼šèŠ±è¿‡å¤šæ—¶é—´ã€‚ -![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/042cf928-3c8e-4815-ae9c-f2780202c68f.png) +#### 2.3 多级å��馈队列 -1. ÉèÖöà¸ö¾ÍÐ÷¶ÓÁУ¬²¢Îª¸÷¸ö¶ÓÁи³Ó費ͬµÄÓÅÏȼ¶¡£µÚÒ»¸ö¶ÓÁеÄÓÅÏȼ¶×î¸ß£¬µÚ¶þ¸ö¶ÓÁдÎÖ®£¬ÆäÓà¸÷¶ÓÁеÄÓÅÏÈȨÖð¸ö½µµÍ¡£¸ÃËã·¨¸³Óè¸÷¸ö¶ÓÁÐÖнø³ÌÖ´ÐÐʱ¼äƬµÄ´óСҲ¸÷²»Ïàͬ£¬ÔÚÓÅÏÈȨԽ¸ßµÄ¶ÓÁÐÖУ¬ÎªÃ¿¸ö½ø³ÌËù¹æ¶¨µÄÖ´ÐÐʱ¼äƬ¾ÍԽС¡£ +![](https://github.com/CyC2018/InterviewNotes/blob/master/pics//042cf928-3c8e-4815-ae9c-f2780202c68f.png) -2. µ±Ò»¸öнø³Ì½øÈëÄÚ´æºó£¬Ê×ÏȽ«Ëü·ÅÈëµÚÒ»¶ÓÁеÄĩ⣬°´ FCFS Ô­ÔòÅŶӵȴýµ÷¶È¡£µ±ÂÖµ½¸Ã½ø³ÌÖ´ÐÐʱ£¬ÈçËüÄÜÔÚ¸Ãʱ¼äƬÄÚÍê³É£¬±ã¿É×¼±¸³·Àëϵͳ£»Èç¹ûËüÔÚÒ»¸öʱ¼äƬ½áÊøÊ±ÉÐδÍê³É£¬µ÷¶È³ÌÐò±ã½«¸Ã½ø³ÌתÈëÏÂÒ»¸ö¶ÓÁеĶÓβ¡£ +1. 设置多个就绪队列,并为å�„个队列赋予ä¸�å�Œçš„优先级。第一个队列的优先级最高,第二个队列次之,其余å�„队列的优先æ�ƒé€�个é™�低。该算法赋予å�„个队列中进程执行时间片的大å°�也å�„ä¸�相å�Œï¼Œåœ¨ä¼˜å…ˆæ�ƒè¶Šé«˜çš„队列中,为æ¯�个进程所规定的执行时间片就越å°�。 -3. ½öµ±Ç° i -1 ¸ö¶ÓÁоù¿Õʱ£¬²Å»áµ÷¶ÈµÚ i ¸ö¶ÓÁÐÖеĽø³Ì¡£ +2. 当一个新进程进入内存å�Žï¼Œé¦–先将它放入第一队列的末尾,按 FCFS 原则排队等待调度。当轮到该进程执行时,如它能在该时间片内完æˆ�,便å�¯å‡†å¤‡æ’¤ç¦»ç³»ç»Ÿï¼›å¦‚果它在一个时间片结æ�Ÿæ—¶å°šæœªå®Œæˆ�,调度程åº�便将该进程转入下一个队列的队尾。 -Óŵ㣺ʵʱÐԺã¬Í¬Ê±ÊʺÏÔËÐжÌ×÷ÒµºÍ³¤×÷Òµ¡£ +3. 仅当å‰� i -1 个队列å�‡ç©ºæ—¶ï¼Œæ‰�会调度第 i 个队列中的进程。 -#### 2.4 ¶Ì½ø³ÌÓÅÏÈ +优点:实时性好,å�Œæ—¶é€‚å�ˆè¿�行短作业和长作业。 -### 3. ʵʱϵͳÖеĵ÷¶È +#### 2.4 短进程优先 -ʵʱϵͳҪһ¸ö·þÎñÇëÇóÔÚÒ»¸öÈ·¶¨Ê±¼äÄڵõ½ÏìÓ¦¡£ +### 3. 实时系统中的调度 -·ÖΪӲʵʱºÍÈíʵʱ£¬Ç°Õß±ØÐëÂú×ã¾ø¶ÔµÄ½ØÖ¹Ê±¼ä£¬ºóÕß¿ÉÒÔÈÝÈÌÒ»¶¨µÄ³¬Ê±¡£ +实时系统è¦�一个æœ�务请求在一个确定时间内得到å“�应。 -## ½ø³Ìͬ²½ +分为硬实时和软实时,å‰�者必须满足ç»�对的截止时间,å�Žè€…å�¯ä»¥å®¹å¿�一定的超时。 -### 1. ÁÙ½çÇø +## 进程å�Œæ­¥ -¶ÔÁÙ½ç×ÊÔ´½øÐзÃÎʵÄÄǶδúÂë³ÆÎªÁÙ½çÇø¡£ +### 1. 临界区 -ΪÁË»¥³â·ÃÎÊÁÙ½ç×ÊÔ´£¬Ã¿¸ö½ø³ÌÔÚ½øÈëÁÙ½çÇøÖ®Ç°£¬ÐèÒªÏȽøÐмì²é¡£ +对临界资æº�进行访问的那段代ç �称为临界区。 + +为了互斥访问临界资æº�,æ¯�个进程在进入临界区之å‰�,需è¦�先进行检查。 ```html // entry section @@ -250,44 +251,44 @@ shortest remaining time next // exit section ``` -### 2. ͬ²½Ó뻥³â +### 2. å�Œæ­¥ä¸Žäº’æ–¥ -ͬ²½Ö¸¶à¸ö½ø³Ì°´Ò»¶¨Ë³ÐòÖ´ÐУ»»¥³âÖ¸¶à¸ö½ø³ÌÔÚͬһʱ¿ÌÖ»ÓÐÒ»¸ö½ø³ÌÄܽøÈëÁÙ½çÇø¡£ +å�Œæ­¥æŒ‡å¤šä¸ªè¿›ç¨‹æŒ‰ä¸€å®šé¡ºåº�执行;互斥指多个进程在å�Œä¸€æ—¶åˆ»å�ªæœ‰ä¸€ä¸ªè¿›ç¨‹èƒ½è¿›å…¥ä¸´ç•ŒåŒºã€‚ -ͬ²½ÊÇÔÚ¶ÔÁÙ½çÇø»¥³â·ÃÎʵĻù´¡ÉÏ£¬Í¨¹ýÆäËü»úÖÆÀ´ÊµÏÖÓÐÐò·ÃÎʵġ£ +å�Œæ­¥æ˜¯åœ¨å¯¹ä¸´ç•ŒåŒºäº’斥访问的基础上,通过其它机制æ�¥å®žçŽ°æœ‰åº�访问的。 -### 3. ÐźÅÁ¿ +### 3. ä¿¡å�·é‡� -**ÐźÅÁ¿£¨Samaphore£©** ÊÇÒ»¸öÕûÐͱäÁ¿£¬¿ÉÒÔ¶ÔÆäÖ´ÐÐ down ºÍ up ²Ù×÷£¬Ò²¾ÍÊdz£¼ûµÄ P ºÍ V ²Ù×÷¡£ +**ä¿¡å�·é‡�(Samaphore)** 是一个整型å�˜é‡�,å�¯ä»¥å¯¹å…¶æ‰§è¡Œ down å’Œ up æ“�作,也就是常è§�çš„ P å’Œ V æ“�作。 -- **down** : Èç¹ûÐźÅÁ¿´óÓÚ 0 £¬Ö´ÐÐ -1 ²Ù×÷£»Èç¹ûÐźÅÁ¿µÈÓÚ 0£¬½«½ø³Ì˯Ãߣ¬µÈ´ýÐźÅÁ¿´óÓÚ 0£» -- **up**£º¶ÔÐźÅÁ¿Ö´ÐÐ +1 ²Ù×÷£¬²¢ÇÒ»½ÐÑ˯ÃߵĽø³Ì£¬Èýø³ÌÍê³É down ²Ù×÷¡£ +- **down** : 如果信å�·é‡�大于 0 ,执行 -1 æ“�作;如果信å�·é‡�等于 0,将进程ç�¡çœ ï¼Œç­‰å¾…ä¿¡å�·é‡�大于 0ï¼› +- **up**:对信å�·é‡�执行 +1 æ“�作,并且唤醒ç�¡çœ çš„进程,让进程完æˆ� down æ“�作。 -down ºÍ up ²Ù×÷ÐèÒª±»Éè¼Æ³ÉÔ­Ó²»¿É·Ö¸î£¬Í¨³£µÄ×ö·¨ÊÇÔÚÖ´ÐÐÕâЩ²Ù×÷µÄʱºòÆÁ±ÎÖжϡ£ +down å’Œ up æ“�作需è¦�被设计æˆ�原语,ä¸�å�¯åˆ†å‰²ï¼Œé€šå¸¸çš„å�šæ³•æ˜¯åœ¨æ‰§è¡Œè¿™äº›æ“�作的时候å±�蔽中断。 -Èç¹ûÐźÅÁ¿µÄȡֵֻÄÜΪ 0 »òÕß 1£¬ÄÇô¾Í³ÉΪÁË**»¥³âÁ¿£¨Mutex£©**£¬0 ±íʾÁÙ½çÇøÒѾ­¼ÓËø£¬1 ±íʾÁÙ½çÇø½âËø¡£ +如果信å�·é‡�çš„å�–值å�ªèƒ½ä¸º 0 或者 1,那么就æˆ�为了**互斥é‡�(Mutex)**,0 表示临界区已ç»�加é”�,1 表示临界区解é”�。 ```c typedef int samaphore; samaphore mutex = 1; void P1() { down(mutex); - // ÁÙ½çÇø + // 临界区 up(mutex); } void P2() { down(mutex); - // ÁÙ½çÇø + // 临界区 up(mutex); } ``` -**ʹÓÃÐźÅÁ¿ÊµÏÖÉú²úÕß-Ïû·ÑÕßÎÊÌâ** +**使用信å�·é‡�实现生产者-消费者问题** -ʹÓÃÒ»¸ö»¥³âÁ¿ mutex À´¶ÔÁÙ½ç×ÊÔ´½øÐзÃÎÊ£»empty ¼Ç¼¿Õ»º³åÇøµÄÊýÁ¿£¬full ¼Ç¼Âú»º³åÇøµÄÊýÁ¿¡£ +使用一个互斥é‡� mutex æ�¥å¯¹ä¸´ç•Œèµ„æº�进行访问;empty 记录空缓冲区的数é‡�,full 记录满缓冲区的数é‡�。 -×¢Ò⣬±ØÐëÏÈÖ´ÐÐ down ²Ù×÷ÔÙÓû¥³âÁ¿¶ÔÁÙ½çÇø¼ÓËø£¬·ñÔò»á³öÏÖËÀËø¡£ÒòΪÈç¹û¶¼ÏȶÔÁÙ½çÇø¼ÓËø£¬È»ºóÔÙÖ´ÐÐ down ²Ù×÷£¬ÄÇô¿ÉÄÜ»á³öÏÖÕâÖÖÇé¿ö£ºÉú²úÕß¶ÔÁÙ½çÇø¼ÓËøºó£¬Ö´ÐÐ down(empty) ²Ù×÷£¬·¢ÏÖ empty = 0£¬´ËʱÉú³ÉÕß˯Ãß¡£Ïû·ÑÕß´Ëʱ²»ÄܽøÈëÁÙ½çÇø£¬ÒòΪÉú²úÕß¶ÔÁÙ½çÇø¼ÓËøÁË£¬Ò²¾ÍÎÞ·¨Ö´ÐÐ up(empty) ²Ù×÷£¬ÄÇôÉú²úÕߺÍÏû·ÑÕ߾ͻáÒ»Ö±µÈ´ýÏÂÈ¥¡£ +注æ„�,必须先执行 down æ“�作å†�用互斥é‡�对临界区加é”�,å�¦åˆ™ä¼šå‡ºçŽ°æ­»é”�。因为如果都先对临界区加é”�,然å�Žå†�执行 down æ“�作,那么å�¯èƒ½ä¼šå‡ºçŽ°è¿™ç§�情况:生产者对临界区加é”�å�Žï¼Œæ‰§è¡Œ down(empty) æ“�作,å�‘现 empty = 0,此时生æˆ�者ç�¡çœ ã€‚消费者此时ä¸�能进入临界区,因为生产者对临界区加é”�了,也就无法执行 up(empty) æ“�作,那么生产者和消费者就会一直等待下去。 ```c #define N 100 @@ -319,11 +320,11 @@ void consumer() { } ``` -### 4. ¹Ü³Ì +### 4. 管程 -ʹÓÃÐźÅÁ¿»úÖÆÊµÏÖµÄÉú²úÕßÏû·ÑÕßÎÊÌâÐèÒª¿Í»§¶Ë´úÂë×öºÜ¶à¿ØÖÆ£¬¶ø¹Ü³Ì°Ñ¿ØÖƵĴúÂë¶ÀÁ¢³öÀ´£¬²»½ö²»ÈÝÒ׳ö´í£¬Ò²Ê¹µÃ¿Í»§¶Ë´úÂëµ÷ÓøüÈÝÒס£ +使用信å�·é‡�机制实现的生产者消费者问题需è¦�客户端代ç �å�šå¾ˆå¤šæŽ§åˆ¶ï¼Œè€Œç®¡ç¨‹æŠŠæŽ§åˆ¶çš„代ç �独立出æ�¥ï¼Œä¸�ä»…ä¸�容易出错,也使得客户端代ç �调用更容易。 -c ÓïÑÔ²»Ö§³Ö¹Ü³Ì£¬ÏÂÃæµÄʾÀý´úÂëʹÓÃÁËÀà Pascal ÓïÑÔÀ´ÃèÊö¹Ü³Ì¡£Ê¾Àý´úÂëÖеĹܳÌÌṩÁË insert() ºÍ remove() ·½·¨£¬¿Í»§¶Ë´úÂëͨ¹ýµ÷ÓÃÕâÁ½¸ö·½·¨À´½â¾öÉú²úÕß-Ïû·ÑÕßÎÊÌâ¡£ +c 语言ä¸�支æŒ�管程,下é�¢çš„示例代ç �使用了类 Pascal 语言æ�¥æ��述管程。示例代ç �中的管程æ��供了 insert() å’Œ remove() 方法,客户端代ç �通过调用这两个方法æ�¥è§£å†³ç”Ÿäº§è€…-消费者问题。 ```pascal monitor ProducerConsumer @@ -342,11 +343,11 @@ monitor ProducerConsumer end monitor; ``` -¹Ü³ÌÓÐÒ»¸öÖØÒªÌØÐÔ£ºÔÚÒ»¸öʱ¿ÌÖ»ÄÜÓÐÒ»¸ö½ø³ÌʹÓù̡ܳ£½ø³ÌÔÚÎÞ·¨¼ÌÐøÖ´ÐеÄʱºò²»ÄÜÒ»Ö±Õ¼Óụ̀ܳ¬·ñÕ߯äËü½ø³ÌÓÀÔ¶²»ÄÜʹÓù̡ܳ£ +管程有一个é‡�è¦�特性:在一个时刻å�ªèƒ½æœ‰ä¸€ä¸ªè¿›ç¨‹ä½¿ç”¨ç®¡ç¨‹ã€‚进程在无法继续执行的时候ä¸�能一直å� ç”¨ç®¡ç¨‹ï¼Œå�¦è€…其它进程永远ä¸�能使用管程。 -¹Ü³ÌÒýÈëÁË **Ìõ¼þ±äÁ¿** ÒÔ¼°Ïà¹ØµÄ²Ù×÷£º**wait()** ºÍ **signal()** À´ÊµÏÖͬ²½²Ù×÷¡£¶ÔÌõ¼þ±äÁ¿Ö´ÐÐ wait() ²Ù×÷»áµ¼Öµ÷Óýø³Ì×èÈû£¬°Ñ¹Ü³ÌÈóöÀ´ÈÃÁíÒ»¸ö½ø³Ì³ÖÓС£signal() ²Ù×÷ÓÃÓÚ»½Ðѱ»×èÈûµÄ½ø³Ì¡£ +管程引入了 **æ�¡ä»¶å�˜é‡�** 以å�Šç›¸å…³çš„æ“�作:**wait()** å’Œ **signal()** æ�¥å®žçްå�Œæ­¥æ“�作。对æ�¡ä»¶å�˜é‡�执行 wait() æ“�作会导致调用进程阻塞,把管程让出æ�¥è®©å�¦ä¸€ä¸ªè¿›ç¨‹æŒ�有。signal() æ“�作用于唤醒被阻塞的进程。 -**ʹÓùܳÌʵÏÖÉú³ÉÕß-Ïû·ÑÕßÎÊÌâ** +**使用管程实现生æˆ�者-消费者问题** ```pascal monitor ProducerConsumer @@ -390,53 +391,53 @@ begin end; ``` -## ½ø³ÌͨÐÅ +## 进程通信 -½ø³ÌͨÐÅ¿ÉÒÔ¿´³ÉÊDz»Í¬½ø³Ì¼äµÄÏß³ÌͨÐÅ£¬¶ÔÓÚͬһ¸ö½ø³ÌÄÚÏ̵߳ÄͨÐÅ·½Ê½£¬Ö÷ҪʹÓÃÐźÅÁ¿¡¢Ìõ¼þ±äÁ¿µÈͬ²½»úÖÆ¡£ +进程通信å�¯ä»¥çœ‹æˆ�是ä¸�å�Œè¿›ç¨‹é—´çš„线程通信,对于å�Œä¸€ä¸ªè¿›ç¨‹å†…线程的通信方å¼�,主è¦�使用信å�·é‡�ã€�æ�¡ä»¶å�˜é‡�ç­‰å�Œæ­¥æœºåˆ¶ã€‚ -### 1. ¹ÜµÀ +### 1. 管é�“ -¹ÜµÀÊǵ¥ÏòµÄ¡¢ÏȽøÏȳöµÄ¡¢Î޽ṹµÄ¡¢¹Ì¶¨´óСµÄ×Ö½ÚÁ÷£¬Ëü°ÑÒ»¸ö½ø³ÌµÄ±ê×¼Êä³öºÍÁíÒ»¸ö½ø³ÌµÄ±ê×¼ÊäÈëÁ¬½ÓÔÚÒ»Æð¡£Ð´½ø³ÌÔڹܵÀµÄβ¶ËдÈëÊý¾Ý£¬¶Á½ø³ÌÔڹܵÀµÄÊ׶˶Á³öÊý¾Ý¡£Êý¾Ý¶Á³öºó½«´Ó¹ÜµÀÖÐÒÆ×ߣ¬ÆäËü¶Á½ø³Ì¶¼²»ÄÜÔÙ¶Áµ½ÕâЩÊý¾Ý¡£ +管é�“是å�•å�‘çš„ã€�先进先出的ã€�无结构的ã€�固定大å°�的字节æµ�,它把一个进程的标准输出和å�¦ä¸€ä¸ªè¿›ç¨‹çš„æ ‡å‡†è¾“入连接在一起。写进程在管é�“的尾端写入数æ�®ï¼Œè¯»è¿›ç¨‹åœ¨ç®¡é�“的首端读出数æ�®ã€‚æ•°æ�®è¯»å‡ºå�Žå°†ä»Žç®¡é�“中移走,其它读进程都ä¸�能å†�读到这些数æ�®ã€‚ -¹ÜµÀÌṩÁ˼òµ¥µÄÁ÷¿ØÖÆ»úÖÆ£¬½ø³ÌÊÔͼ¶Á¿Õ¹ÜµÀʱ£¬ÔÚÓÐÊý¾ÝдÈë¹ÜµÀǰ£¬½ø³Ì½«Ò»Ö±×èÈû¡£Í¬ÑùµØ£¬¹ÜµÀÒѾ­Âúʱ£¬½ø³ÌÔÙÊÔͼд¹ÜµÀ£¬ÔÚÆäËü½ø³Ì´Ó¹ÜµÀÖÐÒÆ×ßÊý¾Ý֮ǰ£¬Ð´½ø³Ì½«Ò»Ö±×èÈû¡£ +管é�“æ��供了简å�•çš„æµ�控制机制,进程试图读空管é�“时,在有数æ�®å†™å…¥ç®¡é�“å‰�,进程将一直阻塞。å�Œæ ·åœ°ï¼Œç®¡é�“å·²ç»�满时,进程å†�试图写管é�“,在其它进程从管é�“中移走数æ�®ä¹‹å‰�,写进程将一直阻塞。 -Linux ÖйܵÀÊÇͨ¹ý¿ÕÎļþÀ´ÊµÏÖ¡£ +Linux 中管é�“是通过空文件æ�¥å®žçŽ°ã€‚ -¹ÜµÀÓÐÈýÖÖ£º +管é�“有三ç§�: -1. ÆÕͨ¹ÜµÀ£ºÓÐÁ½¸öÏÞÖÆ£ºÒ»ÊÇÖ»Ö§³Ö°ëË«¹¤Í¨ÐÅ·½Ê½£¬¼´Ö»Äܵ¥Ïò´«Ê䣻¶þÊÇÖ»ÄÜÔÚ¸¸×Ó½ø³ÌÖ®¼äʹÓã» -2. Á÷¹ÜµÀ£ºÈ¥³ýµÚÒ»¸öÏÞÖÆ£¬Ö§³ÖË«Ïò´«Ê䣻 -3. ÃüÃû¹ÜµÀ£ºÈ¥³ýµÚ¶þ¸öÏÞÖÆ£¬¿ÉÒÔÔÚ²»Ïà¹Ø½ø³ÌÖ®¼ä½øÐÐͨÐÅ¡£ +1. 普通管é�“:有两个é™�制:一是å�ªæ”¯æŒ�å�Šå�Œå·¥é€šä¿¡æ–¹å¼�,å�³å�ªèƒ½å�•å�‘传输;二是å�ªèƒ½åœ¨çˆ¶å­�进程之间使用; +2. æµ�管é�“:去除第一个é™�制,支æŒ�å�Œå�‘传输; +3. 命å��管é�“:去除第二个é™�制,å�¯ä»¥åœ¨ä¸�相关进程之间进行通信。 -### 2. ÐźÅÁ¿ +### 2. ä¿¡å�·é‡� -ÐźÅÁ¿ÊÇÒ»¸ö¼ÆÊýÆ÷£¬¿ÉÒÔÓÃÀ´¿ØÖƶà¸ö½ø³Ì¶Ô¹²Ïí×ÊÔ´µÄ·ÃÎÊ¡£Ëü³£×÷ΪһÖÖËø»úÖÆ£¬·Àֹij½ø³ÌÕýÔÚ·ÃÎʹ²Ïí×ÊԴʱ£¬ÆäËü½ø³ÌÒ²·ÃÎʸÃ×ÊÔ´¡£Òò´Ë£¬Ö÷Òª×÷Ϊ½ø³Ì¼äÒÔ¼°Í¬Ò»½ø³ÌÄÚ²»Í¬Ïß³ÌÖ®¼äµÄͬ²½ÊֶΡ£ +ä¿¡å�·é‡�是一个计数器,å�¯ä»¥ç”¨æ�¥æŽ§åˆ¶å¤šä¸ªè¿›ç¨‹å¯¹å…±äº«èµ„æº�的访问。它常作为一ç§�é”�机制,防止æŸ�进程正在访问共享资æº�时,其它进程也访问该资æº�。因此,主è¦�作为进程间以å�Šå�Œä¸€è¿›ç¨‹å†…ä¸�å�Œçº¿ç¨‹ä¹‹é—´çš„å�Œæ­¥æ‰‹æ®µã€‚ -### 3. ÏûÏ¢¶ÓÁÐ +### 3. 消æ�¯é˜Ÿåˆ— -ÏûÏ¢¶ÓÁп˷þÁËÐźŴ«µÝÐÅÏ¢ÉÙ¡¢¹ÜµÀÖ»ÄܳÐÔØÎÞ¸ñʽ×Ö½ÚÁ÷ÒÔ¼°»º³åÇø´óСÊÜÏÞµÈȱµã¡£ +消æ�¯é˜Ÿåˆ—å…‹æœ�了信å�·ä¼ é€’ä¿¡æ�¯å°‘ã€�管é�“å�ªèƒ½æ‰¿è½½æ— æ ¼å¼�字节æµ�以å�Šç¼“冲区大å°�å�—é™�等缺点。 -### 4. ÐźŠ+### 4. ä¿¡å�· -ÐźÅÊÇÒ»ÖֱȽϸ´ÔÓµÄͨÐÅ·½Ê½£¬ÓÃÓÚ֪ͨ½ÓÊÕ½ø³Ìij¸öʼþÒѾ­·¢Éú¡£ +ä¿¡å�·æ˜¯ä¸€ç§�比较å¤�æ�‚的通信方å¼�,用于通知接收进程æŸ�个事件已ç»�å�‘生。 -### 5. ¹²ÏíÄÚ´æ +### 5. 共享内存 -¹²ÏíÄÚ´æ¾ÍÊÇÓ³ÉäÒ»¶ÎÄܱ»ÆäËü½ø³ÌËù·ÃÎʵÄÄڴ棬Õâ¶Î¹²ÏíÄÚ´æÓÉÒ»¸ö½ø³Ì´´½¨£¬µ«¶à¸ö½ø³Ì¶¼¿ÉÒÔ·ÃÎÊ¡£¹²ÏíÄÚ´æÊÇ×î¿ìµÄ IPC ·½Ê½£¬ËüÊÇÕë¶ÔÆäËü IPC ÔËÐÐЧÂʵͶø×¨ÃÅÉè¼ÆµÄ¡£ËüÍùÍùÓëÆäËüͨÐÅ»úÖÆ£¨ÈçÐźÅÁ¿£©ÅäºÏʹÓã¬À´ÊµÏÖ½ø³Ì¼äµÄͬ²½ºÍͨÐÅ¡£ +共享内存就是映射一段能被其它进程所访问的内存,这段共享内存由一个进程创建,但多个进程都å�¯ä»¥è®¿é—®ã€‚共享内存是最快的 IPC æ–¹å¼�,它是针对其它 IPC è¿�行效率低而专门设计的。它往往与其它通信机制(如信å�·é‡�)é…�å�ˆä½¿ç”¨ï¼Œæ�¥å®žçŽ°è¿›ç¨‹é—´çš„å�Œæ­¥å’Œé€šä¿¡ã€‚ -### 6. Ì×½Ó×Ö +### 6. 套接字 -Ì×½Ó×ÖÒ²ÊÇÒ»ÖÖ½ø³Ì¼äͨÐÅ»úÖÆ£¬ÓëÆäËüͨÐÅ»úÖÆ²»Í¬µÄÊÇ£¬Ëü¿ÉÓÃÓÚ²»Í¬»úÆ÷¼äµÄ½ø³ÌͨÐÅ¡£ +套接字也是一ç§�进程间通信机制,与其它通信机制ä¸�å�Œçš„æ˜¯ï¼Œå®ƒå�¯ç”¨äºŽä¸�å�Œæœºå™¨é—´çš„进程通信。 -## ¾­µäͬ²½ÎÊÌâ +## ç»�å…¸å�Œæ­¥é—®é¢˜ -Éú²úÕߺÍÏû·ÑÕßÎÊÌâÇ°ÃæÒѾ­ÌÖÂÛ¹ý¡£ +生产者和消费者问题å‰�é�¢å·²ç»�讨论过。 -### 1. ¶ÁÕß-дÕßÎÊÌâ +### 1. 读者-写者问题 -ÔÊÐí¶à¸ö½ø³Ìͬʱ¶ÔÊý¾Ý½øÐжÁ²Ù×÷£¬µ«ÊDz»ÔÊÐí¶ÁºÍдÒÔ¼°Ð´ºÍд²Ù×÷ͬʱ·¢Éú¡£ +å…�许多个进程å�Œæ—¶å¯¹æ•°æ�®è¿›è¡Œè¯»æ“�作,但是ä¸�å…�许读和写以å�Šå†™å’Œå†™æ“�作å�Œæ—¶å�‘生。 -Ò»¸öÕûÐͱäÁ¿ count ¼Ç¼ÔÚ¶ÔÊý¾Ý½øÐжÁ²Ù×÷µÄ½ø³ÌÊýÁ¿£¬Ò»¸ö»¥³âÁ¿ count_mutex ÓÃÓÚ¶Ô count ¼ÓËø£¬Ò»¸ö»¥³âÁ¿ data_mutex ÓÃÓÚ¶Ô¶ÁдµÄÊý¾Ý¼ÓËø¡£ +一个整型å�˜é‡� count 记录在对数æ�®è¿›è¡Œè¯»æ“�作的进程数é‡�,一个互斥é‡� count_mutex 用于对 count 加é”�,一个互斥é‡� data_mutex 用于对读写的数æ�®åŠ é”�。 ```c typedef int semaphore; @@ -448,7 +449,7 @@ void reader() { while(TRUE) { down(count_mutex); count++; - if(count == 1) down(data_mutex); // µÚÒ»¸ö¶ÁÕßÐèÒª¶ÔÊý¾Ý½øÐмÓËø£¬·Àֹд½ø³Ì·ÃÎÊ + if(count == 1) down(data_mutex); // 第一个读者需è¦�对数æ�®è¿›è¡ŒåŠ é”�,防止写进程访问 up(count_mutex); read(); down(count_mutex); @@ -467,13 +468,13 @@ void writer() { } ``` -### 2. ÕÜѧ¼Ò½ø²ÍÎÊÌâ +### 2. 哲学家进é¤�问题 -![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/a9077f06-7584-4f2b-8c20-3a8e46928820.jpg) +![](https://github.com/CyC2018/InterviewNotes/blob/master/pics//a9077f06-7584-4f2b-8c20-3a8e46928820.jpg) -Îå¸öÕÜѧ¼ÒΧ×ÅÒ»ÕÅÔ²ÖÜ£¬Ã¿¸öÕÜѧ¼ÒÃæÇ°·Å×Å·¹¡£ÕÜѧ¼ÒµÄÉú»îÓÐÁ½ÖÖ½»Ìæ»î¶¯£º³Ô·¹ÒÔ¼°Ë¼¿¼¡£µ±Ò»¸öÕÜѧ¼Ò³Ô·¹Ê±£¬ÐèÒªÏÈÒ»¸ùÒ»¸ùÄÃÆð×óÓÒÁ½±ßµÄ¿ê×Ó¡£ +五个哲学家围ç�€ä¸€å¼ åœ†å‘¨ï¼Œæ¯�个哲学家é�¢å‰�放ç�€é¥­ã€‚哲学家的生活有两ç§�交替活动:å�ƒé¥­ä»¥å�Šæ€�考。当一个哲学家å�ƒé¥­æ—¶ï¼Œéœ€è¦�先一根一根拿起左å�³ä¸¤è¾¹çš„ç­·å­�。 -ÏÂÃæÊÇÒ»ÖÖ´íÎóµÄ½â·¨£¬¿¼Âǵ½Èç¹ûÿ¸öÕÜѧ¼ÒͬʱÄÃÆð×óÊֱߵĿê×Ó£¬ÄÇô¾ÍÎÞ·¨ÄÃÆðÓÒÊֱߵĿê×Ó£¬Ôì³ÉËÀËø¡£ +下é�¢æ˜¯ä¸€ç§�错误的解法,考虑到如果æ¯�个哲学家å�Œæ—¶æ‹¿èµ·å·¦æ‰‹è¾¹çš„ç­·å­�,那么就无法拿起å�³æ‰‹è¾¹çš„ç­·å­�,造æˆ�æ­»é”�。 ```c #define N 5 @@ -494,7 +495,7 @@ void philosopher(int i) { } ``` -ΪÁË·ÀÖ¹ËÀËøµÄ·¢Éú£¬¿ÉÒÔ¼ÓÒ»µãÏÞÖÆ£¬Ö»ÔÊÐíͬʱÄÃÆð×óÓÒÁ½±ßµÄ¿ê×Ó£¬·½·¨ÊÇÒýÈëÒ»¸ö»¥³âÁ¿£¬¶ÔÄÃÆðÁ½¸ö¿ê×ÓµÄÄǶδúÂë¼ÓËø¡£ +为了防止死é”�çš„å�‘生,å�¯ä»¥åŠ ä¸€ç‚¹é™�制,å�ªå…�许å�Œæ—¶æ‹¿èµ·å·¦å�³ä¸¤è¾¹çš„ç­·å­�,方法是引入一个互斥é‡�,对拿起两个筷å­�的那段代ç �加é”�。 ```c semaphore mutex = 1; @@ -515,220 +516,220 @@ void philosopher(int i) { } ``` -# µÚÈýÕ ËÀËø +# 第三章 æ­»é”� -## ËÀËøµÄÌõ¼þ +## æ­»é”�çš„æ�¡ä»¶ -![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/c037c901-7eae-4e31-a1e4-9d41329e5c3e.png) +![](https://github.com/CyC2018/InterviewNotes/blob/master/pics//c037c901-7eae-4e31-a1e4-9d41329e5c3e.png) -1. »¥³â -2. ÇëÇóÓë±£³Ö -3. ²»¿ÉÇÀÕ¼ -4. »·Â·µÈ´ý +1. 互斥 +2. 请求与ä¿�æŒ� +3. ä¸�å�¯æŠ¢å�  +4. 环路等待 -ÆäÖУ¬ÇëÇóÓë±£³ÖÊÇÖ¸Ò»¸ö½ø³ÌÒòÇëÇó×ÊÔ´¶ø×èÈûʱ£¬¶ÔÒÑ»ñµÃµÄ×ÊÔ´±£³Ö²»·Å¡£ +其中,请求与ä¿�æŒ�是指一个进程因请求资æº�而阻塞时,对已获得的资æº�ä¿�æŒ�ä¸�放。 -## ËÀËøµÄ´¦Àí·½·¨ +## æ­»é”�的处ç�†æ–¹æ³• -### 1. ÍÒÄñ²ßÂÔ +### 1. 鸵鸟策略 -°ÑÍ·ÂñÔÚɳ×ÓÀ¼Ù×°¸ù±¾Ã»·¢ÉúÎÊÌâ¡£ +把头埋在沙å­�里,å�‡è£…根本没å�‘生问题。 -ÕâÖÖ²ßÂÔ²»¿ÉÈ¡¡£ +è¿™ç§�ç­–ç•¥ä¸�å�¯å�–。 -### 2. ËÀËøÔ¤·À +### 2. æ­»é”�预防 -ÔÚ³ÌÐòÔËÐÐ֮ǰԤ·À·¢ÉúËÀËø¡£ +在程åº�è¿�行之å‰�预防å�‘生死é”�。 -#### 2.1 ÆÆ»µ»¥³âÌõ¼þ +#### 2.1 ç ´å��互斥æ�¡ä»¶ -ÀýÈç¼ÙÍÑ»ú´òÓ¡»ú¼¼ÊõÔÊÐíÈô¸É¸ö½ø³ÌͬʱÊä³ö£¬Î¨Ò»ÕæÕýÇëÇóÎïÀí´òÓ¡»úµÄ½ø³ÌÊÇ´òÓ¡»úÊØ»¤½ø³Ì¡£ +例如å�‡è„±æœºæ‰“å�°æœºæŠ€æœ¯å…�许若干个进程å�Œæ—¶è¾“出,唯一真正请求物ç�†æ‰“å�°æœºçš„进程是打å�°æœºå®ˆæŠ¤è¿›ç¨‹ã€‚ -#### 2.2 ÆÆ»µÇëÇóÓë±£³ÖÌõ¼þ +#### 2.2 ç ´å��请求与ä¿�æŒ�æ�¡ä»¶ -Ò»ÖÖʵÏÖ·½Ê½Êǹ涨ËùÓнø³ÌÔÚ¿ªÊ¼Ö´ÐÐǰÇëÇóËùÐèÒªµÄÈ«²¿×ÊÔ´¡£ +一ç§�实现方å¼�是规定所有进程在开始执行å‰�请求所需è¦�的全部资æº�。 -#### 2.3 ÆÆ»µ²»¿ÉÇÀÕ¼Ìõ¼þ +#### 2.3 ç ´å��ä¸�å�¯æŠ¢å� æ�¡ä»¶ -#### 2.4 ÆÆ»µ»·Â·µÈ´ý +#### 2.4 ç ´å��环路等待 -¸ø×ÊԴͳһ±àºÅ£¬½ø³ÌÖ»Äܰ´±àºÅ˳ÐòÀ´ÇëÇó×ÊÔ´¡£ +给资æº�统一编å�·ï¼Œè¿›ç¨‹å�ªèƒ½æŒ‰ç¼–å�·é¡ºåº�æ�¥è¯·æ±‚资æº�。 -### 3. ËÀËø±ÜÃâ +### 3. æ­»é”�é�¿å…� -ÔÚ³ÌÐòÔËÐÐʱ±ÜÃâ·¢ÉúËÀËø¡£ +在程åº�è¿�行时é�¿å…�å�‘生死é”�。 -#### 3.1 °²È«×´Ì¬ +#### 3.1 安全状æ€� -![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/ed523051-608f-4c3f-b343-383e2d194470.png) +![](https://github.com/CyC2018/InterviewNotes/blob/master/pics//ed523051-608f-4c3f-b343-383e2d194470.png) -ͼ a µÄµÚ¶þÁÐ has ±íʾÒÑÓµÓеÄ×ÊÔ´Êý£¬µÚÈýÁÐ max ±íʾ×ܹ²ÐèÒªµÄ×ÊÔ´Êý£¬free ±íʾ»¹ÓпÉÒÔʹÓõÄ×ÊÔ´Êý¡£´Óͼ a ¿ªÊ¼³ö·¢£¬ÏÈÈà B ÓµÓÐËùÐèµÄËùÓÐ×ÊÔ´£¬ÔËÐнáÊøºóÊÍ·Å B£¬´Ëʱ free ±äΪ 4£»½Ó×ÅÒÔͬÑùµÄ·½Ê½ÔËÐÐ C ºÍ A£¬Ê¹µÃËùÓнø³Ì¶¼Äܳɹ¦ÔËÐУ¬Òò´Ë¿ÉÒÔ³ÆÍ¼ a ËùʾµÄ״̬ʱ°²È«µÄ¡£ +图 a 的第二列 has 表示已拥有的资æº�数,第三列 max 表示总共需è¦�的资æº�数,free 表示还有å�¯ä»¥ä½¿ç”¨çš„资æº�数。从图 a 开始出å�‘,先让 B 拥有所需的所有资æº�,è¿�行结æ�Ÿå�Žé‡Šæ”¾ B,此时 free å�˜ä¸º 4;接ç�€ä»¥å�Œæ ·çš„æ–¹å¼�è¿�行 C å’Œ A,使得所有进程都能æˆ�功è¿�行,因此å�¯ä»¥ç§°å›¾ a 所示的状æ€�时安全的。 -¶¨Ò壺Èç¹ûûÓÐËÀËø·¢Éú£¬²¢ÇÒ¼´Ê¹ËùÓнø³ÌͻȻÇëÇó¶Ô×ÊÔ´µÄ×î´óÐèÇó£¬Ò²ÈÔÈ»´æÔÚijÖÖµ÷¶È´ÎÐòÄܹ»Ê¹µÃÿһ¸ö½ø³ÌÔËÐÐÍê±Ï£¬Ôò³Æ¸Ã״̬Êǰ²È«µÄ¡£ +定义:如果没有死é”�å�‘生,并且å�³ä½¿æ‰€æœ‰è¿›ç¨‹çª�然请求对资æº�的最大需求,也ä»�然存在æŸ�ç§�调度次åº�能够使得æ¯�一个进程è¿�行完毕,则称该状æ€�是安全的。 -#### 3.2 µ¥¸ö×ÊÔ´µÄÒøÐмÒËã·¨ +#### 3.2 å�•个资æº�的银行家算法 -Ò»¸öС³ÇÕòµÄÒøÐмң¬ËûÏòһȺ¿Í»§·Ö±ð³ÐŵÁËÒ»¶¨µÄ´û¿î¶î¶È£¬Ëã·¨Òª×öµÄÊÇÅж϶ÔÇëÇóµÄÂú×ãÊÇ·ñ»á½øÈë²»°²È«×´Ì¬£¬Èç¹ûÊÇ£¬¾Í¾Ü¾øÇëÇó£»·ñÔòÓèÒÔ·ÖÅä¡£ +一个å°�城镇的银行家,他å�‘一群客户分别承诺了一定的贷款é¢�度,算法è¦�å�šçš„æ˜¯åˆ¤æ–­å¯¹è¯·æ±‚的满足是å�¦ä¼šè¿›å…¥ä¸�安全状æ€�,如果是,就拒ç»�请求;å�¦åˆ™äºˆä»¥åˆ†é…�。 -![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/d160ec2e-cfe2-4640-bda7-62f53e58b8c0.png) +![](https://github.com/CyC2018/InterviewNotes/blob/master/pics//d160ec2e-cfe2-4640-bda7-62f53e58b8c0.png) -ÉÏͼ c Ϊ²»°²È«×´Ì¬£¬Òò´ËËã·¨»á¾Ü¾øÖ®Ç°µÄÇëÇ󣬴Ӷø±ÜÃâ½øÈëͼ c ÖеÄ״̬¡£ +上图 c 为ä¸�安全状æ€�,因此算法会拒ç»�之å‰�的请求,从而é�¿å…�进入图 c 中的状æ€�。 -#### 3.3 ¶à¸ö×ÊÔ´µÄÒøÐмÒËã·¨ +#### 3.3 多个资æº�的银行家算法 -![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/62e0dd4f-44c3-43ee-bb6e-fedb9e068519.png) +![](https://github.com/CyC2018/InterviewNotes/blob/master/pics//62e0dd4f-44c3-43ee-bb6e-fedb9e068519.png) -ÉÏͼÖÐÓÐÎå¸ö½ø³Ì£¬Ëĸö×ÊÔ´¡£×ó±ßµÄͼ±íʾÒѾ­·ÖÅäµÄ×ÊÔ´£¬ÓұߵÄͼ±íʾ»¹ÐèÒª·ÖÅäµÄ×ÊÔ´¡£×îÓÒ±ßµÄ E¡¢P ÒÔ¼° A ·Ö±ð±íʾ£º×Ü×ÊÔ´¡¢ÒÑ·ÖÅä×ÊÔ´ÒÔ¼°¿ÉÓÃ×ÊÔ´£¬×¢ÒâÕâÈý¸öΪÏòÁ¿£¬¶ø²»ÊǾßÌåÊýÖµ£¬ÀýÈç A=(1020)£¬±íʾ 4 ¸ö×ÊÔ´·Ö±ð»¹Ê£Ï 1/0/2/0¡£ +上图中有五个进程,四个资æº�。左边的图表示已ç»�分é…�的资æº�,å�³è¾¹çš„图表示还需è¦�分é…�的资æº�。最å�³è¾¹çš„ Eã€�P 以å�Š A 分别表示:总资æº�ã€�已分é…�资æº�以å�Šå�¯ç”¨èµ„æº�,注æ„�这三个为å�‘é‡�,而ä¸�是具体数值,例如 A=(1020),表示 4 个资æº�分别还剩下 1/0/2/0。 -¼ì²éÒ»¸ö״̬ÊÇ·ñ°²È«µÄËã·¨ÈçÏ£º +检查一个状æ€�是å�¦å®‰å…¨çš„算法如下: -- ²éÕÒÓұߵľØÕóÊÇ·ñ´æÔÚÒ»ÐÐСÓÚµÈÓÚÏòÁ¿ A¡£Èç¹û²»´æÔÚÕâÑùµÄÐУ¬ÄÇôϵͳ½«»á·¢ÉúËÀËø£¬×´Ì¬ÊDz»°²È«µÄ¡£ -- ¼ÙÈôÕÒµ½ÕâÑùÒ»ÐУ¬½«¸Ã½ø³Ì±ê¼ÇΪÖÕÖ¹£¬²¢½«ÆäÒÑ·ÖÅä×ÊÔ´¼Óµ½ A ÖС£ -- ÖØ¸´ÒÔÉÏÁ½²½£¬Ö±µ½ËùÓнø³Ì¶¼±ê¼ÇΪÖÕÖ¹£¬Ôò״̬ʱ°²È«µÄ¡£ +- 查找å�³è¾¹çš„矩阵是å�¦å­˜åœ¨ä¸€è¡Œå°�于等于å�‘é‡� A。如果ä¸�存在这样的行,那么系统将会å�‘生死é”�,状æ€�是ä¸�安全的。 +- å�‡è‹¥æ‰¾åˆ°è¿™æ ·ä¸€è¡Œï¼Œå°†è¯¥è¿›ç¨‹æ ‡è®°ä¸ºç»ˆæ­¢ï¼Œå¹¶å°†å…¶å·²åˆ†é…�资æº�加到 A 中。 +- é‡�å¤�以上两步,直到所有进程都标记为终止,则状æ€�时安全的。 -### 4. ËÀËø¼ì²âÓëËÀËø»Ö¸´ +### 4. æ­»é”�检测与死é”�æ�¢å¤� -²»ÊÔͼ×èÖ¹ËÀËø£¬¶øÊǵ±¼ì²âµ½ËÀËø·¢Éúʱ£¬²ÉÈ¡´ëÊ©½øÐлָ´¡£ +ä¸�试图阻止死é”�,而是当检测到死é”�å�‘生时,采å�–措施进行æ�¢å¤�。 -#### 4.1 ËÀËø¼ì²âËã·¨ +#### 4.1 æ­»é”�检测算法 -ËÀËø¼ì²âµÄ»ù±¾Ë¼ÏëÊÇ£¬Èç¹ûÒ»¸ö½ø³ÌËùÇëÇóµÄ×ÊÔ´Äܹ»±»Âú×㣬ÄÇô¾ÍÈÃËüÖ´ÐУ¬ÊÍ·ÅËüÓµÓеÄËùÓÐ×ÊÔ´£¬È»ºóÈÃÆäËüÄÜÂú×ãÌõ¼þµÄ½ø³ÌÖ´ÐС£ +æ­»é”�检测的基本æ€�想是,如果一个进程所请求的资æº�能够被满足,那么就让它执行,释放它拥有的所有资æº�,然å�Žè®©å…¶å®ƒèƒ½æ»¡è¶³æ�¡ä»¶çš„进程执行。 -![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/e1eda3d5-5ec8-4708-8e25-1a04c5e11f48.png) +![](https://github.com/CyC2018/InterviewNotes/blob/master/pics//e1eda3d5-5ec8-4708-8e25-1a04c5e11f48.png) -ÉÏͼÖУ¬ÓÐÈý¸ö½ø³ÌËĸö×ÊÔ´£¬Ã¿¸öÊý¾Ý´ú±íµÄº¬ÒåÈçÏ£º +上图中,有三个进程四个资æº�,æ¯�个数æ�®ä»£è¡¨çš„å�«ä¹‰å¦‚下: -- E ÏòÁ¿£º×ÊÔ´×ÜÁ¿ -- A ÏòÁ¿£º×ÊÔ´Ê£ÓàÁ¿ -- C ¾ØÕó£ºÃ¿¸ö½ø³ÌËùÓµÓеÄ×ÊÔ´ÊýÁ¿£¬Ã¿Ò»Ðж¼´ú±íÒ»¸ö½ø³ÌÓµÓÐ×ÊÔ´µÄÊýÁ¿ -- R ¾ØÕó£ºÃ¿¸ö½ø³ÌÇëÇóµÄ×ÊÔ´ÊýÁ¿ +- E å�‘é‡�:资æº�总é‡� +- A å�‘é‡�:资æº�剩余é‡� +- C 矩阵:æ¯�个进程所拥有的资æº�æ•°é‡�,æ¯�一行都代表一个进程拥有资æº�的数é‡� +- R 矩阵:æ¯�个进程请求的资æº�æ•°é‡� -½ø³Ì P1 ºÍ P2 ËùÇëÇóµÄ×ÊÔ´¶¼µÃ²»µ½Âú×㣬ֻÓнø³Ì P3 ¿ÉÒÔ£¬Èà P3 Ö´ÐУ¬Ö®ºóÊÍ·Å P3 ÓµÓеÄ×ÊÔ´£¬´Ëʱ A = (2 2 2 0)¡£P1 ¿ÉÒÔÖ´ÐУ¬Ö´ÐкóÊÍ·Å P1 ÓµÓеÄ×ÊÔ´£¬A = (4 2 2 2) £¬P2 Ò²¿ÉÒÔÖ´ÐС£ËùÓнø³Ì¶¼¿ÉÒÔ˳ÀûÖ´ÐУ¬Ã»ÓÐËÀËø¡£ +进程 P1 å’Œ P2 所请求的资æº�都得ä¸�到满足,å�ªæœ‰è¿›ç¨‹ P3 å�¯ä»¥ï¼Œè®© P3 执行,之å�Žé‡Šæ”¾ P3 拥有的资æº�,此时 A = (2 2 2 0)。P1 å�¯ä»¥æ‰§è¡Œï¼Œæ‰§è¡Œå�Žé‡Šæ”¾ P1 拥有的资æº�,A = (4 2 2 2) ,P2 也å�¯ä»¥æ‰§è¡Œã€‚所有进程都å�¯ä»¥é¡ºåˆ©æ‰§è¡Œï¼Œæ²¡æœ‰æ­»é”�。 -Ëã·¨×ܽáÈçÏ£º +算法总结如下: -ÿ¸ö½ø³Ì×ʼʱ¶¼²»±»±ê¼Ç£¬Ö´Ðйý³ÌÓпÉÄܱ»±ê¼Ç¡£µ±Ëã·¨½áÊøÊ±£¬ÈκÎûÓб»±ê¼ÇµÄ½ø³Ì¶¼ÊÇËÀËø½ø³Ì¡£ +æ¯�个进程最开始时都ä¸�被标记,执行过程有å�¯èƒ½è¢«æ ‡è®°ã€‚当算法结æ�Ÿæ—¶ï¼Œä»»ä½•没有被标记的进程都是死é”�进程。 -1. ѰÕÒÒ»¸öûÓбê¼ÇµÄ½ø³Ì Pi£¬ËüËùÇëÇóµÄ×ÊԴСÓÚµÈÓÚ A¡£ -2. Èç¹ûÕÒµ½ÁËÕâÑùÒ»¸ö½ø³Ì£¬ÄÇô½« C ¾ØÕóµÄµÚ i ÐÐÏòÁ¿¼Óµ½ A ÖУ¬±ê¼Ç¸Ã½ø³Ì£¬²¢×ª»Ø 1¡£ -3. Èç¹ûÓÐûÓÐÕâÑùÒ»¸ö½ø³Ì£¬Ëã·¨ÖÕÖ¹¡£ +1. 寻找一个没有标记的进程 Pi,它所请求的资æº�å°�于等于 A。 +2. 如果找到了这样一个进程,那么将 C 矩阵的第 i 行å�‘é‡�加到 A 中,标记该进程,并转回 1。 +3. 如果有没有这样一个进程,算法终止。 -#### 4.2 ËÀËø»Ö¸´ +#### 4.2 æ­»é”�æ�¢å¤� -- ÀûÓÃÇÀÕ¼»Ö¸´ -- ɱËÀ½ø³Ì +- 利用抢å� æ�¢å¤� +- æ�€æ­»è¿›ç¨‹ -# µÚËÄÕ ´æ´¢Æ÷¹ÜÀí +# 第四章 存储器管ç�† -## ÐéÄâÄÚ´æ +## 虚拟内存 -ÿ¸ö³ÌÐòÓµÓÐ×Ô¼ºµÄµØÖ·¿Õ¼ä£¬Õâ¸öµØÖ·¿Õ¼ä±»·Ö¸î³É¶à¸ö¿é£¬Ã¿Ò»¿é³ÆÎªÒ»Ò³¡£ÕâЩҳ±»Ó³Éäµ½ÎïÀíÄڴ棬µ«²»ÐèÒªÓ³Éäµ½Á¬ÐøµÄÎïÀíÄڴ棬Ҳ²»ÐèÒªËùÓÐÒ³¶¼±ØÐëÔÚÎïÀíÄÚ´æÖС£ +æ¯�个程åº�拥有自己的地å�€ç©ºé—´ï¼Œè¿™ä¸ªåœ°å�€ç©ºé—´è¢«åˆ†å‰²æˆ�多个å�—,æ¯�一å�—称为一页。这些页被映射到物ç�†å†…存,但ä¸�需è¦�映射到连续的物ç�†å†…存,也ä¸�需è¦�所有页都必须在物ç�†å†…存中。 -µ±³ÌÐòÒýÓõ½Ò»²¿·ÖÔÚÎïÀíÄÚ´æÖеĵØÖ·¿Õ¼äʱ£¬ÓÉÓ²¼þÖ´ÐбØÒªµÄÓ³É䣬½«È±Ê§µÄ²¿·Ö×°ÈëÎïÀíÄÚ´æ²¢ÖØÐÂÖ´ÐÐʧ°ÜµÄÖ¸Áî¡£ +当程åº�引用到一部分在物ç�†å†…存中的地å�€ç©ºé—´æ—¶ï¼Œç”±ç¡¬ä»¶æ‰§è¡Œå¿…è¦�的映射,将缺失的部分装入物ç�†å†…存并é‡�新执行失败的指令。 -## ·ÖÒ³Óë·Ö¶Î +## 分页与分段 -### 1. ·ÖÒ³ +### 1. 分页 -Óû§³ÌÐòµÄµØÖ·¿Õ¼ä±»»®·ÖΪÈô¸É¹Ì¶¨´óСµÄÇøÓò£¬³ÆÎª¡°Ò³¡±¡£ÏàÓ¦µØ£¬ÄÚ´æ¿Õ¼ä·Ö³ÉÈô¸É¸öÎïÀí¿é£¬Ò³ºÍ¿éµÄ´óСÏàµÈ¡£¿É½«Óû§³ÌÐòµÄÈÎÒ»Ò³·ÅÔÚÄÚ´æµÄÈÎÒ»¿éÖУ¬ÊµÏÖÁËÀëÉ¢·ÖÅ䣬ÓÉÒ»¸öÒ³±íÀ´Î¬»¤ËüÃÇÖ®¼äµÄÓ³Éä¹ØÏµ¡£ +用户程åº�的地å�€ç©ºé—´è¢«åˆ’分为若干固定大å°�的区域,称为“页â€�。相应地,内存空间分æˆ�若干个物ç�†å�—,页和å�—的大å°�相等。å�¯å°†ç”¨æˆ·ç¨‹åº�的任一页放在内存的任一å�—中,实现了离散分é…�,由一个页表æ�¥ç»´æŠ¤å®ƒä»¬ä¹‹é—´çš„æ˜ å°„关系。 -### 2. ·Ö¶Î +### 2. 分段 -![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/22de0538-7c6e-4365-bd3b-8ce3c5900216.png) +![](https://github.com/CyC2018/InterviewNotes/blob/master/pics//22de0538-7c6e-4365-bd3b-8ce3c5900216.png) -ÉÏͼΪһ¸ö±àÒëÆ÷ÔÚ±àÒë¹ý³ÌÖн¨Á¢µÄ¶à¸ö±í£¬ÓÐ 4 ¸ö±íÊǶ¯Ì¬Ôö³¤µÄ£¬Èç¹ûʹÓ÷ÖҳϵͳµÄһάµØÖ·¿Õ¼ä£¬¶¯Ì¬µÝÔöµÄÌØµã»áµ¼Ö¸²¸ÇÎÊÌâµÄ³öÏÖ¡£ +上图为一个编译器在编译过程中建立的多个表,有 4 个表是动æ€�增长的,如果使用分页系统的一维地å�€ç©ºé—´ï¼ŒåЍæ€�递增的特点会导致覆盖问题的出现。 -![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/e0900bb2-220a-43b7-9aa9-1d5cd55ff56e.png) +![](https://github.com/CyC2018/InterviewNotes/blob/master/pics//e0900bb2-220a-43b7-9aa9-1d5cd55ff56e.png) -·Ö¶ÎµÄ×ö·¨ÊǰÑÿ¸ö±í·Ö³É¶Î£¬Ò»¸ö¶Î¹¹³ÉÒ»¸ö¶ÀÁ¢µÄµØÖ·¿Õ¼ä¡£Ã¿¸ö¶ÎµÄ³¤¶È¿ÉÒÔ²»Í¬£¬²¢ÇÒ¿ÉÒÔ¶¯Ì¬Ôö³¤¡£ +分段的å�šæ³•æ˜¯æŠŠæ¯�个表分æˆ�段,一个段构æˆ�一个独立的地å�€ç©ºé—´ã€‚æ¯�个段的长度å�¯ä»¥ä¸�å�Œï¼Œå¹¶ä¸”å�¯ä»¥åЍæ€�增长。 -ÿ¸ö¶Î¶¼ÐèÒª³ÌÐòÔ±À´»®·Ö¡£ +æ¯�个段都需è¦�程åº�员æ�¥åˆ’分。 -### 3. ¶Îҳʽ +### 3. 段页å¼� -Ó÷ֶη½·¨À´·ÖÅäºÍ¹ÜÀíÐéÄâ´æ´¢Æ÷¡£³ÌÐòµÄµØÖ·¿Õ¼ä°´Âß¼­µ¥Î»·Ö³É»ù±¾¶ÀÁ¢µÄ¶Î£¬¶øÃ¿Ò»¶ÎÓÐ×Ô¼ºµÄ¶ÎÃû£¬ÔÙ°Ñÿ¶Î·Ö³É¹Ì¶¨´óСµÄÈô¸ÉÒ³¡£ +用分段方法æ�¥åˆ†é…�和管ç�†è™šæ‹Ÿå­˜å‚¨å™¨ã€‚程åº�的地å�€ç©ºé—´æŒ‰é€»è¾‘å�•ä½�分æˆ�基本独立的段,而æ¯�一段有自己的段å��,å†�把æ¯�段分æˆ�固定大å°�的若干页。 -Ó÷ÖÒ³·½·¨À´·ÖÅäºÍ¹ÜÀíʵ´æ¡£¼´°ÑÕû¸öÖ÷´æ·Ö³ÉÓëÉÏÊöÒ³´óСÏàµÈµÄ´æ´¢¿é£¬¿É×°Èë×÷ÒµµÄÈκÎÒ»Ò³¡£ +用分页方法æ�¥åˆ†é…�和管ç�†å®žå­˜ã€‚å�³æŠŠæ•´ä¸ªä¸»å­˜åˆ†æˆ�与上述页大å°�相等的存储å�—,å�¯è£…入作业的任何一页。 -³ÌÐò¶ÔÄÚ´æµÄµ÷Èë»òµ÷³öÊǰ´Ò³½øÐе쬵«ËüÓֿɰ´¶ÎʵÏÖ¹²ÏíºÍ±£»¤¡£ +程åº�对内存的调入或调出是按页进行的,但它å�ˆå�¯æŒ‰æ®µå®žçŽ°å…±äº«å’Œä¿�护。 -### 4. ·ÖÒ³Óë·Ö¶ÎÇø±ð +### 4. 分页与分段区别 -- ¶Ô³ÌÐòÔ±µÄ͸Ã÷ÐÔ£º·Öҳ͸Ã÷£¬µ«ÊÇ·Ö¶ÎÐèÒª³ÌÐòÔ±ÏÔʾ»®·Öÿ¸ö¶Î¡£ +- 对程åº�员的é€�明性:分页é€�明,但是分段需è¦�程åº�员显示划分æ¯�个段。 -- µØÖ·¿Õ¼äµÄά¶È£º·ÖÒ³ÊÇһάµØÖ·¿Õ¼ä£¬·Ö¶ÎÊǶþάµÄ¡£ +- 地å�€ç©ºé—´çš„维度:分页是一维地å�€ç©ºé—´ï¼Œåˆ†æ®µæ˜¯äºŒç»´çš„。 -- ´óСÊÇ·ñ¿ÉÒԸı䣺ҳµÄ´óС²»¿É±ä£¬¶ÎµÄ´óС¿ÉÒÔ¶¯Ì¬¸Ä±ä¡£ +- 大å°�是å�¦å�¯ä»¥æ”¹å�˜ï¼šé¡µçš„大å°�ä¸�å�¯å�˜ï¼Œæ®µçš„大å°�å�¯ä»¥åЍæ€�改å�˜ã€‚ -- ³öÏÖµÄÔ­Òò£º·ÖÒ³Ö÷ÒªÓÃÓÚʵÏÖÐéÄâÄڴ棬´Ó¶ø»ñµÃ¸ü´óµÄµØÖ·¿Õ¼ä£»·Ö¶ÎÖ÷ÒªÊÇΪÁËʹ³ÌÐòºÍÊý¾Ý¿ÉÒÔ±»»®·ÖΪÂß¼­É϶ÀÁ¢µÄµØÖ·¿Õ¼ä²¢ÇÒÓÐÖúÓÚ¹²ÏíºÍ±£»¤¡£ +- 出现的原因:分页主è¦�用于实现虚拟内存,从而获得更大的地å�€ç©ºé—´ï¼›åˆ†æ®µä¸»è¦�是为了使程åº�和数æ�®å�¯ä»¥è¢«åˆ’分为逻辑上独立的地å�€ç©ºé—´å¹¶ä¸”有助于共享和ä¿�护。 -## Ò³ÃæÖû»Ëã·¨ +## 页é�¢ç½®æ�¢ç®—法 -ÔÚ³ÌÐòÔËÐйý³ÌÖУ¬ÈôÆäËùÒª·ÃÎʵÄÒ³Ãæ²»ÔÚÄÚ´æ¶øÐèÒª°ÑËüÃǵ÷ÈëÄڴ棬µ«ÊÇÄÚ´æÒÑÎÞ¿ÕÏпռäʱ£¬ÏµÍ³±ØÐë´ÓÄÚ´æÖе÷³öÒ»¸öÒ³Ãæµ½´ÅÅ̶Ի»ÇøÖУ¬²¢ÇÒ½«³ÌÐòËùÐèÒªµÄÒ³Ãæµ÷ÈëÄÚ´æÖС£Ò³ÃæÖû»Ëã·¨µÄÖ÷ҪĿ±êÊÇÊ¹Ò³ÃæÖû»ÆµÂÊ×îµÍ£¨Ò²¿ÉÒÔ˵ȱҳÂÊ×îµÍ£©¡£ +在程åº�è¿�行过程中,若其所è¦�访问的页é�¢ä¸�在内存而需è¦�把它们调入内存,但是内存已无空闲空间时,系统必须从内存中调出一个页é�¢åˆ°ç£�盘对æ�¢åŒºä¸­ï¼Œå¹¶ä¸”将程åº�所需è¦�的页é�¢è°ƒå…¥å†…存中。页é�¢ç½®æ�¢ç®—法的主è¦�目标是使页é�¢ç½®æ�¢é¢‘率最低(也å�¯ä»¥è¯´ç¼ºé¡µçŽ‡æœ€ä½Žï¼‰ã€‚ -### 1. ×î¼Ñ£¨Optimal£© +### 1. 最佳(Optimal) -ËùÑ¡ÔñµÄ±»»»³öµÄÒ³Ãæ½«ÊÇ×ʱ¼äÄÚ²»ÔÙ±»·ÃÎÊ£¬Í¨³£¿ÉÒÔ±£Ö¤»ñµÃ×îµÍµÄȱҳÂÊ¡£ +所选择的被æ�¢å‡ºçš„页é�¢å°†æ˜¯æœ€é•¿æ—¶é—´å†…ä¸�å†�被访问,通常å�¯ä»¥ä¿�è¯�获得最低的缺页率。 -ÊÇÒ»ÖÖÀíÂÛÉϵÄËã·¨£¬ÒòΪÎÞ·¨ÖªµÀÒ»¸öÒ³Ãæ¶à³¤Ê±¼ä»á±»ÔÙ·ÃÎʵ½¡£ +是一ç§�ç�†è®ºä¸Šçš„算法,因为无法知é�“一个页é�¢å¤šé•¿æ—¶é—´ä¼šè¢«å†�访问到。 -¾ÙÀý£ºÒ»¸öϵͳΪij½ø³Ì·ÖÅäÁËÈý¸öÎïÀí¿é£¬²¢ÓÐÈçÏÂÒ³ÃæÒýÓÃÐòÁУº +举例:一个系统为æŸ�进程分é…�了三个物ç�†å�—,并有如下页é�¢å¼•用åº�列: -7£¬0£¬1£¬2£¬0£¬3£¬0£¬4£¬2£¬3£¬0£¬3£¬2£¬1£¬2£¬0£¬1£¬7£¬0£¬1 +7,0,1,2,0,3,0,4,2,3,0,3,2,1,2,0,1,7,0,1 -½ø³ÌÔËÐÐʱ£¬ÏȽ« 7,0,1 Èý¸öÒ³Ãæ×°ÈëÄÚ´æ¡£µ±½ø³ÌÒª·ÃÎÊÒ³Ãæ 2 ʱ£¬²úÉúȱҳÖжϣ¬»á½«Ò³Ãæ 7 »»³ö£¬ÒòÎªÒ³Ãæ 7 Ôٴα»·ÃÎʵÄʱ¼ä×¡£ +进程è¿�行时,先将 7,0,1 三个页é�¢è£…入内存。当进程è¦�访问页é�¢ 2 时,产生缺页中断,会将页é�¢ 7 æ�¢å‡ºï¼Œå› ä¸ºé¡µé�¢ 7 å†�次被访问的时间最长。 -### 2. ÏȽøÏȳö£¨FIFO£© +### 2. 先进先出(FIFO) -ËùÑ¡Ôñ»»³öµÄÒ³ÃæÊÇ×îÏȽøÈëµÄÒ³Ãæ¡£ +所选择æ�¢å‡ºçš„页é�¢æ˜¯æœ€å…ˆè¿›å…¥çš„页é�¢ã€‚ -¸ÃËã·¨»á½«ÄÇЩ¾­³£±»·ÃÎʵÄÒ³ÃæÒ²±»»»³ö£¬´Ó¶øÊ¹È±Ò³ÂÊÉý¸ß¡£ +该算法会将那些ç»�常被访问的页é�¢ä¹Ÿè¢«æ�¢å‡ºï¼Œä»Žè€Œä½¿ç¼ºé¡µçއå�‡é«˜ã€‚ -### 3. ×î½ü×î¾ÃδʹÓã¨LRU, Least Recently Used£© +### 3. 最近最久未使用(LRU, Least Recently Used) -ËäÈ»ÎÞ·¨ÖªµÀ½«À´ÒªÊ¹ÓõÄÒ³ÃæÇé¿ö£¬µ«ÊÇ¿ÉÒÔÖªµÀ¹ýȥʹÓÃÒ³ÃæµÄÇé¿ö¡£LRU ½«×î½ü×î¾ÃδʹÓõÄÒ³Ãæ»»³ö¡£ +虽然无法知é�“å°†æ�¥è¦�使用的页é�¢æƒ…况,但是å�¯ä»¥çŸ¥é�“过去使用页é�¢çš„æƒ…况。LRU 将最近最久未使用的页é�¢æ�¢å‡ºã€‚ -¿ÉÒÔÓÃÕ»À´ÊµÏÖ¸ÃËã·¨£¬Õ»ÖÐ´æ´¢Ò³ÃæµÄÒ³ÃæºÅ¡£µ±½ø³Ì·ÃÎÊÒ»¸öÒ³ÃæÊ±£¬½«¸ÃÒ³ÃæµÄÒ³ÃæºÅ´ÓÕ»ÒÆ³ý£¬²¢½«ËüѹÈëÕ»¶¥¡£ÕâÑù£¬×î½ü±»·ÃÎʵÄÒ³ÃæµÄÒ³ÃæºÅ×ÜÊÇÔÚÕ»¶¥£¬¶ø×î½ü×î¾ÃδʹÓõÄÒ³ÃæµÄÒ³ÃæºÅ×ÜÊÇÔÚÕ»µ×¡£ +å�¯ä»¥ç”¨æ ˆæ�¥å®žçŽ°è¯¥ç®—æ³•ï¼Œæ ˆä¸­å­˜å‚¨é¡µé�¢çš„页é�¢å�·ã€‚当进程访问一个页é�¢æ—¶ï¼Œå°†è¯¥é¡µé�¢çš„页é�¢å�·ä»Žæ ˆç§»é™¤ï¼Œå¹¶å°†å®ƒåŽ‹å…¥æ ˆé¡¶ã€‚è¿™æ ·ï¼Œæœ€è¿‘è¢«è®¿é—®çš„é¡µé�¢çš„页é�¢å�·æ€»æ˜¯åœ¨æ ˆé¡¶ï¼Œè€Œæœ€è¿‘最久未使用的页é�¢çš„页é�¢å�·æ€»æ˜¯åœ¨æ ˆåº•。 -4£¬7£¬0£¬7£¬1£¬0£¬1£¬2£¬1£¬2£¬6 +4,7,0,7,1,0,1,2,1,2,6 -![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/eb859228-c0f2-4bce-910d-d9f76929352b.png) +![](https://github.com/CyC2018/InterviewNotes/blob/master/pics//eb859228-c0f2-4bce-910d-d9f76929352b.png) -### 4. ʱÖÓ£¨Clock£© +### 4. 时钟(Clock) -Clock Ò³ÃæÖû»Ëã·¨ÐèÒªÓõ½Ò»¸ö·ÃÎÊ룬µ±Ò»¸öÒ³Ãæ±»·ÃÎÊʱ£¬½«·ÃÎÊΪÖÃΪ 1¡£ +Clock 页é�¢ç½®æ�¢ç®—法需è¦�用到一个访问ä½�,当一个页é�¢è¢«è®¿é—®æ—¶ï¼Œå°†è®¿é—®ä¸ºç½®ä¸º 1。 -Ê×ÏÈ£¬½«ÄÚ´æÖеÄËùÓÐÒ³ÃæÁ´½Ó³ÉÒ»¸öÑ­»·¶ÓÁУ¬µ±È±Ò³ÖжϷ¢Éúʱ£¬¼ì²éµ±Ç°Ö¸ÕëËùÖ¸ÏòÒ³ÃæµÄ·ÃÎÊ룬Èç¹û·ÃÎÊλΪ 0£¬¾Í½«¸ÃÒ³Ãæ»»³ö£»·ñÔò½«¸ÃÒ³µÄ·ÃÎÊλÉèÖÃΪ 0£¬¸ø¸ÃÒ³ÃæµÚ¶þ´ÎµÄ»ú»á£¬Òƶ¯Ö¸Õë¼ÌÐø¼ì²é¡£ +首先,将内存中的所有页é�¢é“¾æŽ¥æˆ�一个循环队列,当缺页中断å�‘生时,检查当å‰�指针所指å�‘页é�¢çš„访问ä½�,如果访问ä½�为 0,就将该页é�¢æ�¢å‡ºï¼›å�¦åˆ™å°†è¯¥é¡µçš„访问ä½�设置为 0,给该页é�¢ç¬¬äºŒæ¬¡çš„æœºä¼šï¼Œç§»åŠ¨æŒ‡é’ˆç»§ç»­æ£€æŸ¥ã€‚ -# µÚÎåÕ É豸¹ÜÀí +# 第五章 设备管ç�† -## ´ÅÅ̵÷¶ÈËã·¨ +## ç£�盘调度算法 -µ±¶à¸ö½ø³ÌͬʱÇëÇó·ÃÎÊ´ÅÅÌʱ£¬ÐèÒª½øÐдÅÅ̵÷¶ÈÀ´¿ØÖƶԴÅÅ̵ķÃÎÊ¡£´ÅÅ̵÷¶ÈµÄÖ÷ҪĿ±êÊÇʹ´ÅÅÌµÄÆ½¾ùѰµÀʱ¼ä×îÉÙ¡£ +当多个进程å�Œæ—¶è¯·æ±‚访问ç£�盘时,需è¦�进行ç£�盘调度æ�¥æŽ§åˆ¶å¯¹ç£�盘的访问。ç£�盘调度的主è¦�目标是使ç£�盘的平å�‡å¯»é�“时间最少。 -### 1. ÏÈÀ´ÏÈ·þÎñ£¨FCFS, First Come First Serverd£© +### 1. å…ˆæ�¥å…ˆæœ�务(FCFS, First Come First Serverd) -¸ù¾Ý½ø³ÌÇëÇó·ÃÎÊ´ÅÅ̵ÄÏȺó´ÎÐòÀ´½øÐе÷¶È¡£ÓŵãÊǹ«Æ½ºÍ¼òµ¥£¬È±µãÒ²ºÜÃ÷ÏÔ£¬ÒòΪδ¶ÔѰµÀ×öÈκÎÓÅ»¯£¬Ê¹Æ½¾ùѰµÀʱ¼ä¿ÉÄܽϳ¤¡£ +æ ¹æ�®è¿›ç¨‹è¯·æ±‚访问ç£�盘的先å�Žæ¬¡åº�æ�¥è¿›è¡Œè°ƒåº¦ã€‚优点是公平和简å�•,缺点也很明显,因为未对寻é�“å�šä»»ä½•优化,使平å�‡å¯»é�“æ—¶é—´å�¯èƒ½è¾ƒé•¿ã€‚ -### 2. ×î¶ÌѰµÀʱ¼äÓÅÏÈ£¨SSTF, Shortest Seek Time First£© +### 2. 最短寻é�“时间优先(SSTF, Shortest Seek Time First) -ÒªÇó·ÃÎʵĴŵÀÓ뵱ǰ´ÅÍ·ËùÔڴŵÀ¾àÀë×î½üµÄÓÅÏȽøÐе÷¶È¡£ÕâÖÖËã·¨²¢²»Äܱ£Ö¤Æ½¾ùѰµÀʱ¼ä×î¶Ì£¬µ«ÊÇ±È FCFS ºÃºÜ¶à¡£ +è¦�求访问的ç£�é�“与当å‰�ç£�头所在ç£�é�“è·�离最近的优先进行调度。这ç§�算法并ä¸�能ä¿�è¯�å¹³å�‡å¯»é�“时间最短,但是比 FCFS 好很多。 -### 3. ɨÃèËã·¨£¨SCAN£© +### 3. 扫æ��算法(SCAN) -SSTF »á³öÏÖ½øÐм¢¶öÏÖÏ󡣿¼ÂÇÒÔÏÂÇé¿ö£¬Ð½ø³ÌÇëÇó·ÃÎʵĴŵÀÓë´ÅÍ·ËùÔڴŵÀµÄ¾àÀë×ÜÊDZÈÒ»¸öÔڵȴýµÄ½ø³ÌÀ´µÄ½ü£¬ÄÇôµÈ´ýµÄ½ø³Ì»áÒ»Ö±µÈ´ýÏÂÈ¥¡£ +SSTF 会出现进行饥饿现象。考虑以下情况,新进程请求访问的ç£�é�“与ç£�头所在ç£�é�“çš„è·�离总是比一个在等待的进程æ�¥çš„近,那么等待的进程会一直等待下去。 -SCAN Ëã·¨ÔÚ SSTF Ëã·¨Ö®ÉÏ¿¼ÂÇÁË´ÅÍ·µÄÒÆ¶¯·½Ïò£¬ÒªÇóËùÇëÇó·ÃÎʵĴŵÀÔÚ´ÅÍ·µ±Ç°Òƶ¯·½ÏòÉϲÅÄܹ»µÃµ½µ÷¶È¡£ÒòΪ¿¼ÂÇÁËÒÆ¶¯·½Ïò£¬ÄÇôһ¸ö½ø³ÌÇëÇó·ÃÎʵĴŵÀÒ»¶¨»áµÃµ½µ÷¶È¡£ +SCAN 算法在 SSTF 算法之上考虑了ç£�头的移动方å�‘,è¦�求所请求访问的ç£�é�“在ç£�头当å‰�移动方å�‘上æ‰�能够得到调度。因为考虑了移动方å�‘,那么一个进程请求访问的ç£�é�“一定会得到调度。 -µ±Ò»¸ö´ÅÍ·×ÔÀïÏòÍâÒÆ¶¯Ê±£¬ÒƵ½×îÍâ²à»á¸Ä±äÒÆ¶¯·½ÏòΪ×ÔÍâÏòÀÕâÖÖÒÆ¶¯µÄ¹æÂÉÀàËÆÓÚµçÌݵÄÔËÐУ¬Òò´ËÓÖ³£³Æ SCAN Ë㷨ΪµçÌݵ÷¶ÈËã·¨¡£ +当一个ç£�头自里å�‘外移动时,移到最外侧会改å�˜ç§»åŠ¨æ–¹å�‘为自外å�‘里,这ç§�移动的规律类似于电梯的è¿�行,因此å�ˆå¸¸ç§° SCAN 算法为电梯调度算法。 -### 4. Ñ­»·É¨ÃèËã·¨£¨CSCAN£© +### 4. 循环扫æ��算法(CSCAN) -CSCAN ¶Ô SCAN ½øÐÐÁ˸͝£¬ÒªÇó´ÅͷʼÖÕÑØ×ÅÒ»¸ö·½ÏòÒÆ¶¯¡£ +CSCAN 对 SCAN 进行了改动,è¦�求ç£�头始终沿ç�€ä¸€ä¸ªæ–¹å�‘移动。 -# ²Î¿¼×ÊÁÏ +# å�‚考资料 - Tanenbaum A S, Bos H. Modern operating systems[M]. Prentice Hall Press, 2014. -- ÌÀ×Óå­, ÕÜ·ïÆÁ, ÌÀСµ¤. ¼ÆËã»ú²Ù×÷ϵͳ[M]. Î÷°²µç×ӿƼ¼´óѧ³ö°æÉç, 2001. -- Bryant, R. E., & O¡¯Hallaron, D. R. (2004). ÉîÈëÀí½â¼ÆËã»úϵͳ. -- [½ø³Ì¼äµÄ¼¸ÖÖͨÐÅ·½Ê½](http://blog.csdn.net/yufaw/article/details/7409596) +- 汤å­�瀛, 哲凤å±�, 汤å°�丹. 计算机æ“�作系统[M]. 西安电å­�科技大学出版社, 2001. +- Bryant, R. E., & O’Hallaron, D. R. (2004). 深入ç�†è§£è®¡ç®—机系统. +- [进程间的几ç§�通信方å¼�](http://blog.csdn.net/yufaw/article/details/7409596) diff --git a/notes/计算机网络.md b/notes/计算机网络.md index 203d481f..5e56d39c 100644 --- a/notes/计算机网络.md +++ b/notes/计算机网络.md @@ -1,839 +1,840 @@ -* [µÚÒ»Õ ¸ÅÊö](#µÚÒ»ÕÂ-¸ÅÊö) - * [ÍøÂçµÄÍøÂç](#ÍøÂçµÄÍøÂç) +* [第一章 概述](#第一章-概述) + * [网络的网络](#网络的网络) * [ISP](#isp) - * [»¥ÁªÍøµÄ×é³É](#»¥ÁªÍøµÄ×é³É) - * [Ö÷»úÖ®¼äµÄͨÐÅ·½Ê½](#Ö÷»úÖ®¼äµÄͨÐÅ·½Ê½) - * [µç·½»»»Óë·Ö×é½»»»](#µç·½»»»Óë·Ö×é½»»») - * [1. µç·½»»»](#1-µç·½»»») - * [2. ±¨ÎĽ»»»](#2-±¨ÎĽ»»») - * [3. ·Ö×é½»»»](#3-·Ö×é½»»») - * [ʱÑÓ](#ʱÑÓ) - * [1. ·¢ËÍʱÑÓ](#1-·¢ËÍʱÑÓ) - * [2. ´«²¥Ê±ÑÓ](#2-´«²¥Ê±ÑÓ) - * [3. ´¦ÀíʱÑÓ](#3-´¦ÀíʱÑÓ) - * [4. ÅŶÓʱÑÓ](#4-ÅŶÓʱÑÓ) - * [¼ÆËã»úÍøÂçÌåϵ½á¹¹*](#¼ÆËã»úÍøÂçÌåϵ½á¹¹) - * [1. Æß²ãЭÒé](#1-Æß²ãЭÒé) - * [2. Îå²ãЭÒé](#2-Îå²ãЭÒé) - * [3. Êý¾ÝÔÚ¸÷²ãÖ®¼äµÄ´«µÝ¹ý³Ì](#3-Êý¾ÝÔÚ¸÷²ãÖ®¼äµÄ´«µÝ¹ý³Ì) - * [4. TCP/IP Ìåϵ½á¹¹](#4-tcpip-Ìåϵ½á¹¹) -* [µÚ¶þÕ ÎïÀí²ã](#µÚ¶þÕÂ-ÎïÀí²ã) - * [ͨÐÅ·½Ê½](#ͨÐÅ·½Ê½) - * [´øÍ¨µ÷ÖÆ](#´øÍ¨µ÷ÖÆ) - * [ÐŵÀ¸´Óü¼Êõ](#ÐŵÀ¸´Óü¼Êõ) - * [1. Ƶ·Ö¸´Óá¢Ê±·Ö¸´ÓÃ](#1-Ƶ·Ö¸´ÓÃʱ·Ö¸´ÓÃ) - * [2. ͳ¼ÆÊ±·Ö¸´ÓÃ](#2-ͳ¼ÆÊ±·Ö¸´ÓÃ) - * [3. ²¨·Ö¸´ÓÃ](#3-²¨·Ö¸´ÓÃ) - * [4. Âë·Ö¸´ÓÃ](#4-Âë·Ö¸´ÓÃ) -* [µÚÈýÕ Êý¾ÝÁ´Â·²ã](#µÚÈýÕÂ-Êý¾ÝÁ´Â·²ã) - * [Èý¸ö»ù±¾ÎÊÌâ](#Èý¸ö»ù±¾ÎÊÌâ) - * [1. ·â×°³ÉÖ¡](#1-·â×°³ÉÖ¡) - * [2. ͸Ã÷´«Êä](#2-͸Ã÷´«Êä) - * [3. ²î´í¼ì²â](#3-²î´í¼ì²â) - * [µã¶ÔµãÐŵÀ - PPP ЭÒé](#µã¶ÔµãÐŵÀ---ppp-ЭÒé) - * [¾ÖÓòÍøµÄÍØÆË](#¾ÖÓòÍøµÄÍØÆË) - * [¹ã²¥ÐŵÀ - CSMA/CD ЭÒé*](#¹ã²¥ÐŵÀ---csmacd-ЭÒé) - * [¼¯Ï߯÷](#¼¯Ï߯÷) - * [MAC ²ã](#mac-²ã) - * [ÐéÄâ¾ÖÓòÍø](#ÐéÄâ¾ÖÓòÍø) -* [µÚËÄÕÂ ÍøÂç²ã*](#µÚËÄÕÂ-ÍøÂç²ã) - * [Íø¼ÊЭÒé IP ¸ÅÊö](#Íø¼ÊЭÒé-ip-¸ÅÊö) - * [IP Êý¾Ý±¨¸ñʽ](#ip-Êý¾Ý±¨¸ñʽ) - * [IP µØÖ·±àÖ·](#ip-µØÖ·±àÖ·) - * [1. ·ÖÀà](#1-·ÖÀà) - * [2. ×ÓÍø»®·Ö](#2-×ÓÍø»®·Ö) - * [3. ÎÞ·ÖÀà](#3-ÎÞ·ÖÀà) - * [IP µØÖ·ºÍ MAC µØÖ·](#ip-µØÖ·ºÍ-mac-µØÖ·) - * [µØÖ·½âÎöЭÒé ARP](#µØÖ·½âÎöЭÒé-arp) - * [·ÓÉÆ÷µÄ½á¹¹](#·ÓÉÆ÷µÄ½á¹¹) - * [½»»»»úÓë·ÓÉÆ÷µÄÇø±ð](#½»»»»úÓë·ÓÉÆ÷µÄÇø±ð) - * [·ÓÉÆ÷·Ö×éת·¢Á÷³Ì](#·ÓÉÆ÷·Ö×éת·¢Á÷³Ì) - * [·ÓÉÑ¡ÔñЭÒé](#·ÓÉÑ¡ÔñЭÒé) - * [1. ÄÚ²¿Íø¹ØÐ­Òé RIP](#1-ÄÚ²¿Íø¹ØÐ­Òé-rip) - * [2. ÄÚ²¿Íø¹ØÐ­Òé OSPF](#2-ÄÚ²¿Íø¹ØÐ­Òé-ospf) - * [3. Íâ²¿Íø¹ØÐ­Òé BGP](#3-Íâ²¿Íø¹ØÐ­Òé-bgp) - * [Íø¼Ê¿ØÖƱ¨ÎÄЭÒé ICMP](#Íø¼Ê¿ØÖƱ¨ÎÄЭÒé-icmp) - * [·Ö×éÍø¼ä̽²â PING](#·Ö×éÍø¼ä̽²â-ping) - * [IP ¶à²¥](#ip-¶à²¥) - * [ÐéÄâרÓÃÍø VPN](#ÐéÄâרÓÃÍø-vpn) - * [ÍøÂçµØÖ·×ª»» NAT](#ÍøÂçµØÖ·×ª»»-nat) -* [µÚÎåÕ ÔËÊä²ã*](#µÚÎåÕÂ-ÔËÊä²ã) - * [UDP ºÍ TCP µÄÌØµã](#udp-ºÍ-tcp-µÄÌØµã) - * [UDP Êײ¿¸ñʽ](#udp-Êײ¿¸ñʽ) - * [TCP Êײ¿¸ñʽ](#tcp-Êײ¿¸ñʽ) - * [TCP µÄÈý´ÎÎÕÊÖ](#tcp-µÄÈý´ÎÎÕÊÖ) - * [TCP µÄËĴλÓÊÖ](#tcp-µÄËĴλÓÊÖ) - * [TCP »¬¶¯´°¿Ú](#tcp-»¬¶¯´°¿Ú) - * [TCP ¿É¿¿´«Êä](#tcp-¿É¿¿´«Êä) - * [TCP Á÷Á¿¿ØÖÆ](#tcp-Á÷Á¿¿ØÖÆ) - * [TCP ÓµÈû¿ØÖÆ](#tcp-ÓµÈû¿ØÖÆ) - * [Âý¿ªÊ¼ÓëÓµÈû±ÜÃâ](#Âý¿ªÊ¼ÓëÓµÈû±ÜÃâ) - * [¿ìÖØ´«Óë¿ì»Ö¸´](#¿ìÖØ´«Óë¿ì»Ö¸´) -* [µÚÁùÕ ӦÓòã*](#µÚÁùÕÂ-Ó¦Óòã) - * [ÓòÃûϵͳ DNS](#ÓòÃûϵͳ-dns) - * [1. ²ã´Î½á¹¹](#1-²ã´Î½á¹¹) - * [2. ½âÎö¹ý³Ì](#2-½âÎö¹ý³Ì) - * [Îļþ´«ÊäЭÒé FTP](#Îļþ´«ÊäЭÒé-ftp) - * [Ô¶³ÌÖÕ¶ËЭÒé TELNET](#Ô¶³ÌÖÕ¶ËЭÒé-telnet) - * [ÍòÎ¬Íø WWW](#ÍòÎ¬Íø-www) - * [µç×ÓÓʼþЭÒé](#µç×ÓÓʼþЭÒé) + * [互è�”网的组æˆ�](#互è�”网的组æˆ�) + * [主机之间的通信方å¼�](#主机之间的通信方å¼�) + * [电路交æ�¢ä¸Žåˆ†ç»„交æ�¢](#电路交æ�¢ä¸Žåˆ†ç»„交æ�¢) + * [1. 电路交æ�¢](#1-电路交æ�¢) + * [2. 报文交æ�¢](#2-报文交æ�¢) + * [3. 分组交æ�¢](#3-分组交æ�¢) + * [æ—¶å»¶](#æ—¶å»¶) + * [1. å�‘é€�æ—¶å»¶](#1-å�‘é€�æ—¶å»¶) + * [2. ä¼ æ’­æ—¶å»¶](#2-ä¼ æ’­æ—¶å»¶) + * [3. 处ç�†æ—¶å»¶](#3-处ç�†æ—¶å»¶) + * [4. 排队时延](#4-排队时延) + * [计算机网络体系结构*](#计算机网络体系结构) + * [1. 七层å��è®®](#1-七层å��è®®) + * [2. 五层å��è®®](#2-五层å��è®®) + * [3. æ•°æ�®åœ¨å�„层之间的传递过程](#3-æ•°æ�®åœ¨å�„层之间的传递过程) + * [4. TCP/IP 体系结构](#4-tcpip-体系结构) +* [第二章 物ç�†å±‚](#第二章-物ç�†å±‚) + * [通信方å¼�](#通信方å¼�) + * [带通调制](#带通调制) + * [ä¿¡é�“å¤�用技术](#ä¿¡é�“å¤�用技术) + * [1. 频分å¤�用ã€�时分å¤�用](#1-频分å¤�用时分å¤�用) + * [2. 统计时分å¤�用](#2-统计时分å¤�用) + * [3. 波分å¤�用](#3-波分å¤�用) + * [4. ç �分å¤�用](#4-ç �分å¤�用) +* [第三章 æ•°æ�®é“¾è·¯å±‚](#第三章-æ•°æ�®é“¾è·¯å±‚) + * [三个基本问题](#三个基本问题) + * [1. å°�装æˆ�帧](#1-å°�装æˆ�帧) + * [2. é€�明传输](#2-é€�明传输) + * [3. 差错检测](#3-差错检测) + * [点对点信é�“ - PPP å��è®®](#点对点信é�“---ppp-å��è®®) + * [局域网的拓扑](#局域网的拓扑) + * [广播信é�“ - CSMA/CD å��è®®*](#广播信é�“---csmacd-å��è®®) + * [集线器](#集线器) + * [MAC 层](#mac-层) + * [虚拟局域网](#虚拟局域网) +* [第四章 网络层*](#第四章-网络层) + * [网际å��è®® IP 概述](#网际å��è®®-ip-概述) + * [IP æ•°æ�®æŠ¥æ ¼å¼�](#ip-æ•°æ�®æŠ¥æ ¼å¼�) + * [IP 地å�€ç¼–å�€](#ip-地å�€ç¼–å�€) + * [1. 分类](#1-分类) + * [2. å­�网划分](#2-å­�网划分) + * [3. 无分类](#3-无分类) + * [IP 地å�€å’Œ MAC 地å�€](#ip-地å�€å’Œ-mac-地å�€) + * [地å�€è§£æž�å��è®® ARP](#地å�€è§£æž�å��è®®-arp) + * [路由器的结构](#路由器的结构) + * [交æ�¢æœºä¸Žè·¯ç”±å™¨çš„区别](#交æ�¢æœºä¸Žè·¯ç”±å™¨çš„区别) + * [路由器分组转å�‘æµ�程](#路由器分组转å�‘æµ�程) + * [路由选择å��è®®](#路由选择å��è®®) + * [1. 内部网关å��è®® RIP](#1-内部网关å��è®®-rip) + * [2. 内部网关å��è®® OSPF](#2-内部网关å��è®®-ospf) + * [3. 外部网关å��è®® BGP](#3-外部网关å��è®®-bgp) + * [网际控制报文å��è®® ICMP](#网际控制报文å��è®®-icmp) + * [分组网间探测 PING](#分组网间探测-ping) + * [IP 多播](#ip-多播) + * [虚拟专用网 VPN](#虚拟专用网-vpn) + * [网络地å�€è½¬æ�¢ NAT](#网络地å�€è½¬æ�¢-nat) +* [第五章 è¿�输层*](#第五章-è¿�输层) + * [UDP å’Œ TCP 的特点](#udp-å’Œ-tcp-的特点) + * [UDP 首部格å¼�](#udp-首部格å¼�) + * [TCP 首部格å¼�](#tcp-首部格å¼�) + * [TCP 的三次æ�¡æ‰‹](#tcp-的三次æ�¡æ‰‹) + * [TCP 的四次挥手](#tcp-的四次挥手) + * [TCP 滑动窗å�£](#tcp-滑动窗å�£) + * [TCP å�¯é� ä¼ è¾“](#tcp-å�¯é� ä¼ è¾“) + * [TCP æµ�é‡�控制](#tcp-æµ�é‡�控制) + * [TCP 拥塞控制](#tcp-拥塞控制) + * [慢开始与拥塞é�¿å…�](#慢开始与拥塞é�¿å…�) + * [å¿«é‡�传与快æ�¢å¤�](#å¿«é‡�传与快æ�¢å¤�) +* [第六章 应用层*](#第六章-应用层) + * [域å��系统 DNS](#域å��系统-dns) + * [1. 层次结构](#1-层次结构) + * [2. è§£æž�过程](#2-è§£æž�过程) + * [文件传输å��è®® FTP](#文件传输å��è®®-ftp) + * [远程终端å��è®® TELNET](#远程终端å��è®®-telnet) + * [万维网 WWW](#万维网-www) + * [电å­�邮件å��è®®](#电å­�邮件å��è®®) * [POP3](#pop3) * [IMAP](#imap) * [SMTP](#smtp) - * [¶¯Ì¬Ö÷»úÅäÖÃЭÒé DHCP](#¶¯Ì¬Ö÷»úÅäÖÃЭÒé-dhcp) - * [µã¶Ôµã´«Êä P2P](#µã¶Ôµã´«Êä-p2p) - * [Web Ò³ÃæÇëÇó¹ý³Ì](#web-Ò³ÃæÇëÇó¹ý³Ì) - * [³£Óö˿Ú](#³£Óö˿Ú) -* [²Î¿¼×ÊÁÏ](#²Î¿¼×ÊÁÏ) + * [动æ€�主机é…�ç½®å��è®® DHCP](#动æ€�主机é…�ç½®å��è®®-dhcp) + * [点对点传输 P2P](#点对点传输-p2p) + * [Web 页é�¢è¯·æ±‚过程](#web-页é�¢è¯·æ±‚过程) + * [常用端å�£](#常用端å�£) +* [å�‚考资料](#å�‚考资料) -# µÚÒ»Õ ¸ÅÊö -## ÍøÂçµÄÍøÂç +# 第一章 概述 -ÍøÂç°ÑÖ÷»úÁ¬½ÓÆðÀ´£¬¶ø»¥ÁªÍøÊǰѶàÖÖ²»Í¬µÄÍøÂçÁ¬½ÓÆðÀ´£¬Òò´Ë»¥ÁªÍøÊÇÍøÂçµÄÍøÂç¡£ +## 网络的网络 -![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/04ff7ae6-7bee-4cf8-82f8-dfe2ba1f3616.jpg) +网络把主机连接起æ�¥ï¼Œè€Œäº’è�”网是把多ç§�ä¸�å�Œçš„网络连接起æ�¥ï¼Œå› æ­¤äº’è�”网是网络的网络。 + +![](https://github.com/CyC2018/InterviewNotes/blob/master/pics//04ff7ae6-7bee-4cf8-82f8-dfe2ba1f3616.jpg) ## ISP -»¥ÁªÍø·þÎñÌṩÉÌ ISP ¿ÉÒÔ´Ó»¥ÁªÍø¹ÜÀí»ú¹¹»ñµÃÐí¶à IP µØÖ·£¬Í¬Ê±ÓµÓÐͨÐÅÏß·ÒÔ¼°Â·ÓÉÆ÷µÈÁªÍøÉ豸£¬¸öÈË»ò»ú¹¹Ïò ISP ½ÉÄÉÒ»¶¨µÄ·ÑÓþͿÉÒÔ½ÓÈ뻥ÁªÍø¡£ +互è�”网æœ�务æ��供商 ISP å�¯ä»¥ä»Žäº’è�”网管ç�†æœºæž„获得许多 IP 地å�€ï¼Œå�Œæ—¶æ‹¥æœ‰é€šä¿¡çº¿è·¯ä»¥å�Šè·¯ç”±å™¨ç­‰è�”网设备,个人或机构å�‘ ISP 缴纳一定的费用就å�¯ä»¥æŽ¥å…¥äº’è�”网。 -ĿǰµÄ»¥ÁªÍøÊÇÒ»ÖÖ¶à²ã´Î ISP ½á¹¹£¬ISP ¸ù¾Ý¸²¸ÇÃæ»ýµÄ´óС·ÖΪÖ÷¸É ISP¡¢µØÇø ISP ºÍ±¾µØ ISP¡£ +ç›®å‰�的互è�”网是一ç§�多层次 ISP 结构,ISP æ ¹æ�®è¦†ç›–é�¢ç§¯çš„大å°�分为主干 ISPã€�地区 ISP 和本地 ISP。 -»¥ÁªÍø½»»»µã IXP ÔÊÐíÁ½¸ö ISP Ö±½ÓÏàÁ¬¶ø²»Óþ­¹ýµÚÈý¸ö ISP¡£ +互è�”网交æ�¢ç‚¹ IXP å…�许两个 ISP 直接相连而ä¸�用ç»�过第三个 ISP。 -![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/17d807ef-03bf-4824-a97c-ea5fb58ec61d.jpg) +![](https://github.com/CyC2018/InterviewNotes/blob/master/pics//17d807ef-03bf-4824-a97c-ea5fb58ec61d.jpg) -## »¥ÁªÍøµÄ×é³É +## 互è�”网的组æˆ� -1. ±ßÔµ²¿·Ö£ºËùÓÐÁ¬½ÓÔÚ»¥ÁªÍøÉϵÄÖ÷»ú£¬Óû§¿ÉÒÔÖ±½ÓʹÓã» -2. ºËÐIJ¿·Ö£ºÓÉ´óÁ¿µÄÍøÂçºÍÁ¬½ÓÕâÐ©ÍøÂçµÄ·ÓÉÆ÷×é³É£¬Îª±ßÔµ²¿·ÖµÄÖ÷»úÌṩ·þÎñ¡£ +1. 边缘部分:所有连接在互è�”网上的主机,用户å�¯ä»¥ç›´æŽ¥ä½¿ç”¨ï¼› +2. 核心部分:由大é‡�的网络和连接这些网络的路由器组æˆ�,为边缘部分的主机æ��ä¾›æœ�务。 -![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/005d83c2-e64a-41f0-bbdd-51c71d494a18.jpg) +![](https://github.com/CyC2018/InterviewNotes/blob/master/pics//005d83c2-e64a-41f0-bbdd-51c71d494a18.jpg) -## Ö÷»úÖ®¼äµÄͨÐÅ·½Ê½ +## 主机之间的通信方å¼� -**1. ¿Í»§ - ·þÎñÆ÷£¨C/S£©** +**1. 客户 - æœ�务器(C/S)** -¿Í»§¼´ÊÇ·þÎñÇëÇó·½£¬·þÎñÆ÷ÊÇ·þÎñÌṩ·½¡£ +客户å�³æ˜¯æœ�务请求方,æœ�务器是æœ�务æ��供方。 -**2. ¶ÔµÈ£¨P2P£©** +**2. 对等(P2P)** -²»Çø·Ö¿Í»§ºÍ·þÎñÆ÷¡£ +ä¸�区分客户和æœ�务器。 -## µç·½»»»Óë·Ö×é½»»» +## 电路交æ�¢ä¸Žåˆ†ç»„交æ�¢ -![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/b97958dd-3e43-45f7-97f5-3ec20f3f8b88.jpg) +![](https://github.com/CyC2018/InterviewNotes/blob/master/pics//b97958dd-3e43-45f7-97f5-3ec20f3f8b88.jpg) -### 1. µç·½»»» +### 1. 电路交æ�¢ -µç·½»»»ÓÃÓڵ绰ͨÐÅϵͳ£¬Á½¸öÓû§ÒªÍ¨ÐÅ֮ǰÐèÒª½¨Á¢Ò»ÌõרÓõÄÎïÀíÁ´Â·£¬²¢ÇÒÔÚÕû¸öͨÐŹý³ÌÖÐʼÖÕÕ¼ÓøÃÁ´Â·¡£ÓÉÓÚͨÐŵĹý³ÌÖв»¿ÉÄÜÒ»Ö±ÔÚʹÓô«ÊäÏß·£¬Òò´Ëµç·½»»»¶ÔÏß·µÄÀûÓÃÂʺܵͣ¬ÍùÍù²»µ½ 10%¡£ +电路交æ�¢ç”¨äºŽç”µè¯�通信系统,两个用户è¦�通信之å‰�需è¦�建立一æ�¡ä¸“用的物ç�†é“¾è·¯ï¼Œå¹¶ä¸”在整个通信过程中始终å� ç”¨è¯¥é“¾è·¯ã€‚由于通信的过程中ä¸�å�¯èƒ½ä¸€ç›´åœ¨ä½¿ç”¨ä¼ è¾“线路,因此电路交æ�¢å¯¹çº¿è·¯çš„利用率很低,往往ä¸�到 10%。 -### 2. ±¨ÎĽ»»» +### 2. 报文交æ�¢ -±¨ÎĽ»»»ÓÃÓÚÓʾÖͨÐÅϵͳ£¬ÓʾֽÓÊÕµ½Ò»·Ý±¨ÎÄÖ®ºó£¬ÏÈ´æ´¢ÏÂÀ´£¬È»ºó°ÑÏàͬĿµÄµØµÄ±¨ÎÄÒ»Æðת·¢µ½ÏÂÒ»¸öÄ¿µÄµØ£¬Õâ¸ö¹ý³Ì¾ÍÊǴ洢ת·¢¹ý³Ì¡£ +报文交æ�¢ç”¨äºŽé‚®å±€é€šä¿¡ç³»ç»Ÿï¼Œé‚®å±€æŽ¥æ”¶åˆ°ä¸€ä»½æŠ¥æ–‡ä¹‹å�Žï¼Œå…ˆå­˜å‚¨ä¸‹æ�¥ï¼Œç„¶å�ŽæŠŠç›¸å�Œç›®çš„地的报文一起转å�‘到下一个目的地,这个过程就是存储转å�‘过程。 -### 3. ·Ö×é½»»» +### 3. 分组交æ�¢ -·Ö×é½»»»Ò²Ê¹ÓÃÁ˴洢ת·¢£¬µ«ÊÇת·¢µÄÊÇ·Ö×é¶ø²»ÊDZ¨ÎÄ¡£°ÑÕû¿éÊý¾Ý³ÆÎªÒ»¸ö±¨ÎÄ£¬ÓÉÓÚÒ»¸ö±¨ÎÄ¿ÉÄܺܳ¤£¬ÐèÒªÏȽøÐÐÇз֣¬À´Âú×ã·Ö×éÄÜ´¦ÀíµÄ´óС¡£ÔÚÿ¸öÇзֵÄÊý¾ÝÇ°Ãæ¼ÓÉÏÊײ¿Ö®ºó¾Í³ÉΪÁË·Ö×飬Êײ¿°üº¬ÁËÄ¿µÄµØÖ·ºÍÔ´µØÖ·µÈ¿ØÖÆÐÅÏ¢¡£ +分组交æ�¢ä¹Ÿä½¿ç”¨äº†å­˜å‚¨è½¬å�‘,但是转å�‘的是分组而ä¸�是报文。把整å�—æ•°æ�®ç§°ä¸ºä¸€ä¸ªæŠ¥æ–‡ï¼Œç”±äºŽä¸€ä¸ªæŠ¥æ–‡å�¯èƒ½å¾ˆé•¿ï¼Œéœ€è¦�先进行切分,æ�¥æ»¡è¶³åˆ†ç»„能处ç�†çš„大å°�。在æ¯�个切分的数æ�®å‰�é�¢åŠ ä¸Šé¦–éƒ¨ä¹‹å�Žå°±æˆ�为了分组,首部包å�«äº†ç›®çš„地å�€å’Œæº�地å�€ç­‰æŽ§åˆ¶ä¿¡æ�¯ã€‚ -![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/6f4af159-8b03-4246-8d0e-222db65bb83c.jpg) +![](https://github.com/CyC2018/InterviewNotes/blob/master/pics//6f4af159-8b03-4246-8d0e-222db65bb83c.jpg) -´æ´¢×ª·¢ÔÊÐíÔÚÒ»Ìõ´«ÊäÏß·ÉÏ´«ËͶà¸öÖ÷»úµÄ·Ö×飬Òò´Ë²»ÐèÒªÕ¼Óö˵½¶ËµÄÏß·×ÊÔ´¡£ +存储转å�‘å…�许在一æ�¡ä¼ è¾“线路上传é€�多个主机的分组,因此ä¸�需è¦�å� ç”¨ç«¯åˆ°ç«¯çš„线路资æº�。 -Ïà±ÈÓÚ±¨ÎĽ»»»£¬ÓÉÓÚ·Ö×é±È±¨ÎĸüС£¬´æ´¢×ª·¢µÄËÙ¶ÈÒ²¾Í¸ü¿ì¡£ +相比于报文交æ�¢ï¼Œç”±äºŽåˆ†ç»„比报文更å°�,存储转å�‘的速度也就更快。 -## ʱÑÓ +## æ—¶å»¶ -×ÜʱÑÓ = ·¢ËÍʱÑÓ + ´«²¥Ê±ÑÓ + ´¦ÀíʱÑÓ + ÅŶÓʱÑÓ +总时延 = å�‘é€�æ—¶å»¶ + ä¼ æ’­æ—¶å»¶ + 处ç�†æ—¶å»¶ + 排队时延 -![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/ceee91c2-da26-4169-94c3-e4608b46b9ac.png) +![](https://github.com/CyC2018/InterviewNotes/blob/master/pics//ceee91c2-da26-4169-94c3-e4608b46b9ac.png) -### 1. ·¢ËÍʱÑÓ +### 1. å�‘é€�æ—¶å»¶ -Ö÷»ú»ò·ÓÉÆ÷·¢ËÍÊý¾ÝÖ¡ËùÐèÒªµÄʱ¼ä¡£ +主机或路由器å�‘é€�æ•°æ�®å¸§æ‰€éœ€è¦�的时间。 -![](http://latex.codecogs.com/gif.latex?\\\\delay=\frac{l(bit)}{v(bit/s)}) +
-ÆäÖÐ l ±íʾÊý¾ÝÖ¡µÄ³¤¶È£¬v ±íʾ·¢ËÍËÙÂÊ¡£ +其中 l 表示数æ�®å¸§çš„长度,v 表示å�‘é€�速率。 -### 2. ´«²¥Ê±ÑÓ +### 2. ä¼ æ’­æ—¶å»¶ -µç´Å²¨ÔÚÐŵÀÖд«²¥Ò»¶¨µÄ¾àÀëÐèÒª»¨·ÑµÄʱ¼ä£¬µç´Å²¨´«²¥ËٶȽӽü¹âËÙ¡£ +电ç£�波在信é�“中传播一定的è·�离需è¦�花费的时间,电ç£�波传播速度接近光速。 -![](http://latex.codecogs.com/gif.latex?\\\\delay=\frac{l(m)}{v(m/s)}) +
-ÆäÖÐ l ±íʾÐŵÀ³¤¶È£¬v ±íʾµç´Å²¨ÔÚÐŵÀÉϵĴ«²¥ËÙÂÊ¡£ +其中 l 表示信é�“长度,v 表示电ç£�波在信é�“上的传播速率。 -### 3. ´¦ÀíʱÑÓ +### 3. 处ç�†æ—¶å»¶ -Ö÷»ú»ò·ÓÉÆ÷ÊÕµ½·Ö×éʱ½øÐд¦ÀíËùÐèÒªµÄʱ¼ä£¬ÀýÈç·ÖÎöÊײ¿£¬´Ó·Ö×éÖÐÌáÈ¡Êý¾Ý²¿·ÖµÈ¡£ +主机或路由器收到分组时进行处ç�†æ‰€éœ€è¦�的时间,例如分æž�首部,从分组中æ��å�–æ•°æ�®éƒ¨åˆ†ç­‰ã€‚ -### 4. ÅŶÓʱÑÓ +### 4. 排队时延 -·Ö×éÔÚ·ÓÉÆ÷µÄÊäÈë¶ÓÁкÍÊä³ö¶ÓÁÐÖÐÅŶӵȴýµÄʱ¼ä£¬È¡¾öÓÚÍøÂ統ǰµÄͨÐÅÁ¿¡£ +分组在路由器的输入队列和输出队列中排队等待的时间,å�–决于网络当å‰�的通信é‡�。 -## ¼ÆËã»úÍøÂçÌåϵ½á¹¹* +## 计算机网络体系结构* -![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/1005dc9d-9049-4b06-9524-6171e56ebd8c.png) +![](https://github.com/CyC2018/InterviewNotes/blob/master/pics//1005dc9d-9049-4b06-9524-6171e56ebd8c.png) -### 1. Æß²ãЭÒé +### 1. 七层å��è®® -Èçͼ a Ëùʾ£¬ÆäÖбíʾ²ãºÍ»á»°²ãÓÃ;ÈçÏ£º +如图 a 所示,其中表示层和会è¯�层用途如下: -1. ±íʾ²ã£ºÐÅÏ¢µÄÓï·¨ÓïÒåÒÔ¼°ËüÃǵĹØÁª£¬Èç¼ÓÃܽâÃÜ¡¢×ª»»·­Ò롢ѹËõ½âѹËõ£» -2. »á»°²ã£º²»Í¬»úÆ÷ÉϵÄÓû§Ö®¼ä½¨Á¢¼°¹ÜÀí»á»°¡£ +1. 表示层:信æ�¯çš„语法语义以å�Šå®ƒä»¬çš„å…³è�”,如加密解密ã€�转æ�¢ç¿»è¯‘ã€�压缩解压缩; +2. 会è¯�层:ä¸�å�Œæœºå™¨ä¸Šçš„用户之间建立å�Šç®¡ç�†ä¼šè¯�。 -### 2. Îå²ãЭÒé +### 2. 五层å��è®® -1. Ó¦ÓÃ²ã£ºÎªÌØ¶¨Ó¦ÓóÌÐòÌṩÊý¾Ý´«Êä·þÎñ£¬ÀýÈç HTTP¡¢DNS µÈ¡£Êý¾Ýµ¥Î»Îª±¨ÎÄ¡£ +1. 应用层:为特定应用程åº�æ��供数æ�®ä¼ è¾“æœ�务,例如 HTTPã€�DNS 等。数æ�®å�•ä½�为报文。 -2. ÔËÊä²ã£ºÌṩµÄÊǽø³Ì¼äµÄͨÓÃÊý¾Ý´«Êä·þÎñ¡£ÓÉÓÚÓ¦ÓòãЭÒéºÜ¶à£¬¶¨ÒåͨÓõÄÔËÊä²ãЭÒé¾Í¿ÉÒÔÖ§³Ö²»¶ÏÔö¶àµÄÓ¦ÓòãЭÒé¡£ÔËÊä²ã°üÀ¨Á½ÖÖЭÒ飺´«Êä¿ØÖÆÐ­Òé TCP£¬Ìá¹©ÃæÏòÁ¬½Ó¡¢¿É¿¿µÄÊý¾Ý´«Êä·þÎñ£¬Êý¾Ýµ¥Î»Îª±¨ÎĶΣ»Óû§Êý¾Ý±¨Ð­Òé UDP£¬ÌṩÎÞÁ¬½Ó¡¢¾¡×î´óŬÁ¦µÄÊý¾Ý´«Êä·þÎñ£¬Êý¾Ýµ¥Î»ÎªÓû§Êý¾Ý±¨¡£TCP Ö÷ÒªÌṩÍêÕûÐÔ·þÎñ£¬UDP Ö÷ÒªÌṩ¼°Ê±ÐÔ·þÎñ¡£ +2. è¿�输层:æ��供的是进程间的通用数æ�®ä¼ è¾“æœ�务。由于应用层å��议很多,定义通用的è¿�输层å��议就å�¯ä»¥æ”¯æŒ�ä¸�断增多的应用层å��议。è¿�输层包括两ç§�å��议:传输控制å��è®® TCP,æ��ä¾›é�¢å�‘连接ã€�å�¯é� çš„æ•°æ�®ä¼ è¾“æœ�务,数æ�®å�•ä½�为报文段;用户数æ�®æŠ¥å��è®® UDP,æ��供无连接ã€�尽最大努力的数æ�®ä¼ è¾“æœ�务,数æ�®å�•ä½�为用户数æ�®æŠ¥ã€‚TCP 主è¦�æ��供完整性æœ�务,UDP 主è¦�æ��ä¾›å�Šæ—¶æ€§æœ�务。 -3. ÍøÂç²ã£ºÎªÖ÷»úÖ®¼äÌṩ·þÎñ£¬¶ø²»ÊÇÏñÔËÊä²ãЭÒéÄÇÑùÊÇΪÖ÷»úÖеĽø³ÌÌṩ·þÎñ¡£ÍøÂç²ã°ÑÔËÊä²ã²úÉúµÄ±¨ÎĶλòÕßÓû§Êý¾Ý±¨·â×°³É·Ö×éÀ´½øÐд«Êä¡£ +3. 网络层:为主机之间æ��ä¾›æœ�务,而ä¸�是åƒ�è¿�输层å��议那样是为主机中的进程æ��ä¾›æœ�务。网络层把è¿�输层产生的报文段或者用户数æ�®æŠ¥å°�装æˆ�分组æ�¥è¿›è¡Œä¼ è¾“。 -4. Êý¾ÝÁ´Â·²ã£ºÍøÂç²ãÕë¶ÔµÄ»¹ÊÇÖ÷»úÖ®¼ä£¬¶øÖ÷»úÖ®¼ä¿ÉÒÔÓкܶàÁ´Â·£¬Á´Â·²ãЭÒé¾ÍÊÇΪÏàÁÚ½áµãÖ®¼äÌṩ·þÎñ¡£Êý¾ÝÁ´Â·²ã°ÑÍøÂç²ã´«À´µÄ·Ö×é·â×°³ÉÖ¡¡£ +4. æ•°æ�®é“¾è·¯å±‚:网络层针对的还是主机之间,而主机之间å�¯ä»¥æœ‰å¾ˆå¤šé“¾è·¯ï¼Œé“¾è·¯å±‚å��议就是为相邻结点之间æ��ä¾›æœ�务。数æ�®é“¾è·¯å±‚把网络层传æ�¥çš„分组å°�装æˆ�帧。 -5. ÎïÀí²ã£º¿¼ÂǵÄÊÇÔõÑùÔÚ´«ÊäýÌåÉÏ´«ÊäÊý¾Ý±ÈÌØÁ÷£¬¶ø²»ÊÇÖ¸¾ßÌåµÄ´«ÊäýÌå¡£ÎïÀí²ãµÄ×÷ÓÃÊǾ¡¿ÉÄÜÆÁ±Î´«ÊäýÌåºÍͨÐÅÊֶεIJîÒ죬ʹÎïÀí²ãÉϵÄÊý¾ÝÁ´Â·²ã¸Ð¾õ²»µ½ÕâЩ²îÒì¡£ +5. 物ç�†å±‚:考虑的是怎样在传输媒体上传输数æ�®æ¯”特æµ�,而ä¸�是指具体的传输媒体。物ç�†å±‚的作用是尽å�¯èƒ½å±�蔽传输媒体和通信手段的差异,使物ç�†å±‚上的数æ�®é“¾è·¯å±‚感觉ä¸�到这些差异。 -### 3. Êý¾ÝÔÚ¸÷²ãÖ®¼äµÄ´«µÝ¹ý³Ì +### 3. æ•°æ�®åœ¨å�„层之间的传递过程 -ÔÚÏòϵĹý³ÌÖУ¬ÐèÒªÌí¼ÓϲãЭÒéËùÐèÒªµÄÊײ¿»òÕßβ²¿£¬¶øÔÚÏòÉϵĹý³ÌÖв»¶Ï²ð¿ªÊײ¿ºÍβ²¿¡£ +在å�‘下的过程中,需è¦�添加下层å��议所需è¦�的首部或者尾部,而在å�‘上的过程中ä¸�断拆开首部和尾部。 -·ÓÉÆ÷Ö»ÓÐÏÂÃæÈý²ãЭÒ飬ÒòΪ·ÓÉÆ÷λÓÚÍøÂçºËÐÄÖУ¬²»ÐèҪΪ½ø³Ì»òÕßÓ¦ÓóÌÐòÌṩ·þÎñ£¬Òò´ËÒ²¾Í²»ÐèÒªÔËÊä²ãºÍÓ¦Óò㡣 +路由器å�ªæœ‰ä¸‹é�¢ä¸‰å±‚å��议,因为路由器ä½�于网络核心中,ä¸�需è¦�为进程或者应用程åº�æ��ä¾›æœ�务,因此也就ä¸�需è¦�è¿�输层和应用层。 -![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/f7d5da89-2d75-4d8f-85e7-6b608865dc00.jpg) +![](https://github.com/CyC2018/InterviewNotes/blob/master/pics//f7d5da89-2d75-4d8f-85e7-6b608865dc00.jpg) -### 4. TCP/IP Ìåϵ½á¹¹ +### 4. TCP/IP 体系结构 -ËüÖ»ÓÐËIJ㣬Ï൱ÓÚÎå²ãЭÒéÖÐÊý¾ÝÁ´Â·²ãºÍÎïÀí²ãºÏ²¢ÎªÍøÂç½Ó¿Ú²ã¡£ +它å�ªæœ‰å››å±‚,相当于五层å��议中数æ�®é“¾è·¯å±‚和物ç�†å±‚å�ˆå¹¶ä¸ºç½‘络接å�£å±‚。 -ÏÖÔÚµÄ TCP/IP Ìåϵ½á¹¹²»Ñϸñ×ñÑ­ OSI ·Ö²ã¸ÅÄӦÓòã¿ÉÄÜ»áÖ±½ÓʹÓà IP ²ã»òÕßÍøÂç½Ó¿Ú²ã¡£ +现在的 TCP/IP 体系结构ä¸�严格é�µå¾ª OSI 分层概念,应用层å�¯èƒ½ä¼šç›´æŽ¥ä½¿ç”¨ IP 层或者网络接å�£å±‚。 -![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/3e2200b3-1c18-4853-ae42-7788e8e1f939.png) +![](https://github.com/CyC2018/InterviewNotes/blob/master/pics//3e2200b3-1c18-4853-ae42-7788e8e1f939.png) -TCP/IP ЭÒé×åÊÇÒ»ÖÖɳ©ÐÎ×´£¬ÖмäСÁ½±ß´ó£¬IP ЭÒéÔÚÆäÖÐÕ¼ÓþÙ×ãÇáÖØµÄµØÎ»¡£ +TCP/IP å��è®®æ—�是一ç§�æ²™æ¼�形状,中间å°�两边大,IP å��议在其中å� ç”¨ä¸¾è¶³è½»é‡�的地ä½�。 -![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/9ecaebee-670e-4cb2-9cdb-3029c00f33bd.png) +![](https://github.com/CyC2018/InterviewNotes/blob/master/pics//9ecaebee-670e-4cb2-9cdb-3029c00f33bd.png) -# µÚ¶þÕ ÎïÀí²ã +# 第二章 物ç�†å±‚ -## ͨÐÅ·½Ê½ +## 通信方å¼� -1. µ¥ÏòͨÐÅ£¬ÓÖ³ÆÎªµ¥¹¤Í¨ÐÅ£» -2. Ë«Ïò½»ÌæÍ¨ÐÅ£¬ÓÖ³ÆÎª°ëË«¹¤Í¨ÐÅ£» -3. Ë«ÏòͬʱͨÐÅ£¬ÓÖ³ÆÎªÈ«Ë«¹¤Í¨ÐÅ¡£ +1. å�•å�‘通信,å�ˆç§°ä¸ºå�•工通信; +2. å�Œå�‘交替通信,å�ˆç§°ä¸ºå�Šå�Œå·¥é€šä¿¡ï¼› +3. å�Œå�‘å�Œæ—¶é€šä¿¡ï¼Œå�ˆç§°ä¸ºå…¨å�Œå·¥é€šä¿¡ã€‚ -## ´øÍ¨µ÷ÖÆ +## 带通调制 -Ä£ÄâÐźÅÊÇÁ¬ÐøµÄÐźţ¬Êý×ÖÐźÅÊÇÀëÉ¢µÄÐźš£´øÍ¨µ÷ÖÆ°ÑÊý×ÖÐźÅת»»ÎªÄ£ÄâÐźš£ +模拟信å�·æ˜¯è¿žç»­çš„ä¿¡å�·ï¼Œæ•°å­—ä¿¡å�·æ˜¯ç¦»æ•£çš„ä¿¡å�·ã€‚带通调制把数字信å�·è½¬æ�¢ä¸ºæ¨¡æ‹Ÿä¿¡å�·ã€‚ -![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/d2c55c84-aa1f-43c1-bd97-457bcb7816b3.png) +![](https://github.com/CyC2018/InterviewNotes/blob/master/pics//d2c55c84-aa1f-43c1-bd97-457bcb7816b3.png) -## ÐŵÀ¸´Óü¼Êõ +## ä¿¡é�“å¤�用技术 -### 1. Ƶ·Ö¸´Óá¢Ê±·Ö¸´Óà +### 1. 频分å¤�用ã€�时分å¤�用 -Ƶ·Ö¸´ÓõÄËùÓÐÓû§ÔÚÏàͬµÄʱ¼äÕ¼Óò»Í¬µÄƵÂÊ´ø¿í×ÊÔ´£»Ê±·Ö¸´ÓõÄËùÓÐÓû§ÔÚ²»Í¬µÄʱ¼äÕ¼ÓÃÏàͬµÄƵÂÊ´ø¿í×ÊÔ´¡£ +频分å¤�用的所有用户在相å�Œçš„æ—¶é—´å� ç”¨ä¸�å�Œçš„频率带宽资æº�;时分å¤�用的所有用户在ä¸�å�Œçš„æ—¶é—´å� ç”¨ç›¸å�Œçš„频率带宽资æº�。 -ʹÓÃÕâÁ½ÖÖ·½Ê½½øÐÐͨÐÅ£¬ÔÚͨÐŵĹý³ÌÖÐÓû§»áÒ»Ö±Õ¼ÓÃÒ»²¿·ÖÐŵÀ×ÊÔ´¡£µ«ÊÇÓÉÓÚ¼ÆËã»úÊý¾ÝµÄÍ»·¢ÐÔÖÊ£¬Ã»±ØÒªÒ»Ö±Õ¼ÓÃÐŵÀ×ÊÔ´¶ø²»Èóö¸øÆäËüÓû§Ê¹Óã¬Òò´ËÕâÁ½ÖÖ·½Ê½¶ÔÐŵÀµÄÀûÓÃÂʶ¼²»¸ß¡£ +使用这两ç§�æ–¹å¼�进行通信,在通信的过程中用户会一直å� ç”¨ä¸€éƒ¨åˆ†ä¿¡é�“资æº�。但是由于计算机数æ�®çš„çª�å�‘性质,没必è¦�一直å� ç”¨ä¿¡é�“资æº�而ä¸�让出给其它用户使用,因此这两ç§�æ–¹å¼�对信é�“的利用率都ä¸�高。 -![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/543d47a1-f0dd-414f-b23c-0c142c814854.png) +![](https://github.com/CyC2018/InterviewNotes/blob/master/pics//543d47a1-f0dd-414f-b23c-0c142c814854.png) -### 2. ͳ¼ÆÊ±·Ö¸´Óà +### 2. 统计时分å¤�用 -ÊǶÔʱ·Ö¸´ÓõÄÒ»ÖָĽø£¬²»¹Ì¶¨Ã¿¸öÓû§ÔÚʱ·Ö¸´ÓÃÖ¡ÖеÄλÖã¬Ö»ÒªÓÐÊý¾Ý¾Í¼¯ÖÐÆðÀ´×é³Éʱ·Ö¸´ÓÃÖ¡È»ºó·¢ËÍ¡£ +是对时分å¤�用的一ç§�改进,ä¸�固定æ¯�个用户在时分å¤�用帧中的ä½�置,å�ªè¦�有数æ�®å°±é›†ä¸­èµ·æ�¥ç»„æˆ�时分å¤�用帧然å�Žå�‘é€�。 -![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/29058e09-bb72-4040-a73d-4c497895e9ce.jpg) +![](https://github.com/CyC2018/InterviewNotes/blob/master/pics//29058e09-bb72-4040-a73d-4c497895e9ce.jpg) -### 3. ²¨·Ö¸´Óà +### 3. 波分å¤�用 -¹âµÄƵ·Ö¸´Óá£ÓÉÓÚ¹âµÄƵÂʺܸߣ¬Òò´Ëϰ¹ßÉÏÓò¨³¤¶ø²»ÊÇÆµÂÊÀ´±íʾËùʹÓõĹâÔØ²¨¡£ +光的频分å¤�用。由于光的频率很高,因此习惯上用波长而ä¸�是频率æ�¥è¡¨ç¤ºæ‰€ä½¿ç”¨çš„光载波。 -![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/78534153-88d1-4f83-a6e0-59064dbdc43a.png) +![](https://github.com/CyC2018/InterviewNotes/blob/master/pics//78534153-88d1-4f83-a6e0-59064dbdc43a.png) -### 4. Âë·Ö¸´Óà +### 4. ç �分å¤�用 -Ϊÿ¸öÓû§·ÖÅä m bit µÄÂëÆ¬£¬²¢ÇÒËùÓеÄÂëÆ¬Õý½»£¬¶ÔÓÚÈÎÒâÁ½¸öÂëÆ¬ $\vec{S}$ ºÍ $\vec{T}$ ÓÐ +为æ¯�个用户分é…� m bit çš„ç �片,并且所有的ç �片正交,对于任æ„�两个ç �片 å’Œ 有 -![](http://latex.codecogs.com/gif.latex?\\\\\vec{S}\cdot\vec{T}=0) +
-ΪÁË·½±ã£¬È¡ m=8£¬ÉèÂëÆ¬ $\vec{S}$ Ϊ 00011011¡£ÔÚÓµÓиÃÂëÆ¬µÄÓû§·¢ËͱÈÌØ 1 ʱ¾Í·¢Ë͸ÃÂëÆ¬£¬·¢ËͱÈÌØ 0 ʱ¾Í·¢Ë͸ÃÂëÆ¬µÄ·´Âë 11100100¡£ +为了方便,å�– m=8,设ç �片 为 00011011。在拥有该ç �片的用户å�‘é€�比特 1 æ—¶å°±å�‘é€�该ç �片,å�‘é€�比特 0 æ—¶å°±å�‘é€�该ç �片的å��ç � 11100100。 -ÔÚ¼ÆËãʱ½« 00011011 ¼Ç×÷ (-1 -1 -1 +1 +1 -1 +1 +1)£¬¿ÉÒԵõ½ +在计算时将 00011011 记作 (-1 -1 -1 +1 +1 -1 +1 +1),å�¯ä»¥å¾—到 -![](http://latex.codecogs.com/gif.latex?\\\\\frac{1}{m}\vec{S}\cdot\vec{S}=1) +
-![](http://latex.codecogs.com/gif.latex?\\\\\frac{1}{m}\vec{S}\cdot\vec{S'}=-1) +
-ÆäÖÐ $\vec{S'}$ Ϊ $\vec{S}$ µÄ·´Âë¡£ +其中 为 çš„å��ç �。 -ÀûÓÃÉÏÃæµÄʽ×ÓÎÒÃÇÖªµÀ£¬µ±½ÓÊÕ¶ËʹÓÃÂëÆ¬ $\vec{S}$ ¶Ô½ÓÊÕµ½µÄÊý¾Ý½øÐÐÄÚ»ýÔËËãʱ£¬½á¹ûΪ 0 µÄÊÇÆäËüÓû§·¢Ë͵ÄÊý¾Ý£¬½á¹ûΪ 1 µÄÊÇÓû§·¢Ë͵ıÈÌØ 1£¬½á¹ûΪ -1 µÄÊÇÓû§·¢Ë͵ıÈÌØ 0¡£ +利用上é�¢çš„å¼�å­�我们知é�“,当接收端使用ç �片 对接收到的数æ�®è¿›è¡Œå†…积è¿�算时,结果为 0 的是其它用户å�‘é€�的数æ�®ï¼Œç»“果为 1 的是用户å�‘é€�的比特 1,结果为 -1 的是用户å�‘é€�的比特 0。 -Âë·Ö¸´ÓÃÐèÒª·¢Ë͵ÄÊý¾ÝÁ¿ÎªÔ­Ï鵀 m ±¶¡£ +ç �分å¤�用需è¦�å�‘é€�的数æ�®é‡�为原先的 m å€�。 -![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/0042edad-8e3b-4279-bd93-6906fcd1b640.jpg) +![](https://github.com/CyC2018/InterviewNotes/blob/master/pics//0042edad-8e3b-4279-bd93-6906fcd1b640.jpg) -# µÚÈýÕ Êý¾ÝÁ´Â·²ã +# 第三章 æ•°æ�®é“¾è·¯å±‚ -## Èý¸ö»ù±¾ÎÊÌâ +## 三个基本问题 -### 1. ·â×°³ÉÖ¡ +### 1. å°�装æˆ�帧 -½«ÍøÂç²ã´«ÏÂÀ´µÄ·Ö×éÌí¼ÓÊײ¿ºÍβ²¿£¬ÓÃÓÚ±ê¼ÇÖ¡µÄ¿ªÊ¼ºÍ½áÊø¡£ +将网络层传下æ�¥çš„分组添加首部和尾部,用于标记帧的开始和结æ�Ÿã€‚ -![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/ea5ed9b2-6d9f-48fb-b890-0288caf9088a.jpg) +![](https://github.com/CyC2018/InterviewNotes/blob/master/pics//ea5ed9b2-6d9f-48fb-b890-0288caf9088a.jpg) -### 2. ͸Ã÷´«Êä +### 2. é€�明传输 -͸Ã÷±íʾһ¸öʵ¼Ê´æÔÚµÄÊÂÎï¿´ÆðÀ´ºÃÏñ²»´æÔÚÒ»Ñù¡£ +é€�明表示一个实际存在的事物看起æ�¥å¥½åƒ�ä¸�存在一样。 -Ö¡ÖÐÓÐÊײ¿ºÍβ²¿£¬Èç¹ûÖ¡µÄÊý¾Ý²¿·Öº¬ÓкÍÊײ¿Î²²¿ÏàͬµÄÄÚÈÝ£¬ÄÇô֡µÄ¿ªÊ¼ºÍ½áÊøÎ»Öþͻᱻ´íÎóµÄÅж¨¡£ÐèÒªÔÚÊý¾ÝÖгöÏÖÊײ¿Î²²¿ÏàͬµÄÄÚÈÝÇ°Ãæ²åÈëתÒå×Ö·û£¬Èç¹ûÐèÒª´«ÊäµÄÄÚÈÝÕýºÃ¾ÍÊÇתÒå×Ö·û£¬ÄÇô¾ÍÔÚתÒå×Ö·ûÇ°ÃæÔÙ¼Ó¸öתÒå×Ö·û£¬ÔÚ½ÓÊն˽øÐд¦ÀíÖ®ºó¿ÉÒÔ»¹Ô­³öԭʼÊý¾Ý¡£Õâ¸ö¹ý³Ì͸Ã÷´«ÊäµÄÄÚÈÝÊÇתÒå×Ö·û£¬Óû§²ì¾õ²»µ½×ªÒå×Ö·ûµÄ´æÔÚ¡£ +帧中有首部和尾部,如果帧的数æ�®éƒ¨åˆ†å�«æœ‰å’Œé¦–部尾部相å�Œçš„内容,那么帧的开始和结æ�Ÿä½�置就会被错误的判定。需è¦�在数æ�®ä¸­å‡ºçŽ°é¦–éƒ¨å°¾éƒ¨ç›¸å�Œçš„内容å‰�é�¢æ�’入转义字符,如果需è¦�传输的内容正好就是转义字符,那么就在转义字符å‰�é�¢å†�加个转义字符,在接收端进行处ç�†ä¹‹å�Žå�¯ä»¥è¿˜åŽŸå‡ºåŽŸå§‹æ•°æ�®ã€‚这个过程é€�明传输的内容是转义字符,用户察觉ä¸�到转义字符的存在。 -![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/44e1d90e-3fe6-4dd6-8dce-6daab12e7663.jpg) +![](https://github.com/CyC2018/InterviewNotes/blob/master/pics//44e1d90e-3fe6-4dd6-8dce-6daab12e7663.jpg) -### 3. ²î´í¼ì²â +### 3. 差错检测 -ĿǰÊý¾ÝÁ´Â·²ã¹ã·ºÊ¹ÓÃÁËÑ­»·ÈßÓà¼ìÑ飨CRC£©À´¼ì²é±ÈÌØ²î´í¡£ +ç›®å‰�æ•°æ�®é“¾è·¯å±‚广泛使用了循环冗余检验(CRC)æ�¥æ£€æŸ¥æ¯”特差错。 -³ýÁË CRC£¬»¹ÓеļìÑé·½·¨±ÈÈ磺 +除了 CRC,还有的检验方法比如: -- ÆæÅ¼Ð£Ñ飺Ìí¼Ó 1 λʹ 1 µÄλÊýÎªÆæÊý»òżÊý£¬¸ü½øÒ»²½µÄ¶þÎ¬ÆæÅ¼Ð£Ñé·½·¨£¬²»µ«¿ÉÒÔ¼ì´í»¹¿ÉÒÔ¾À´í²¿·Ö´íÎó¡£ -- ¼ìÑéºÍ·½·¨£º¾ßÌå²Î¿¼ UDP ¼ìÑéºÍ¼ÆËã·½·¨£» +- 奇å�¶æ ¡éªŒï¼šæ·»åŠ  1 ä½�使 1 çš„ä½�数为奇数或å�¶æ•°ï¼Œæ›´è¿›ä¸€æ­¥çš„二维奇å�¶æ ¡éªŒæ–¹æ³•,ä¸�但å�¯ä»¥æ£€é”™è¿˜å�¯ä»¥çº é”™éƒ¨åˆ†é”™è¯¯ã€‚ +- 检验和方法:具体å�‚考 UDP 检验和计算方法; -## µã¶ÔµãÐŵÀ - PPP ЭÒé +## 点对点信é�“ - PPP å��è®® -»¥ÁªÍøÓû§Í¨³£ÐèÒªÁ¬½Óµ½Ä³¸ö ISP Ö®ºó²ÅÄܽÓÈëµ½»¥ÁªÍø£¬PPP ЭÒé¾ÍÊÇÓû§¼ÆËã»úºÍ ISP ½øÐÐͨÐÅʱËùʹÓõÄÊý¾ÝÁ´Â·²ãЭÒé¡£ +互è�”网用户通常需è¦�连接到æŸ�个 ISP 之å�Žæ‰�能接入到互è�”网,PPP å��议就是用户计算机和 ISP 进行通信时所使用的数æ�®é“¾è·¯å±‚å��议。 -![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/8b5bd2c8-8425-4a8b-89db-235c95800de9.jpg) +![](https://github.com/CyC2018/InterviewNotes/blob/master/pics//8b5bd2c8-8425-4a8b-89db-235c95800de9.jpg) -ÔÚ PPP µÄÖ¡ÖУ¬F ×Ö¶ÎΪ֡µÄ¶¨½ç·û£¬A ºÍ C ÔÝʱûÓÐÒâÒå¡£FCS ÊÇʹÓà CRC µÄ¼ìÑéÐòÁС£ÐÅÏ¢²¿·ÖµÄ³¤¶È²»³¬¹ý 1500¡£ +在 PPP 的帧中,F 字段为帧的定界符,A å’Œ C 暂时没有æ„�义。FCS 是使用 CRC 的检验åº�列。信æ�¯éƒ¨åˆ†çš„长度ä¸�超过 1500。 -![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/a5fa89e7-54b9-4e2f-8c48-a35712d7b2f5.jpg) +![](https://github.com/CyC2018/InterviewNotes/blob/master/pics//a5fa89e7-54b9-4e2f-8c48-a35712d7b2f5.jpg) -## ¾ÖÓòÍøµÄÍØÆË +## 局域网的拓扑 -![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/8b15e36f-69b4-46b6-a07c-7234ac7c7927.jpg) +![](https://github.com/CyC2018/InterviewNotes/blob/master/pics//8b15e36f-69b4-46b6-a07c-7234ac7c7927.jpg) -## ¹ã²¥ÐŵÀ - CSMA/CD ЭÒé* +## 广播信é�“ - CSMA/CD å��è®®* -Ôڹ㲥ÐŵÀÉÏ£¬Í¬Ò»Ê±¼äÖ»ÄÜÔÊÐíһ̨¼ÆËã»ú·¢ËÍÊý¾Ý¡£ +在广播信é�“上,å�Œä¸€æ—¶é—´å�ªèƒ½å…�许一å�°è®¡ç®—机å�‘é€�æ•°æ�®ã€‚ -CSMA/CD ±íÊ¾ÔØ²¨¼àÌý¶àµã½ÓÈë / Åöײ¼ì²â¡£ +CSMA/CD 表示载波监å�¬å¤šç‚¹æŽ¥å…¥ / 碰撞检测。 -- **¶àµã½ÓÈë**£ºËµÃ÷ÕâÊÇ×ÜÏßÐÍÍøÂ磬Ðí¶à¼ÆËã»úÒÔ¶àµãµÄ·½Ê½Á¬½Óµ½×ÜÏßÉÏ¡£ -- **ÔØ²¨¼àÌý**£ºÃ¿¸öÕ¾¶¼±ØÐ벻ͣµØ¼ìÌýÐŵÀ¡£ÔÚ·¢ËÍǰ£¬Èç¹û¼ìÌýÐŵÀÕýÔÚʹÓ㬾ͱØÐëµÈ´ý¡£ -- **Åöײ¼ì²â**£ºÔÚ·¢ËÍÖУ¬Èç¹û¼ìÌýÐŵÀÒÑÓÐÆäËüÕ¾ÕýÔÚ·¢ËÍÊý¾Ý£¬¾Í±íʾ·¢ÉúÁËÅöײ¡£ËäȻÿһ¸öÕ¾ÔÚ·¢ËÍÊý¾Ý֮ǰ¶¼ÒѾ­¼ìÌýÐŵÀΪ¿ÕÏУ¬µ«ÊÇÓÉÓÚµç´Å²¨µÄ´«²¥Ê±ÑӵĴæÔÚ£¬»¹ÊÇÓпÉÄܻᷢÉúÅöײ¡£ +- **多点接入**:说明这是总线型网络,许多计算机以多点的方å¼�连接到总线上。 +- **载波监å�¬**:æ¯�个站都必须ä¸�å�œåœ°æ£€å�¬ä¿¡é�“。在å�‘é€�å‰�,如果检å�¬ä¿¡é�“正在使用,就必须等待。 +- **碰撞检测**:在å�‘é€�中,如果检å�¬ä¿¡é�“已有其它站正在å�‘é€�æ•°æ�®ï¼Œå°±è¡¨ç¤ºå�‘生了碰撞。虽然æ¯�一个站在å�‘é€�æ•°æ�®ä¹‹å‰�都已ç»�检å�¬ä¿¡é�“为空闲,但是由于电ç£�波的传播时延的存在,还是有å�¯èƒ½ä¼šå�‘生碰撞。 -![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/f9ed4da5-0032-41e6-991a-36d995ec28fd.png) +![](https://github.com/CyC2018/InterviewNotes/blob/master/pics//f9ed4da5-0032-41e6-991a-36d995ec28fd.png) -¼Ç¶Ëµ½¶ËµÄ´«²¥Ê±ÑÓΪ ¦Ó£¬×îÏÈ·¢Ë͵ÄÕ¾µã×î¶à¾­¹ý 2¦Ó ¾Í¿ÉÒÔÖªµÀÊÇ·ñ·¢ÉúÁËÅöײ£¬³Æ 2¦Ó Ϊ **ÕùÓÃÆÚ**¡£Ö»Óо­¹ýÕùÓÃÆÚÖ®ºó»¹Ã»Óмì²âµ½Åöײ£¬²ÅÄܿ϶¨Õâ´Î·¢ËͲ»»á·¢ÉúÅöײ¡£ +记端到端的传播时延为 τ,最先å�‘é€�的站点最多ç»�过 2Ï„ å°±å�¯ä»¥çŸ¥é�“是å�¦å�‘生了碰撞,称 2Ï„ 为 **争用期**。å�ªæœ‰ç»�过争用期之å�Žè¿˜æ²¡æœ‰æ£€æµ‹åˆ°ç¢°æ’žï¼Œæ‰�能肯定这次å�‘é€�ä¸�会å�‘生碰撞。 -µ±·¢ÉúÅöײʱ£¬Õ¾µãҪֹͣ·¢ËÍ£¬µÈ´ýÒ»¶Îʱ¼äÔÙ·¢ËÍ¡£Õâ¸öʱ¼ä²ÉÓà **½Ø¶Ï¶þ½øÖÆÖ¸ÊýÍ˱ÜËã·¨** À´È·¶¨£¬´ÓÀëÉ¢µÄÕûÊý¼¯ºÏ {0, 1, .., (2k-1)} ÖÐËæ»úÈ¡³öÒ»¸öÊý£¬¼Ç×÷ r£¬È»ºóÈ¡ r ±¶µÄÕùÓÃÆÚ×÷ÎªÖØ´«µÈ´ýʱ¼ä¡£ +当å�‘生碰撞时,站点è¦�å�œæ­¢å�‘é€�,等待一段时间å†�å�‘é€�。这个时间采用 **截断二进制指数退é�¿ç®—法** æ�¥ç¡®å®šï¼Œä»Žç¦»æ•£çš„æ•´æ•°é›†å�ˆ {0, 1, .., (2k-1)} 中éš�机å�–出一个数,记作 r,然å�Žå�– r å€�的争用期作为é‡�传等待时间。 -## ¼¯Ï߯÷ +## 集线器 -´Ó±íÃæÉÏ¿´£¬Ê¹Óü¯Ï߯÷µÄ¾ÖÓòÍøÔÚÎïÀíÉÏÊÇÒ»¸öÐÇÐÍÍø¡£µ«ÊǼ¯Ï߯÷ʹÓõç×ÓÆ÷¼þÀ´Ä£Äâʵ¼ÊÀÂÏߵŤ×÷£¬Âß¼­ÉÏÈÔÊÇÒ»¸ö×ÜÏßÍø£¬Õû¸öϵͳÈÔÏñÒ»¸ö´«Í³ÒÔÌ«ÍøÄÇÑùÔËÐС£ +从表é�¢ä¸Šçœ‹ï¼Œä½¿ç”¨é›†çº¿å™¨çš„局域网在物ç�†ä¸Šæ˜¯ä¸€ä¸ªæ˜Ÿåž‹ç½‘。但是集线器使用电å­�器件æ�¥æ¨¡æ‹Ÿå®žé™…缆线的工作,逻辑上ä»�是一个总线网,整个系统ä»�åƒ�一个传统以太网那样è¿�行。 -![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/897a4f4e-2683-44e1-a26a-c0d0234dc576.jpg) +![](https://github.com/CyC2018/InterviewNotes/blob/master/pics//897a4f4e-2683-44e1-a26a-c0d0234dc576.jpg) -![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/40c3f8e5-3a20-45b6-a60c-77b9b952e104.jpg) +![](https://github.com/CyC2018/InterviewNotes/blob/master/pics//40c3f8e5-3a20-45b6-a60c-77b9b952e104.jpg) -## MAC ²ã +## MAC 层 -MAC µØÖ·ÊÇ 6 ×Ö½Ú£¨48 룩µÄµØÖ·£¬ÓÃÓÚΨһ±íÊ¾ÍøÂçÊÊÅäÆ÷£¨Íø¿¨£©£¬Ò»Ì¨Ö÷»úÓµÓжàÉÙ¸öÊÊÅäÆ÷¾ÍÓжàÉÙ¸ö MAC µØÖ·£¬ÀýÈç±Ê¼Ç±¾µçÄÔÆÕ±é´æÔÚÎÞÏßÍøÂçÊÊÅäÆ÷ºÍÓÐÏßÍøÂçÊÊÅäÆ÷¡£ +MAC 地å�€æ˜¯ 6 字节(48 ä½�)的地å�€ï¼Œç”¨äºŽå”¯ä¸€è¡¨ç¤ºç½‘络适é…�器(网å�¡ï¼‰ï¼Œä¸€å�°ä¸»æœºæ‹¥æœ‰å¤šå°‘个适é…�器就有多少个 MAC 地å�€ï¼Œä¾‹å¦‚笔记本电脑普é��存在无线网络适é…�器和有线网络适é…�器。 -![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/50d38e84-238f-4081-8876-14ef6d7938b5.jpg) +![](https://github.com/CyC2018/InterviewNotes/blob/master/pics//50d38e84-238f-4081-8876-14ef6d7938b5.jpg) -- **ÀàÐÍ**£º±ê¼ÇÉϲãʹÓõÄЭÒ飻 -- **Êý¾Ý**£º³¤¶ÈÔÚ 46-1500 Ö®¼ä£¬Èç¹û̫СÔòÐèÒªÌî³ä£» -- **FCS**£ºÖ¡¼ìÑéÐòÁУ¬Ê¹ÓõÄÊÇ CRC ¼ìÑé·½·¨£» -- **ǰͬ²½Âë**£ºÖ»ÊÇΪÁ˼ÆËã FCS ÁÙʱ¼ÓÈëµÄ£¬¼ÆËã½áÊøÖ®ºó»á¶ªÆú¡£ +- **类型**:标记上层使用的å��议; +- **æ•°æ�®**:长度在 46-1500 之间,如果太å°�则需è¦�å¡«å……ï¼› +- **FCS**:帧检验åº�列,使用的是 CRC 检验方法; +- **å‰�å�Œæ­¥ç �**:å�ªæ˜¯ä¸ºäº†è®¡ç®— FCS 临时加入的,计算结æ�Ÿä¹‹å�Žä¼šä¸¢å¼ƒã€‚ -## ÐéÄâ¾ÖÓòÍø +## 虚拟局域网 -ÐéÄâ¾ÖÓòÍø¿ÉÒÔ½¨Á¢ÓëÎïÀíλÖÃÎ޹صÄÂß¼­×飬ֻÓÐÔÚͬһ¸öÐéÄâ¾ÖÓòÍøÖеijÉÔ±²Å»áÊÕµ½Á´Â·²ã¹ã²¥ÐÅÏ¢£¬ÀýÈçÏÂͼÖÐ (A1, A2, A3, A4) ÊôÓÚÒ»¸öÐéÄâ¾ÖÓòÍø£¬A1 ·¢Ë͵Ĺ㲥»á±» A2¡¢A3¡¢A4 ÊÕµ½£¬¶øÆäËüÕ¾µãÊÕ²»µ½¡£ +虚拟局域网å�¯ä»¥å»ºç«‹ä¸Žç‰©ç�†ä½�置无关的逻辑组,å�ªæœ‰åœ¨å�Œä¸€ä¸ªè™šæ‹Ÿå±€åŸŸç½‘中的æˆ�员æ‰�会收到链路层广播信æ�¯ï¼Œä¾‹å¦‚下图中 (A1, A2, A3, A4) 属于一个虚拟局域网,A1 å�‘é€�的广播会被 A2ã€�A3ã€�A4 收到,而其它站点收ä¸�到。 -![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/a74b70ac-323a-4b31-b4d5-90569b8a944b.png) +![](https://github.com/CyC2018/InterviewNotes/blob/master/pics//a74b70ac-323a-4b31-b4d5-90569b8a944b.png) -# µÚËÄÕÂ ÍøÂç²ã* +# 第四章 网络层* -## Íø¼ÊЭÒé IP ¸ÅÊö +## 网际å��è®® IP 概述 -ÒòÎªÍøÂç²ãÊÇÕû¸ö»¥ÁªÍøµÄºËÐÄ£¬Òò´ËÓ¦µ±ÈÃÍøÂç²ã¾¡¿ÉÄܼòµ¥¡£ÍøÂç²ãÏòÉÏÖ»Ìṩ¼òµ¥Áé»îµÄ¡¢ÎÞÁ¬½ÓµÄ¡¢¾¡×î´óŬÁ¦½»»¥µÄÊý¾Ý±¨·þÎñ¡£ +因为网络层是整个互è�”网的核心,因此应当让网络层尽å�¯èƒ½ç®€å�•。网络层å�‘上å�ªæ��供简å�•ç�µæ´»çš„ã€�无连接的ã€�尽最大努力交互的数æ�®æŠ¥æœ�务。 -ʹÓà IP ЭÒ飬¿ÉÒÔ°ÑÒì¹¹µÄÎïÀíÍøÂçÁ¬½ÓÆðÀ´£¬Ê¹µÃÔÚÍøÂç²ã¿´ÆðÀ´ºÃÏñÊÇÒ»¸öͳһµÄÍøÂç¡£ +使用 IP å��议,å�¯ä»¥æŠŠå¼‚构的物ç�†ç½‘络连接起æ�¥ï¼Œä½¿å¾—在网络层看起æ�¥å¥½åƒ�是一个统一的网络。 -![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/fe3d224c-8ffd-40f9-85b1-86ffe1393f6c.jpg) +![](https://github.com/CyC2018/InterviewNotes/blob/master/pics//fe3d224c-8ffd-40f9-85b1-86ffe1393f6c.jpg) -Óë IP ЭÒéÅäÌ×ʹÓõϹÓÐÈý¸öЭÒ飺 +与 IP å��è®®é…�套使用的还有三个å��议: -1. µØÖ·½âÎöЭÒé ARP£¨Address Resolution Protocol£© -2. Íø¼Ê¿ØÖƱ¨ÎÄЭÒé ICMP£¨Internet Control Message Protocol£© -3. Íø¼Ê×é¹ÜÀíЭÒé IGMP£¨Internet Group Management Protocol£© +1. 地å�€è§£æž�å��è®® ARP(Address Resolution Protocol) +2. 网际控制报文å��è®® ICMP(Internet Control Message Protocol) +3. 网际组管ç�†å��è®® IGMP(Internet Group Management Protocol) -![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/163cf8b4-5f30-46c9-af00-316a71b3c890.jpg) +![](https://github.com/CyC2018/InterviewNotes/blob/master/pics//163cf8b4-5f30-46c9-af00-316a71b3c890.jpg) -## IP Êý¾Ý±¨¸ñʽ +## IP æ•°æ�®æŠ¥æ ¼å¼� -![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/8681db55-0873-434b-aa98-83d07e8392ae.jpg) +![](https://github.com/CyC2018/InterviewNotes/blob/master/pics//8681db55-0873-434b-aa98-83d07e8392ae.jpg) -- **°æ±¾** : ÓÐ 4£¨IPv4£©ºÍ 6£¨IPv6£©Á½¸öÖµ£» +- **版本** : 有 4(IPv4)和 6(IPv6)两个值; -- **Êײ¿³¤¶È** : Õ¼ 4 룬Òò´Ë×î´óֵΪ 15¡£ÖµÎª 1 ±íʾµÄÊÇ 1 ¸ö 32 λ×ֵij¤¶È£¬Ò²¾ÍÊÇ 4 ×Ö½Ú¡£ÒòΪÊײ¿¹Ì¶¨³¤¶ÈΪ 20 ×Ö½Ú£¬Òò´Ë¸ÃÖµ×îСΪ 5¡£Èç¹û¿ÉÑ¡²¿·ÖµÄ³¤¶È²»ÊÇ 4 ×Ö½ÚµÄÕûÊý±¶£¬¾ÍÓÃβ²¿µÄÌî³ä²¿·ÖÀ´Ìî³ä¡£ +- **首部长度** : å�  4 ä½�,因此最大值为 15。值为 1 表示的是 1 个 32 ä½�字的长度,也就是 4 字节。因为首部固定长度为 20 字节,因此该值最å°�为 5。如果å�¯é€‰éƒ¨åˆ†çš„长度ä¸�是 4 字节的整数å€�,就用尾部的填充部分æ�¥å¡«å……。 -- **Çø·Ö·þÎñ** : ÓÃÀ´»ñµÃ¸üºÃµÄ·þÎñ£¬Ò»°ãÇé¿öϲ»Ê¹Óᣠ+- **区分æœ�务** : 用æ�¥èŽ·å¾—æ›´å¥½çš„æœ�务,一般情况下ä¸�使用。 -- **×ܳ¤¶È** : °üÀ¨Êײ¿³¤¶ÈºÍÊý¾Ý²¿·Ö³¤¶È¡£ +- **总长度** : 包括首部长度和数æ�®éƒ¨åˆ†é•¿åº¦ã€‚ -- **±êʶ** : ÔÚÊý¾Ý±¨³¤¶È¹ý³¤´Ó¶ø·¢Éú·ÖƬµÄÇé¿öÏ£¬ÏàͬÊý¾Ý±¨µÄ²»Í¬·ÖƬ¾ßÓÐÏàͬµÄ±êʶ·û¡£ +- **标识** : 在数æ�®æŠ¥é•¿åº¦è¿‡é•¿ä»Žè€Œå�‘生分片的情况下,相å�Œæ•°æ�®æŠ¥çš„ä¸�å�Œåˆ†ç‰‡å…·æœ‰ç›¸å�Œçš„æ ‡è¯†ç¬¦ã€‚ -- **Æ¬Æ«ÒÆ** : ºÍ±êʶ·ûÒ»Æð£¬ÓÃÓÚ·¢Éú·ÖƬµÄÇé¿ö¡£Æ¬Æ«ÒƵĵ¥Î»Îª 8 ×Ö½Ú¡£ +- **片å��ç§»** : 和标识符一起,用于å�‘生分片的情况。片å��移的å�•ä½�为 8 字节。 -![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/45c86855-9b18-4cf4-a9a7-f8b6eb78d133.png) +![](https://github.com/CyC2018/InterviewNotes/blob/master/pics//45c86855-9b18-4cf4-a9a7-f8b6eb78d133.png) -- **Éú´æÊ±¼ä** £ºTTL£¬ËüµÄ´æÔÚÊÇΪÁË·ÀÖ¹ÎÞ·¨½»¸¶µÄÊý¾Ý±¨ÔÚ»¥ÁªÍøÖв»¶Ï¶µÈ¦×Ó¡£ÒÔ·ÓÉÆ÷ÌøÊýΪµ¥Î»£¬µ± TTL Ϊ 0 ʱ¾Í¶ªÆúÊý¾Ý±¨¡£ +- **生存时间** :TTL,它的存在是为了防止无法交付的数æ�®æŠ¥åœ¨äº’è�”网中ä¸�断兜圈å­�。以路由器跳数为å�•ä½�,当 TTL 为 0 时就丢弃数æ�®æŠ¥ã€‚ -- **ЭÒé**£ºÖ¸³öЯ´øµÄÊý¾ÝÓ¦¸ÃÉϽ»¸øÄĸöЭÒé½øÐд¦Àí£¬ÀýÈç ICMP¡¢TCP¡¢UDP µÈ¡£ +- **å��è®®**:指出æ�ºå¸¦çš„æ•°æ�®åº”该上交给哪个å��议进行处ç�†ï¼Œä¾‹å¦‚ ICMPã€�TCPã€�UDP 等。 -- **Êײ¿¼ìÑéºÍ**£ºÒòΪÊý¾Ý±¨Ã¿¾­¹ýÒ»¸ö·ÓÉÆ÷£¬¶¼ÒªÖØÐ¼ÆËã¼ìÑéºÍ£¬Òò´Ë¼ìÑéºÍ²»°üº¬Êý¾Ý²¿·Ö¿ÉÒÔ¼õÉÙ¼ÆËãµÄ¹¤×÷Á¿¡£ +- **首部检验和**:因为数æ�®æŠ¥æ¯�ç»�过一个路由器,都è¦�é‡�新计算检验和,因此检验和ä¸�包å�«æ•°æ�®éƒ¨åˆ†å�¯ä»¥å‡�少计算的工作é‡�。 -## IP µØÖ·±àÖ· +## IP 地å�€ç¼–å�€ -IP µØÖ·µÄ±àÖ··½Ê½¾­ÀúÁËÈý¸öÀúÊ·½×¶Î£º +IP 地å�€çš„ç¼–å�€æ–¹å¼�ç»�历了三个历å�²é˜¶æ®µï¼š -1. ·ÖÀࣻ -2. ×ÓÍø»®·Ö£» -3. ÎÞ·ÖÀà¡£ +1. 分类; +2. å­�网划分; +3. 无分类。 -### 1. ·ÖÀà +### 1. 分类 -ÓÉÁ½²¿·Ö×é³É£¬ÍøÂçºÅºÍÖ÷»úºÅ£¬ÆäÖв»Í¬Àà±ð¾ßÓв»Í¬µÄÍøÂçºÅ³¤¶È£¬²¢ÇÒÊǹ̶¨µÄ¡£ +由两部分组æˆ�,网络å�·å’Œä¸»æœºå�·ï¼Œå…¶ä¸­ä¸�å�Œç±»åˆ«å…·æœ‰ä¸�å�Œçš„网络å�·é•¿åº¦ï¼Œå¹¶ä¸”是固定的。 -IP µØÖ· ::= {< ÍøÂçºÅ >, < Ö÷»úºÅ >} +IP 地å�€ ::= {< 网络å�· >, < 主机å�· >} -![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/2ddd6132-60be-4a72-9daa-3d9756191f4a.png) +![](https://github.com/CyC2018/InterviewNotes/blob/master/pics//2ddd6132-60be-4a72-9daa-3d9756191f4a.png) -### 2. ×ÓÍø»®·Ö +### 2. å­�网划分 -ͨ¹ýÔÚÍøÂçºÅ×Ö¶ÎÖÐÄÃÒ»²¿·Ö×÷Ϊ×ÓÍøºÅ£¬°ÑÁ½¼¶ IP µØÖ·»®·ÖΪÈý¼¶ IP µØÖ·¡£×¢Ò⣬Íâ²¿ÍøÂç¿´²»µ½×ÓÍøµÄ´æÔÚ¡£ +通过在网络å�·å­—段中拿一部分作为å­�网å�·ï¼ŒæŠŠä¸¤çº§ IP 地å�€åˆ’分为三级 IP 地å�€ã€‚注æ„�,外部网络看ä¸�到å­�网的存在。 -IP µØÖ· ::= {< ÍøÂçºÅ >, < ×ÓÍøºÅ >, < Ö÷»úºÅ >} +IP 地å�€ ::= {< 网络å�· >, < å­�网å�· >, < 主机å�· >} -ҪʹÓÃ×ÓÍø£¬±ØÐëÅäÖÃ×ÓÍøÑÚÂë¡£Ò»¸ö B ÀàµØÖ·µÄĬÈÏ×ÓÍøÑÚÂëΪ 255.255.0.0£¬Èç¹û B ÀàµØÖ·µÄ×ÓÍøÕ¼Á½¸ö±ÈÌØ£¬ÄÇô×ÓÍøÑÚÂëΪ 11111111 11111111 11000000 000000£¬Ò²¾ÍÊÇ 255.255.192.0¡£ +è¦�使用å­�网,必须é…�ç½®å­�网掩ç �。一个 B 类地å�€çš„默认å­�网掩ç �为 255.255.0.0,如果 B 类地å�€çš„å­�网å� ä¸¤ä¸ªæ¯”特,那么å­�网掩ç �为 11111111 11111111 11000000 000000,也就是 255.255.192.0。 -### 3. ÎÞ·ÖÀà +### 3. 无分类 -ÎÞ·ÖÀà±àÖ· CIDR Ïû³ýÁË´«Í³ A Àà¡¢B ÀàºÍ C ÀàµØÖ·ÒÔ¼°»®·Ö×ÓÍøµÄ¸ÅÄʹÓÃÍøÂçǰ׺ºÍÖ÷»úºÅÀ´¶Ô IP µØÖ·½øÐбàÂë£¬ÍøÂçǰ׺µÄ³¤¶È¿ÉÒÔ¸ù¾ÝÐèÒª±ä»¯¡£ +无分类编å�€ CIDR 消除了传统 A ç±»ã€�B 类和 C 类地å�€ä»¥å�Šåˆ’分å­�网的概念,使用网络å‰�缀和主机å�·æ�¥å¯¹ IP 地å�€è¿›è¡Œç¼–ç �,网络å‰�缀的长度å�¯ä»¥æ ¹æ�®éœ€è¦�å�˜åŒ–。 -IP µØÖ· ::= {< ÍøÂçǰ׺ºÅ >, < Ö÷»úºÅ >} +IP 地å�€ ::= {< 网络å‰�ç¼€å�· >, < 主机å�· >} -CIDR µÄ¼Ç·¨ÉϲÉÓÃÔÚ IP µØÖ·ºóÃæ¼ÓÉÏÍøÂçǰ׺³¤¶ÈµÄ·½·¨£¬ÀýÈç 128.14.35.7/20 ±íʾǰ 20 Î»ÎªÍøÂçǰ׺¡£ +CIDR 的记法上采用在 IP 地å�€å�Žé�¢åŠ ä¸Šç½‘ç»œå‰�缀长度的方法,例如 128.14.35.7/20 表示å‰� 20 ä½�为网络å‰�缀。 -CIDR µÄµØÖ·ÑÚÂë¿ÉÒÔ¼ÌÐø³ÆÎª×ÓÍøÑÚÂ룬×ÓÍøÑÚÂëÊ× 1 ³¤¶ÈÎªÍøÂçǰ׺µÄ³¤¶È¡£ +CIDR 的地å�€æŽ©ç �å�¯ä»¥ç»§ç»­ç§°ä¸ºå­�网掩ç �,å­�网掩ç �首 1 长度为网络å‰�缀的长度。 -Ò»¸ö CIDR µØÖ·¿éÖÐÓÐºÜ¶àµØÖ·£¬Ò»¸ö CIDR ±íʾµÄÍøÂç¾Í¿ÉÒÔ±íʾԭÀ´µÄºÜ¶à¸öÍøÂ磬²¢ÇÒÔÚ·ÓɱíÖÐÖ»ÐèÒªÒ»¸ö·ÓɾͿÉÒÔ´úÌæÔ­À´µÄ¶à¸ö·ÓÉ£¬¼õÉÙÁË·ÓɱíÏîµÄÊýÁ¿¡£°ÑÕâÖÖͨ¹ýʹÓÃÍøÂçǰ׺À´¼õÉÙ·ÓɱíÏîµÄ·½Ê½³ÆÎªÂ·Óɾۺϣ¬Ò²³ÆÎª **¹¹³É³¬Íø**¡£ +一个 CIDR 地å�€å�—中有很多地å�€ï¼Œä¸€ä¸ª CIDR 表示的网络就å�¯ä»¥è¡¨ç¤ºåŽŸæ�¥çš„很多个网络,并且在路由表中å�ªéœ€è¦�一个路由就å�¯ä»¥ä»£æ›¿åŽŸæ�¥çš„多个路由,å‡�少了路由表项的数é‡�。把这ç§�通过使用网络å‰�ç¼€æ�¥å‡�少路由表项的方å¼�称为路由è�šå�ˆï¼Œä¹Ÿç§°ä¸º **æž„æˆ�超网**。 -ÔÚ·ÓɱíÖеÄÏîÄ¿ÓÉ¡°ÍøÂçǰ׺¡±ºÍ¡°ÏÂÒ»ÌøµØÖ·¡±×é³É£¬ÔÚ²éÕÒʱ¿ÉÄÜ»áµÃµ½²»Ö¹Ò»¸öÆ¥Åä½á¹û£¬Ó¦µ±²ÉÓÃ×ǰ׺ƥÅäÀ´È·¶¨Ó¦¸ÃÆ¥ÅäÄÄÒ»¸ö¡£ +在路由表中的项目由“网络å‰�ç¼€â€�和“下一跳地å�€â€�组æˆ�,在查找时å�¯èƒ½ä¼šå¾—到ä¸�止一个匹é…�结果,应当采用最长å‰�缀匹é…�æ�¥ç¡®å®šåº”该匹é…�哪一个。 -## IP µØÖ·ºÍ MAC µØÖ· +## IP 地å�€å’Œ MAC 地å�€ -ÍøÂç²ãʵÏÖÖ÷»úÖ®¼äµÄͨÐÅ£¬¶øÁ´Â·²ãʵÏÖ¾ßÌåÿ¶ÎÁ´Â·Ö®¼äµÄͨÐÅ¡£Òò´ËÔÚͨÐŹý³ÌÖУ¬IP Êý¾Ý±¨µÄÔ´µØÖ·ºÍÄ¿µÄµØÖ·Ê¼ÖÕ²»±ä£¬¶ø MAC µØÖ·Ëæ×ÅÁ´Â·µÄ¸Ä±ä¶ø¸Ä±ä¡£ +网络层实现主机之间的通信,而链路层实现具体æ¯�段链路之间的通信。因此在通信过程中,IP æ•°æ�®æŠ¥çš„æº�地å�€å’Œç›®çš„地å�€å§‹ç»ˆä¸�å�˜ï¼Œè€Œ MAC 地å�€éš�ç�€é“¾è·¯çš„æ”¹å�˜è€Œæ”¹å�˜ã€‚ -![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/86b71296-0d1e-4a63-bcd9-54955b6b781b.jpg) +![](https://github.com/CyC2018/InterviewNotes/blob/master/pics//86b71296-0d1e-4a63-bcd9-54955b6b781b.jpg) -## µØÖ·½âÎöЭÒé ARP +## 地å�€è§£æž�å��è®® ARP -ʵÏÖÓÉ IP µØÖ·µÃµ½ MAC µØÖ·¡£ +实现由 IP 地å�€å¾—到 MAC 地å�€ã€‚ -ÿ¸öÖ÷»ú¶¼ÓÐÒ»¸ö ARP ¸ßËÙ»º´æ£¬´æ·ÅÓ³Éä±í¡£Èç¹ûÒ»¸ö IP µØÖ·µ½ MAC µØÖ·µÄÓ³Éä²»ÔڸñíÖУ¬Ö÷»úͨ¹ý¹ã²¥µÄ·½Ê½·¢ËÍ ARP ÇëÇó·Ö×飬ƥÅä IP µØÖ·µÄÖ÷»ú»á·¢ËÍ ARP ÏìÓ¦·Ö×é¸æÖªÆä MAC µØÖ·¡£ +æ¯�个主机都有一个 ARP 高速缓存,存放映射表。如果一个 IP 地å�€åˆ° MAC 地å�€çš„æ˜ å°„ä¸�在该表中,主机通过广播的方å¼�å�‘é€� ARP 请求分组,匹é…� IP 地å�€çš„主机会å�‘é€� ARP å“�应分组告知其 MAC 地å�€ã€‚ -![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/8bc6fc2c-d198-4759-b06c-18d94d851e97.png) +![](https://github.com/CyC2018/InterviewNotes/blob/master/pics//8bc6fc2c-d198-4759-b06c-18d94d851e97.png) -## ·ÓÉÆ÷µÄ½á¹¹ +## 路由器的结构 -·ÓÉÆ÷´Ó¹¦ÄÜÉÏ¿ÉÒÔ»®·ÖΪÁ½´ó²¿·Ö£ºÂ·ÓÉÑ¡ÔñºÍ·Ö×éת·¢¡£ +路由器从功能上å�¯ä»¥åˆ’分为两大部分:路由选择和分组转å�‘。 -·Ö×éת·¢²¿·ÖÓÉÈý²¿·Ö×é³É£º½»»»½á¹¹¡¢Ò»×éÊäÈë¶Ë¿ÚºÍÒ»×éÊä³ö¶Ë¿Ú¡£ +分组转å�‘部分由三部分组æˆ�:交æ�¢ç»“æž„ã€�一组输入端å�£å’Œä¸€ç»„输出端å�£ã€‚ -![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/3a676c54-b559-4466-9b21-eb10f1e25879.jpg) +![](https://github.com/CyC2018/InterviewNotes/blob/master/pics//3a676c54-b559-4466-9b21-eb10f1e25879.jpg) -½»»»½á¹¹µÄ½»»»ÍøÂçÓÐÒÔÏÂÈýÖÖʵÏÖ·½Ê½£º +交æ�¢ç»“构的交æ�¢ç½‘络有以下三ç§�实现方å¼�: -![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/7f82fd18-7f16-4125-ada6-bb6b795b4fda.png) +![](https://github.com/CyC2018/InterviewNotes/blob/master/pics//7f82fd18-7f16-4125-ada6-bb6b795b4fda.png) -## ½»»»»úÓë·ÓÉÆ÷µÄÇø±ð +## 交æ�¢æœºä¸Žè·¯ç”±å™¨çš„区别 -- ½»»»»ú¹¤×÷ÓÚÊý¾ÝÁ´Â·²ã£¬ÄÜʶ±ð MAC µØÖ·£¬¸ù¾Ý MAC µØÖ·×ª·¢Á´Â·²ãÊý¾ÝÖ¡¡£¾ßÓÐ×Ôѧ»úÖÆÀ´Î¬»¤ IP µØÖ·Óë MAC µØÖ·µÄÓ³Éä¡£ -- ·ÓÉÆ÷λÓÚÍøÂç²ã£¬ÄÜʶ±ð IP µØÖ·²¢¸ù¾Ý IP µØÖ·×ª·¢·Ö×顣ά»¤×Å·ÓÉ±í£¬¸ù¾Ý·ÓɱíÑ¡Ôñ×î¼Ñ·Ïß¡£ +- 交æ�¢æœºå·¥ä½œäºŽæ•°æ�®é“¾è·¯å±‚,能识别 MAC 地å�€ï¼Œæ ¹æ�® MAC 地å�€è½¬å�‘链路层数æ�®å¸§ã€‚具有自学机制æ�¥ç»´æŠ¤ IP 地å�€ä¸Ž MAC 地å�€çš„æ˜ å°„。 +- 路由器ä½�于网络层,能识别 IP 地å�€å¹¶æ ¹æ�® IP 地å�€è½¬å�‘分组。维护ç�€è·¯ç”±è¡¨ï¼Œæ ¹æ�®è·¯ç”±è¡¨é€‰æ‹©æœ€ä½³è·¯çº¿ã€‚ -## ·ÓÉÆ÷·Ö×éת·¢Á÷³Ì +## 路由器分组转å�‘æµ�程 -1. ´ÓÊý¾Ý±¨µÄÊײ¿ÌáȡĿµÄÖ÷»úµÄ IP µØÖ· D£¬µÃµ½Ä¿µÄÍøÂçµØÖ· N¡££¨Â·ÓɱíÏîÊÇÍøÂçºÅ¶ø²»ÊÇ IP µØÖ·£¬ÕâÑù×ö´ó´ó¼õÉÙÁË·ÓɱíÌõÄ¿ÊýÁ¿£© -2. Èô N ¾ÍÊÇÓë´Ë·ÓÉÆ÷Ö±½ÓÏàÁ¬µÄij¸öÍøÂçµØÖ·£¬Ôò½øÐÐÖ±½Ó½»¸¶£» -3. Èô·ÓɱíÖÐÓÐÄ¿µÄµØÖ·Îª D µÄÌØ¶¨Ö÷»ú·ÓÉ£¬Ôò°ÑÊý¾Ý±¨´«Ë͸ø±íÖÐËùÖ¸Ã÷µÄÏÂÒ»ÌøÂ·ÓÉÆ÷£» -4. Èô·ÓɱíÖÐÓе½´ïÍøÂç N µÄ·ÓÉ£¬Ôò°ÑÊý¾Ý±¨´«Ë͸øÂ·ÓɱíÖÐËùÖ¸Ã÷µÄÏÂÒ»ÌøÂ·ÓÉÆ÷£» -5. Èô·ÓɱíÖÐÓÐÒ»¸öĬÈÏ·ÓÉ£¬Ôò°ÑÊý¾Ý±¨´«Ë͸øÂ·ÓɱíÖÐËùÖ¸Ã÷µÄĬÈÏ·ÓÉÆ÷£» -6. ±¨¸æ×ª·¢·Ö×é³ö´í¡£ +1. 从数æ�®æŠ¥çš„首部æ��å�–目的主机的 IP 地å�€ D,得到目的网络地å�€ N。(路由表项是网络å�·è€Œä¸�是 IP 地å�€ï¼Œè¿™æ ·å�šå¤§å¤§å‡�少了路由表æ�¡ç›®æ•°é‡�) +2. è‹¥ N 就是与此路由器直接相连的æŸ�个网络地å�€ï¼Œåˆ™è¿›è¡Œç›´æŽ¥äº¤ä»˜ï¼› +3. 若路由表中有目的地å�€ä¸º D 的特定主机路由,则把数æ�®æŠ¥ä¼ é€�给表中所指明的下一跳路由器; +4. 若路由表中有到达网络 N 的路由,则把数æ�®æŠ¥ä¼ é€�给路由表中所指明的下一跳路由器; +5. 若路由表中有一个默认路由,则把数æ�®æŠ¥ä¼ é€�给路由表中所指明的默认路由器; +6. 报告转å�‘分组出错。 -![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/8d211911-0e62-4190-ab00-d8610adec4a0.jpg) +![](https://github.com/CyC2018/InterviewNotes/blob/master/pics//8d211911-0e62-4190-ab00-d8610adec4a0.jpg) -## ·ÓÉÑ¡ÔñЭÒé +## 路由选择å��è®® -»¥ÁªÍøÊ¹ÓõÄ·ÓÉÑ¡ÔñЭÒé¶¼ÊÇ×ÔÊÊÓ¦µÄ£¬ÄÜËæ×ÅÍøÂçͨÐÅÁ¿ºÍÍØÆË½á¹¹µÄ±ä»¯¶ø×ÔÊÊÓ¦µØ½øÐе÷Õû¡£ +互è�”网使用的路由选择å��议都是自适应的,能éš�ç�€ç½‘络通信é‡�和拓扑结构的å�˜åŒ–而自适应地进行调整。 -»¥ÁªÍø¿ÉÒÔ»®·ÖΪÐí¶à½ÏСµÄ×ÔÖÎϵͳ AS£¬Ò»¸ö AS ¿ÉÒÔʹÓÃÒ»ÖֺͱðµÄ AS ²»Í¬µÄ·ÓÉÑ¡ÔñЭÒé¡£ +互è�”网å�¯ä»¥åˆ’分为许多较å°�的自治系统 AS,一个 AS å�¯ä»¥ä½¿ç”¨ä¸€ç§�和别的 AS ä¸�å�Œçš„路由选择å��议。 -¿ÉÒÔ°Ñ·ÓÉÑ¡ÔñЭÒé»®·ÖΪÁ½´óÀࣺ +å�¯ä»¥æŠŠè·¯ç”±é€‰æ‹©å��议划分为两大类: -1. ÄÚ²¿Íø¹ØÐ­Òé IGP£¨Interior Gateway Protocol£©£ºÔÚ AS ÄÚ²¿Ê¹Óã¬Èç RIP ºÍ OSPF¡£ -2. Íâ²¿Íø¹ØÐ­Òé EGP£¨External Gateway Protocol£©£ºÔÚ AS Ö®¼äʹÓã¬Èç BGP¡£ +1. 内部网关å��è®® IGP(Interior Gateway Protocol):在 AS 内部使用,如 RIP å’Œ OSPF。 +2. 外部网关å��è®® EGP(External Gateway Protocol):在 AS 之间使用,如 BGP。 -![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/e0be6970-5b0e-44a2-bc71-df4d61c42b8f.jpg) +![](https://github.com/CyC2018/InterviewNotes/blob/master/pics//e0be6970-5b0e-44a2-bc71-df4d61c42b8f.jpg) -### 1. ÄÚ²¿Íø¹ØÐ­Òé RIP +### 1. 内部网关å��è®® RIP -RIP ÊÇÒ»ÖÖ·Ö²¼Ê½µÄ»ùÓÚ¾àÀëÏòÁ¿µÄ·ÓÉÑ¡ÔñЭÒé¡£¾àÀëÊÇÖ¸ÌøÊý£¬Ö±½ÓÏàÁ¬µÄ·ÓÉÆ÷ÌøÊýΪ 1£¬ÌøÊý×î¶àΪ 15£¬³¬¹ý 15 ±íʾ²»¿É´ï¡£ +RIP 是一ç§�分布å¼�的基于è·�离å�‘é‡�的路由选择å��议。è·�离是指跳数,直接相连的路由器跳数为 1,跳数最多为 15,超过 15 表示ä¸�å�¯è¾¾ã€‚ -RIP °´¹Ì¶¨µÄʱ¼ä¼ä¸ô½öºÍÏàÁÚ·ÓÉÆ÷½»»»×Ô¼ºµÄ·ÓÉ±í£¬¾­¹ýÈô¸É´Î½»»»Ö®ºó£¬ËùÓзÓÉÆ÷×îÖÕ»áÖªµÀµ½´ï±¾×ÔÖÎϵͳÖÐÈκÎÒ»¸öÍøÂçµÄ×î¶Ì¾àÀëºÍÏÂÒ»ÌøÂ·ÓÉÆ÷µØÖ·¡£ +RIP 按固定的时间间隔仅和相邻路由器交æ�¢è‡ªå·±çš„路由表,ç»�过若干次交æ�¢ä¹‹å�Žï¼Œæ‰€æœ‰è·¯ç”±å™¨æœ€ç»ˆä¼šçŸ¥é�“到达本自治系统中任何一个网络的最短è·�离和下一跳路由器地å�€ã€‚ -¾àÀëÏòÁ¿Ëã·¨£º +è·�离å�‘é‡�算法: -1. ¶ÔµØÖ·Îª X µÄÏàÁÚ·ÓÉÆ÷·¢À´µÄ RIP ±¨ÎÄ£¬ÏÈÐ޸ı¨ÎÄÖеÄËùÓÐÏîÄ¿£¬°ÑÏÂÒ»Ìø×Ö¶ÎÖеĵØÖ·¸ÄΪ X£¬²¢°ÑËùÓеľàÀë×Ö¶Î¼Ó 1£» -2. ¶ÔÐ޸ĺóµÄ RIP ±¨ÎÄÖеÄÿһ¸öÏîÄ¿£¬½øÐÐÒÔϲ½Ö裺 - - ÈôÔ­À´µÄ·ÓɱíÖÐûÓÐÄ¿µÄÍøÂç N£¬Ôò°Ñ¸ÃÏîÄ¿Ìí¼Óµ½Â·ÓɱíÖУ» - - ·ñÔò£ºÈôÏÂÒ»ÌøÂ·ÓÉÆ÷µØÖ·ÊÇ X£¬Ôò°ÑÊÕµ½µÄÏîÄ¿Ìæ»»Ô­À´Â·ÓɱíÖеÄÏîÄ¿£»·ñÔò£ºÈôÊÕµ½µÄÏîÄ¿ÖеľàÀë d СÓÚ·ÓɱíÖеľàÀ룬Ôò½øÐиüУ¨ÀýÈçԭʼ·ÓɱíÏîΪ Net2, 5, P£¬Ð±íÏîΪ Net2, 4, X£¬Ôò¸üУ©£»·ñÔòʲôҲ²»×ö¡£ -3. Èô 3 ·ÖÖÓ»¹Ã»ÓÐÊÕµ½ÏàÁÚ·ÓÉÆ÷µÄ¸üзÓÉ±í£¬Ôò°Ñ¸ÃÏàÁÚ·ÓÉÆ÷±êΪ²»¿É´ï£¬¼´°Ñ¾àÀëÖÃΪ 16¡£ +1. 对地å�€ä¸º X 的相邻路由器å�‘æ�¥çš„ RIP 报文,先修改报文中的所有项目,把下一跳字段中的地å�€æ”¹ä¸º X,并把所有的è·�离字段加 1ï¼› +2. 对修改å�Žçš„ RIP 报文中的æ¯�一个项目,进行以下步骤: + - 若原æ�¥çš„路由表中没有目的网络 N,则把该项目添加到路由表中; + - å�¦åˆ™ï¼šè‹¥ä¸‹ä¸€è·³è·¯ç”±å™¨åœ°å�€æ˜¯ X,则把收到的项目替æ�¢åŽŸæ�¥è·¯ç”±è¡¨ä¸­çš„项目;å�¦åˆ™ï¼šè‹¥æ”¶åˆ°çš„项目中的è·�离 d å°�于路由表中的è·�离,则进行更新(例如原始路由表项为 Net2, 5, P,新表项为 Net2, 4, X,则更新);å�¦åˆ™ä»€ä¹ˆä¹Ÿä¸�å�šã€‚ +3. è‹¥ 3 分钟还没有收到相邻路由器的更新路由表,则把该相邻路由器标为ä¸�å�¯è¾¾ï¼Œå�³æŠŠè·�离置为 16。 -RIP ЭÒéʵÏÖ¼òµ¥£¬¿ªÏúС£¬µ«ÊÇ RIP ÄÜʹÓõÄ×î´ó¾àÀëΪ 15£¬ÏÞÖÆÁËÍøÂçµÄ¹æÄ£¡£²¢ÇÒµ±ÍøÂç³öÏÖ¹ÊÕÏʱ£¬Òª¾­¹ý±È½Ï³¤µÄʱ¼ä²ÅÄܽ«´ËÏûÏ¢´«Ë͵½ËùÓзÓÉÆ÷¡£ +RIP å��议实现简å�•,开销å°�,但是 RIP 能使用的最大è·�离为 15,é™�制了网络的规模。并且当网络出现故障时,è¦�ç»�过比较长的时间æ‰�能将此消æ�¯ä¼ é€�到所有路由器。 -### 2. ÄÚ²¿Íø¹ØÐ­Òé OSPF +### 2. 内部网关å��è®® OSPF -¿ª·Å×î¶Ì·¾¶ÓÅÏÈ OSPF£¬ÊÇΪÁ˿˷þ RIP µÄȱµã¶ø¿ª·¢³öÀ´µÄ¡£ +开放最短路径优先 OSPF,是为了克æœ� RIP 的缺点而开å�‘出æ�¥çš„。 -¿ª·Å±íʾ OSPF ²»ÊÜijһ¼Ò³§ÉÌ¿ØÖÆ£¬¶øÊǹ«¿ª·¢±íµÄ£»×î¶Ì·¾¶ÓÅÏȱíʾʹÓÃÁË Dijkstra Ìá³öµÄ×î¶Ì·¾¶Ëã·¨ SPF¡£ +开放表示 OSPF ä¸�å�—æŸ�一家厂商控制,而是公开å�‘表的;最短路径优先表示使用了 Dijkstra æ��出的最短路径算法 SPF。 -OSPF ¾ßÓÐÒÔÏÂÌØµã£º +OSPF 具有以下特点: -- Ïò±¾×ÔÖÎϵͳÖеÄËùÓзÓÉÆ÷·¢ËÍÐÅÏ¢£¬ÕâÖÖ·½·¨ÊǺ鷺·¨¡£ -- ·¢Ë͵ÄÐÅÏ¢¾ÍÊÇÓëÏàÁÚ·ÓÉÆ÷µÄÁ´Â·×´Ì¬£¬Á´Â·×´Ì¬°üÀ¨ÓëÄÄЩ·ÓÉÆ÷ÏàÁ¬ÒÔ¼°Á´Â·µÄ¶ÈÁ¿£¬¶ÈÁ¿Ó÷ÑÓᢾàÀ롢ʱÑÓ¡¢´ø¿íµÈÀ´±íʾ¡£ -- Ö»Óе±Á´Â·×´Ì¬·¢Éú±ä»¯Ê±£¬Â·ÓÉÆ÷²Å»á·¢ËÍÐÅÏ¢¡£ +- å�‘本自治系统中的所有路由器å�‘é€�ä¿¡æ�¯ï¼Œè¿™ç§�方法是洪泛法。 +- å�‘é€�的信æ�¯å°±æ˜¯ä¸Žç›¸é‚»è·¯ç”±å™¨çš„链路状æ€�,链路状æ€�包括与哪些路由器相连以å�Šé“¾è·¯çš„度é‡�,度é‡�用费用ã€�è·�离ã€�æ—¶å»¶ã€�带宽等æ�¥è¡¨ç¤ºã€‚ +- å�ªæœ‰å½“链路状æ€�å�‘生å�˜åŒ–时,路由器æ‰�会å�‘é€�ä¿¡æ�¯ã€‚ -ËùÓзÓÉÆ÷¶¼¾ßÓÐÈ«ÍøµÄÍØÆË½á¹¹Í¼£¬²¢ÇÒÊÇÒ»Öµġ£Ïà±ÈÓÚ RIP£¬OSPF µÄ¸üйý³ÌÊÕÁ²µÄºÜ¿ì¡£ +所有路由器都具有全网的拓扑结构图,并且是一致的。相比于 RIP,OSPF 的更新过程收敛的很快。 -### 3. Íâ²¿Íø¹ØÐ­Òé BGP +### 3. 外部网关å��è®® BGP -AS Ö®¼äµÄ·ÓÉÑ¡ÔñºÜÀ§ÄÑ£¬Ö÷ÒªÊÇ»¥ÁªÍø¹æÄ£ºÜ´ó¡£²¢ÇÒ¸÷¸ö AS ÄÚ²¿Ê¹Óò»Í¬µÄ·ÓÉÑ¡ÔñЭÒ飬¾ÍÎÞ·¨×¼È·¶¨Òå·¾¶µÄ¶ÈÁ¿¡£²¢ÇÒ AS Ö®¼äµÄ·ÓÉÑ¡Ôñ±ØÐ뿼ÂÇÓйصIJßÂÔ£¬±ÈÈçÓÐЩ AS ²»Ô¸ÒâÈÃÆäËü AS ¾­¹ý¡£ +AS 之间的路由选择很困难,主è¦�是互è�”网规模很大。并且å�„个 AS 内部使用ä¸�å�Œçš„路由选择å��议,就无法准确定义路径的度é‡�。并且 AS 之间的路由选择必须考虑有关的策略,比如有些 AS ä¸�æ„¿æ„�让其它 AS ç»�过。 -BGP Ö»ÄÜѰÕÒÒ»Ìõ±È½ÏºÃµÄ·ÓÉ£¬¶ø²»ÊÇ×î¼Ñ·ÓÉ¡£Ëü²ÉÓ÷¾¶ÏòÁ¿Â·ÓÉÑ¡ÔñЭÒé¡£ +BGP å�ªèƒ½å¯»æ‰¾ä¸€æ�¡æ¯”较好的路由,而ä¸�是最佳路由。它采用路径å�‘é‡�路由选择å��议。 -ÿ¸ö AS ¶¼±ØÐëÅäÖà BGP ·¢ÑÔÈË£¬Í¨¹ýÔÚÁ½¸öÏàÁÚ BGP ·¢ÑÔÈËÖ®¼ä½¨Á¢ TCP Á¬½ÓÀ´½»»»Â·ÓÉÐÅÏ¢¡£ +æ¯�个 AS 都必须é…�ç½® BGP å�‘言人,通过在两个相邻 BGP å�‘言人之间建立 TCP 连接æ�¥äº¤æ�¢è·¯ç”±ä¿¡æ�¯ã€‚ -![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/eb6271de-22c9-4f4b-8b31-eab1f560efac.png) +![](https://github.com/CyC2018/InterviewNotes/blob/master/pics//eb6271de-22c9-4f4b-8b31-eab1f560efac.png) -## Íø¼Ê¿ØÖƱ¨ÎÄЭÒé ICMP +## 网际控制报文å��è®® ICMP -ICMP ÊÇΪÁ˸üÓÐЧµØ×ª·¢ IP Êý¾Ý±¨ºÍÌá¸ß½»¸¶³É¹¦µÄ»ú»á¡£Ëü·â×°ÔÚ IP Êý¾Ý±¨ÖУ¬µ«ÊDz»ÊôÓڸ߲ãЭÒé¡£ +ICMP 是为了更有效地转å�‘ IP æ•°æ�®æŠ¥å’Œæ��高交付æˆ�功的机会。它å°�装在 IP æ•°æ�®æŠ¥ä¸­ï¼Œä½†æ˜¯ä¸�属于高层å��议。 -![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/9b5e0fa0-9274-4219-a3a9-84fbb509c735.jpg) +![](https://github.com/CyC2018/InterviewNotes/blob/master/pics//9b5e0fa0-9274-4219-a3a9-84fbb509c735.jpg) -ICMP ±¨ÎÄ·ÖΪ²î´í±¨¸æ±¨ÎĺÍѯÎʱ¨ÎÄ¡£ +ICMP 报文分为差错报告报文和询问报文。 -![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/6e11b122-95ce-4869-bf7d-3b0d7591707e.jpg) +![](https://github.com/CyC2018/InterviewNotes/blob/master/pics//6e11b122-95ce-4869-bf7d-3b0d7591707e.jpg) -## ·Ö×éÍø¼ä̽²â PING +## 分组网间探测 PING -PING ÊÇ ICMP µÄÒ»¸öÖØÒªÓ¦Óã¬Ö÷ÒªÓÃÀ´²âÊÔÁ½Ì¨Ö÷»úÖ®¼äµÄÁ¬Í¨ÐÔ¡£ +PING 是 ICMP 的一个é‡�è¦�应用,主è¦�用æ�¥æµ‹è¯•两å�°ä¸»æœºä¹‹é—´çš„连通性。 -PING µÄ¹ý³Ì£º +PING 的过程: -1. PING ͬһ¸öÍø¶ÎµÄÖ÷»ú£º²éÕÒÄ¿µÄÖ÷»úµÄ MAC µØÖ·£¬È»ºóÖ±½Ó½»¸¶¡£Èç¹ûÎÞ·¨²éÕÒµ½ MAC µØÖ·£¬¾ÍÒª½øÐÐÒ»´Î ARP ÇëÇó¡£ -2. PING ²»Í¬Íø¶ÎµÄÖ÷»ú£º·¢Ë͵½Íø¹ØÈÃÆä½øÐÐת·¢¡£Í¬ÑùÒª·¢Ë͵½Íø¹ØÒ²ÐèҪͨ¹ý²éÕÒÍø¹ØµÄ MAC µØÖ·£¬¸ù¾Ý MAC µØÖ·½øÐÐת·¢¡£ +1. PING å�Œä¸€ä¸ªç½‘段的主机:查找目的主机的 MAC 地å�€ï¼Œç„¶å�Žç›´æŽ¥äº¤ä»˜ã€‚如果无法查找到 MAC 地å�€ï¼Œå°±è¦�进行一次 ARP 请求。 +2. PING ä¸�å�Œç½‘段的主机:å�‘é€�到网关让其进行转å�‘。å�Œæ ·è¦�å�‘é€�到网关也需è¦�通过查找网关的 MAC 地å�€ï¼Œæ ¹æ�® MAC 地å�€è¿›è¡Œè½¬å�‘。 -## IP ¶à²¥ +## IP 多播 -ÔÚÒ»¶Ô¶àµÄͨÐÅÖУ¬¶à²¥²»ÐèÒª½«·Ö×鏴֯¶à·Ý£¬´Ó¶ø´ó´ó½ÚÔ¼ÍøÂç×ÊÔ´¡£ +在一对多的通信中,多播ä¸�需è¦�将分组å¤�制多份,从而大大节约网络资æº�。 -![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/c77b6a18-dfac-42a2-ac89-7e99481275dc.jpg) +![](https://github.com/CyC2018/InterviewNotes/blob/master/pics//c77b6a18-dfac-42a2-ac89-7e99481275dc.jpg) -## ÐéÄâרÓÃÍø VPN +## 虚拟专用网 VPN -ÓÉÓÚ IP µØÖ·µÄ½ôȱ£¬Ò»¸ö»ú¹¹ÄÜÉêÇëµ½µÄ IP µØÖ·ÊýÍùÍùԶСÓÚ±¾»ú¹¹ËùÓµÓеÄÖ÷»úÊý¡£²¢ÇÒÒ»¸ö»ú¹¹²¢²»ÐèÒª°ÑËùÓеÄÖ÷»ú½ÓÈëµ½ÍⲿµÄ»¥ÁªÍøÖУ¬»ú¹¹ÄڵļÆËã»ú¿ÉÒÔʹÓýöÔÚ±¾»ú¹¹ÓÐЧµÄ IP µØÖ·£¨×¨ÓõØÖ·£©¡£ +由于 IP 地å�€çš„紧缺,一个机构能申请到的 IP 地å�€æ•°å¾€å¾€è¿œå°�于本机构所拥有的主机数。并且一个机构并ä¸�需è¦�把所有的主机接入到外部的互è�”网中,机构内的计算机å�¯ä»¥ä½¿ç”¨ä»…在本机构有效的 IP 地å�€ï¼ˆä¸“用地å�€ï¼‰ã€‚ -ÓÐÈý¸öרÓõØÖ·¿é£º +有三个专用地å�€å�—: 1. 10.0.0.0 \~ 10.255.255.255 2. 172.16.0.0 \~ 172.31.255.255 3. 192.168.0.0 \~ 192.168.255.255 -VPN ʹÓù«ÓõĻ¥ÁªÍø×÷Ϊ±¾»ú¹¹¸÷רÓÃÍøÖ®¼äµÄͨÐÅÔØÌ塣רÓÃÖ¸»ú¹¹ÄÚµÄÖ÷»úÖ»Óë±¾»ú¹¹Ä򵀮äËüÖ÷»úͨÐÅ£»ÐéÄâÖ¸¡°ºÃÏñÊÇ¡±£¬¶øÊµ¼ÊÉϲ¢²»ÊÇ£¬ËüÓо­¹ý¹«ÓõĻ¥ÁªÍø¡£ +VPN 使用公用的互è�”网作为本机构å�„专用网之间的通信载体。专用指机构内的主机å�ªä¸Žæœ¬æœºæž„内的其它主机通信;虚拟指“好åƒ�是â€�,而实际上并ä¸�是,它有ç»�过公用的互è�”网。 -ÏÂͼÖУ¬³¡Ëù A ºÍ B µÄͨÐŲ¿¾­¹ý»¥ÁªÍø£¬Èç¹û³¡Ëù A µÄÖ÷»ú X ÒªºÍÁíÒ»¸ö³¡Ëù B µÄÖ÷»ú Y ͨÐÅ£¬IP Êý¾Ý±¨µÄÔ´µØÖ·ÊÇ 10.1.0.1£¬Ä¿µÄµØÖ·ÊÇ 10.2.0.3¡£Êý¾Ý±¨ÏÈ·¢Ë͵½Ó뻥ÁªÍøÏàÁ¬µÄ·ÓÉÆ÷ R1£¬R1 ¶ÔÄÚ²¿Êý¾Ý½øÐмÓÃÜ£¬È»ºóÖØÐ¼ÓÉÏÊý¾Ý±¨µÄÊײ¿£¬Ô´µØÖ·ÊÇ·ÓÉÆ÷ R1 µÄÈ«ÇòµØÖ· 125.1.2.3£¬Ä¿µÄµØÖ·ÊÇ·ÓÉÆ÷ R2 µÄÈ«ÇòµØÖ· 194.4.5.6¡£Â·ÓÉÆ÷ R2 ÊÕµ½Êý¾Ý±¨ºó½«Êý¾Ý²¿·Ö½øÐнâÃÜ£¬»Ö¸´Ô­À´µÄÊý¾Ý±¨£¬´ËʱĿµÄµØÖ·Îª 10.2.0.3£¬¾Í½»¸¶¸ø Y¡£ +下图中,场所 A å’Œ B 的通信部ç»�过互è�”网,如果场所 A 的主机 X è¦�å’Œå�¦ä¸€ä¸ªåœºæ‰€ B 的主机 Y 通信,IP æ•°æ�®æŠ¥çš„æº�地å�€æ˜¯ 10.1.0.1,目的地å�€æ˜¯ 10.2.0.3。数æ�®æŠ¥å…ˆå�‘é€�到与互è�”网相连的路由器 R1,R1 对内部数æ�®è¿›è¡ŒåŠ å¯†ï¼Œç„¶å�Žé‡�新加上数æ�®æŠ¥çš„首部,æº�地å�€æ˜¯è·¯ç”±å™¨ R1 的全ç�ƒåœ°å�€ 125.1.2.3,目的地å�€æ˜¯è·¯ç”±å™¨ R2 的全ç�ƒåœ°å�€ 194.4.5.6。路由器 R2 收到数æ�®æŠ¥å�Žå°†æ•°æ�®éƒ¨åˆ†è¿›è¡Œè§£å¯†ï¼Œæ�¢å¤�原æ�¥çš„æ•°æ�®æŠ¥ï¼Œæ­¤æ—¶ç›®çš„地å�€ä¸º 10.2.0.3,就交付给 Y。 -![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/bf4ed077-d481-4db7-9e7a-85d841a5a8c3.jpg) +![](https://github.com/CyC2018/InterviewNotes/blob/master/pics//bf4ed077-d481-4db7-9e7a-85d841a5a8c3.jpg) -## ÍøÂçµØÖ·×ª»» NAT +## 网络地å�€è½¬æ�¢ NAT -רÓÃÍøÄÚ²¿µÄÖ÷»úʹÓñ¾µØ IP µØÖ·ÓÖÏëºÍ»¥ÁªÍøÉϵÄÖ÷»úͨÐÅʱ£¬¿ÉÒÔʹÓà NAT À´½«±¾µØ IP ת»»ÎªÈ«Çò IP¡£ +专用网内部的主机使用本地 IP 地å�€å�ˆæƒ³å’Œäº’è�”网上的主机通信时,å�¯ä»¥ä½¿ç”¨ NAT æ�¥å°†æœ¬åœ° IP 转æ�¢ä¸ºå…¨ç�ƒ IP。 -ÔÚÒÔǰ£¬NAT ½«±¾µØ IP ºÍÈ«Çò IP Ò»Ò»¶ÔÓ¦£¬ÕâÖÖ·½Ê½ÏÂÓµÓÐ n ¸öÈ«Çò IP µØÖ·µÄרÓÃÍøÄÚ×î¶àÖ»¿ÉÒÔͬʱÓÐ n ̨Ö÷»ú½ÓÈ뻥ÁªÍø¡£ÎªÁ˸üÓÐЧµØÀûÓÃÈ«Çò IP µØÖ·£¬ÏÖÔÚ³£ÓÃµÄ NAT ת»»±í°ÑÔËÊä²ãµÄ¶Ë¿ÚºÅÒ²ÓÃÉÏÁË£¬Ê¹µÃ¶à¸öרÓÃÍøÄÚ²¿µÄÖ÷»ú¹²ÓÃÒ»¸öÈ«Çò IP µØÖ·¡£Ê¹ÓÃ¶Ë¿ÚºÅµÄ NAT Ò²½Ð×öÍøÂçµØÖ·Óë¶Ë¿Úת»» NAPT¡£ +在以å‰�,NAT 将本地 IP 和全ç�ƒ IP 一一对应,这ç§�æ–¹å¼�下拥有 n 个全ç�ƒ IP 地å�€çš„专用网内最多å�ªå�¯ä»¥å�Œæ—¶æœ‰ n å�°ä¸»æœºæŽ¥å…¥äº’è�”网。为了更有效地利用全ç�ƒ IP 地å�€ï¼ŒçŽ°åœ¨å¸¸ç”¨çš„ NAT 转æ�¢è¡¨æŠŠè¿�输层的端å�£å�·ä¹Ÿç”¨ä¸Šäº†ï¼Œä½¿å¾—多个专用网内部的主机共用一个全ç�ƒ IP 地å�€ã€‚使用端å�£å�·çš„ NAT 也å�«å�šç½‘络地å�€ä¸Žç«¯å�£è½¬æ�¢ NAPT。 -![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/0f31bc7a-d60b-48a6-8e3f-597708369e52.png) +![](https://github.com/CyC2018/InterviewNotes/blob/master/pics//0f31bc7a-d60b-48a6-8e3f-597708369e52.png) -# µÚÎåÕ ÔËÊä²ã* +# 第五章 è¿�输层* -ÍøÂç²ãÖ»°Ñ·Ö×é·¢Ë͵½Ä¿µÄÖ÷»ú£¬µ«ÊÇÕæÕýͨÐŵIJ¢²»ÊÇÖ÷»ú¶øÊÇÖ÷»úÖеĽø³Ì¡£ +网络层å�ªæŠŠåˆ†ç»„å�‘é€�到目的主机,但是真正通信的并ä¸�是主机而是主机中的进程。 -ÔËÊä²ãÌṩÁËÓ¦Óýø³Ì¼äµÄÂß¼­Í¨ÐÅ¡£ÔËÊä²ãÏò¸ß²ãÓû§ÆÁ±ÎÁËÏÂÃæÍøÂç²ãµÄºËÐÄϸ½Ú£¬Ê¹Ó¦ÓóÌÐò¿´¼ûµÄºÃÏñÔÚÁ½¸öÔËÊä²ãʵÌåÖ®¼äÓÐÒ»Ìõ¶Ëµ½¶ËµÄÂß¼­Í¨ÐÅÐŵÀ¡£ +è¿�输层æ��供了应用进程间的逻辑通信。è¿�输层å�‘高层用户å±�蔽了下é�¢ç½‘络层的核心细节,使应用程åº�看è§�的好åƒ�在两个è¿�输层实体之间有一æ�¡ç«¯åˆ°ç«¯çš„逻辑通信信é�“。 -## UDP ºÍ TCP µÄÌØµã +## UDP å’Œ TCP 的特点 -- Óû§Êý¾Ý°üЭÒé UDP£¨User Datagram Protocol£©ÊÇÎÞÁ¬½ÓµÄ£¬¾¡×î´ó¿ÉÄܽ»¸¶£¬Ã»ÓÐÓµÈû¿ØÖÆ£¬ÃæÏò±¨ÎÄ£¨¶ÔÓÚÓ¦ÓóÌÐò´«ÏÂÀ´µÄ±¨ÎIJ»ºÏ²¢Ò²²»²ð·Ö£¬Ö»ÊÇÌí¼Ó UDP Êײ¿£©¡£ +- 用户数æ�®åŒ…å��è®® UDP(User Datagram Protocol)是无连接的,尽最大å�¯èƒ½äº¤ä»˜ï¼Œæ²¡æœ‰æ‹¥å¡žæŽ§åˆ¶ï¼Œé�¢å�‘报文(对于应用程åº�传下æ�¥çš„æŠ¥æ–‡ä¸�å�ˆå¹¶ä¹Ÿä¸�拆分,å�ªæ˜¯æ·»åŠ  UDP 首部)。 -- ´«Êä¿ØÖÆÐ­Òé TCP£¨Transmission Control Protocol£© ÊÇÃæÏòÁ¬½ÓµÄ£¬Ìṩ¿É¿¿½»¸¶£¬ÓÐÁ÷Á¿¿ØÖÆ£¬ÓµÈû¿ØÖÆ£¬Ìṩȫ˫¹¤Í¨ÐÅ£¬ÃæÏò×Ö½ÚÁ÷£¨°ÑÓ¦Óò㴫ÏÂÀ´µÄ±¨ÎÄ¿´³É×Ö½ÚÁ÷£¬°Ñ×Ö½ÚÁ÷×éÖ¯³É´óС²»µÈµÄÊý¾Ý¿é£© +- 传输控制å��è®® TCP(Transmission Control Protocol) 是é�¢å�‘连接的,æ��ä¾›å�¯é� äº¤ä»˜ï¼Œæœ‰æµ�é‡�控制,拥塞控制,æ��供全å�Œå·¥é€šä¿¡ï¼Œé�¢å�‘字节æµ�(把应用层传下æ�¥çš„æŠ¥æ–‡çœ‹æˆ�字节æµ�,把字节æµ�组织æˆ�大å°�ä¸�等的数æ�®å�—) -## UDP Êײ¿¸ñʽ +## UDP 首部格å¼� -![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/bd6c05f3-02ee-4c8a-b374-40c87154a898.jpg) +![](https://github.com/CyC2018/InterviewNotes/blob/master/pics//bd6c05f3-02ee-4c8a-b374-40c87154a898.jpg) -Êײ¿×Ö¶ÎÖ»ÓÐ 8 ¸ö×Ö½Ú£¬°üÀ¨Ô´¶Ë¿Ú¡¢Ä¿µÄ¶Ë¿Ú¡¢³¤¶È¡¢¼ìÑéºÍ¡£12 ×Ö½ÚµÄαÊײ¿ÊÇΪÁ˼ÆËã¼ìÑéºÍ¶øÁÙʱÌí¼ÓµÄ¡£ +首部字段å�ªæœ‰ 8 个字节,包括æº�端å�£ã€�目的端å�£ã€�长度ã€�检验和。12 字节的伪首部是为了计算检验和而临时添加的。 -## TCP Êײ¿¸ñʽ +## TCP 首部格å¼� -![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/21a00b02-c0a6-4bcd-9af0-5ec6bb66e34c.jpg) +![](https://github.com/CyC2018/InterviewNotes/blob/master/pics//21a00b02-c0a6-4bcd-9af0-5ec6bb66e34c.jpg) -- **ÐòºÅ** £ºÓÃÓÚ¶Ô×Ö½ÚÁ÷½øÐбàºÅ£¬ÀýÈçÐòºÅΪ 301£¬±íʾµÚÒ»¸ö×ֽڵıàºÅΪ 301£¬Èç¹ûЯ´øµÄÊý¾Ý³¤¶ÈΪ 100 ×Ö½Ú£¬ÄÇôÏÂÒ»¸ö±¨ÎĶεÄÐòºÅӦΪ 401¡£ +- **åº�å�·** :用于对字节æµ�进行编å�·ï¼Œä¾‹å¦‚åº�å�·ä¸º 301,表示第一个字节的编å�·ä¸º 301,如果æ�ºå¸¦çš„æ•°æ�®é•¿åº¦ä¸º 100 字节,那么下一个报文段的åº�å�·åº”为 401。 -- **È·ÈϺÅ** £ºÆÚÍûÊÕµ½µÄÏÂÒ»¸ö±¨ÎĶεÄÐòºÅ¡£ÀýÈç B ÕýÈ·ÊÕµ½ A ·¢ËÍÀ´µÄÒ»¸ö±¨ÎĶΣ¬ÐòºÅΪ 501£¬Ð¯´øµÄÊý¾Ý³¤¶ÈΪ 200 ×Ö½Ú£¬Òò´Ë B ÆÚÍûÏÂÒ»¸ö±¨ÎĶεÄÐòºÅΪ 701£¬B ·¢Ë͸ø A µÄÈ·Èϱ¨ÎĶÎÖÐÈ·ÈϺžÍΪ 701¡£ +- **确认å�·** :期望收到的下一个报文段的åº�å�·ã€‚例如 B 正确收到 A å�‘é€�æ�¥çš„一个报文段,åº�å�·ä¸º 501,æ�ºå¸¦çš„æ•°æ�®é•¿åº¦ä¸º 200 字节,因此 B 期望下一个报文段的åº�å�·ä¸º 701,B å�‘é€�ç»™ A 的确认报文段中确认å�·å°±ä¸º 701。 -- **Êý¾ÝÆ«ÒÆ** £ºÖ¸µÄÊÇÊý¾Ý²¿·Ö¾àÀ뱨ÎÄ¶ÎÆðʼ´¦µÄÆ«ÒÆÁ¿£¬Êµ¼ÊÉÏÖ¸µÄÊÇÊײ¿µÄ³¤¶È¡£ +- **æ•°æ�®å��ç§»** :指的是数æ�®éƒ¨åˆ†è·�离报文段起始处的å��ç§»é‡�,实际上指的是首部的长度。 -- **È·ÈÏ ACK** £ºµ± ACK=1 ʱȷÈϺÅ×Ö¶ÎÓÐЧ£¬·ñÔòÎÞЧ¡£TCP ¹æ¶¨£¬ÔÚÁ¬½Ó½¨Á¢ºóËùÓд«Ë͵ı¨ÎĶζ¼±ØÐë°Ñ ACK Öà 1¡£ +- **确认 ACK** :当 ACK=1 时确认å�·å­—段有效,å�¦åˆ™æ— æ•ˆã€‚TCP 规定,在连接建立å�Žæ‰€æœ‰ä¼ é€�的报文段都必须把 ACK ç½® 1。 -- **ͬ²½ SYN** £ºÔÚÁ¬½Ó½¨Á¢Ê±ÓÃÀ´Í¬²½ÐòºÅ¡£µ± SYN=1£¬ACK=0 ʱ±íʾÕâÊÇÒ»¸öÁ¬½ÓÇëÇó±¨ÎĶΡ£Èô¶Ô·½Í¬Ò⽨Á¢Á¬½Ó£¬ÔòÏìÓ¦±¨ÎÄÖÐ SYN=1£¬ACK=1¡£ +- **å�Œæ­¥ SYN** :在连接建立时用æ�¥å�Œæ­¥åº�å�·ã€‚当 SYN=1,ACK=0 时表示这是一个连接请求报文段。若对方å�Œæ„�建立连接,则å“�应报文中 SYN=1,ACK=1。 -- **ÖÕÖ¹ FIN** £ºÓÃÀ´ÊÍ·ÅÒ»¸öÁ¬½Ó£¬µ± FIN=1 ʱ£¬±íʾ´Ë±¨ÎĶεķ¢ËÍ·½µÄÊý¾ÝÒÑ·¢ËÍÍê±Ï£¬²¢ÒªÇóÊÍ·ÅÔËÊäÁ¬½Ó¡£ +- **终止 FIN** :用æ�¥é‡Šæ”¾ä¸€ä¸ªè¿žæŽ¥ï¼Œå½“ FIN=1 时,表示此报文段的å�‘é€�方的数æ�®å·²å�‘é€�完毕,并è¦�求释放è¿�输连接。 -- **´°¿Ú** £º´°¿ÚÖµ×÷Ϊ½ÓÊÕ·½È÷¢ËÍ·½ÉèÖÃÆä·¢ËÍ´°¿ÚµÄÒÀ¾Ý¡£Ö®ËùÒÔÒªÓÐÕâ¸öÏÞÖÆ£¬ÊÇÒòΪ½ÓÊÕ·½µÄÊý¾Ý»º´æ¿Õ¼äÊÇÓÐÏ޵ġ£ +- **窗å�£** :窗å�£å€¼ä½œä¸ºæŽ¥æ”¶æ–¹è®©å�‘é€�方设置其å�‘é€�窗å�£çš„ä¾�æ�®ã€‚之所以è¦�有这个é™�制,是因为接收方的数æ�®ç¼“存空间是有é™�的。 -## TCP µÄÈý´ÎÎÕÊÖ +## TCP 的三次æ�¡æ‰‹ -![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/086871db-5871-460f-97b7-126cd738bb0e.jpg) +![](https://github.com/CyC2018/InterviewNotes/blob/master/pics//086871db-5871-460f-97b7-126cd738bb0e.jpg) -¼ÙÉè A Ϊ¿Í»§¶Ë£¬B Ϊ·þÎñÆ÷¶Ë¡£ +å�‡è®¾ A 为客户端,B 为æœ�务器端。 -1. Ê×ÏÈ B ´¦ÓÚ LISTEN£¨¼àÌý£©×´Ì¬£¬µÈ´ý¿Í»§µÄÁ¬½ÓÇëÇó¡£ -2. A Ïò B ·¢ËÍÁ¬½ÓÇëÇó±¨ÎĶΣ¬SYN=1£¬ACK=0£¬Ñ¡ÔñÒ»¸ö³õʼµÄÐòºÅ x¡£ -3. B ÊÕµ½Á¬½ÓÇëÇó±¨ÎĶΣ¬Èç¹ûͬÒ⽨Á¢Á¬½Ó£¬ÔòÏò A ·¢ËÍÁ¬½ÓÈ·Èϱ¨ÎĶΣ¬SYN=1£¬ACK=1£¬È·ÈϺÅΪ x+1£¬Í¬Ê±Ò²Ñ¡ÔñÒ»¸ö³õʼµÄÐòºÅ y¡£ -4. A ÊÕµ½ B µÄÁ¬½ÓÈ·Èϱ¨ÎĶκ󣬻¹ÒªÏò B ·¢³öÈ·ÈÏ£¬È·ÈϺÅΪ y+1£¬ÐòºÅΪ x+1¡£ -5. B ÊÕµ½ A µÄÈ·ÈϺó£¬Á¬½Ó½¨Á¢¡£ +1. 首先 B 处于 LISTEN(监å�¬ï¼‰çжæ€�,等待客户的连接请求。 +2. A å�‘ B å�‘é€�连接请求报文段,SYN=1,ACK=0,选择一个åˆ�å§‹çš„åº�å�· x。 +3. B 收到连接请求报文段,如果å�Œæ„�建立连接,则å�‘ A å�‘é€�连接确认报文段,SYN=1,ACK=1,确认å�·ä¸º x+1,å�Œæ—¶ä¹Ÿé€‰æ‹©ä¸€ä¸ªåˆ�å§‹çš„åº�å�· y。 +4. A 收到 B 的连接确认报文段å�Žï¼Œè¿˜è¦�å�‘ B å�‘出确认,确认å�·ä¸º y+1,åº�å�·ä¸º x+1。 +5. B 收到 A 的确认å�Žï¼Œè¿žæŽ¥å»ºç«‹ã€‚ -## TCP µÄËĴλÓÊÖ +## TCP 的四次挥手 -![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/78f65456-666b-4044-b4ee-f7692dbbc0d3.jpg) +![](https://github.com/CyC2018/InterviewNotes/blob/master/pics//78f65456-666b-4044-b4ee-f7692dbbc0d3.jpg) -ÒÔÏÂÃèÊö²»ÌÖÂÛÐòºÅºÍÈ·ÈϺţ¬ÒòΪÐòºÅºÍÈ·ÈϺŵĹæÔò±È½Ï¼òµ¥¡£²¢ÇÒ²»ÌÖÂÛ ACK£¬ÒòΪ ACK ÔÚÁ¬½Ó½¨Á¢Ö®ºó¶¼Îª 1¡£ +以下æ��è¿°ä¸�讨论åº�å�·å’Œç¡®è®¤å�·ï¼Œå› ä¸ºåº�å�·å’Œç¡®è®¤å�·çš„规则比较简å�•。并且ä¸�讨论 ACK,因为 ACK 在连接建立之å�Žéƒ½ä¸º 1。 -1. A ·¢ËÍÁ¬½ÓÊͷű¨ÎĶΣ¬FIN=1£» -2. B ÊÕµ½Ö®ºó·¢³öÈ·ÈÏ£¬´Ëʱ TCP ÊôÓÚ°ë¹Ø±Õ״̬£¬B ÄÜÏò A ·¢ËÍÊý¾Ýµ«ÊÇ A ²»ÄÜÏò B ·¢ËÍÊý¾Ý£» -3. µ± B Òª²»ÔÙÐèÒªÁ¬½Óʱ£¬·¢ËÍÁ¬½ÓÊÍ·ÅÇëÇó±¨ÎĶΣ¬FIN=1£» -4. A ÊÕµ½ºó·¢³öÈ·ÈÏ£¬´ËʱÁ¬½ÓÊÍ·Å¡£ +1. A å�‘é€�连接释放报文段,FIN=1ï¼› +2. B 收到之å�Žå�‘出确认,此时 TCP 属于å�Šå…³é—­çжæ€�,B 能å�‘ A å�‘é€�æ•°æ�®ä½†æ˜¯ A ä¸�能å�‘ B å�‘é€�æ•°æ�®ï¼› +3. 当 B è¦�ä¸�å†�需è¦�连接时,å�‘é€�连接释放请求报文段,FIN=1ï¼› +4. A 收到å�Žå�‘出确认,此时连接释放。 **TIME_WAIT** -¿Í»§¶Ë½ÓÊÕµ½·þÎñÆ÷¶ËµÄ FIN ±¨Îĺó½øÈë´Ë״̬£¬´Ëʱ²¢²»ÊÇÖ±½Ó½øÈë CLOSED ״̬£¬»¹ÐèÒªµÈ´ýÒ»¸öʱ¼ä¼ÆÊ±Æ÷ÉèÖõÄʱ¼ä¡£Õâô×öÓÐÁ½¸öÀíÓÉ£º +客户端接收到æœ�务器端的 FIN 报文å�Žè¿›å…¥æ­¤çжæ€�,此时并ä¸�是直接进入 CLOSED 状æ€�,还需è¦�等待一个时间计时器设置的时间。这么å�šæœ‰ä¸¤ä¸ªç�†ç”±ï¼š -1. È·±£×îºóÒ»¸öÈ·Èϱ¨ÎĶÎÄܹ»µ½´ï¡£Èç¹û B ûÊÕµ½ A ·¢ËÍÀ´µÄÈ·Èϱ¨ÎĶΣ¬ÄÇô¾Í»áÖØÐ·¢ËÍÁ¬½ÓÊÍ·ÅÇëÇó±¨ÎĶΣ¬A µÈ´ýÒ»¶Îʱ¼ä¾ÍÊÇΪÁË´¦ÀíÕâÖÖÇé¿öµÄ·¢Éú¡£ -2. ¿ÉÄÜ´æÔÚ¡°ÒÑʧЧµÄÁ¬½ÓÇëÇó±¨ÎĶΡ±£¬ÎªÁË·ÀÖ¹ÕâÖÖ±¨ÎĶγöÏÖÔÚ±¾´ÎÁ¬½ÓÖ®Í⣬ÐèÒªµÈ´ýÒ»¶Îʱ¼ä¡£ +1. ç¡®ä¿�最å�Žä¸€ä¸ªç¡®è®¤æŠ¥æ–‡æ®µèƒ½å¤Ÿåˆ°è¾¾ã€‚如果 B 没收到 A å�‘é€�æ�¥çš„确认报文段,那么就会é‡�æ–°å�‘é€�连接释放请求报文段,A 等待一段时间就是为了处ç�†è¿™ç§�情况的å�‘生。 +2. å�¯èƒ½å­˜åœ¨â€œå·²å¤±æ•ˆçš„连接请求报文段â€�,为了防止这ç§�报文段出现在本次连接之外,需è¦�等待一段时间。 -## TCP »¬¶¯´°¿Ú +## TCP 滑动窗å�£ -![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/223fc26e-2fd6-484c-bcb7-443cac134f15.jpg) +![](https://github.com/CyC2018/InterviewNotes/blob/master/pics//223fc26e-2fd6-484c-bcb7-443cac134f15.jpg) -´°¿ÚÊÇ»º´æµÄÒ»²¿·Ö£¬ÓÃÀ´ÔÝʱ´æ·Å×Ö½ÚÁ÷¡£·¢ËÍ·½ºÍ½ÓÊÕ·½¸÷ÓÐÒ»¸ö´°¿Ú£¬½ÓÊÕ·½Í¨¹ý TCP ±¨ÎĶÎÖеĴ°¿Ú×ֶθæËß·¢ËÍ·½×Ô¼ºµÄ´°¿Ú´óС£¬·¢ËÍ·½¸ù¾ÝÕâ¸öÖµºÍÆäËüÐÅÏ¢ÉèÖÃ×Ô¼ºµÄ´°¿Ú´óС¡£ +窗å�£æ˜¯ç¼“存的一部分,用æ�¥æš‚时存放字节æµ�。å�‘é€�方和接收方å�„有一个窗å�£ï¼ŒæŽ¥æ”¶æ–¹é€šè¿‡ TCP 报文段中的窗å�£å­—段告诉å�‘é€�方自己的窗å�£å¤§å°�,å�‘é€�方根æ�®è¿™ä¸ªå€¼å’Œå…¶å®ƒä¿¡æ�¯è®¾ç½®è‡ªå·±çš„窗å�£å¤§å°�。 -·¢ËÍ´°¿ÚÄÚµÄ×Ö½Ú¶¼ÔÊÐí±»·¢ËÍ£¬½ÓÊÕ´°¿ÚÄÚµÄ×Ö½Ú¶¼ÔÊÐí±»½ÓÊÕ¡£Èç¹û·¢ËÍ´°¿Ú×󲿵Ä×Ö½ÚÒѾ­·¢ËͲ¢ÇÒÊÕµ½ÁËÈ·ÈÏ£¬ÄÇô¾Í½«·¢ËÍ´°¿ÚÏòÓÒ»¬¶¯Ò»¶¨¾àÀ룬ֱµ½×󲿵ÚÒ»¸ö×Ö½Ú²»ÊÇÒÑ·¢ËͲ¢ÇÒÒÑÈ·ÈϵÄ״̬£»½ÓÊÕ´°¿ÚµÄ»¬¶¯ÀàËÆ£¬½ÓÊÕ´°¿Ú×ó²¿×Ö½ÚÒѾ­·¢ËÍÈ·Èϲ¢½»¸¶Ö÷»ú£¬¾ÍÏòÓÒ»¬¶¯½ÓÊÕ´°¿Ú¡£ +å�‘é€�窗å�£å†…的字节都å…�许被å�‘é€�,接收窗å�£å†…的字节都å…�许被接收。如果å�‘é€�窗å�£å·¦éƒ¨çš„字节已ç»�å�‘é€�并且收到了确认,那么就将å�‘é€�窗å�£å�‘å�³æ»‘动一定è·�离,直到左部第一个字节ä¸�是已å�‘é€�并且已确认的状æ€�;接收窗å�£çš„æ»‘动类似,接收窗å�£å·¦éƒ¨å­—节已ç»�å�‘é€�确认并交付主机,就å�‘å�³æ»‘动接收窗å�£ã€‚ -½ÓÊÕ´°¿ÚÖ»»á¶Ô´°¿ÚÄÚ×îºóÒ»¸ö°´Ðòµ½´ïµÄ×Ö½Ú½øÐÐÈ·ÈÏ£¬ÀýÈç½ÓÊÕ´°¿ÚÒѾ­ÊÕµ½µÄ×Ö½ÚΪ {31, 32, 34, 35}£¬ÆäÖÐ {31, 32} °´Ðòµ½´ï£¬¶ø {34, 35} ¾Í²»ÊÇ£¬Òò´ËÖ»¶Ô×Ö½Ú 32 ½øÐÐÈ·ÈÏ¡£·¢ËÍ·½µÃµ½Ò»¸ö×Ö½ÚµÄÈ·ÈÏÖ®ºó£¬¾ÍÖªµÀÕâ¸ö×Ö½Ú֮ǰµÄËùÓÐ×Ö½Ú¶¼ÒѾ­±»½ÓÊÕ¡£ +接收窗å�£å�ªä¼šå¯¹çª—å�£å†…最å�Žä¸€ä¸ªæŒ‰åº�到达的字节进行确认,例如接收窗å�£å·²ç»�收到的字节为 {31, 32, 34, 35},其中 {31, 32} 按åº�到达,而 {34, 35} å°±ä¸�是,因此å�ªå¯¹å­—节 32 进行确认。å�‘é€�方得到一个字节的确认之å�Žï¼Œå°±çŸ¥é�“这个字节之å‰�的所有字节都已ç»�被接收。 -## TCP ¿É¿¿´«Êä +## TCP å�¯é� ä¼ è¾“ -TCP ʹÓó¬Ê±ÖØ´«À´ÊµÏÖ¿É¿¿´«Ê䣺Èç¹ûÒ»¸öÒѾ­·¢Ë͵ı¨ÎĶÎÔÚ³¬Ê±Ê±¼äÄÚûÓÐÊÕµ½È·ÈÏ£¬ÄÇô¾ÍÖØ´«Õâ¸ö±¨ÎĶΡ£ +TCP 使用超时é‡�ä¼ æ�¥å®žçްå�¯é� ä¼ è¾“:如果一个已ç»�å�‘é€�的报文段在超时时间内没有收到确认,那么就é‡�传这个报文段。 -Ò»¸ö±¨ÎĶδӷ¢ËÍÔÙµ½½ÓÊÕµ½È·ÈÏËù¾­¹ýµÄʱ¼ä³ÆÎªÍù·µÊ±¼ä RTT£¬¼ÓȨƽ¾ùÍù·µÊ±¼ä RTTs ¼ÆËãÈçÏ£º +一个报文段从å�‘é€�å†�到接收到确认所ç»�过的时间称为往返时间 RTT,加æ�ƒå¹³å�‡å¾€è¿”æ—¶é—´ RTTs 计算如下: -![](http://latex.codecogs.com/gif.latex?\\\\RTTs=(1-a)*(RTTs)+a*RTT) +
-³¬Ê±Ê±¼ä RTO Ó¦¸ÃÂÔ´óÓÚ RRTs£¬TCP ʹÓõij¬Ê±Ê±¼ä¼ÆËãÈçÏ£º +è¶…æ—¶æ—¶é—´ RTO 应该略大于 RRTs,TCP 使用的超时时间计算如下: -![](http://latex.codecogs.com/gif.latex?\\\\RTO=RTTs+4*RTT_d) +
-ÆäÖÐ RTTd Ϊƫ²î£¬ËüÓëÐ嵀 RRT ºÍ RRTs Óйء£ +其中 RTTd 为å��差,它与新的 RRT å’Œ RRTs 有关。 -## TCP Á÷Á¿¿ØÖÆ +## TCP æµ�é‡�控制 -Á÷Á¿¿ØÖÆÊÇΪÁË¿ØÖÆ·¢ËÍ·½·¢ËÍËÙÂÊ£¬±£Ö¤½ÓÊÕ·½À´µÃ¼°½ÓÊÕ¡£ +æµ�é‡�控制是为了控制å�‘é€�æ–¹å�‘é€�速率,ä¿�è¯�接收方æ�¥å¾—å�ŠæŽ¥æ”¶ã€‚ -½ÓÊÕ·½·¢Ë͵ÄÈ·Èϱ¨ÎÄÖеĴ°¿Ú×ֶοÉÒÔÓÃÀ´¿ØÖÆ·¢ËÍ·½´°¿Ú´óС£¬´Ó¶øÓ°Ïì·¢ËÍ·½µÄ·¢ËÍËÙÂÊ¡£ÀýÈ罫´°¿Ú×Ö¶ÎÉèÖÃΪ 0£¬Ôò·¢ËÍ·½²»ÄÜ·¢ËÍÊý¾Ý¡£ +接收方å�‘é€�的确认报文中的窗å�£å­—段å�¯ä»¥ç”¨æ�¥æŽ§åˆ¶å�‘é€�方窗å�£å¤§å°�,从而影å“�å�‘é€�方的å�‘é€�速率。例如将窗å�£å­—段设置为 0,则å�‘é€�æ–¹ä¸�能å�‘é€�æ•°æ�®ã€‚ -## TCP ÓµÈû¿ØÖÆ +## TCP 拥塞控制 -Èç¹ûÍøÂç³öÏÖÓµÈû£¬·Ö×齫»á¶ªÊ§£¬´Ëʱ·¢ËÍ·½»á¼ÌÐøÖØ´«£¬´Ó¶øµ¼ÖÂÍøÂçÓµÈû³Ì¶È¸ü¸ß¡£Òò´Ëµ±³öÏÖÓµÈûʱ£¬Ó¦µ±¿ØÖÆ·¢ËÍ·½µÄËÙÂÊ¡£ÕâÒ»µãºÍÁ÷Á¿¿ØÖƺÜÏñ£¬µ«Êdzö·¢µã²»Í¬¡£Á÷Á¿¿ØÖÆÊÇΪÁËÈýÓÊÕ·½ÄÜÀ´µÃ¼°½ÓÊÜ£¬¶øÓµÈû¿ØÖÆÊÇΪÁ˽µµÍÕû¸öÍøÂçµÄÓµÈû³Ì¶È¡£ +如果网络出现拥塞,分组将会丢失,此时å�‘é€�方会继续é‡�传,从而导致网络拥塞程度更高。因此当出现拥塞时,应当控制å�‘é€�方的速率。这一点和æµ�é‡�控制很åƒ�,但是出å�‘点ä¸�å�Œã€‚æµ�é‡�控制是为了让接收方能æ�¥å¾—å�пޥå�—,而拥塞控制是为了é™�低整个网络的拥塞程度。 -![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/a69af9bb-b5ad-4896-862d-697e5ee4feb1.png) +![](https://github.com/CyC2018/InterviewNotes/blob/master/pics//a69af9bb-b5ad-4896-862d-697e5ee4feb1.png) -TCP Ö÷Ҫͨ¹ýËÄÖÖËã·¨À´½øÐÐÓµÈû¿ØÖÆ£ºÂý¿ªÊ¼¡¢ÓµÈû±ÜÃâ¡¢¿ìÖØ´«¡¢¿ì»Ö¸´¡£·¢ËÍ·½ÐèҪά»¤ÓÐÒ»¸ö½Ð×öÓµÈû´°¿Ú£¨cwnd£©µÄ״̬±äÁ¿¡£×¢ÒâÓµÈû´°¿ÚÓë·¢ËÍ·½´°¿ÚµÄÇø±ð£¬ÓµÈû´°¿ÚÖ»ÊÇÒ»¸ö״̬±äÁ¿£¬Êµ¼Ê¾ö¶¨·¢ËÍ·½ÄÜ·¢ËͶàÉÙÊý¾ÝµÄÊÇ·¢ËÍ·½´°¿Ú¡£ +TCP 主è¦�通过四ç§�算法æ�¥è¿›è¡Œæ‹¥å¡žæŽ§åˆ¶ï¼šæ…¢å¼€å§‹ã€�拥塞é�¿å…�ã€�å¿«é‡�ä¼ ã€�å¿«æ�¢å¤�。å�‘é€�方需è¦�维护有一个å�«å�šæ‹¥å¡žçª—å�£ï¼ˆcwnd)的状æ€�å�˜é‡�。注æ„�拥塞窗å�£ä¸Žå�‘é€�方窗å�£çš„区别,拥塞窗å�£å�ªæ˜¯ä¸€ä¸ªçжæ€�å�˜é‡�,实际决定å�‘é€�方能å�‘é€�多少数æ�®çš„æ˜¯å�‘é€�方窗å�£ã€‚ -ΪÁ˱ãÓÚÌÖÂÛ£¬×öÈçϼÙÉ裺 +为了便于讨论,å�šå¦‚下å�‡è®¾ï¼š -1. ½ÓÊÕ·½ÓÐ×ã¹»´óµÄ½ÓÊÕ»º´æ£¬Òò´Ë²»»á·¢ÉúÁ÷Á¿¿ØÖÆ£» -2. ËäÈ» TCP µÄ´°¿Ú»ùÓÚ×Ö½Ú£¬µ«ÊÇÕâÀïÉè´°¿ÚµÄ´óСµ¥Î»Îª±¨ÎĶΡ£ +1. 接收方有足够大的接收缓存,因此ä¸�会å�‘生æµ�é‡�控制; +2. 虽然 TCP 的窗å�£åŸºäºŽå­—节,但是这里设窗å�£çš„大å°�å�•ä½�为报文段。 -![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/346244ff-98c1-4f12-9a87-d0832e8c04cf.jpg) +![](https://github.com/CyC2018/InterviewNotes/blob/master/pics//346244ff-98c1-4f12-9a87-d0832e8c04cf.jpg) -### Âý¿ªÊ¼ÓëÓµÈû±ÜÃâ +### 慢开始与拥塞é�¿å…� -·¢Ë͵Ä×î³õÖ´ÐÐÂý¿ªÊ¼£¬Áî cwnd=1£¬·¢ËÍ·½Ö»ÄÜ·¢ËÍ 1 ¸ö±¨ÎĶΣ»µ±ÊÕµ½È·ÈϺ󣬽« cwnd ¼Ó±¶£¬Òò´ËÖ®ºó·¢ËÍ·½Äܹ»·¢Ë͵ı¨ÎĶÎΪ£º2¡¢4¡¢8 ... +å�‘é€�的最åˆ�执行慢开始,令 cwnd=1,å�‘é€�æ–¹å�ªèƒ½å�‘é€� 1 个报文段;当收到确认å�Žï¼Œå°† cwnd 加å€�,因此之å�Žå�‘é€�方能够å�‘é€�的报文段为:2ã€�4ã€�8 ... -×¢Òâµ½Âý¿ªÊ¼Ã¿¸öÂִζ¼½« cwnd ¼Ó±¶£¬ÕâÑù»áÈà cwnd Ôö³¤Ëٶȷdz£¿ì£¬´Ó¶øÊ¹µÃ·¢ËÍ·½·¢Ë͵ÄËÙ¶ÈÔö³¤Ëٶȹý¿ì£¬ÍøÂçÓµÈûµÄ¿ÉÄÜÒ²¾Í¸ü¸ß¡£ÉèÖÃÒ»¸öÂý¿ªÊ¼ÃÅÏÞ ssthresh£¬µ± cwnd >= ssthresh ʱ£¬½øÈëÓµÈû±ÜÃ⣬ÿ¸öÂÖ´ÎÖ»½« cwnd ¼Ó 1¡£ +注æ„�到慢开始æ¯�个轮次都将 cwnd 加å€�,这样会让 cwnd 增长速度é�žå¸¸å¿«ï¼Œä»Žè€Œä½¿å¾—å�‘é€�æ–¹å�‘é€�的速度增长速度过快,网络拥塞的å�¯èƒ½ä¹Ÿå°±æ›´é«˜ã€‚设置一个慢开始门é™� ssthresh,当 cwnd >= ssthresh 时,进入拥塞é�¿å…�,æ¯�个轮次å�ªå°† cwnd 加 1。 -Èç¹û³öÏÖÁ˳¬Ê±£¬ÔòÁî ssthresh = cwnd / 2£¬È»ºóÖØÐÂÖ´ÐÐÂý¿ªÊ¼¡£ +如果出现了超时,则令 ssthresh = cwnd / 2,然å�Žé‡�新执行慢开始。 -### ¿ìÖØ´«Óë¿ì»Ö¸´ +### å¿«é‡�传与快æ�¢å¤� -ÔÚ½ÓÊÕ·½£¬ÒªÇóÿ´Î½ÓÊÕµ½±¨ÎĶζ¼Ó¦¸Ã·¢ËͶÔÒÑÊÕµ½ÓÐÐò±¨ÎĶεÄÈ·ÈÏ£¬ÀýÈçÒѾ­½ÓÊÕµ½ M1 ºÍ M2£¬´ËʱÊÕµ½ M4£¬Ó¦µ±·¢ËÍ¶Ô M2 µÄÈ·ÈÏ¡£ +在接收方,è¦�求æ¯�次接收到报文段都应该å�‘é€�对已收到有åº�报文段的确认,例如已ç»�接收到 M1 å’Œ M2,此时收到 M4,应当å�‘é€�对 M2 的确认。 -ÔÚ·¢ËÍ·½£¬Èç¹ûÊÕµ½Èý¸öÖØ¸´È·ÈÏ£¬ÄÇô¿ÉÒÔÈ·ÈÏÏÂÒ»¸ö±¨ÎĶζªÊ§£¬ÀýÈçÊÕµ½Èý¸ö M2 £¬Ôò M3 ¶ªÊ§¡£´ËʱִÐпìÖØ´«£¬Á¢¼´ÖØ´«ÏÂÒ»¸ö±¨ÎĶΡ£ +在å�‘é€�方,如果收到三个é‡�å¤�确认,那么å�¯ä»¥ç¡®è®¤ä¸‹ä¸€ä¸ªæŠ¥æ–‡æ®µä¸¢å¤±ï¼Œä¾‹å¦‚收到三个 M2 ,则 M3 丢失。此时执行快é‡�传,立å�³é‡�传下一个报文段。 -ÔÚÕâÖÖÇé¿öÏ£¬Ö»ÊǶªÊ§¸ö±ð±¨ÎĶΣ¬¶ø²»ÊÇÍøÂçÓµÈû£¬Òò´ËÖ´Ðпì»Ö¸´£¬Áî ssthresh = cwnd / 2 £¬cwnd = ssthresh£¬×¢Òâµ½´Ëʱֱ½Ó½øÈëÓµÈû±ÜÃâ¡£ +在这ç§�情况下,å�ªæ˜¯ä¸¢å¤±ä¸ªåˆ«æŠ¥æ–‡æ®µï¼Œè€Œä¸�是网络拥塞,因此执行快æ�¢å¤�,令 ssthresh = cwnd / 2 ,cwnd = ssthresh,注æ„�到此时直接进入拥塞é�¿å…�。 -![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/b18d679b-c8e2-4564-88ee-7600090e46da.jpg) +![](https://github.com/CyC2018/InterviewNotes/blob/master/pics//b18d679b-c8e2-4564-88ee-7600090e46da.jpg) -# µÚÁùÕ ӦÓòã* +# 第六章 应用层* -## ÓòÃûϵͳ DNS +## 域å��系统 DNS -°ÑÖ÷»úÃû½âÎöΪ IP µØÖ·¡£ +把主机å��è§£æž�为 IP 地å�€ã€‚ -±»Éè¼Æ³É·Ö²¼Ê½ÏµÍ³¡£ +被设计æˆ�分布å¼�系统。 -### 1. ²ã´Î½á¹¹ +### 1. 层次结构 -Ò»¸öÓòÃûÓɶà¸ö²ã´Î¹¹³É£¬´ÓÉϲ㵽ϲã·Ö±ðΪ¶¥¼¶ÓòÃû¡¢¶þ¼¶ÓòÃû¡¢Èý¼¶ÓòÃûÒÔ¼°Ëļ¶ÓòÃû¡£ËùÓÐÓòÃû¿ÉÒÔ»­³ÉÒ»¿ÅÓòÃûÊ÷¡£ +一个域å��由多个层次构æˆ�,从上层到下层分别为顶级域å��ã€�二级域å��ã€�三级域å��以å�Šå››çº§åŸŸå��。所有域å��å�¯ä»¥ç”»æˆ�一颗域å��树。 -![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/c2117f61-1177-4768-bf33-cf4f950d911c.png) +![](https://github.com/CyC2018/InterviewNotes/blob/master/pics//c2117f61-1177-4768-bf33-cf4f950d911c.png) -![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/a4b162e5-db2a-4a27-b213-1fe481c5a06a.png) +![](https://github.com/CyC2018/InterviewNotes/blob/master/pics//a4b162e5-db2a-4a27-b213-1fe481c5a06a.png) -ÓòÃû·þÎñÆ÷¿ÉÒÔ·ÖΪÒÔÏÂËÄÀࣺ +域å��æœ�务器å�¯ä»¥åˆ†ä¸ºä»¥ä¸‹å››ç±»ï¼š -1. ¸ùÓòÃû·þÎñÆ÷£º½âÎö¶¥¼¶ÓòÃû£» -2. ¶¥¼¶ÓòÃû·þÎñÆ÷£º½âÎö¶þ¼¶ÓòÃû£» -3. ȨÏÞÓòÃû·þÎñÆ÷£º½âÎöÇøÄÚµÄÓòÃû£» -4. ±¾µØÓòÃû·þÎñÆ÷£ºÒ²³ÆÎªÄ¬ÈÏÓòÃû·þÎñÆ÷¡£¿ÉÒÔÔÚÆäÖÐÅäÖøßËÙ»º´æ¡£ +1. 根域å��æœ�务器:解æž�顶级域å��ï¼› +2. 顶级域å��æœ�务器:解æž�二级域å��ï¼› +3. æ�ƒé™�域å��æœ�务器:解æž�区内的域å��ï¼› +4. 本地域å��æœ�务器:也称为默认域å��æœ�务器。å�¯ä»¥åœ¨å…¶ä¸­é…�置高速缓存。 -ÇøºÍÓòµÄ¸ÅÄͬ£¬¿ÉÒÔÔÚÒ»¸öÓòÖл®·Ö¶à¸öÇø¡£Í¼ b ÔÚÓò abc.com Öл®·ÖÁËÁ½¸öÇø£ºabc.com ºÍ y.abc.com +区和域的概念ä¸�å�Œï¼Œå�¯ä»¥åœ¨ä¸€ä¸ªåŸŸä¸­åˆ’分多个区。图 b 在域 abc.com 中划分了两个区:abc.com å’Œ y.abc.com -![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/fc0c6b2d-68c7-4de8-aaaa-97355a4f0472.jpg) +![](https://github.com/CyC2018/InterviewNotes/blob/master/pics//fc0c6b2d-68c7-4de8-aaaa-97355a4f0472.jpg) -Òò´Ë¾ÍÐèÒªÁ½¸öȨÏÞÓòÃû·þÎñÆ÷£º +因此就需è¦�两个æ�ƒé™�域å��æœ�务器: -![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/8b335d94-c1ca-42e1-ad48-bb179d28a4f1.jpg) +![](https://github.com/CyC2018/InterviewNotes/blob/master/pics//8b335d94-c1ca-42e1-ad48-bb179d28a4f1.jpg) -### 2. ½âÎö¹ý³Ì +### 2. è§£æž�过程 -Ö÷»úÏò±¾µØÓòÃû·þÎñÆ÷½âÎöµÄ¹ý³Ì²ÉÓõݹ飬¶ø±¾µØÓòÃû·þÎñÆ÷ÏòÆäËüÓòÃû·þÎñÆ÷½âÎö¿ÉÒÔʹÓõݹéºÍµü´úÁ½ÖÖ·½Ê½¡£ +主机å�‘本地域å��æœ�务器解æž�的过程采用递归,而本地域å��æœ�务器å�‘其它域å��æœ�务器解æž�å�¯ä»¥ä½¿ç”¨é€’归和迭代两ç§�æ–¹å¼�。 -µü´úµÄ·½Ê½Ï£¬±¾µØÓòÃû·þÎñÆ÷ÏòÒ»¸öÓòÃû·þÎñÆ÷½âÎöÇëÇó½âÎöÖ®ºó£¬½á¹û·µ»Øµ½±¾µØÓòÃû·þÎñÆ÷£¬È»ºó±¾µØÓòÃû·þÎñÆ÷¼ÌÐøÏòÆäËüÓòÃû·þÎñÆ÷ÇëÇó½âÎö£»¶øµÝ¹éµØ·½Ê½Ï£¬½á¹û²»ÊÇÖ±½Ó·µ»ØµÄ£¬¶øÊǼÌÐøÏòǰÇëÇó½âÎö£¬×îºóµÄ½á¹û²Å»á·µ»Ø¡£ +迭代的方å¼�下,本地域å��æœ�务器å�‘一个域å��æœ�务器解æž�请求解æž�之å�Žï¼Œç»“果返回到本地域å��æœ�务器,然å�Žæœ¬åœ°åŸŸå��æœ�务器继续å�‘其它域å��æœ�务器请求解æž�;而递归地方å¼�下,结果ä¸�是直接返回的,而是继续å�‘å‰�请求解æž�,最å�Žçš„结果æ‰�会返回。 -![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/6bc61bb8-3b1c-4dc8-ac25-cef925ace0eb.jpg) +![](https://github.com/CyC2018/InterviewNotes/blob/master/pics//6bc61bb8-3b1c-4dc8-ac25-cef925ace0eb.jpg) -## Îļþ´«ÊäЭÒé FTP +## 文件传输å��è®® FTP -FTP ÔÚÔËÊä²ãʹÓà TCP£¬²¢ÇÒÐèÒª½¨Á¢Á½¸ö²¢ÐÐµÄ TCP Á¬½Ó£º¿ØÖÆÁ¬½ÓºÍÊý¾ÝÁ¬½Ó¡£¿ØÖÆÁ¬½ÓÔÚÕû¸ö»á»°ÆÚ¼äÒ»Ö±±£³Ö´ò¿ª£¬¶øÊý¾ÝÁ¬½ÓÔÚÊý¾Ý´«ËÍÍê±ÏÖ®ºó¾Í¹Ø±Õ¡£¿ØÖÆÁ¬½ÓʹÓö˿ںŠ21£¬Êý¾ÝÁ¬½ÓʹÓö˿ںŠ20¡£ +FTP 在è¿�输层使用 TCP,并且需è¦�建立两个并行的 TCP 连接:控制连接和数æ�®è¿žæŽ¥ã€‚控制连接在整个会è¯�期间一直ä¿�æŒ�打开,而数æ�®è¿žæŽ¥åœ¨æ•°æ�®ä¼ é€�完毕之å�Žå°±å…³é—­ã€‚控制连接使用端å�£å�· 21,数æ�®è¿žæŽ¥ä½¿ç”¨ç«¯å�£å�· 20。 -![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/58633775-8584-4a01-ad3f-eee4d9a466e1.jpg) +![](https://github.com/CyC2018/InterviewNotes/blob/master/pics//58633775-8584-4a01-ad3f-eee4d9a466e1.jpg) -## Ô¶³ÌÖÕ¶ËЭÒé TELNET +## 远程终端å��è®® TELNET -TELNET ÓÃÓڵǼµ½Ô¶³ÌÖ÷»úÉÏ£¬²¢ÇÒÔ¶³ÌÖ÷»úÉϵÄÊä³öÒ²»á·µ»Ø¡£ +TELNET 用于登录到远程主机上,并且远程主机上的输出也会返回。 -TELNET ¿ÉÒÔÊÊÓ¦Ðí¶à¼ÆËã»úºÍ²Ù×÷ϵͳµÄ²îÒ죬ÀýÈ粻ͬ²Ù×÷ϵͳϵͳµÄ»»Ðзû¶¨Òå¡£ +TELNET å�¯ä»¥é€‚应许多计算机和æ“�作系统的差异,例如ä¸�å�Œæ“�作系统系统的æ�¢è¡Œç¬¦å®šä¹‰ã€‚ -## ÍòÎ¬Íø WWW +## 万维网 WWW [HTTP](https://github.com/CyC2018/InterviewNotes/blob/master/notes/HTTP.md) -## µç×ÓÓʼþЭÒé +## 电å­�邮件å��è®® -Ò»¸öµç×ÓÓʼþϵͳÓÉÈý²¿·Ö×é³É£ºÓû§´úÀí¡¢Óʼþ·þÎñÆ÷ÒÔ¼°Óʼþ·¢ËÍЭÒéºÍ¶ÁȡЭÒé¡£ÆäÖз¢ËÍЭÒé³£Óà SMTP£¬¶ÁȡЭÒé³£Óà POP3 ºÍ IMAP¡£ +一个电å­�邮件系统由三部分组æˆ�:用户代ç�†ã€�邮件æœ�务器以å�Šé‚®ä»¶å�‘é€�å��议和读å�–å��议。其中å�‘é€�å��议常用 SMTP,读å�–å��议常用 POP3 å’Œ IMAP。 -![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/de1e46d2-748f-4da3-a29e-7de7bc840366.jpg) +![](https://github.com/CyC2018/InterviewNotes/blob/master/pics//de1e46d2-748f-4da3-a29e-7de7bc840366.jpg) ### POP3 -POP3 µÄÌØµãÊÇÖ»ÒªÓû§´Ó·þÎñÆ÷É϶ÁÈ¡ÁËÓʼþ£¬¾Í°Ñ¸ÃÓʼþɾ³ý¡£ +POP3 的特点是å�ªè¦�用户从æœ�务器上读å�–了邮件,就把该邮件删除。 ### IMAP -IMAP ЭÒéÖпͻ§¶ËºÍ·þÎñÆ÷ÉϵÄÓʼþ±£³Öͬ²½£¬Èç¹û²»È¥ÊÖ¶¯É¾³ýÓʼþ£¬ÄÇô·þÎñÆ÷ÉϵÄÓʼþÒ²²»»á±»É¾³ý¡£IMAP ÕâÖÖ×ö·¨¿ÉÒÔÈÃÓû§ËæÊ±ËæµØÈ¥·ÃÎÊ·þÎñÆ÷ÉϵÄÓʼþ¡£IMAP ЭÒéÒ²Ö§³Ö´´½¨×Ô¶¨ÒåµÄÎļþ¼Ð¡£ +IMAP å��议中客户端和æœ�务器上的邮件ä¿�æŒ�å�Œæ­¥ï¼Œå¦‚æžœä¸�去手动删除邮件,那么æœ�务器上的邮件也ä¸�会被删除。IMAP è¿™ç§�å�𿳕å�¯ä»¥è®©ç”¨æˆ·éš�æ—¶éš�地去访问æœ�务器上的邮件。IMAP å��议也支æŒ�创建自定义的文件夹。 ### SMTP -SMTP Ö»ÄÜ·¢ËÍ ASCII Â룬¶ø»¥ÁªÍøÓʼþÀ©³ä MIME ¿ÉÒÔ·¢ËͶþ½øÖÆÎļþ¡£MIME ²¢Ã»Óи͝»òÕßÈ¡´ú SMTP£¬¶øÊÇÔö¼ÓÓʼþÖ÷ÌâµÄ½á¹¹£¬¶¨ÒåÁË·Ç ASCII ÂëµÄ±àÂë¹æÔò¡£ +SMTP å�ªèƒ½å�‘é€� ASCII ç �,而互è�”网邮件扩充 MIME å�¯ä»¥å�‘é€�二进制文件。MIME 并没有改动或者å�–代 SMTP,而是增加邮件主题的结构,定义了é�ž ASCII ç �的编ç �规则。 -![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/ed5522bb-3a60-481c-8654-43e7195a48fe.png) +![](https://github.com/CyC2018/InterviewNotes/blob/master/pics//ed5522bb-3a60-481c-8654-43e7195a48fe.png) -## ¶¯Ì¬Ö÷»úÅäÖÃЭÒé DHCP +## 动æ€�主机é…�ç½®å��è®® DHCP -DHCP ÌṩÁ˼´²å¼´ÓõÄÁ¬Íø·½Ê½£¬Óû§²»ÔÙÐèҪȥÊÖ¶¯ÅäÖà IP µØÖ·µÈÐÅÏ¢¡£ +DHCP æ��供了å�³æ�’å�³ç”¨çš„连网方å¼�,用户ä¸�å†�需è¦�去手动é…�ç½® IP 地å�€ç­‰ä¿¡æ�¯ã€‚ -DHCP ÅäÖõÄÄÚÈݲ»½öÊÇ IP µØÖ·£¬»¹°üÀ¨×ÓÍøÑÚÂ롢ĬÈÏ·ÓÉÆ÷ IP µØÖ·¡¢ÓòÃû·þÎñÆ÷µÄ IP µØÖ·¡£ +DHCP é…�置的内容ä¸�仅是 IP 地å�€ï¼Œè¿˜åŒ…括å­�网掩ç �ã€�默认路由器 IP 地å�€ã€�域å��æœ�务器的 IP 地å�€ã€‚ -¹¤×÷·½Ê½ÈçÏ£ºÐèÒª IP µØÖ·µÄÖ÷»ú¹ã²¥·¢ËÍ DHCP ·¢ÏÖ±¨ÎÄ£¨½«Ä¿µÄµØÖ·ÖÃΪȫ 1£¬¼´ 255.255.255.255:67£¬Ô´µØÖ·ÉèÖÃΪȫ 0£¬¼´ 0.0.0.0:68£©£¬DHCP ·þÎñÆ÷ÊÕµ½·¢ÏÖ±¨ÎÄÖ®ºó£¬ÔòÔÚ IP µØÖ·³ØÖÐȡһ¸öµØÖ·£¬·¢ËÍ DHCP Ìṩ±¨Îĸø¸ÃÖ÷»ú¡£ +工作方å¼�如下:需è¦� IP 地å�€çš„主机广播å�‘é€� DHCP å�‘现报文(将目的地å�€ç½®ä¸ºå…¨ 1,å�³ 255.255.255.255:67,æº�地å�€è®¾ç½®ä¸ºå…¨ 0,å�³ 0.0.0.0:68),DHCP æœ�务器收到å�‘现报文之å�Žï¼Œåˆ™åœ¨ IP 地å�€æ± ä¸­å�–一个地å�€ï¼Œå�‘é€� DHCP æ��供报文给该主机。 -## µã¶Ôµã´«Êä P2P +## 点对点传输 P2P -°Ñij¸öÎļþ·Ö·¢µÄËùÓжԵȼ¯ºÏ³ÆÎªÒ»¸öºéÁ÷¡£ÎļþµÄÊý¾Ýµ¥Ôª³ÆÎªÎļþ¿é£¬ËüµÄ´óСÊǹ̶¨µÄ¡£Ò»¸öеĶԵȷ½¼ÓÈëij¸öºéÁ÷£¬Ò»¿ªÊ¼²¢Ã»ÓÐÎļþ¿é£¬µ«ÊÇÄܹ»´ÓÆäËü¶ÔµÈ·½ÖÐÖð½¥µØÏÂÔØµ½Ò»Ð©Îļþ¿é£¬Óë´Ëͬʱ£¬ËüҲΪ±ðµÄ¶ÔµÈ·½ÉÏ´«Ò»Ð©Îļþ¿é¡£ +把æŸ�个文件分å�‘的所有对等集å�ˆç§°ä¸ºä¸€ä¸ªæ´ªæµ�。文件的数æ�®å�•元称为文件å�—,它的大å°�是固定的。一个新的对等方加入æŸ�个洪æµ�,一开始并没有文件å�—,但是能够从其它对等方中é€�æ¸�地下载到一些文件å�—,与此å�Œæ—¶ï¼Œå®ƒä¹Ÿä¸ºåˆ«çš„对等方上传一些文件å�—。 -ÿ¸öºéÁ÷¶¼ÓÐÒ»¸ö»ù´¡ÉèÊ©£¬³ÆÎª×·×ÙÆ÷¡£µ±Ò»¸ö¶ÔµÈ·½¼ÓÈëºéÁ÷ʱ£¬±ØÐëÏò×·×ÙÆ÷µÇ¼Ç£¬²¢ÖÜÆÚÐÔµØÍ¨Öª×·×ÙÆ÷ËüÈÔÔÚºéÁ÷ÖС£¿ÉÒÔÔÚÈκÎʱ¼ä¼ÓÈëºÍÍ˳öij¸öºéÁ÷¡£ +æ¯�个洪æµ�都有一个基础设施,称为追踪器。当一个对等方加入洪æµ�时,必须å�‘追踪器登记,并周期性地通知追踪器它ä»�在洪æµ�中。å�¯ä»¥åœ¨ä»»ä½•时间加入和退出æŸ�个洪æµ�。 -Ò»¸öеĶԵȷ½¼ÓÈëºéÁ÷ʱ£¬×·×ÙÆ÷»áËæ»ú´ÓºéÁ÷ÖÐÑ¡ÔñÈô¸É¸ö¶ÔµÈ·½£¬²¢ÈÃжԵȷ½ÓëÕâЩ¶ÔµÈ·½½¨Á¢Á¬½Ó£¬°ÑÕâЩ¶ÔµÈ·½³ÆÎªÏàÁڶԵȷ½¡£½ÓÊպͷ¢ËÍÎļþ¿é¶¼ÊÇÔÚÏàÁڶԵȷ½ÖнøÐС£ +一个新的对等方加入洪æµ�时,追踪器会éš�机从洪æµ�中选择若干个对等方,并让新对等方与这些对等方建立连接,把这些对等方称为相邻对等方。接收和å�‘é€�文件å�—都是在相邻对等方中进行。 -µ±Ò»¸ö¶ÔµÈ·½ÐèÒªºÜ¶àÎļþ¿éʱ£¬Í¨¹ýʹÓÃ×îÏ¡ÓÐÓÅÏȵIJßÂÔÀ´È¡µÃÎļþ¿é£¬Ò²¾ÍÊÇÒ»¸öÎļþ¿éÔÚÏàÁڶԵȷ½Öи±±¾×îÉÙ£¬ÄÇô¾ÍÓÅÏÈÇëÇóÕâ¸öÎļþ¿é¡£ +当一个对等方需è¦�很多文件å�—时,通过使用最稀有优先的策略æ�¥å�–得文件å�—,也就是一个文件å�—在相邻对等方中副本最少,那么就优先请求这个文件å�—。 -µ±ºÜ¶à¶ÔµÈ·½Ïòͬһ¸ö¶ÔµÈ·½ÇëÇóÎļþ¿éʱ£¬¸Ã¶ÔµÈ·½ÓÅÏÈÑ¡ÔñÒÔ×î¸ßËÙÂÊÏòÆä·¢ËÍÎļþ¿éµÄ¶ÔµÈ·½¡£ +当很多对等方å�‘å�Œä¸€ä¸ªå¯¹ç­‰æ–¹è¯·æ±‚文件å�—时,该对等方优先选择以最高速率å�‘å…¶å�‘é€�文件å�—的对等方。 -P2P ÊÇÒ»¸ö·Ö²¼Ê½ÏµÍ³£¬ÈκÎʱºò¶¼ÓжԵȷ½¼ÓÈë»òÕßÍ˳ö¡£Ê¹Ó÷ֲ¼Ê½É¢Áбí DHT£¬¿ÉÒÔ²éÕÒºéÁ÷ÖеÄ×ÊÔ´ºÍ IP µØÖ·Ó³Éä¡£ +P2P 是一个分布å¼�系统,任何时候都有对等方加入或者退出。使用分布å¼�散列表 DHT,å�¯ä»¥æŸ¥æ‰¾æ´ªæµ�中的资æº�å’Œ IP 地å�€æ˜ å°„。 -## Web Ò³ÃæÇëÇó¹ý³Ì +## Web 页é�¢è¯·æ±‚过程 -1. Ïò DNS ·þÎñÆ÷·¢ËÍ DNS ²éѯ±¨ÎÄÀ´½âÎöÓòÃû¡£ +1. å�‘ DNS æœ�务器å�‘é€� DNS 查询报文æ�¥è§£æž�域å��。 -2. ¿ªÊ¼½øÐÐ HTTP »á»°£¬ÐèÒªÏȽ¨Á¢ TCP Á¬½Ó¡£ +2. 开始进行 HTTP 会è¯�,需è¦�先建立 TCP 连接。 -3. ÔÚÔËÊä²ãµÄ´«Êä¹ý³ÌÖУ¬HTTP ±¨Îı»·â×°½ø TCP ÖС£HTTP ÇëÇó±¨ÎÄʹÓö˿ںŠ80£¬ÒòΪ·þÎñÆ÷¼àÌýµÄÊÇ 80 ¶Ë¿Ú¡£Á¬½Ó½¨Á¢Ö®ºó£¬·þÎñÆ÷»áËæ»ú·ÖÅäÒ»¸ö¶Ë¿ÚºÅ¸øÌض¨µÄ¿Í»§¶Ë£¬Ö®ºóµÄ TCP ´«Êä¶¼ÊÇÓÃÕâ¸ö·ÖÅäµÄ¶Ë¿ÚºÅ¡£ +3. 在è¿�输层的传输过程中,HTTP 报文被å°�装进 TCP 中。HTTP 请求报文使用端å�£å�· 80,因为æœ�务器监å�¬çš„æ˜¯ 80 端å�£ã€‚连接建立之å�Žï¼Œæœ�务器会éš�机分é…�一个端å�£å�·ç»™ç‰¹å®šçš„客户端,之å�Žçš„ TCP 传输都是用这个分é…�的端å�£å�·ã€‚ -4. ÔÚÍøÂç²ãµÄ´«Êä¹ý³ÌÖУ¬TCP ±¨ÎĶλᱻ·â×°½ø IP ·Ö×éÖУ¬IP ·Ö×é¾­¹ý·ÓÉÑ¡Ôñ£¬×îºóµ½´ïÄ¿µÄµØ¡£ +4. 在网络层的传输过程中,TCP 报文段会被å°�装进 IP 分组中,IP 分组ç»�过路由选择,最å�Žåˆ°è¾¾ç›®çš„地。 -5. ÔÚÁ´Â·²ã£¬IP ·Ö×é»á±»·â×°½ø MAC Ö¡ÖУ¬IP µØÖ·½âÎö³É MAC µØÖ·ÐèҪʹÓà ARP¡£ +5. 在链路层,IP 分组会被å°�装进 MAC 帧中,IP 地å�€è§£æž�æˆ� MAC 地å�€éœ€è¦�使用 ARP。 -6. ¿Í»§¶Ë·¢ËÍ HTTP ÇëÇó±¨ÎÄ£¬ÇëÇó»ñÈ¡Ò³Ãæ¡£ +6. 客户端å�‘é€� HTTP 请求报文,请求获å�–页é�¢ã€‚ -7. ·þÎñÆ÷·¢ËÍ HTTP ÏàÓ¦±¨ÎÄ£¬¿Í»§¶Ë´Ó¶ø»ñÈ¡¸ÃÒ³Ãæ¡£ +7. æœ�务器å�‘é€� HTTP 相应报文,客户端从而获å�–该页é�¢ã€‚ -8. ä¯ÀÀÆ÷µÃµ½Ò³ÃæÄÚÈÝÖ®ºó£¬½âÎö²¢äÖȾ£¬ÏòÓû§Õ¹Ê¾Ò³Ãæ¡£ +8. æµ�览器得到页é�¢å†…容之å�Žï¼Œè§£æž�并渲染,å�‘用户展示页é�¢ã€‚ -## ³£ÓÃ¶Ë¿Ú +## 常用端å�£ -| Ó¦ÓòãЭÒé | ¶Ë¿ÚºÅ | ÔËÊä²ãЭÒé | +| 应用层å��è®® | 端å�£å�· | è¿�输层å��è®® | | -- | -- | -- | | DNS | 53 | UDP | -| FTP | ¿ØÖÆÁ¬½Ó 21£¬Êý¾ÝÁ¬½Ó 20 | TCP | +| FTP | 控制连接 21,数æ�®è¿žæŽ¥ 20 | TCP | | TELNET | 23 | TCP | | DHCP | 67 68 | UDP | | HTTP | 80 | TCP | @@ -841,7 +842,7 @@ P2P | POP3 | 110 | TCP | | IMAP | 143 | TCP | -# ²Î¿¼×ÊÁÏ +# å�‚考资料 -- ¼ÆËã»úÍøÂç µÚÆß°æ -- ¼ÆËã»úÍøÂç ×Ô¶¥ÏòÏ·½·¨ +- 计算机网络 第七版 +- 计算机网络 自顶å�‘下方法 diff --git a/notes/设计模å¼�.md b/notes/设计模å¼�.md index 1876532c..eeba2a3e 100644 --- a/notes/设计模å¼�.md +++ b/notes/设计模å¼�.md @@ -1,72 +1,73 @@ -* [µÚ 1 Õ Éè¼ÆÄ£Ê½ÈëÃÅ](#µÚ-1-ÕÂ-Éè¼ÆÄ£Ê½ÈëÃÅ) -* [µÚ 2 Õ ¹Û²ìÕßģʽ](#µÚ-2-ÕÂ-¹Û²ìÕßģʽ) -* [µÚ 3 Õ װÊÎģʽ](#µÚ-3-ÕÂ-×°ÊÎģʽ) -* [µÚ 4 Õ ¹¤³§Ä£Ê½](#µÚ-4-ÕÂ-¹¤³§Ä£Ê½) - * [4.1 ¼òµ¥¹¤³§](#41-¼òµ¥¹¤³§) - * [4.2 ¹¤³§·½·¨Ä£Ê½](#42-¹¤³§·½·¨Ä£Ê½) - * [4.3 ³éÏ󹤳§Ä£Ê½](#43-³éÏ󹤳§Ä£Ê½) -* [µÚ 5 Õ µ¥¼þģʽ](#µÚ-5-ÕÂ-µ¥¼þģʽ) -* [µÚ 6 Õ ÃüÁîģʽ](#µÚ-6-ÕÂ-ÃüÁîģʽ) -* [µÚ 7 Õ ÊÊÅäÆ÷ģʽÓëÍâ¹Ûģʽ](#µÚ-7-ÕÂ-ÊÊÅäÆ÷ģʽÓëÍâ¹Ûģʽ) - * [7.1 ÊÊÅäÆ÷ģʽ](#71-ÊÊÅäÆ÷ģʽ) - * [7.2 Íâ¹Ûģʽ](#72-Íâ¹Ûģʽ) -* [µÚ 8 Õ ģ°å·½·¨Ä£Ê½](#µÚ-8-ÕÂ-Ä£°å·½·¨Ä£Ê½) -* [µÚ 9 Õ µü´úÆ÷ºÍ×éºÏģʽ](#µÚ-9-ÕÂ-µü´úÆ÷ºÍ×éºÏģʽ) - * [9.1 µü´úÆ÷ģʽ](#91-µü´úÆ÷ģʽ) - * [9.2 Java ÄÚÖõĵü´úÆ÷](#92-java-ÄÚÖõĵü´úÆ÷) - * [9.3 ×éºÏģʽ](#93-×éºÏģʽ) -* [µÚ 10 Õ ״̬ģʽ](#µÚ-10-ÕÂ-״̬ģʽ) -* [µÚ 11 Õ ´úÀíģʽ](#µÚ-11-ÕÂ-´úÀíģʽ) -* [µÚ 12 Õ ¸´ºÏģʽ](#µÚ-12-ÕÂ-¸´ºÏģʽ) +* [第 1 ç«  设计模å¼�入门](#第-1-ç« -设计模å¼�入门) +* [第 2 ç«  观察者模å¼�](#第-2-ç« -观察者模å¼�) +* [第 3 ç«  装饰模å¼�](#第-3-ç« -装饰模å¼�) +* [第 4 ç«  工厂模å¼�](#第-4-ç« -工厂模å¼�) + * [4.1 简å�•工厂](#41-简å�•工厂) + * [4.2 工厂方法模å¼�](#42-工厂方法模å¼�) + * [4.3 抽象工厂模å¼�](#43-抽象工厂模å¼�) +* [第 5 ç«  å�•件模å¼�](#第-5-ç« -å�•件模å¼�) +* [第 6 ç«  命令模å¼�](#第-6-ç« -命令模å¼�) +* [第 7 ç«  适é…�器模å¼�与外观模å¼�](#第-7-ç« -适é…�器模å¼�与外观模å¼�) + * [7.1 适é…�器模å¼�](#71-适é…�器模å¼�) + * [7.2 外观模å¼�](#72-外观模å¼�) +* [第 8 ç«  模æ�¿æ–¹æ³•模å¼�](#第-8-ç« -模æ�¿æ–¹æ³•模å¼�) +* [第 9 ç«  迭代器和组å�ˆæ¨¡å¼�](#第-9-ç« -迭代器和组å�ˆæ¨¡å¼�) + * [9.1 迭代器模å¼�](#91-迭代器模å¼�) + * [9.2 Java 内置的迭代器](#92-java-内置的迭代器) + * [9.3 组å�ˆæ¨¡å¼�](#93-组å�ˆæ¨¡å¼�) +* [第 10 ç«  状æ€�模å¼�](#第-10-ç« -状æ€�模å¼�) +* [第 11 ç«  代ç�†æ¨¡å¼�](#第-11-ç« -代ç�†æ¨¡å¼�) +* [第 12 ç«  å¤�å�ˆæ¨¡å¼�](#第-12-ç« -å¤�å�ˆæ¨¡å¼�) * [12.1 MVC](#121-mvc) -* [µÚ 13 Õ ÓëÉè¼ÆÄ£Ê½Ïà´¦](#µÚ-13-ÕÂ-ÓëÉè¼ÆÄ£Ê½Ïà´¦) -* [µÚ 14 Õ ʣϵÄģʽ](#µÚ-14-ÕÂ-ʣϵÄģʽ) +* [第 13 ç«  与设计模å¼�相处](#第-13-ç« -与设计模å¼�相处) +* [第 14 ç«  剩下的模å¼�](#第-14-ç« -剩下的模å¼�) -# µÚ 1 Õ Éè¼ÆÄ£Ê½ÈëÃÅ -**1. Éè¼ÆÄ£Ê½¸ÅÄî** +# 第 1 ç«  设计模å¼�入门 -Éè¼ÆÄ£Ê½²»ÊÇ´úÂ룬¶øÊǽâ¾öÎÊÌâµÄ·½°¸£¬Ñ§Ï°ÏÖÓеÄÉè¼ÆÄ£Ê½¿ÉÒÔ×öµ½¾­Ñ鸴Óᣠ+**1. 设计模å¼�概念** -ÓµÓÐÉè¼ÆÄ£Ê½´Ê»ã£¬ÔÚ¹µÍ¨Ê±¾ÍÄÜÓøüÉٵĴʻãÀ´ÌÖÂÛ£¬²¢ÇÒ²»ÐèÒªÁ˽âµ×²ãϸ½Ú¡£ +设计模å¼�ä¸�是代ç �,而是解决问题的方案,学习现有的设计模å¼�å�¯ä»¥å�šåˆ°ç»�验å¤�用。 -**2. ÎÊÌâÃèÊö** +拥有设计模å¼�è¯�汇,在沟通时就能用更少的è¯�汇æ�¥è®¨è®ºï¼Œå¹¶ä¸”ä¸�需è¦�了解底层细节。 -Éè¼Æ²»Í¬ÖÖÀàµÄѼ×ÓÓµÓв»Í¬µÄ½ÐÉùºÍ·ÉÐз½Ê½¡£ +**2. 问题æ��è¿°** -**3. ¼òµ¥ÊµÏÖ·½°¸** +设计ä¸�å�Œç§�类的鸭å­�拥有ä¸�å�Œçš„å�«å£°å’Œé£žè¡Œæ–¹å¼�。 -ʹÓü̳еĽâ¾ö·½°¸ÈçÏ£¬ÕâÖÖ·½°¸´úÂëÎÞ·¨¸´Óã¬Èç¹ûÁ½¸öѼ×ÓÀàÓµÓÐͬÑùµÄ·ÉÐз½Ê½£¬¾ÍÓÐÁ½·ÝÖØ¸´µÄ´úÂë¡£ +**3. 简å�•实现方案** -![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/144d28a0-1dc5-4aba-8961-ced5bc88428a.jpg) +使用继承的解决方案如下,这ç§�方案代ç �无法å¤�用,如果两个鸭å­�类拥有å�Œæ ·çš„飞行方å¼�,就有两份é‡�å¤�的代ç �。 -**4. Éè¼ÆÔ­Ôò** +![](https://github.com/CyC2018/InterviewNotes/blob/master/pics//144d28a0-1dc5-4aba-8961-ced5bc88428a.jpg) -**·â×°±ä»¯**ÔÚÕâÀï±ä»¯µÄÊÇѼ×ӽкͷÉÐеÄÐÐΪ·½Ê½¡£ +**4. 设计原则** -**Õë¶Ô½Ó¿Ú±à³Ì£¬¶ø²»ÊÇÕë¶ÔʵÏÖ±à³Ì** ±äÁ¿ÉùÃ÷µÄÀàÐÍΪ¸¸À࣬¶ø²»ÊǾßÌåµÄij¸ö×ÓÀà¡£¸¸ÀàÖеķ½·¨ÊµÏÖ²»ÔÚ¸¸À࣬¶øÊÇÔÚ¸÷¸ö×ÓÀà¡£³ÌÐòÔÚÔËÐÐʱ¿ÉÒÔ¶¯Ì¬¸Ä±ä±äÁ¿ËùÖ¸ÏòµÄ×ÓÀàÀàÐÍ¡£ +**å°�装å�˜åŒ–**在这里å�˜åŒ–的是鸭å­�å�«å’Œé£žè¡Œçš„行为方å¼�。 -ÔËÓÃÕâÒ»Ô­Ôò£¬½«½ÐºÍ·ÉÐеÄÐÐΪ³éÏó³öÀ´£¬ÊµÏÖ¶àÖÖ²»Í¬µÄ½ÐºÍ·ÉÐеÄ×ÓÀ࣬ÈÃ×ÓÀàȥʵÏÖ¾ßÌåµÄ½ÐºÍ·ÉÐз½Ê½¡£ +**针对接å�£ç¼–程,而ä¸�是针对实现编程** å�˜é‡�声明的类型为父类,而ä¸�是具体的æŸ�个å­�类。父类中的方法实现ä¸�在父类,而是在å�„个å­�类。程åº�在è¿�行时å�¯ä»¥åЍæ€�改å�˜å�˜é‡�所指å�‘çš„å­�类类型。 -![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/1c8ccf5c-7ecd-4b8a-b160-3f72a510ce26.png) +è¿�用这一原则,将å�«å’Œé£žè¡Œçš„行为抽象出æ�¥ï¼Œå®žçŽ°å¤šç§�ä¸�å�Œçš„å�«å’Œé£žè¡Œçš„å­�类,让å­�类去实现具体的å�«å’Œé£žè¡Œæ–¹å¼�。 -**¶àÓÃ×éºÏ£¬ÉÙÓü̳Ð** ×éºÏÒ²¾ÍÊÇ has-a ¹ØÏµ£¬Í¨¹ý×éºÏ£¬¿ÉÒÔÔÚÔËÐÐʱ¶¯Ì¬¸Ä±äʵÏÖ£¬Ö»ÒªÍ¨¹ý¸Ä±ä¸¸Àà¶ÔÏó¾ßÌåÖ¸ÏòÄĸö×ÓÀ༴¿É¡£¶ø¼Ì³Ð¾Í²»ÄÜ×öµ½ÕâЩ£¬¼Ì³ÐÌåϵÔÚ´´½¨Ààʱ¾ÍÒѾ­È·¶¨¡£ +![](https://github.com/CyC2018/InterviewNotes/blob/master/pics//1c8ccf5c-7ecd-4b8a-b160-3f72a510ce26.png) -ÔËÓÃÕâÒ»Ô­Ôò£¬ÔÚ Duck ÀàÖÐ×éºÏ FlyBehavior ºÍ QuackBehavior À࣬performQuack() ºÍ performFly() ·½·¨Î¯ÍиøÕâÁ½¸öÀàÈ¥´¦Àí¡£Í¨¹ýÕâÖÖ·½Ê½£¬Ò»¸ö Duck ×ÓÀà¿ÉÒÔ¸ù¾ÝÐèҪȥʵÀý»¯ FlyBehavior ºÍ QuackBehavior µÄ×ÓÀà¶ÔÏ󣬲¢ÇÒÒ²¿ÉÒÔ¶¯Ì¬µØ½øÐиı䡣 +**多用组å�ˆï¼Œå°‘用继承** 组å�ˆä¹Ÿå°±æ˜¯ has-a 关系,通过组å�ˆï¼Œå�¯ä»¥åœ¨è¿�行时动æ€�改å�˜å®žçŽ°ï¼Œå�ªè¦�通过改å�˜çˆ¶ç±»å¯¹è±¡å…·ä½“指å�‘哪个å­�ç±»å�³å�¯ã€‚而继承就ä¸�能å�šåˆ°è¿™äº›ï¼Œç»§æ‰¿ä½“系在创建类时就已ç»�确定。 -![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/29574e6f-295c-444e-83c7-b162e8a73a83.jpg) +è¿�用这一原则,在 Duck 类中组å�ˆ FlyBehavior å’Œ QuackBehavior 类,performQuack() å’Œ performFly() 方法委托给这两个类去处ç�†ã€‚通过这ç§�æ–¹å¼�,一个 Duck å­�ç±»å�¯ä»¥æ ¹æ�®éœ€è¦�去实例化 FlyBehavior å’Œ QuackBehavior çš„å­�类对象,并且也å�¯ä»¥åЍæ€�地进行改å�˜ã€‚ -**5. ÕûÌåÉè¼ÆÍ¼** +![](https://github.com/CyC2018/InterviewNotes/blob/master/pics//29574e6f-295c-444e-83c7-b162e8a73a83.jpg) -![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/e13833c8-e215-462e-855c-1d362bb8d4a0.jpg) +**5. 整体设计图** -**6. ģʽ¶¨Òå** +![](https://github.com/CyC2018/InterviewNotes/blob/master/pics//e13833c8-e215-462e-855c-1d362bb8d4a0.jpg) -**²ßÂÔģʽ** £º¶¨ÒåÁËËã·¨×壬·Ö±ð·â×°ÆðÀ´£¬ÈÃËüÃÇÖ®¼ä¿ÉÒÔ»¥ÏàÌæ»»£¬´ËģʽÈÃËã·¨µÄ±ä»¯¶ÀÁ¢ÓÚʹÓÃËã·¨µÄ¿Í»§¡£ +**6. 模å¼�定义** -**7. ʵÏÖ´úÂë** +**策略模å¼�** :定义了算法æ—�,分别å°�装起æ�¥ï¼Œè®©å®ƒä»¬ä¹‹é—´å�¯ä»¥äº’相替æ�¢ï¼Œæ­¤æ¨¡å¼�让算法的å�˜åŒ–独立于使用算法的客户。 + +**7. 实现代ç �** ```java public abstract class Duck { @@ -162,42 +163,42 @@ public class MiniDuckSimulator { } } ``` -Ö´Ðнá¹û +执行结果 ```html QuackBehavior.Quack FlyBehavior.FlyWithWings FlyBehavior.FlyNoWay ``` -# µÚ 2 Õ ¹Û²ìÕßģʽ +# 第 2 ç«  观察者模å¼� -**1. ģʽ¶¨Òå** +**1. 模å¼�定义** -¶¨ÒåÁ˶ÔÏóÖ®¼äµÄÒ»¶Ô¶àÒÀÀµ£¬µ±Ò»¸ö¶ÔÏó¸Ä±ä״̬ʱ£¬ËüµÄËùÓÐÒÀÀµÕß¶¼»áÊܵ½Í¨Öª²¢×Ô¶¯¸üС£Ö÷Ì⣨Subject£©ÊDZ»¹Û²ìµÄ¶ÔÏ󣬶øÆäËùÓÐÒÀÀµÕߣ¨Observer£©³ÉΪ¹Û²ìÕß¡£ +定义了对象之间的一对多ä¾�赖,当一个对象改å�˜çжæ€�时,它的所有ä¾�赖者都会å�—到通知并自动更新。主题(Subject)是被观察的对象,而其所有ä¾�赖者(Observer)æˆ�为观察者。 -![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/26cb5e7e-6fa3-44ad-854e-fe24d1a5278c.jpg) +![](https://github.com/CyC2018/InterviewNotes/blob/master/pics//26cb5e7e-6fa3-44ad-854e-fe24d1a5278c.jpg) -**2. ģʽÀàͼ** +**2. 模å¼�类图** -Ö÷ÌâÖоßÓÐ×¢²áºÍÒÆ³ý¹Û²ìÕߣ¬²¢Í¨ÖªËùÓÐ×¢²áÕߵŦÄÜ£¬Ö÷ÌâÊÇͨ¹ýά»¤Ò»ÕŹ۲ìÕßÁбíÀ´ÊµÏÖÕâЩ²Ù×÷µÄ¡£ +主题中具有注册和移除观察者,并通知所有注册者的功能,主题是通过维护一张观察者列表æ�¥å®žçŽ°è¿™äº›æ“�作的。 -¹Û²ìÕßÓµÓÐÒ»¸öÖ÷Ìâ¶ÔÏóµÄÒýÓã¬ÒòΪע²á¡¢ÒƳý»¹ÓÐÊý¾Ý¶¼ÔÚÖ÷Ìâµ±ÖУ¬±ØÐëͨ¹ý²Ù×÷Ö÷Ìâ²ÅÄÜÍê³ÉÏàÓ¦¹¦ÄÜ¡£ +观察者拥有一个主题对象的引用,因为注册ã€�移除还有数æ�®éƒ½åœ¨ä¸»é¢˜å½“中,必须通过æ“�作主题æ‰�能完æˆ�相应功能。 -![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/5c558190-fccd-4b5e-98ed-1896653fc97f.jpg) +![](https://github.com/CyC2018/InterviewNotes/blob/master/pics//5c558190-fccd-4b5e-98ed-1896653fc97f.jpg) -**3. ÎÊÌâÃèÊö** +**3. 问题æ��è¿°** -ÌìÆøÊý¾Ý²¼¸æ°å»áÔÚÌìÆøÐÅÏ¢·¢Éú¸Ä±äʱ¸üÐÂÆäÄÚÈÝ£¬²¼¸æ°åÓжà¸ö£¬²¢ÇÒÔÚ½«À´»á¼ÌÐøÔö¼Ó¡£ +天气数æ�®å¸ƒå‘Šæ�¿ä¼šåœ¨å¤©æ°”ä¿¡æ�¯å�‘生改å�˜æ—¶æ›´æ–°å…¶å†…容,布告æ�¿æœ‰å¤šä¸ªï¼Œå¹¶ä¸”在将æ�¥ä¼šç»§ç»­å¢žåŠ ã€‚ -**4. ½â¾ö·½°¸Ààͼ** +**4. 解决方案类图** -![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/760a5d63-d96d-4dd9-bf9a-c3d126b2f401.jpg) +![](https://github.com/CyC2018/InterviewNotes/blob/master/pics//760a5d63-d96d-4dd9-bf9a-c3d126b2f401.jpg) -**5. Éè¼ÆÔ­Ôò** +**5. 设计原则** -**Ϊ½»»¥¶ÔÏóÖ®¼äµÄËÉñîºÏÉè¼Æ¶øÅ¬Á¦** µ±Á½¸ö¶ÔÏóÖ®¼äËÉñîºÏ£¬ËüÃÇÒÀÈ»¿ÉÒÔ½»»¥£¬µ«ÊDz»Ì«Çå³þ±Ë´ËµÄϸ½Ú¡£ÓÉÓÚËÉñîºÏµÄÁ½¸ö¶ÔÏóÖ®¼ä»¥ÏàÒÀÀµ³Ì¶ÈºÜµÍ£¬Òò´Ëϵͳ¾ßÓе¯ÐÔ£¬Äܹ»Ó¦¶Ô±ä»¯¡£ +**为交互对象之间的æ�¾è€¦å�ˆè®¾è®¡è€ŒåŠªåŠ›** 当两个对象之间æ�¾è€¦å�ˆï¼Œå®ƒä»¬ä¾�ç„¶å�¯ä»¥äº¤äº’,但是ä¸�太清楚彼此的细节。由于æ�¾è€¦å�ˆçš„两个对象之间互相ä¾�赖程度很低,因此系统具有弹性,能够应对å�˜åŒ–。 -**6. ʵÏÖ´úÂë** +**6. 实现代ç �** ```java public interface Subject { @@ -295,7 +296,7 @@ public class WeatherStation { } } ``` -Ö´Ðнá¹û +执行结果 ```html CurrentConditionsDisplay.update:0.0 0.0 0.0 StatisticsDisplay.update:0.0 0.0 0.0 @@ -303,39 +304,39 @@ CurrentConditionsDisplay.update:1.0 1.0 1.0 StatisticsDisplay.update:1.0 1.0 1.0 ``` -# µÚ 3 Õ װÊÎģʽ +# 第 3 ç«  装饰模å¼� -**1. ÎÊÌâÃèÊö** +**1. 问题æ��è¿°** -Éè¼Æ²»Í¬ÖÖÀàµÄÒûÁÏ£¬²¢ÇÒÿÖÖÒûÁÏ¿ÉÒÔ¶¯Ì¬Ìí¼ÓеIJÄÁÏ£¬±ÈÈç¿ÉÒÔÌí¼ÓÅ£ÄÌ¡£¼ÆËãÒ»ÖÖÒûÁϵļ۸ñ¡£ +设计ä¸�å�Œç§�类的饮料,并且æ¯�ç§�饮料å�¯ä»¥åЍæ€�添加新的æ��料,比如å�¯ä»¥æ·»åŠ ç‰›å¥¶ã€‚è®¡ç®—ä¸€ç§�饮料的价格。 -**2. ģʽ¶¨Òå** +**2. 模å¼�定义** -¶¯Ì¬µØ½«ÔðÈθ½¼Óµ½¶ÔÏóÉÏ¡£ÔÚÀ©Õ¹¹¦ÄÜÉÏ£¬×°ÊÎÕßÌṩÁ˱ȼ̳иüÓе¯ÐÔµÄÌæ´ú·½°¸¡£ +动æ€�地将责任附加到对象上。在扩展功能上,装饰者æ��供了比继承更有弹性的替代方案。 -ÏÂͼÖÐ DarkRoast ¶ÔÏó±» Mocha °ü¹ü£¬Mocha ¶ÔÏóÓÖ±» Whip °ü¹ü£¬²¢ÇÒËûÃǶ¼¼Ì³Ð×ÔÏàͬ¸¸À࣬¶¼ÓÐ cost() ·½·¨£¬µ«ÊÇÍâ²ã¶ÔÏóµÄ cost() ·½·¨ÊµÏÖµ÷ÓÃÁËÄÚ²ã¶ÔÏóµÄ cost() ·½·¨¡£Òò´Ë£¬Èç¹ûÒªÔÚ DarkRoast ÉÏÌí¼Ó Mocha£¬ÄÇôֻÐèÒªÓà Mocha °ü¹ü DarkRoast£¬Èç¹û»¹ÐèÒª Whip £¬¾ÍÓà Whip °ü¹ü Mocha£¬×îºóµ÷Óà cost() ·½·¨ÄܰÑÈýÖÖ¶ÔÏóµÄ¼Û¸ñ¶¼°üº¬½øÈ¥¡£ +下图中 DarkRoast 对象被 Mocha 包裹,Mocha 对象å�ˆè¢« Whip 包裹,并且他们都继承自相å�Œçˆ¶ç±»ï¼Œéƒ½æœ‰ cost() 方法,但是外层对象的 cost() 方法实现调用了内层对象的 cost() 方法。因此,如果è¦�在 DarkRoast 上添加 Mocha,那么å�ªéœ€è¦�用 Mocha 包裹 DarkRoast,如果还需è¦� Whip ,就用 Whip 包裹 Mocha,最å�Žè°ƒç”¨ cost() 方法能把三ç§�对象的价格都包å�«è¿›åŽ»ã€‚ -![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/41a4cb30-f393-4b3b-abe4-9941ccf8fa1f.jpg) +![](https://github.com/CyC2018/InterviewNotes/blob/master/pics//41a4cb30-f393-4b3b-abe4-9941ccf8fa1f.jpg) -**3. ģʽÀàͼ** +**3. 模å¼�类图** -×°ÊÎÕߺ;ßÌå×é¼þ¶¼¼Ì³Ð×Ô×é¼þÀàÐÍ£¬ÆäÖоßÌå×é¼þµÄ·½·¨ÊµÏÖ²»ÐèÒªÒÀÀµÓÚÆäËü¶ÔÏ󣬶ø×°ÊÎÕßÓµÓÐÒ»¸ö×é¼þÀàÐͶÔÏó£¬ÕâÑùËü¿ÉÒÔ×°ÊÎÆäËü×°ÊÎÕß»òÕß¾ßÌå×é¼þ¡£ËùνװÊΣ¬¾ÍÊǰÑÕâ¸ö×°ÊÎÕßÌ×ÔÚ±»×°ÊεĶÔÏóÖ®Í⣬´Ó¶ø¶¯Ì¬À©Õ¹±»×°ÊÎÕߵŦÄÜ¡£×°ÊÎÕߵķ½·¨ÓÐÒ»²¿·ÖÊÇ×Ô¼ºµÄ£¬ÕâÊôÓÚËüµÄ¹¦ÄÜ£¬È»ºóµ÷Óñ»×°ÊÎÕߵķ½·¨ÊµÏÖ£¬´Ó¶øÒ²±£ÁôÁ˱»×°ÊÎÕߵŦÄÜ¡£¿ÉÒÔ¿´µ½£¬¾ßÌå×é¼þÓ¦µ±ÊÇ×°Êβã´ÎµÄ×îµÍ²ã£¬ÒòΪֻÓоßÌå×é¼þÓÐÖ±½ÓʵÏÖ¶ø²»ÐèҪίÍиøÆäËü¶ÔÏóÈ¥´¦Àí¡£ +装饰者和具体组件都继承自组件类型,其中具体组件的方法实现ä¸�需è¦�ä¾�赖于其它对象,而装饰者拥有一个组件类型对象,这样它å�¯ä»¥è£…饰其它装饰者或者具体组件。所谓装饰,就是把这个装饰者套在被装饰的对象之外,从而动æ€�扩展被装饰者的功能。装饰者的方法有一部分是自己的,这属于它的功能,然å�Žè°ƒç”¨è¢«è£…饰者的方法实现,从而也ä¿�留了被装饰者的功能。å�¯ä»¥çœ‹åˆ°ï¼Œå…·ä½“组件应当是装饰层次的最低层,因为å�ªæœ‰å…·ä½“组件有直接实现而ä¸�需è¦�委托给其它对象去处ç�†ã€‚ -![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/3dc454fb-efd4-4eb8-afde-785b2182caeb.jpg) +![](https://github.com/CyC2018/InterviewNotes/blob/master/pics//3dc454fb-efd4-4eb8-afde-785b2182caeb.jpg) -**4. ÎÊÌâ½â¾ö·½°¸µÄÀàͼ** +**4. 问题解决方案的类图** -![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/9c997ac5-c8a7-44fe-bf45-2c10eb773e53.jpg) +![](https://github.com/CyC2018/InterviewNotes/blob/master/pics//9c997ac5-c8a7-44fe-bf45-2c10eb773e53.jpg) -**5. Éè¼ÆÔ­Ôò** +**5. 设计原则** -**ÀàÓ¦¸Ã¶ÔÀ©Õ¹¿ª·Å£¬¶ÔÐ޸Ĺرա£** Ò²¾ÍÊÇÌí¼Óй¦ÄÜʱ²»ÐèÒªÐ޸ĴúÂë¡£ÔÚ±¾ÕÂÎÊÌâÖиÃÔ­ÔòÌåÏÖÔÚ£¬ÔÚÒûÁÏÖÐÌí¼ÓеIJÄÁÏ£¬¶ø²»ÐèҪȥÐÞ¸ÄÒûÁϵĴúÂë¡£¹Û²ìÔòģʽҲ·ûºÏÕâ¸öÔ­Ôò¡£²»¿ÉÄÜËùÓÐÀà¶¼ÄÜʵÏÖÕâ¸öÔ­Ôò£¬Ó¦µ±°Ñ¸ÃÔ­ÔòÓ¦ÓÃÓÚÉè¼ÆÖÐ×îÓпÉÄܸıäµÄµØ·½¡£ +**类应该对扩展开放,对修改关闭。** 也就是添加新功能时ä¸�需è¦�修改代ç �。在本章问题中该原则体现在,在饮料中添加新的æ��料,而ä¸�需è¦�去修改饮料的代ç �。观察则模å¼�也符å�ˆè¿™ä¸ªåŽŸåˆ™ã€‚ä¸�å�¯èƒ½æ‰€æœ‰ç±»éƒ½èƒ½å®žçŽ°è¿™ä¸ªåŽŸåˆ™ï¼Œåº”å½“æŠŠè¯¥åŽŸåˆ™åº”ç”¨äºŽè®¾è®¡ä¸­æœ€æœ‰å�¯èƒ½æ”¹å�˜çš„地方。 -**6. Java I/O ÖеÄ×°ÊÎÕßģʽ** +**6. Java I/O 中的装饰者模å¼�** -![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/2a40042a-03c8-4556-ad1f-72d89f8c555c.jpg) +![](https://github.com/CyC2018/InterviewNotes/blob/master/pics//2a40042a-03c8-4556-ad1f-72d89f8c555c.jpg) -**7. ´úÂëʵÏÖ** +**7. 代ç �实现** ```java public interface Beverage { @@ -400,32 +401,32 @@ public class StartbuzzCoffee { } ``` -Êä³ö +输出 ```html 3.0 ``` -# µÚ 4 Õ ¹¤³§Ä£Ê½ +# 第 4 ç«  工厂模å¼� -## 4.1 ¼òµ¥¹¤³§ +## 4.1 简å�•工厂 -**1. ÎÊÌâÃèÊö** +**1. 问题æ��è¿°** -Óв»Í¬µÄ Pizza£¬¸ù¾Ý²»Í¬µÄÇé¿öÓò»Í¬µÄ×ÓÀàʵÀý»¯Ò»¸ö Pizza ¶ÔÏó¡£ +有ä¸�å�Œçš„ Pizza,根æ�®ä¸�å�Œçš„æƒ…况用ä¸�å�Œçš„å­�类实例化一个 Pizza 对象。 -**2. ¶¨Òå** +**2. 定义** -¼òµ¥¹¤³§²»ÊÇÉè¼ÆÄ£Ê½£¬¸üÏñÊÇÒ»ÖÖ±à³Ìϰ¹ß¡£ÔÚʵÀý»¯Ò»¸ö³¬ÀàµÄ¶ÔÏóʱ£¬¿ÉÒÔÓÃËüµÄËùÓÐ×ÓÀàÀ´½øÐÐʵÀý»¯£¬Òª¸ù¾Ý¾ßÌåÐèÇóÀ´¾ö¶¨Ê¹ÓÃÄĸö×ÓÀà¡£ÔÚÕâÖÖÇé¿öÏ£¬°ÑʵÀý»¯µÄ²Ù×÷·Åµ½¹¤³§À´ÖУ¬Èù¤³§ÀàÀ´¾ö¶¨Ó¦¸ÃÓÃÄĸö×ÓÀàÀ´ÊµÀý»¯¡£ÕâÑù×ö°Ñ¿Í»§¶ÔÏóºÍ¾ßÌå×ÓÀàµÄʵÏÖ½âñ¿Í»§¶ÔÏó²»ÔÙÐèÒªÖªµÀÓÐÄÄЩ×ÓÀàÒÔ¼°ÊµÀý»¯Äĸö×ÓÀà¡£ÒòΪ¿Í»§ÀàÍùÍùÓжà¸ö£¬Èç¹û²»Ê¹Óüòµ¥¹¤³§£¬ÄÇôËùÓеĿͻ§Àà¶¼ÒªÖªµÀËùÓÐ×ÓÀàµÄϸ½Ú£¬Ò»µ©×ÓÀà·¢Éú¸Ä±ä£¬ÀýÈçÔö¼Ó×ÓÀ࣬ÄÇôËùÓеĿͻ§Àà¶¼Òª·¢Éú¸Ä±ä¡£ +简å�•工厂ä¸�是设计模å¼�,更åƒ�是一ç§�编程习惯。在实例化一个超类的对象时,å�¯ä»¥ç”¨å®ƒçš„æ‰€æœ‰å­�ç±»æ�¥è¿›è¡Œå®žä¾‹åŒ–,è¦�æ ¹æ�®å…·ä½“需求æ�¥å†³å®šä½¿ç”¨å“ªä¸ªå­�类。在这ç§�情况下,把实例化的æ“�作放到工厂æ�¥ä¸­ï¼Œè®©å·¥åŽ‚ç±»æ�¥å†³å®šåº”该用哪个å­�ç±»æ�¥å®žä¾‹åŒ–。这样å�šæŠŠå®¢æˆ·å¯¹è±¡å’Œå…·ä½“å­�类的实现解耦,客户对象ä¸�å†�需è¦�知é�“有哪些å­�类以å�Šå®žä¾‹åŒ–哪个å­�类。因为客户类往往有多个,如果ä¸�使用简å�•工厂,那么所有的客户类都è¦�知é�“所有å­�类的细节,一旦å­�ç±»å�‘生改å�˜ï¼Œä¾‹å¦‚增加å­�类,那么所有的客户类都è¦�å�‘生改å�˜ã€‚ -![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/c470eb9b-fb05-45c5-8bb7-1057dc3c16de.jpg) +![](https://github.com/CyC2018/InterviewNotes/blob/master/pics//c470eb9b-fb05-45c5-8bb7-1057dc3c16de.jpg) -**3. ½â¾ö·½°¸Ààͼ** +**3. 解决方案类图** -![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/dc3e704c-7c57-42b8-93ea-ddd068665964.jpg) +![](https://github.com/CyC2018/InterviewNotes/blob/master/pics//dc3e704c-7c57-42b8-93ea-ddd068665964.jpg) -**4. ´úÂëʵÏÖ** +**4. 代ç �实现** ```java public interface Pizza { @@ -471,35 +472,35 @@ public class PizzaStore { } ``` -ÔËÐнá¹û +è¿�行结果 ```java CheesePizza ``` -## 4.2 ¹¤³§·½·¨Ä£Ê½ +## 4.2 工厂方法模å¼� -**1. ÎÊÌâÃèÊö** +**1. 问题æ��è¿°** -ÿ¸öµØÇøµÄ Pizza µêËäÈ»ÖÖÀàÏàͬ£¬µ«ÊǶ¼ÓÐ×Ô¼ºµÄ·ç棬ÐèÒªµ¥¶ÀÇø·Ö¡£ÀýÈ磬һ¸ö¿Í»§µãÁËŦԼµÄ cheese ÖÖÀàµÄ Pizza ºÍÔÚÖ¥¼Ó¸çµãµÄÏàͬÖÖÀàµÄ Pizza ÊDz»Í¬µÄ¡£ +æ¯�个地区的 Pizza 店虽然ç§�类相å�Œï¼Œä½†æ˜¯éƒ½æœ‰è‡ªå·±çš„风味,需è¦�å�•独区分。例如,一个客户点了纽约的 cheese ç§�类的 Pizza 和在èŠ�加哥点的相å�Œç§�类的 Pizza 是ä¸�å�Œçš„。 -**2. ģʽ¶¨Òå** +**2. 模å¼�定义** -¶¨ÒåÁËÒ»¸ö´´½¨¶ÔÏóµÄ½Ó¿Ú£¬µ«ÓÉ×ÓÀà¾ö¶¨ÒªÊµÀý»¯µÄÀàÊÇÄÄÒ»¸ö¡£¹¤³§·½·¨ÈÃÀà°ÑʵÀý»¯ÍƳٵ½×ÓÀà¡£ +定义了一个创建对象的接å�£ï¼Œä½†ç”±å­�类决定è¦�实例化的类是哪一个。工厂方法让类把实例化推迟到å­�类。 -**3. ģʽÀàͼ** +**3. 模å¼�类图** -ÔÚ¼òµ¥¹¤³§ÖУ¬´´½¨¶ÔÏóµÄÊÇÁíÒ»¸öÀ࣬¶øÔÚ¹¤³§·½·¨ÖУ¬ÊÇÓÉ×ÓÀàÀ´´´½¨¶ÔÏó¡£ÏÂͼÖУ¬Creator ÓÐÒ»¸ö anOperation() ·½·¨£¬Õâ¸ö·½·¨ÐèÒªÓõ½Ò»×é²úÆ·À࣬Õâ×é²úÆ·ÀàÓÉÿ¸ö×ÓÀàÀ´´´½¨¡£ +在简å�•工厂中,创建对象的是å�¦ä¸€ä¸ªç±»ï¼Œè€Œåœ¨å·¥åŽ‚æ–¹æ³•ä¸­ï¼Œæ˜¯ç”±å­�ç±»æ�¥åˆ›å»ºå¯¹è±¡ã€‚下图中,Creator 有一个 anOperation() 方法,这个方法需è¦�用到一组产å“�类,这组产å“�类由æ¯�个å­�ç±»æ�¥åˆ›å»ºã€‚ -¿ÉÒÔΪÿ¸ö×ÓÀà´´½¨µ¥¶ÀµÄ¼òµ¥¹¤³§À´´´½¨Ã¿Ò»¸ö²úÆ·À࣬µ«ÊǰѼòµ¥¹¤³§Öд´½¨¶ÔÏóµÄ´úÂë·Åµ½×ÓÀàÖÐÀ´¿ÉÒÔ¼õÉÙÀàµÄÊýÄ¿£¬ÒòΪ×ÓÀ಻ËãÊDzúÆ·À࣬Òò´ËÍêÈ«¿ÉÒÔÕâô×ö¡£ +å�¯ä»¥ä¸ºæ¯�个å­�类创建å�•独的简å�•工厂æ�¥åˆ›å»ºæ¯�一个产å“�类,但是把简å�•工厂中创建对象的代ç �放到å­�类中æ�¥å�¯ä»¥å‡�少类的数目,因为å­�ç±»ä¸�算是产å“�类,因此完全å�¯ä»¥è¿™ä¹ˆå�šã€‚ -![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/903093ec-acc8-4f9b-bf2c-b990b9a5390c.jpg) +![](https://github.com/CyC2018/InterviewNotes/blob/master/pics//903093ec-acc8-4f9b-bf2c-b990b9a5390c.jpg) -**4. ½â¾ö·½°¸Ààͼ** +**4. 解决方案类图** -![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/664f8901-5dc7-4644-a072-dad88cc5133a.jpg) +![](https://github.com/CyC2018/InterviewNotes/blob/master/pics//664f8901-5dc7-4644-a072-dad88cc5133a.jpg) -**5. ´úÂëʵÏÖ** +**5. 代ç �实现** ```java public interface Pizza { @@ -588,36 +589,36 @@ public class PizzaTestDrive { } ``` -ÔËÐнá¹û +è¿�行结果 ```html NYStyleCheesePizza is making.. ChicagoStyleCheesePizza is making.. ``` -## 4.3 ³éÏ󹤳§Ä£Ê½ +## 4.3 抽象工厂模å¼� -**1. Éè¼ÆÔ­Ôò** +**1. 设计原则** -**ÒÀÀµµ¹ÖÃÔ­Ôò**£ºÒªÒÀÀµ³éÏ󣬲»ÒªÒÀÀµ¾ßÌåÀà¡£ÌýÆðÀ´ÏñÊÇÕë¶Ô½Ó¿Ú±à³Ì£¬²»Õë¶ÔʵÏÖ±à³Ì£¬µ«ÊÇÕâ¸öÔ­Ôò˵Ã÷ÁË£º²»ÄÜÈø߲ã×é¼þÒÀÀµµ×²ã×é¼þ£¬¶øÇÒ£¬²»¹Ü¸ß²ã»òµ×²ã×é¼þ£¬Á½Õß¶¼Ó¦¸ÃÒÀÀµÓÚ³éÏó¡£ÀýÈ磬ÏÂͼÖÐ PizzaStore ÊôÓڸ߲ã×é¼þ£¬ËüÒÀÀµµÄÊÇ Pizza µÄ³éÏóÀ࣬ÕâÑù¾Í¿ÉÒÔ²»ÓùØÐÄ Pizza µÄ¾ßÌåʵÏÖϸ½Ú¡£ +**ä¾�赖倒置原则**:è¦�ä¾�赖抽象,ä¸�è¦�ä¾�赖具体类。å�¬èµ·æ�¥åƒ�是针对接å�£ç¼–程,ä¸�针对实现编程,但是这个原则说明了:ä¸�能让高层组件ä¾�赖底层组件,而且,ä¸�管高层或底层组件,两者都应该ä¾�赖于抽象。例如,下图中 PizzaStore 属于高层组件,它ä¾�赖的是 Pizza 的抽象类,这样就å�¯ä»¥ä¸�用关心 Pizza 的具体实现细节。 -![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/ddf72ca9-c0be-49d7-ab81-57a99a974c8e.jpg) +![](https://github.com/CyC2018/InterviewNotes/blob/master/pics//ddf72ca9-c0be-49d7-ab81-57a99a974c8e.jpg) -**2. ģʽ¶¨Òå** +**2. 模å¼�定义** -Ìṩһ¸ö½Ó¿Ú£¬ÓÃÓÚ´´½¨Ïà¹Ø»òÒÀÀµ¶ÔÏóµÄ¼Ò×壬¶ø²»ÐèÒªÃ÷È·Ö¸¶¨¾ßÌåÀà¡£ +æ��供一个接å�£ï¼Œç”¨äºŽåˆ›å»ºç›¸å…³æˆ–ä¾�赖对象的家æ—�,而ä¸�需è¦�明确指定具体类。 -**3. ģʽÀàͼ** +**3. 模å¼�类图** -³éÏ󹤳§Ä£Ê½´´½¨µÄÊǶÔÏó¼Ò×壬Ҳ¾ÍÊǺܶà¶ÔÏó¶ø²»ÊÇÒ»¸ö¶ÔÏ󣬲¢ÇÒÕâЩ¶ÔÏóÊÇÏà¹ØµÄ£¬Ò²¾ÍÊÇ˵±ØÐëÒ»Æð´´½¨³öÀ´¡£¶ø¹¤³§Ä£Ê½Ö»ÊÇÓÃÓÚ´´½¨Ò»¸ö¶ÔÏó£¬ÕâºÍ³éÏ󹤳§Ä£Ê½Óкܴó²»Í¬¡£²¢ÇÒ£¬³éÏ󹤳§Ä£Ê½Ò²Óõ½Á˹¤³§Ä£Ê½À´´´½¨µ¥Ò»¶ÔÏó£¬ÔÚÀàͼ×󲿣¬AbstractFactory ÖÐµÄ CreateProductA ºÍ CreateProductB ·½·¨¶¼ÊÇÈÃ×ÓÀàÀ´ÊµÏÖ£¬ÕâÁ½¸ö·½·¨µ¥¶ÀÀ´¿´¾ÍÊÇÔÚ´´½¨Ò»¸ö¶ÔÏó£¬Õâ·ûºÏ¹¤³§Ä£Ê½µÄ¶¨Òå¡£ÖÁÓÚ´´½¨¶ÔÏóµÄ¼Ò×åÕâÒ»¸ÅÄîÊÇÔÚ Client ÌåÏÖ£¬Client Ҫͨ¹ý AbstractFactory ͬʱµ÷ÓÃÁ½¸ö·½·¨À´´´½¨³öÁ½¸ö¶ÔÏó£¬ÔÚÕâÀïÕâÁ½¸ö¶ÔÏó¾ÍÓкܴóµÄÏà¹ØÐÔ£¬Client ÐèÒªÕâÁ½¸ö¶ÔÏóµÄЭ×÷²ÅÄÜÍê³ÉÈÎÎñ¡£´Ó¸ß²ã´ÎÀ´¿´£¬³éÏ󹤳§Ê¹ÓÃÁË×éºÏ£¬¼´ Cilent ×éºÏÁË AbstractFactory £¬¶ø¹¤³§Ä£Ê½Ê¹ÓÃÁ˼̳С£ +抽象工厂模å¼�创建的是对象家æ—�,也就是很多对象而ä¸�是一个对象,并且这些对象是相关的,也就是说必须一起创建出æ�¥ã€‚而工厂模å¼�å�ªæ˜¯ç”¨äºŽåˆ›å»ºä¸€ä¸ªå¯¹è±¡ï¼Œè¿™å’ŒæŠ½è±¡å·¥åŽ‚æ¨¡å¼�有很大ä¸�å�Œã€‚并且,抽象工厂模å¼�也用到了工厂模å¼�æ�¥åˆ›å»ºå�•一对象,在类图左部,AbstractFactory 中的 CreateProductA å’Œ CreateProductB 方法都是让å­�ç±»æ�¥å®žçŽ°ï¼Œè¿™ä¸¤ä¸ªæ–¹æ³•å�•独æ�¥çœ‹å°±æ˜¯åœ¨åˆ›å»ºä¸€ä¸ªå¯¹è±¡ï¼Œè¿™ç¬¦å�ˆå·¥åŽ‚æ¨¡å¼�的定义。至于创建对象的家æ—�这一概念是在 Client 体现,Client è¦�通过 AbstractFactory å�Œæ—¶è°ƒç”¨ä¸¤ä¸ªæ–¹æ³•æ�¥åˆ›å»ºå‡ºä¸¤ä¸ªå¯¹è±¡ï¼Œåœ¨è¿™é‡Œè¿™ä¸¤ä¸ªå¯¹è±¡å°±æœ‰å¾ˆå¤§çš„相关性,Client 需è¦�这两个对象的å��作æ‰�能完æˆ�任务。从高层次æ�¥çœ‹ï¼ŒæŠ½è±¡å·¥åŽ‚ä½¿ç”¨äº†ç»„å�ˆï¼Œå�³ Cilent 组å�ˆäº† AbstractFactory ,而工厂模å¼�使用了继承。 -![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/d301774f-e0d2-41f3-95f4-bfe39859b52e.jpg) +![](https://github.com/CyC2018/InterviewNotes/blob/master/pics//d301774f-e0d2-41f3-95f4-bfe39859b52e.jpg) -**4. ½â¾ö·½°¸Ààͼ** +**4. 解决方案类图** -![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/8785dabd-1285-4bd0-b3aa-b05cc060a24a.jpg) +![](https://github.com/CyC2018/InterviewNotes/blob/master/pics//8785dabd-1285-4bd0-b3aa-b05cc060a24a.jpg) -**5. ´úÂëʵÏÖ** +**5. 代ç �实现** ```java public interface Dough { @@ -719,28 +720,28 @@ public class NYPizzaStoreTestDrive { } ``` -ÔËÐнá¹û +è¿�行结果 ```html ThickCrustDough MarinaraSauce ``` -# µÚ 5 Õ µ¥¼þģʽ +# 第 5 ç«  å�•件模å¼� -**1. ģʽ¶¨Òå** +**1. 模å¼�定义** -È·±£Ò»¸öÀàÖ»ÓÐÒ»¸öʵÀý£¬²¢ÌṩÁËÒ»¸öÈ«¾Ö·ÃÎʵ㡣 +ç¡®ä¿�一个类å�ªæœ‰ä¸€ä¸ªå®žä¾‹ï¼Œå¹¶æ��供了一个全局访问点。 -**2. ģʽÀàͼ** +**2. 模å¼�类图** -µ¥¼þģʽµÄ Java ʵÏÖÓÃÒ»¸ö˽Óй¹ÔìÆ÷¡¢Ò»¸ö˽Óо²Ì¬±äÁ¿ÒÔ¼°Ò»¸ö¹«Óо²Ì¬º¯Êý£¬¸Ãº¯Êý·µ»ØË½ÓбäÁ¿£¬Ê¹µÃËùÓÐͨ¹ý¸Ãº¯Êý»ñÈ¡µÄ¶ÔÏó¶¼Ö¸ÏòÕâ¸öΨһµÄ˽Óо²Ì¬±äÁ¿¡£ +å�•件模å¼�çš„ Java 实现用一个ç§�有构造器ã€�一个ç§�有é�™æ€�å�˜é‡�以å�Šä¸€ä¸ªå…¬æœ‰é�™æ€�函数,该函数返回ç§�有å�˜é‡�,使得所有通过该函数获å�–的对象都指å�‘这个唯一的ç§�有é�™æ€�å�˜é‡�。 -![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/59aff6c1-8bc5-48e4-9e9c-082baeb2f274.jpg) +![](https://github.com/CyC2018/InterviewNotes/blob/master/pics//59aff6c1-8bc5-48e4-9e9c-082baeb2f274.jpg) -**3. ¾­µäʵÏÖ** +**3. ç»�典实现** -ÒÔÏÂʵÏÖÖУ¬Ë½Óо²Ì¬±äÁ¿±»ÑÓ³Ù»¯ÊµÀý»¯£¬ÕâÑù×öµÄºÃ´¦ÊÇ£¬Èç¹ûûÓÐÓõ½¸ÃÀ࣬ÄÇô¾Í²»»á´´½¨¸Ã˽Óо²Ì¬±äÁ¿£¬´Ó¶ø½ÚÔ¼×ÊÔ´¡£Õâ¸öʵÏÖÔÚ¶àÏ̻߳·¾³ÏÂÊDz»°²È«µÄ£¬ÒòΪ¶à¸öÏß³ÌÄܹ»Í¬Ê±½øÈë if(uniqueInstance == null) ÄÚµÄÓï¾ä¿é£¬ÄÇô¾Í»á¶à´ÎʵÀý»¯ uniqueInstance ˽Óо²Ì¬±äÁ¿¡£ +以下实现中,ç§�有é�™æ€�å�˜é‡�被延迟化实例化,这样å�šçš„好处是,如果没有用到该类,那么就ä¸�会创建该ç§�有é�™æ€�å�˜é‡�,从而节约资æº�。这个实现在多线程环境下是ä¸�安全的,因为多个线程能够å�Œæ—¶è¿›å…¥ if(uniqueInstance == null) 内的语å�¥å�—,那么就会多次实例化 uniqueInstance ç§�有é�™æ€�å�˜é‡�。 ```java public class Singleton { @@ -759,9 +760,9 @@ public class Singleton { } ``` -**4. Ï̲߳»°²È«ÎÊÌâµÄ½â¾ö·½°¸Ò»** +**4. 线程ä¸�安全问题的解决方案一** -Ö»ÐèÒª¶Ô getUniqueInstance() ·½·¨¼ÓËø£¬¾ÍÄÜÈø÷½·¨Ò»´ÎÖ»ÄÜÒ»¸öÏ̷߳ÃÎÊ£¬´Ó¶ø±ÜÃâÁË¶Ô uniqueInstance ±äÁ¿½øÐжà´ÎʵÀý»¯µÄÎÊÌâ¡£µ«ÊÇÕâÑùÓÐÒ»¸öÎÊÌâÊÇÒ»´ÎÖ»ÄÜÒ»¸öÏ߳̽øÈ룬ÐÔÄÜÉÏ»áÓÐÒ»¶¨µÄÀË·Ñ¡£ +å�ªéœ€è¦�对 getUniqueInstance() 方法加é”�,就能让该方法一次å�ªèƒ½ä¸€ä¸ªçº¿ç¨‹è®¿é—®ï¼Œä»Žè€Œé�¿å…�了对 uniqueInstance å�˜é‡�进行多次实例化的问题。但是这样有一个问题是一次å�ªèƒ½ä¸€ä¸ªçº¿ç¨‹è¿›å…¥ï¼Œæ€§èƒ½ä¸Šä¼šæœ‰ä¸€å®šçš„æµªè´¹ã€‚ ```java public static synchronized Singleton getUniqueInstance() { @@ -772,17 +773,17 @@ public class Singleton { } ``` -**5. Ï̲߳»°²È«ÎÊÌâµÄ½â¾ö·½°¸¶þ** +**5. 线程ä¸�安全问题的解决方案二** -²»ÓÃÑÓ³ÙʵÀý»¯£¬²ÉÓÃÖ±½ÓʵÀý»¯¡£ +ä¸�用延迟实例化,采用直接实例化。 ```java private static Singleton uniqueInstance = new Singleton(); ``` -**6. Ï̲߳»°²È«ÎÊÌâµÄ½â¾ö·½°¸Èý** +**6. 线程ä¸�安全问题的解决方案三** -¿¼ÂǵÚÒ»¸ö½â¾ö·½°¸£¬ËüÊÇÖ±½Ó¶Ô getUniqueInstance() ·½·¨½øÐмÓËø£¬¶øÊµ¼ÊÉÏÖ»ÐèÒª¶Ô uniqueInstance = new Singleton(); ÕâÌõÓï¾ä¼ÓËø¼´¿É¡£Ê¹ÓÃÁ½¸öÌõ¼þÓï¾äÀ´ÅÐ¶Ï uniqueInstance ÊÇ·ñÒѾ­ÊµÀý»¯£¬Èç¹ûûÓÐʵÀý»¯²ÅÐèÒª¼ÓËø¡£ +考虑第一个解决方案,它是直接对 getUniqueInstance() 方法进行加é”�,而实际上å�ªéœ€è¦�对 uniqueInstance = new Singleton(); è¿™æ�¡è¯­å�¥åŠ é”�å�³å�¯ã€‚使用两个æ�¡ä»¶è¯­å�¥æ�¥åˆ¤æ–­ uniqueInstance 是å�¦å·²ç»�实例化,如果没有实例化æ‰�需è¦�加é”�。 ```java public class Singleton { @@ -805,31 +806,31 @@ public class Singleton { } ``` -# µÚ 6 Õ ÃüÁîģʽ +# 第 6 ç«  命令模å¼� -**1. ÎÊÌâÃèÊö** +**1. 问题æ��è¿°** -Éè¼ÆÒ»¸öÒ£¿ØÆ÷£¬ËüÓкܶఴť£¬Ã¿¸ö°´Å¥¿ÉÒÔ·¢ÆðÒ»¸öÃüÁÈÃÒ»¸ö¼ÒµçÍê³ÉÏàÓ¦²Ù×÷¡£Óзdz£¶àµÄ¼Òµç£¬²¢ÇÒÒ²»áÔö¼Ó¼Òµç¡£ +设计一个é�¥æŽ§å™¨ï¼Œå®ƒæœ‰å¾ˆå¤šæŒ‰é’®ï¼Œæ¯�个按钮å�¯ä»¥å�‘起一个命令,让一个家电完æˆ�相应æ“�作。有é�žå¸¸å¤šçš„家电,并且也会增加家电。 -![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/7b8f0d8e-a4fa-4c9d-b9a0-3e6a11cb3e33.jpg) +![](https://github.com/CyC2018/InterviewNotes/blob/master/pics//7b8f0d8e-a4fa-4c9d-b9a0-3e6a11cb3e33.jpg) -![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/c3ca36b2-8459-4cf1-98b0-cc95a0e94f20.jpg) +![](https://github.com/CyC2018/InterviewNotes/blob/master/pics//c3ca36b2-8459-4cf1-98b0-cc95a0e94f20.jpg) -**2. ģʽ¶¨Òå** +**2. 模å¼�定义** -½«ÃüÁî·â×°³É¶ÔÏó£¬ÒÔ±ãʹÓò»Í¬µÄÃüÁîÀ´²ÎÊý»¯ÆäËü¶ÔÏó¡£ +将命令å°�装æˆ�对象,以便使用ä¸�å�Œçš„命令æ�¥å�‚数化其它对象。 -**3. ģʽÀàͼ** +**3. 模å¼�类图** -![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/1e09d75f-6268-4425-acf8-8ecd1b4a0ef3.jpg) +![](https://github.com/CyC2018/InterviewNotes/blob/master/pics//1e09d75f-6268-4425-acf8-8ecd1b4a0ef3.jpg) -**4. ½â¾ö·½°¸Ààͼ** +**4. 解决方案类图** -Invoker ÊÇÒ£¿ØÆ÷£¬Ëü¿ÉÒÔÉèÖÃÃüÁ²¢ÇÒµ÷ÓÃÃüÁî¶ÔÏóµÄ execute() ·½·¨¡£Receiver ÊÇµçµÆ£¬ÊÇÃüÁîÕæÕýµÄÖ´ÐÐÕß¡£ConcreteCommand Àà×éºÏÁËÒ»¸ö Receiver ¶ÔÏó£¬ÃüÁîµÄÖ´ÐÐίÍиø Receiver ¶ÔÏóÀ´´¦Àí£¬Ò²¾ÍÊÇ LightOnCommand ÃüÁîµÄ excute ·½·¨Î¯Íиø Light ¶ÔÏóÀ´´¦Àí£¬Light ¶ÔÏóͨ¹ýµ÷Óà on() ·½·¨À´Íê³É²Ù×÷¡£Invoker ²»ÊÇ Client ¶ÔÏó£¬ÊÇÒòΪÃüÁîµÄ´´½¨²»ÊÇÔÚ Invoker ÖÐÍê³ÉµÄ£¬Òò´ËÐèÒª¶îÍâµÄ Client ¶ÔÏóÀ´´¦ÀíÕâЩ²Ù×÷¡£ +Invoker 是é�¥æŽ§å™¨ï¼Œå®ƒå�¯ä»¥è®¾ç½®å‘½ä»¤ï¼Œå¹¶ä¸”调用命令对象的 execute() 方法。Receiver 是电ç�¯ï¼Œæ˜¯å‘½ä»¤çœŸæ­£çš„æ‰§è¡Œè€…。ConcreteCommand 类组å�ˆäº†ä¸€ä¸ª Receiver 对象,命令的执行委托给 Receiver 对象æ�¥å¤„ç�†ï¼Œä¹Ÿå°±æ˜¯ LightOnCommand 命令的 excute 方法委托给 Light 对象æ�¥å¤„ç�†ï¼ŒLight 对象通过调用 on() 方法æ�¥å®Œæˆ�æ“�作。Invoker ä¸�是 Client 对象,是因为命令的创建ä¸�是在 Invoker 中完æˆ�的,因此需è¦�é¢�外的 Client 对象æ�¥å¤„ç�†è¿™äº›æ“�作。 -![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/5ef94f62-98ce-464d-a646-842d9c72c8b8.jpg) +![](https://github.com/CyC2018/InterviewNotes/blob/master/pics//5ef94f62-98ce-464d-a646-842d9c72c8b8.jpg) -**5. ´úÂëʵÏÖ** +**5. 代ç �实现** ```java public interface Command { @@ -864,7 +865,7 @@ public class LightOnCommand implements Command{ ``` ```java /** - * Ò£¿ØÆ÷Àà + * é�¥æŽ§å™¨ç±» */ public class SimpleRemoteControl { Command slot; @@ -895,39 +896,39 @@ public class RemoteLoader { } ``` -Êä³ö +输出 ```html Light is on! ``` -# µÚ 7 Õ ÊÊÅäÆ÷ģʽÓëÍâ¹Ûģʽ +# 第 7 ç«  适é…�器模å¼�与外观模å¼� -## 7.1 ÊÊÅäÆ÷ģʽ +## 7.1 适é…�器模å¼� -**1. ģʽ¶¨Òå** +**1. 模å¼�定义** -½«Ò»¸öÀàµÄ½Ó¿Ú£¬×ª»»Îª¿Í»§ÆÚÍûµÄÁíÒ»¸ö½Ó¿Ú¡£ÊÊÅäÆ÷ÈÃÔ­±¾²»¼æÈݵÄÀà¿ÉÒÔºÏ×÷Î޼䡣 +将一个类的接å�£ï¼Œè½¬æ�¢ä¸ºå®¢æˆ·æœŸæœ›çš„å�¦ä¸€ä¸ªæŽ¥å�£ã€‚适é…�器让原本ä¸�兼容的类å�¯ä»¥å�ˆä½œæ— é—´ã€‚ -![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/8e8ba824-7a9e-4934-a212-e6a41dcc1602.jpg) +![](https://github.com/CyC2018/InterviewNotes/blob/master/pics//8e8ba824-7a9e-4934-a212-e6a41dcc1602.jpg) -**2. ģʽÀàͼ** +**2. 模å¼�类图** -ÓÐÁ½ÖÖÊÊÅäÆ÷ģʽµÄʵÏÖ£¬Ò»ÖÖÊǶÔÏó·½Ê½£¬Ò»ÖÖÊÇÀ෽ʽ¡£¶ÔÏó·½Ê½ÊÇͨ¹ý×éºÏµÄ·½·¨£¬ÈÃÊÊÅäÆ÷ÀࣨAdapter£©ÓµÓÐÒ»¸ö´ýÊÊÅäµÄ¶ÔÏó£¨Adaptee£©£¬´Ó¶ø°ÑÏàÓ¦µÄ´¦ÀíίÍиø´ýÊÊÅäµÄ¶ÔÏó¡£À෽ʽÓõ½¶àÖØ¼Ì³Ð£¬Adapter ¿ÉÒÔ¿´³É Target ºÍ Adaptee ÀàÐÍ£¬ÏȰÑËüµ±³É Adaptee ÀàÐÍÈ»ºóʵÀý»¯Ò»¸ö Adapter ¶ÔÏó£¬ÔÙ°ÑËüµ±³É Target ÀàÐ͵ģ¬ÕâÑù Client ¾Í¿ÉÒÔ°ÑÕâ¸ö¶ÔÏóµ±³É Target µÄ¶ÔÏóÀ´´¦Àí¡£ +有两ç§�适é…�器模å¼�的实现,一ç§�是对象方å¼�,一ç§�是类方å¼�。对象方å¼�是通过组å�ˆçš„æ–¹æ³•,让适é…�器类(Adapter)拥有一个待适é…�的对象(Adaptee),从而把相应的处ç�†å§”托给待适é…�的对象。类方å¼�用到多é‡�继承,Adapter å�¯ä»¥çœ‹æˆ� Target å’Œ Adaptee 类型,先把它当æˆ� Adaptee 类型然å�Žå®žä¾‹åŒ–一个 Adapter 对象,å†�把它当æˆ� Target 类型的,这样 Client å°±å�¯ä»¥æŠŠè¿™ä¸ªå¯¹è±¡å½“æˆ� Target 的对象æ�¥å¤„ç�†ã€‚ -![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/253bd869-ea48-4092-9aed-6906ccb2f3b0.jpg) +![](https://github.com/CyC2018/InterviewNotes/blob/master/pics//253bd869-ea48-4092-9aed-6906ccb2f3b0.jpg) -![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/a797959a-0ed5-475b-8d97-df157c672019.jpg) +![](https://github.com/CyC2018/InterviewNotes/blob/master/pics//a797959a-0ed5-475b-8d97-df157c672019.jpg) -**3. ÎÊÌâÃèÊö** +**3. 问题æ��è¿°** -ÈÃѼ×Ó£¨Duck£©ÊÊÅä»ð¼¦£¨Turkey£©£¬Duck ÓÐ quack() ·½·¨£¬¶ø Turkey Ö»ÓÐ gobble() ·½·¨¡£Ò²¾ÍÊÇÒªÈà Turkey Ò²ÓÐ Duck µÄ quack() ·½·¨¡£ +让鸭å­�(Duck)适é…�ç�«é¸¡ï¼ˆTurkey),Duck 有 quack() 方法,而 Turkey å�ªæœ‰ gobble() 方法。也就是è¦�让 Turkey 也有 Duck çš„ quack() 方法。 -**4. ½â¾ö·½°¸Ààͼ** +**4. 解决方案类图** -![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/1a511c76-bb6b-40ab-b8aa-39eeb619d673.jpg) +![](https://github.com/CyC2018/InterviewNotes/blob/master/pics//1a511c76-bb6b-40ab-b8aa-39eeb619d673.jpg) -**5. ´úÂëʵÏÖ** +**5. 代ç �实现** ```java public interface Duck { @@ -984,69 +985,69 @@ public class DuckTestDrive { } ``` -ÔËÐнá¹û +è¿�行结果 ```html gobble! fly! ``` -## 7.2 Íâ¹Ûģʽ +## 7.2 外观模å¼� -**1. ģʽ¶¨Òå** +**1. 模å¼�定义** -ÌṩÁËÒ»¸öͳһµÄ½Ó¿Ú£¬ÓÃÀ´·ÃÎÊ×ÓϵͳÖеÄһȺ½Ó¿Ú¡£Íâ¹Û¶¨ÒåÁËÒ»¸ö¸ß²ã½Ó¿Ú£¬ÈÃ×Óϵͳ¸üÈÝÒ×ʹÓᣠ+æ��供了一个统一的接å�£ï¼Œç”¨æ�¥è®¿é—®å­�系统中的一群接å�£ã€‚外观定义了一个高层接å�£ï¼Œè®©å­�系统更容易使用。 -**2. ģʽÀàͼ** +**2. 模å¼�类图** -![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/78f2314e-2643-41df-8f3d-b7e28294094b.jpg) +![](https://github.com/CyC2018/InterviewNotes/blob/master/pics//78f2314e-2643-41df-8f3d-b7e28294094b.jpg) -**3. ÎÊÌâÃèÊö** +**3. 问题æ��è¿°** -¼ÒÍ¥Ó°ÔºÖÐÓÐÖÚ¶àµçÆ÷£¬µ±Òª½øÐйۿ´µçӰʱÐèÒª¶ÔºÜ¶àµçÆ÷½øÐвÙ×÷¡£ÒªÇó¼ò»¯ÕâЩ²Ù×÷£¬Ê¹µÃ¼ÒÍ¥Ó°ÔºÀàÖ»Ìṩһ¸ö¼ò»¯µÄ½Ó¿Ú£¬ÀýÈçÌṩһ¸ö¿´µçÓ°µÄ½Ó¿Ú¶ø²»ÓþßÌå²Ù×÷ÖÚ¶àµçÆ÷¡£ +家庭影院中有众多电器,当è¦�进行观看电影时需è¦�对很多电器进行æ“�作。è¦�求简化这些æ“�作,使得家庭影院类å�ªæ��供一个简化的接å�£ï¼Œä¾‹å¦‚æ��供一个看电影的接å�£è€Œä¸�用具体æ“�作众多电器。 -![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/106f5585-b2e7-4718-be5d-3b322d1ef42a.jpg) +![](https://github.com/CyC2018/InterviewNotes/blob/master/pics//106f5585-b2e7-4718-be5d-3b322d1ef42a.jpg) -**4. ½â¾ö·½°¸Ààͼ** +**4. 解决方案类图** -![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/25387681-89f8-4365-a2fa-83b86449ee84.jpg) +![](https://github.com/CyC2018/InterviewNotes/blob/master/pics//25387681-89f8-4365-a2fa-83b86449ee84.jpg) -**5. Éè¼ÆÔ­Ôò** +**5. 设计原则** -**×îÉÙ֪ʶԭÔò**£ºÖ»ºÍÄãµÄÃÜÓÑ̸»°¡£Ò²¾ÍÊÇÓ¦µ±Ê¹µÃ¿Í»§¶ÔÏóËùÐèÒª½»»¥µÄ¶ÔÏóÓ¦µ±¾¡¿ÉÄÜÉÙ¡£ +**最少知识原则**:å�ªå’Œä½ çš„密å�‹è°ˆè¯�。也就是应当使得客户对象所需è¦�交互的对象应当尽å�¯èƒ½å°‘。 -# µÚ 8 Õ ģ°å·½·¨Ä£Ê½ +# 第 8 ç«  模æ�¿æ–¹æ³•模å¼� -**1. ģʽ¶¨Òå** +**1. 模å¼�定义** -ÔÚÒ»¸ö·½·¨Öж¨ÒåÒ»¸öËã·¨µÄ¹Ç¼Ü£¬¶ø½«Ò»Ð©²½ÖèÑÓ³Ùµ½×ÓÀàÖС£ +在一个方法中定义一个算法的骨架,而将一些步骤延迟到å­�类中。 -Ä£°å·½·¨Ê¹µÃ×ÓÀà¿ÉÒÔÔÚ²»¸Ä±äËã·¨½á¹¹µÄÇé¿öÏ£¬ÖØÐ¶¨ÒåËã·¨ÖеÄijЩ²½Öè¡£ +模æ�¿æ–¹æ³•使得å­�ç±»å�¯ä»¥åœ¨ä¸�改å�˜ç®—法结构的情况下,é‡�新定义算法中的æŸ�些步骤。 -**2. ģʽÀàͼ** +**2. 模å¼�类图** -Ä£°å·½·¨ templateMethod() ¶¨ÒåÁËËã·¨µÄ¹Ç¼Ü£¬È·¶¨ÁË primitiveOperation1() ºÍ primitiveOperation2() ·½·¨Ö´ÐеÄ˳Ðò£¬¶ø primitiveOperation1() ºÍ primitiveOperation2() ÈÃ×ÓÀàÈ¥¾ßÌåʵÏÖ¡£ +模æ�¿æ–¹æ³• templateMethod() 定义了算法的骨架,确定了 primitiveOperation1() å’Œ primitiveOperation2() 方法执行的顺åº�,而 primitiveOperation1() å’Œ primitiveOperation2() 让å­�类去具体实现。 -![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/ed62f400-192c-4185-899b-187958201f0c.jpg) +![](https://github.com/CyC2018/InterviewNotes/blob/master/pics//ed62f400-192c-4185-899b-187958201f0c.jpg) -**3. ÎÊÌâÃèÊö** +**3. 问题æ��è¿°** -³å¿§·ÈºÍ³å²è¶¼ÓÐÀàËÆµÄÁ÷³Ì£¬µ«ÊÇijЩ²½Öè»áÓе㲻һÑù¡£ +冲咖啡和冲茶都有类似的æµ�程,但是æŸ�些步骤会有点ä¸�一样。 -![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/d8f873fc-00bc-41ee-a87c-c1b4c0172844.png) +![](https://github.com/CyC2018/InterviewNotes/blob/master/pics//d8f873fc-00bc-41ee-a87c-c1b4c0172844.png) -**4. ½â¾ö·½°¸Ààͼ** +**4. 解决方案类图** -![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/aa20c123-b6b5-432a-83d3-45dc39172192.jpg) +![](https://github.com/CyC2018/InterviewNotes/blob/master/pics//aa20c123-b6b5-432a-83d3-45dc39172192.jpg) -**5. Éè¼ÆÔ­Ôò** +**5. 设计原则** -**ºÃÀ³ÎëÔ­Ôò**£º±ðµ÷Ó㨴òµç»°¸ø£©ÎÒÃÇ£¬ÎÒÃÇ»áµ÷Ó㨴òµç»°¸ø£©Äã¡£ÕâÒ»Ô­Ôò¿ÉÒÔ·ÀÖ¹ÒÀÀµ¸¯°Ü£¬¼´·ÀÖ¹¸ß²ã×é¼þÒÀÀµµ×²ã×é¼þ£¬µ×²ã×é¼þÓÖÒÀÀµ¸ß²ã×é¼þ¡£¸ÃÔ­ÔòÔÚÄ£°å·½·¨µÄÌåÏÖΪ£¬Ö»Óи¸Àà»áµ÷ÓÃ×ÓÀ࣬×ÓÀ಻»áµ÷Óø¸Àà¡£ +**好莱å�žåŽŸåˆ™**:别调用(打电è¯�给)我们,我们会调用(打电è¯�给)你。这一原则å�¯ä»¥é˜²æ­¢ä¾�èµ–è…�败,å�³é˜²æ­¢é«˜å±‚组件ä¾�赖底层组件,底层组件å�ˆä¾�赖高层组件。该原则在模æ�¿æ–¹æ³•的体现为,å�ªæœ‰çˆ¶ç±»ä¼šè°ƒç”¨å­�类,å­�ç±»ä¸�会调用父类。 -**6. ¹³×Ó** +**6. é’©å­�** -¹³×Ó£¨hock£©£ºÄ³Ð©²½ÖèÔÚ²»Í¬ÊµÏÖÖпÉÓпÉÎÞ£¬¿ÉÒÔÏȶ¨ÒåÒ»¸öʲô¶¼²»×öµÄ·½·¨£¬°ÑËü¼Óµ½Ä£°å·½·¨ templteMethod() ÖУ¬Èç¹û×ÓÀàÐèÒªËü¾Í¸²¸ÇĬÈÏʵÏÖ²¢¼ÓÉÏ×Ô¼ºµÄʵÏÖ¡£ +é’©å­�(hock):æŸ�些步骤在ä¸�å�Œå®žçް䏭å�¯æœ‰å�¯æ— ï¼Œå�¯ä»¥å…ˆå®šä¹‰ä¸€ä¸ªä»€ä¹ˆéƒ½ä¸�å�šçš„æ–¹æ³•,把它加到模æ�¿æ–¹æ³• templteMethod() 中,如果å­�类需è¦�它就覆盖默认实现并加上自己的实现。 -**7. ´úÂëʵÏÖ** +**7. 代ç �实现** ```java public abstract class CaffeineBeverage { @@ -1109,7 +1110,7 @@ public class CaffeineBeverageTestDrive { } ``` -ÔËÐнá¹û +è¿�行结果 ```html boilWater @@ -1123,21 +1124,21 @@ pourInCup Tea.addCondiments ``` -# µÚ 9 Õ µü´úÆ÷ºÍ×éºÏģʽ +# 第 9 ç«  迭代器和组å�ˆæ¨¡å¼� -## 9.1 µü´úÆ÷ģʽ +## 9.1 迭代器模å¼� -**1. ģʽ¶¨Òå** +**1. 模å¼�定义** -ÌṩһÖÖ˳Ðò·ÃÎÊÒ»¸ö¾ÛºÏ¶ÔÏóÖеĸ÷¸öÔªËØµÄ·½·¨£¬¶øÓÖ²»±©Â¶ÆäÄÚ²¿µÄ±íʾ¡£ +æ��供一ç§�顺åº�访问一个è�šå�ˆå¯¹è±¡ä¸­çš„å�„个元素的方法,而å�ˆä¸�暴露其内部的表示。 -**2. ģʽÀàͼ** +**2. 模å¼�类图** -¿Í»§ÀàÓµÓÐÒ»¸ö¾ÛºÏ¶ÔÏóºÍµü´úÆ÷¶ÔÏ󣬵ü´úÆ÷¶ÔÏóÊǾۺ϶ÔÏóÉú³ÉµÄ¡£Ö»ÐèÒªµü´úÆ÷¶¨ÒåºÃÒÆ¶¯µÄ²Ù×÷£¬¾Í¿ÉÒÔÈþۺ϶ÔÏóÄܹ»Ë³Ðò±éÀú¡£ +客户类拥有一个è�šå�ˆå¯¹è±¡å’Œè¿­ä»£å™¨å¯¹è±¡ï¼Œè¿­ä»£å™¨å¯¹è±¡æ˜¯è�šå�ˆå¯¹è±¡ç”Ÿæˆ�的。å�ªéœ€è¦�迭代器定义好移动的æ“�作,就å�¯ä»¥è®©è�šå�ˆå¯¹è±¡èƒ½å¤Ÿé¡ºåº�é��历。 -![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/439deca7-fed0-4c89-87e5-7088d10f1fdb.jpg) +![](https://github.com/CyC2018/InterviewNotes/blob/master/pics//439deca7-fed0-4c89-87e5-7088d10f1fdb.jpg) -**3. ´úÂëʵÏÖ** +**3. 代ç �实现** ```java public class Aggregate { @@ -1195,7 +1196,7 @@ public class Client { } } ``` -ÔËÐнá¹û +è¿�行结果 ```html 0 1 @@ -1209,13 +1210,13 @@ public class Client { 9 ``` -## 9.2 Java ÄÚÖõĵü´úÆ÷ +## 9.2 Java 内置的迭代器 -**1. ʵÏÖ½Ó¿Ú** +**1. 实现接å�£** -Java ÖÐÒѾ­ÓÐÁË Iterator ½Ó¿Ú£¬ÔÚʹÓà Java ʵÏÖʱ£¬ÐèÒªÈþۺ϶ÔÏóʵÏÖ Iterable ½Ó¿Ú£¬¸Ã½Ó¿ÚÓÐÒ»¸ö iterator() ·½·¨»á·µ»ØÒ»¸ö Iterator ¶ÔÏó¡£Ê¹Óà Java ÄÚÖõĵü´úÆ÷ʵÏÖ£¬¿Í»§¶ÔÏó¿ÉÒÔʹÓà foreach Ñ­»·À´±éÀú¾ÛºÏ¶ÔÏóÖеÄÿ¸öÔªËØ¡£ +Java 中已ç»�有了 Iterator 接å�£ï¼Œåœ¨ä½¿ç”¨ Java 实现时,需è¦�让è�šå�ˆå¯¹è±¡å®žçް Iterable 接å�£ï¼Œè¯¥æŽ¥å�£æœ‰ä¸€ä¸ª iterator() 方法会返回一个 Iterator 对象。使用 Java 内置的迭代器实现,客户对象å�¯ä»¥ä½¿ç”¨ foreach 循环æ�¥é��历è�šå�ˆå¯¹è±¡ä¸­çš„æ¯�个元素。 -**2. ´úÂëʵÏÖ** +**2. 代ç �实现** ```java import java.util.Iterator; @@ -1271,25 +1272,25 @@ public class Client { } ``` -## 9.3 ×éºÏģʽ +## 9.3 组å�ˆæ¨¡å¼� -**1. Éè¼ÆÔ­Ôò** +**1. 设计原则** -Ò»¸öÀàÓ¦¸ÃÖ»ÓÐÒ»¸öÒýÆð¸Ä±äµÄÔ­Òò¡£ +一个类应该å�ªæœ‰ä¸€ä¸ªå¼•起改å�˜çš„原因。 -**2. ģʽ¶¨Òå** +**2. 模å¼�定义** -ÔÊÐí½«¶ÔÏó×éºÏ³ÉÊ÷ÐνṹÀ´±íÏÖ¡°ÕûÌå / ²¿·Ö¡±²ã´Î½á¹¹¡£ +å…�许将对象组å�ˆæˆ�树形结构æ�¥è¡¨çŽ°â€œæ•´ä½“ / 部分â€�层次结构。 -×éºÏÄÜÈÿͻ§ÒÔÒ»Öµķ½Ê½´¦Àí¸ö±ð¶ÔÏóÒÔ¼°¶ÔÏó×éºÏ¡£ +组å�ˆèƒ½è®©å®¢æˆ·ä»¥ä¸€è‡´çš„æ–¹å¼�处ç�†ä¸ªåˆ«å¯¹è±¡ä»¥å�Šå¯¹è±¡ç»„å�ˆã€‚ -**3. ģʽÀàͼ** +**3. 模å¼�类图** -ÓÉÓÚ×éºÏ£¨Composite£©ÀàÓµÓÐÒ»¸ö×é¼þ£¨Component£©¶ÔÏó£¬Òò´Ë×éºÏ¶ÔÏóλÓÚÊ÷ÐνṹµÄÖм䣬Ëü»¹¿ÉÒÔ¼ÌÐø²Ù×÷Õâ¸ö×é¼þ¶ÔÏ󣬲¢ºöÂÔ×é¼þ¶ÔÏóµÄ¾ßÌåÀàÐÍ¡£ +由于组å�ˆï¼ˆComposite)类拥有一个组件(Component)对象,因此组å�ˆå¯¹è±¡ä½�于树形结构的中间,它还å�¯ä»¥ç»§ç»­æ“�作这个组件对象,并忽略组件对象的具体类型。 -![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/f99c019e-7e91-4c2e-b94d-b031c402dcb5.jpg) +![](https://github.com/CyC2018/InterviewNotes/blob/master/pics//f99c019e-7e91-4c2e-b94d-b031c402dcb5.jpg) -**4. ´úÂëʵÏÖ** +**4. 代ç �实现** ```java public abstract class Component { @@ -1316,7 +1317,7 @@ public class Leaf extends Component { @Override public void addChild(Component component) { - throw new UnsupportedOperationException(); // ÎþÉü͸Ã÷ÐÔ»»È¡µ¥Ò»Ö°ÔðÔ­Ôò , ÕâÑù¾Í²»Óÿ¼ÂÇÊÇÒ¶×ӽڵ㻹ÊÇ×éºÏ½Úµã + throw new UnsupportedOperationException(); // 牺牲é€�明性æ�¢å�–å�•一è�Œè´£åŽŸåˆ™ , 这样就ä¸�用考虑是å�¶å­�节点还是组å�ˆèŠ‚ç‚¹ } @Override @@ -1378,7 +1379,7 @@ public class Client { } } ``` -ÔËÐнá¹û +è¿�行结果 ```html Composite:root @@ -1390,56 +1391,56 @@ Composite:root --left:3 ``` -# µÚ 10 Õ ״̬ģʽ +# 第 10 ç«  状æ€�模å¼� -**1. ģʽ¶¨Òå** +**1. 模å¼�定义** -ÔÊÐí¶ÔÏóÔÚÄÚ²¿×´Ì¬¸Ä±äʱ¸Ä±äËüµÄÐÐΪ£¬¶ÔÏó¿´ÆðÀ´ºÃÏñÐÞ¸ÄÁËËüµÄÀà¡£ +å…�许对象在内部状æ€�改å�˜æ—¶æ”¹å�˜å®ƒçš„行为,对象看起æ�¥å¥½åƒ�修改了它的类。 -״̬ģʽµÄÀàͼºÍ²ßÂÔģʽһÑù£¬²¢ÇÒ¶¼ÊÇÄܹ»¶¯Ì¬¸Ä±ä¶ÔÏóµÄÐÐΪ¡£µ«ÊÇ״̬ģʽÊÇͨ¹ý״̬¶ÔÏóµÄ×´Ì¬×ªÒÆÀ´¸Ä±ä¿Í»§¶ÔÏó×éºÏµÄ״̬¶ÔÏ󣬶ø²ßÂÔģʽÊÇͨ¹ý¿Í»§¶ÔÏó±¾ÉíµÄ¾ö²ßÀ´¸Ä±ä×éºÏµÄ²ßÂÔ¶ÔÏó¡£ÀýÈ磬״̬ģʽÏ£¬¿Í»§¶ÔÏóίÍÐ״̬¶ÔÏó½øÐÐÒ»¸ö´¦Àí²Ù×÷£¬ÄÇô״̬¶ÔÏóÓпÉÄÜ·¢Éú×´Ì¬×ªÒÆ£¬Ê¹µÃ¿Í»§¶ÔÏóÓµÓеÄ״̬¶ÔÏó·¢Éú¸Ä±ä¡£×´Ì¬¶ÔÏó×éºÏÁ˿ͻ§¶ÔÏó£¬×´Ì¬×ªÒÆÊÇ״̬¶ÔÏóͨ¹ý¸Ä±ä¿Í»§¶ÔÏóËù×éºÏµÄ״̬¶ÔÏóʵÏֵġ£ +状æ€�模å¼�的类图和策略模å¼�一样,并且都是能够动æ€�改å�˜å¯¹è±¡çš„行为。但是状æ€�模å¼�是通过状æ€�对象的状æ€�转移æ�¥æ”¹å�˜å®¢æˆ·å¯¹è±¡ç»„å�ˆçš„状æ€�对象,而策略模å¼�是通过客户对象本身的决策æ�¥æ”¹å�˜ç»„å�ˆçš„策略对象。例如,状æ€�模å¼�下,客户对象委托状æ€�对象进行一个处ç�†æ“�作,那么状æ€�对象有å�¯èƒ½å�‘生状æ€�转移,使得客户对象拥有的状æ€�对象å�‘生改å�˜ã€‚状æ€�对象组å�ˆäº†å®¢æˆ·å¯¹è±¡ï¼Œçжæ€�转移是状æ€�对象通过改å�˜å®¢æˆ·å¯¹è±¡æ‰€ç»„å�ˆçš„状æ€�对象实现的。 -**2. ģʽÀàͼ** +**2. 模å¼�类图** -![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/c28fd93a-0d55-4a19-810f-72652feee00d.jpg) +![](https://github.com/CyC2018/InterviewNotes/blob/master/pics//c28fd93a-0d55-4a19-810f-72652feee00d.jpg) -**3. ÎÊÌâÃèÊö** +**3. 问题æ��è¿°** -ÌǹûÏúÊÛ»úÓжàÖÖ״̬£¬Ã¿ÖÖ״̬ÏÂÏúÊÛ»úÓв»Í¬µÄÐÐΪ£¬×´Ì¬¿ÉÒÔ·¢Éú×ªÒÆ£¬Ê¹µÃÏúÊÛ»úµÄÐÐΪҲ·¢Éú¸Ä±ä¡£ +糖果销售机有多ç§�状æ€�,æ¯�ç§�状æ€�下销售机有ä¸�å�Œçš„行为,状æ€�å�¯ä»¥å�‘生转移,使得销售机的行为也å�‘生改å�˜ã€‚ -![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/f7d880c9-740a-4a16-ac6d-be502281b4b2.jpg) +![](https://github.com/CyC2018/InterviewNotes/blob/master/pics//f7d880c9-740a-4a16-ac6d-be502281b4b2.jpg) -**4. Ö±½Ó½â¾ö·½°¸** +**4. 直接解决方案** -ÔÚÌǹû»úµÄÿ¸ö²Ù×÷º¯ÊýÀïÃæ£¬Åжϵ±Ç°µÄ״̬£¬¸ù¾Ý²»Í¬µÄ״̬½øÐв»Í¬µÄ´¦Àí£¬²¢ÇÒ·¢Éú²»Í¬µÄ×´Ì¬×ªÒÆ¡£ÕâÖÖ½â¾ö·½°¸°ÑËùÓеÄʵÏÖϸ½Ú¶¼·Åµ½¿Í»§À࣬ÕâÑùÔÚÐÂÔö״̬µÄʱºò¾ÍҪȥÐ޸Ŀͻ§ÀàµÄ´úÂë¡£ +在糖果机的æ¯�个æ“�作函数里é�¢ï¼Œåˆ¤æ–­å½“å‰�的状æ€�,根æ�®ä¸�å�Œçš„状æ€�进行ä¸�å�Œçš„处ç�†ï¼Œå¹¶ä¸”å�‘生ä¸�å�Œçš„状æ€�转移。这ç§�解决方案把所有的实现细节都放到客户类,这样在新增状æ€�的时候就è¦�去修改客户类的代ç �。 -![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/62ebbb63-8fd7-4488-a866-76a9dc911662.png) +![](https://github.com/CyC2018/InterviewNotes/blob/master/pics//62ebbb63-8fd7-4488-a866-76a9dc911662.png) -**5. ʹÓÃ״̬ģʽµÄ½â¾ö·½°¸** +**5. 使用状æ€�模å¼�的解决方案** -״̬µÄ×ªÒÆ±»ÒƵ½×´Ì¬ÀàÀïÃæ£¬¿Í»§ÀàµÄÿ¸ö²Ù×÷Ö»ÐèҪίÍиø×´Ì¬À༴¿É£¬¶ø²»ÐèÒªÖªµÀµ±Ç°ÊÇʲô״̬ÒÔ¼°×´Ì¬Ê±ÈçºÎ½øÐÐ×ªÒÆµÄ¡£ +状æ€�的转移被移到状æ€�类里é�¢ï¼Œå®¢æˆ·ç±»çš„æ¯�个æ“�作å�ªéœ€è¦�委托给状æ€�ç±»å�³å�¯ï¼Œè€Œä¸�需è¦�知é�“当å‰�是什么状æ€�以å�Šçжæ€�时如何进行转移的。 -**6. ´úÂëʵÏÖ** +**6. 代ç �实现** ```java public interface State { /** - * ͶÈë25 ·ÖÇ® + * 投入25 分钱 */ void insertQuarter(); /** - * ÍË»Ø25 ·ÖÇ® + * 退回25 分钱 */ void ejectQuarter(); /** - * ת¶¯Çú±ú + * 转动曲柄 */ void turnCrank(); /** - * ·¢·ÅÌǹû + * å�‘放糖果 */ void dispense(); } @@ -1667,7 +1668,7 @@ public class GumballMachineTestDrive { } } ``` -ÔËÐнá¹û +è¿�行结果 ```html You insert a quarter You turned... @@ -1696,34 +1697,34 @@ You turned, but there are no gumballs No gumball dispensed ``` -# µÚ 11 Õ ´úÀíģʽ +# 第 11 ç«  代ç�†æ¨¡å¼� -# µÚ 12 Õ ¸´ºÏģʽ +# 第 12 ç«  å¤�å�ˆæ¨¡å¼� ## 12.1 MVC -**´«Í³ MVC** +**传统 MVC** -ÊÓͼʹÓÃ×éºÏģʽ£¬Ä£ÐÍʹÓÃÁ˹۲ìÕßģʽ£¬¿ØÖÆÆ÷ʹÓÃÁ˲ßÂÔģʽ¡£ +视图使用组å�ˆæ¨¡å¼�,模型使用了观察者模å¼�,控制器使用了策略模å¼�。 -![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/4f67611d-492f-4958-9fa0-4948010e345f.jpg) +![](https://github.com/CyC2018/InterviewNotes/blob/master/pics//4f67611d-492f-4958-9fa0-4948010e345f.jpg) -**Web ÖÐµÄ MVC** +**Web 中的 MVC** -ģʽ²»ÔÙʹÓù۲ìÕßģʽ¡£ +模å¼�ä¸�å†�使用观察者模å¼�。 -![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/1dd56e61-2970-4d27-97c2-6e81cee86978.jpg) +![](https://github.com/CyC2018/InterviewNotes/blob/master/pics//1dd56e61-2970-4d27-97c2-6e81cee86978.jpg) -# µÚ 13 Õ ÓëÉè¼ÆÄ£Ê½Ïà´¦ +# 第 13 ç«  与设计模å¼�相处 -¶¨Ò壺ÔÚij **Çé¾³** Ï£¬Õë¶Ôij **ÎÊÌâ** µÄijÖÖ **½â¾ö·½°¸**¡£ +定义:在æŸ� **情境** 下,针对æŸ� **问题** çš„æŸ�ç§� **解决方案**。 -¹ý¶ÈʹÓÃÉè¼ÆÄ£Ê½¿ÉÄܵ¼Ö´úÂë±»¹ý¶È¹¤³Ì»¯£¬Ó¦¸Ã×ÜÊÇÓÃ×î¼òµ¥µÄ½â¾ö·½°¸Íê³É¹¤×÷£¬²¢ÔÚÕæÕýÐèҪģʽµÄµØ·½²ÅʹÓÃËü¡£ +过度使用设计模å¼�å�¯èƒ½å¯¼è‡´ä»£ç �被过度工程化,应该总是用最简å�•的解决方案完æˆ�工作,并在真正需è¦�模å¼�的地方æ‰�使用它。 -·´Ä£Ê½£º²»ºÃµÄ½â¾ö·½°¸À´½â¾öÒ»¸öÎÊÌâ¡£Ö÷Òª×÷ÓÃÊÇΪÁ˾¯¸æ²»ÒªÊ¹ÓÃÕâЩ½â¾ö·½°¸¡£ +å��模å¼�:ä¸�好的解决方案æ�¥è§£å†³ä¸€ä¸ªé—®é¢˜ã€‚主è¦�作用是为了警告ä¸�è¦�使用这些解决方案。 -ģʽ·ÖÀࣺ +模å¼�分类: -![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/524a237c-ffd7-426f-99c2-929a6bf4c847.jpg) +![](https://github.com/CyC2018/InterviewNotes/blob/master/pics//524a237c-ffd7-426f-99c2-929a6bf4c847.jpg) -# µÚ 14 Õ ʣϵÄģʽ +# 第 14 ç«  剩下的模å¼� diff --git a/notes/é‡�æž„.md b/notes/é‡�æž„.md index a7d15340..a25e566b 100644 --- a/notes/é‡�æž„.md +++ b/notes/é‡�æž„.md @@ -1,300 +1,301 @@ -* [µÚÒ»Õ µÚÒ»¸ö°¸Àý](#µÚÒ»ÕÂ-µÚÒ»¸ö°¸Àý) -* [µÚ¶þÕÂ ÖØ¹¹Ô­Ôò](#µÚ¶þÕÂ-ÖØ¹¹Ô­Ôò) -* [µÚÈýÕ ´úÂëµÄ»µÎ¶µÀ](#µÚÈýÕÂ-´úÂëµÄ»µÎ¶µÀ) - * [1. Duplicated Code£¨Öظ´´úÂ룩](#1-duplicated-codeÖØ¸´´úÂë) - * [2. Long Method£¨¹ý³¤º¯Êý£©](#2-long-method¹ý³¤º¯Êý) - * [3. Large Class£¨¹ý´óµÄÀࣩ](#3-large-class¹ý´óµÄÀà) - * [4. Long Parameter List£¨¹ý³¤µÄ²ÎÊýÁУ©](#4-long-parameter-list¹ý³¤µÄ²ÎÊýÁÐ) - * [5. Divergent Change£¨·¢É¢Ê½±ä»¯£©](#5-divergent-change·¢É¢Ê½±ä»¯) - * [6. Shotgun Surgery£¨É¢µ¯Ê½Ð޸ģ©](#6-shotgun-surgeryÉ¢µ¯Ê½ÐÞ¸Ä) - * [7. Feature Envy£¨ÒÀÁµÇé½á£©](#7-feature-envyÒÀÁµÇé½á) - * [8. Data Clumps£¨Êý¾ÝÄàÍÅ£©](#8-data-clumpsÊý¾ÝÄàÍÅ) - * [9. Primitive Obsession£¨»ù±¾ÀàÐÍÆ«Ö´£©](#9-primitive-obsession»ù±¾ÀàÐÍÆ«Ö´) - * [10. Switch Statements£¨switch ¾ªã¤ÏÖÉí£©](#10-switch-statementsswitch-¾ªã¤ÏÖÉí) - * [11. Parallel Inheritance Hierarchies£¨Æ½Ðм̳ÐÌåϵ£©](#11-parallel-inheritance-hierarchiesƽÐм̳ÐÌåϵ) - * [12. Lazy Class£¨ÈßÓàÀࣩ](#12-lazy-classÈßÓàÀà) - * [13. Speculative Generality£¨¿ä¿äÆä̸δÀ´ÐÔ£©](#13-speculative-generality¿ä¿äÆä̸δÀ´ÐÔ) - * [14. Temporary Field£¨ÁîÈËÃÔ»óµÄÔÝʱ×ֶΣ©](#14-temporary-fieldÁîÈËÃÔ»óµÄÔÝʱ×Ö¶Î) - * [15. Message Chains£¨¹ý¶ÈñîºÏµÄÏûÏ¢Á´£©](#15-message-chains¹ý¶ÈñîºÏµÄÏûÏ¢Á´) - * [16. Middle Man£¨ÖмäÈË£©](#16-middle-manÖмäÈË) - * [17. Inappropriate Intimacy£¨áòêǹØÏµ£©](#17-inappropriate-intimacyáòêǹØÏµ) - * [18. Alernative Classes with Different Interfaces£¨ÒìÇúͬ¹¤µÄÀࣩ](#18-alernative-classes-with-different-interfacesÒìÇúͬ¹¤µÄÀà) - * [19. Incomplete Library Class£¨²»ÍêÃÀµÄÀà¿â£©](#19-incomplete-library-class²»ÍêÃÀµÄÀà¿â) - * [20. Data Class£¨Ó×ÖɵÄÊý¾ÝÀࣩ](#20-data-classÓ×ÖɵÄÊý¾ÝÀà) - * [21. Refused Bequest£¨±»¾Ü¾øµÄÀ¡Ôù£©](#21-refused-bequest±»¾Ü¾øµÄÀ¡Ôù) - * [22. Comments£¨¹ý¶àµÄ×¢ÊÍ£©](#22-comments¹ý¶àµÄ×¢ÊÍ) -* [µÚËÄÕ ¹¹Öþ²âÊÔÌåϵ](#µÚËÄÕÂ-¹¹Öþ²âÊÔÌåϵ) -* [µÚÎåÕÂ ÖØ¹¹Áбí](#µÚÎåÕÂ-ÖØ¹¹Áбí) -* [µÚÁùÕÂ ÖØÐÂ×éÖ¯º¯Êý](#µÚÁùÕÂ-ÖØÐÂ×éÖ¯º¯Êý) - * [1. Extract Method£¨ÌáÁ¶º¯Êý£©](#1-extract-methodÌáÁ¶º¯Êý) - * [2. Inline Method£¨ÄÚÁªº¯Êý£©](#2-inline-methodÄÚÁªº¯Êý) - * [3. Inline Temp£¨ÄÚÁªÁÙʱ±äÁ¿£©](#3-inline-tempÄÚÁªÁÙʱ±äÁ¿) - * [4. Replace Temp with Query£¨ÒÔ²éѯȡ´úÁÙʱ±äÁ¿£©](#4-replace-temp-with-queryÒÔ²éѯȡ´úÁÙʱ±äÁ¿) - * [5. Introduce Explaining Variable£¨ÒýÆð½âÊͱäÁ¿£©](#5-introduce-explaining-variableÒýÆð½âÊͱäÁ¿) - * [6. Split Temporary Variable£¨·Ö½âÁÙʱ±äÁ¿£©](#6-split-temporary-variable·Ö½âÁÙʱ±äÁ¿) - * [7. Remove Assigments to Parameters£¨ÒƳý¶Ô²ÎÊýµÄ¸³Öµ£©](#7-remove-assigments-to-parametersÒÆ³ý¶Ô²ÎÊýµÄ¸³Öµ) - * [8. Replace Method with Method Object£¨ÒÔº¯Êý¶ÔÏóÈ¡´úº¯Êý£©](#8-replace-method-with-method-objectÒÔº¯Êý¶ÔÏóÈ¡´úº¯Êý) - * [9. Subsititute Algorithn£¨Ìæ»»Ëã·¨£©](#9-subsititute-algorithnÌæ»»Ëã·¨) -* [µÚÆßÕ ÔÚ¶ÔÏóÖ®¼ä°áÒÆÌØÐÔ](#µÚÆßÕÂ-ÔÚ¶ÔÏóÖ®¼ä°áÒÆÌØÐÔ) - * [1. Move Method£¨°áÒÆº¯Êý£©](#1-move-method°áÒÆº¯Êý) - * [2. Move Field£¨°áÒÆ×ֶΣ©](#2-move-field°áÒÆ×Ö¶Î) - * [3. Extract Class£¨ÌáÁ¶Àࣩ](#3-extract-classÌáÁ¶Àà) - * [4. Inline Class£¨½«ÀàÄÚÁª»¯£©](#4-inline-class½«ÀàÄÚÁª»¯) - * [5. Hide Delegate£¨Òþ²Ø¡°Î¯ÍйØÏµ¡±£©](#5-hide-delegateÒþ²Ø¡°Î¯ÍйØÏµ¡±) - * [6. Remove Middle Man£¨ÒƳýÖмäÈË£©](#6-remove-middle-manÒÆ³ýÖмäÈË) - * [7. Introduce Foreign Method£¨ÒýÈëÍâ¼Óº¯Êý£©](#7-introduce-foreign-methodÒýÈëÍâ¼Óº¯Êý) - * [8. Introduce Local Extension£¨ÒýÈë±¾µØÀ©Õ¹£©](#8-introduce-local-extensionÒýÈë±¾µØÀ©Õ¹) -* [µÚ°ËÕÂ ÖØÐÂ×éÖ¯Êý¾Ý](#µÚ°ËÕÂ-ÖØÐÂ×éÖ¯Êý¾Ý) - * [1. Self Encapsulate Field£¨×Ô·â×°×ֶΣ©](#1-self-encapsulate-field×Ô·â×°×Ö¶Î) - * [2. Replace Data Value with Object£¨ÒÔ¶ÔÏóÈ¡´úÊý¾ÝÖµ£©](#2-replace-data-value-with-objectÒÔ¶ÔÏóÈ¡´úÊý¾ÝÖµ) - * [3. Change Value to Reference£¨½«Öµ¶ÔÏó¸Ä³ÉÒýÓöÔÏó£©](#3-change-value-to-reference½«Öµ¶ÔÏó¸Ä³ÉÒýÓöÔÏó) - * [4. Change Reference to value£¨½«ÒýÓöÔÏó¸ÄΪֵ¶ÔÏó£©](#4-change-reference-to-value½«ÒýÓöÔÏó¸ÄΪֵ¶ÔÏó) - * [5. Replace Array with Object£¨ÒÔ¶ÔÏóÈ¡´úÊý×飩](#5-replace-array-with-objectÒÔ¶ÔÏóÈ¡´úÊý×é) - * [6. Duplicate Observed Data£¨¸³Öµ¡°±»¼àÊÓÊý¾Ý¡±£©](#6-duplicate-observed-data¸³Öµ¡°±»¼àÊÓÊý¾Ý¡±) - * [7. Change Unidirectional Association to Bidirectional£¨½«µ¥Ïò¹ØÁª¸ÄΪ˫Ïò¹ØÁª£©](#7-change-unidirectional-association-to-bidirectional½«µ¥Ïò¹ØÁª¸ÄΪ˫Ïò¹ØÁª) - * [8. Change Bidirectional Association to Unidirectional£¨½«Ë«Ïò¹ØÁª¸ÄΪµ¥Ïò¹ØÁª£©](#8-change-bidirectional-association-to-unidirectional½«Ë«Ïò¹ØÁª¸ÄΪµ¥Ïò¹ØÁª) - * [9. Replace Magic Number with Symbolic Constant£¨ÒÔ×ÖÃæ³£Á¿È¡´úħ·¨Êý£©](#9-replace-magic-number-with-symbolic-constantÒÔ×ÖÃæ³£Á¿È¡´úħ·¨Êý) - * [10. Encapsulate Field£¨·â×°×ֶΣ©](#10-encapsulate-field·â×°×Ö¶Î) - * [11. Encapsulate Collection£¨·â×°¼¯ºÏ£©](#11-encapsulate-collection·â×°¼¯ºÏ) - * [12. Replace Record with Data Class£¨ÒÔÊý¾ÝÀàÈ¡´ú¼Ç¼£©](#12-replace-record-with-data-classÒÔÊý¾ÝÀàÈ¡´ú¼Ç¼) - * [13. Replace Type Code with Class£¨ÒÔÀàÈ¡´úÀàÐÍÂ룩](#13-replace-type-code-with-classÒÔÀàÈ¡´úÀàÐÍÂë) - * [14. Replace Type Code with Subcalsses£¨ÒÔ×ÓÀàÈ¡´úÀàÐÍÂ룩](#14-replace-type-code-with-subcalssesÒÔ×ÓÀàÈ¡´úÀàÐÍÂë) - * [15. Replace Type Code with State/Strategy £¨ÒÔ State/Strategy È¡´úÀàÐÍÂ룩](#15-replace-type-code-with-statestrategy-ÒÔ-statestrategy-È¡´úÀàÐÍÂë) - * [16. Replace Subclass with Fields£¨ÒÔ×Ö¶ÎÈ¡´ú×ÓÀࣩ](#16-replace-subclass-with-fieldsÒÔ×Ö¶ÎÈ¡´ú×ÓÀà) -* [µÚ¾ÅÕ ¼ò»¯Ìõ¼þ±í´ïʽ](#µÚ¾ÅÕÂ-¼ò»¯Ìõ¼þ±í´ïʽ) - * [1. Decompose Conditional£¨·Ö½âÌõ¼þ±í´ïʽ£©](#1-decompose-conditional·Ö½âÌõ¼þ±í´ïʽ) - * [2. Consolidate Conditional Expression£¨ºÏ²¢Ìõ¼þ±í´ïʽ£©](#2-consolidate-conditional-expressionºÏ²¢Ìõ¼þ±í´ïʽ) - * [3. Consolidate Duplicate Conditional Fragments £¨ºÏ²¢Öظ´µÄÌõ¼þƬ¶Î£©](#3-consolidate-duplicate-conditional-fragments-ºÏ²¢Öظ´µÄÌõ¼þƬ¶Î) - * [4. Remove Control Flag£¨ÒƳý¿ØÖƱê¼Ç£©](#4-remove-control-flagÒÆ³ý¿ØÖƱê¼Ç) - * [5. Replace Nested Conditional with Guard Clauses £¨ÒÔÎÀÓï¾äÈ¡´úǶÌ×Ìõ¼þ±í´ïʽ£©](#5-replace-nested-conditional-with-guard-clauses-ÒÔÎÀÓï¾äÈ¡´úǶÌ×Ìõ¼þ±í´ïʽ) - * [6. Replace Conditional with Polymorphism £¨ÒÔ¶à̬ȡ´úÌõ¼þ±í´ïʽ£©](#6-replace-conditional-with-polymorphism-ÒÔ¶à̬ȡ´úÌõ¼þ±í´ïʽ) - * [7. Introduce Null Object£¨ÒýÈëNull¶ÔÏó£©](#7-introduce-null-objectÒýÈënull¶ÔÏó) - * [8. Introduce Assertion£¨ÒýÈë¶ÏÑÔ£©](#8-introduce-assertionÒýÈë¶ÏÑÔ) -* [µÚʮՠ¼ò»¯º¯Êýµ÷ÓÃ](#µÚÊ®ÕÂ-¼ò»¯º¯Êýµ÷ÓÃ) - * [1. Rename Method£¨º¯Êý¸ÄÃû£©](#1-rename-methodº¯Êý¸ÄÃû) - * [2. Add Parameter£¨Ìí¼Ó²ÎÊý£©](#2-add-parameterÌí¼Ó²ÎÊý) - * [3. Remove Parameter£¨ÒƳý²ÎÊý£©](#3-remove-parameterÒÆ³ý²ÎÊý) - * [4. Separate Query from Modifier£¨½«²éѯº¯ÊýºÍÐ޸ĺ¯Êý·ÖÀ룩](#4-separate-query-from-modifier½«²éѯº¯ÊýºÍÐ޸ĺ¯Êý·ÖÀë) - * [5. Parameterize Method£¨ÁÊýЯ´ø²ÎÊý£©](#5-parameterize-methodÁÊýЯ´ø²ÎÊý) - * [6. Replace Parameter with Explicit Methods£¨ÒÔÃ÷È·º¯ÊýÈ¡´ú²ÎÊý£©](#6-replace-parameter-with-explicit-methodsÒÔÃ÷È·º¯ÊýÈ¡´ú²ÎÊý) - * [7. Preserve Whole Object£¨±£³Ö¶ÔÏóÍêÕû£©](#7-preserve-whole-object±£³Ö¶ÔÏóÍêÕû) - * [8. Replace Parameter with Methods£¨ÒÔº¯ÊýÈ¡´ú²ÎÊý£©](#8-replace-parameter-with-methodsÒÔº¯ÊýÈ¡´ú²ÎÊý) - * [9. Introduce Parameter Object£¨ÒýÈë²ÎÊý¶ÔÏó£©](#9-introduce-parameter-objectÒýÈë²ÎÊý¶ÔÏó) - * [10. Remove Setting Method£¨ÒƳýÉèÖµº¯Êý£©](#10-remove-setting-methodÒÆ³ýÉèÖµº¯Êý) - * [11. Hide Method£¨Òþ²Øº¯Êý£©](#11-hide-methodÒþ²Øº¯Êý) - * [12. Replace Constructor with Factory Method £¨ÒÔ¹¤³§º¯ÊýÈ¡´ú¹¹Ô캯Êý£©](#12-replace-constructor-with-factory-method-ÒÔ¹¤³§º¯ÊýÈ¡´ú¹¹Ô캯Êý) - * [13. Encapsulate Downcast£¨·â×°ÏòÏÂתÐÍ£©](#13-encapsulate-downcast·â×°ÏòÏÂתÐÍ) - * [14. Replace Error Code with Exception £¨ÒÔÒ쳣ȡ´ú´íÎóÂ룩](#14-replace-error-code-with-exception-ÒÔÒ쳣ȡ´ú´íÎóÂë) - * [15. Replace Exception with Test£¨ÒÔ²âÊÔÈ¡´úÒì³££©](#15-replace-exception-with-testÒÔ²âÊÔÈ¡´úÒì³£) -* [µÚʮһÕ ´¦Àí¸ÅÀ¨¹ØÏµ](#µÚʮһÕÂ-´¦Àí¸ÅÀ¨¹ØÏµ) - * [1. Pull Up Field£¨×Ö¶ÎÉÏÒÆ£©](#1-pull-up-field×Ö¶ÎÉÏÒÆ) - * [2. Pull Up Method£¨º¯ÊýÉÏÒÆ£©](#2-pull-up-methodº¯ÊýÉÏÒÆ) - * [3. Pull Up Constructor Body£¨¹¹Ô캯Êý±¾ÌåÉÏÒÆ£©](#3-pull-up-constructor-body¹¹Ô캯Êý±¾ÌåÉÏÒÆ) - * [4. Push Down Method£¨º¯ÊýÏÂÒÆ£©](#4-push-down-methodº¯ÊýÏÂÒÆ) - * [5. Push Down Field£¨×Ö¶ÎÏÂÒÆ£©](#5-push-down-field×Ö¶ÎÏÂÒÆ) - * [6. Extract Subclass£¨ÌáÁ¶×ÓÀࣩ](#6-extract-subclassÌáÁ¶×ÓÀà) - * [7. Extract Superclass£¨ÌáÁ¶³¬Àࣩ](#7-extract-superclassÌáÁ¶³¬Àà) - * [8. Extract Interface£¨ÌáÁ¶½Ó¿Ú£©](#8-extract-interfaceÌáÁ¶½Ó¿Ú) - * [9. Collapse Hierarchy£¨ÕÛµþ¼Ì³ÐÌåϵ£©](#9-collapse-hierarchyÕÛµþ¼Ì³ÐÌåϵ) - * [10. Form Template Method£¨ËÜÔìÄ£°åº¯Êý£©](#10-form-template-methodËÜÔìÄ£°åº¯Êý) - * [11. Replace Inheritance with Delegation £¨ÒÔίÍÐÈ¡´ú¼Ì³Ð£©](#11-replace-inheritance-with-delegation-ÒÔίÍÐÈ¡´ú¼Ì³Ð) - * [12. Replace Delegation with Inheritance £¨ÒԼ̳ÐÈ¡´úίÍУ©](#12-replace-delegation-with-inheritance-ÒԼ̳ÐÈ¡´úίÍÐ) +* [第一章 第一个案例](#第一章-第一个案例) +* [第二章 é‡�构原则](#第二章-é‡�构原则) +* [第三章 代ç �çš„å��味é�“](#第三章-代ç �çš„å��味é�“) + * [1. Duplicated Code(é‡�å¤�代ç �)](#1-duplicated-codeé‡�å¤�代ç �) + * [2. Long Method(过长函数)](#2-long-method过长函数) + * [3. Large Class(过大的类)](#3-large-class过大的类) + * [4. Long Parameter List(过长的å�‚数列)](#4-long-parameter-list过长的å�‚数列) + * [5. Divergent Change(å�‘æ•£å¼�å�˜åŒ–)](#5-divergent-changeå�‘æ•£å¼�å�˜åŒ–) + * [6. Shotgun Surgery(散弹å¼�修改)](#6-shotgun-surgery散弹å¼�修改) + * [7. Feature Envy(ä¾�æ�‹æƒ…结)](#7-feature-envyä¾�æ�‹æƒ…结) + * [8. Data Clumps(数æ�®æ³¥å›¢ï¼‰](#8-data-clumpsæ•°æ�®æ³¥å›¢) + * [9. Primitive Obsession(基本类型å��执)](#9-primitive-obsession基本类型å��执) + * [10. Switch Statements(switch 惊悚现身)](#10-switch-statementsswitch-惊悚现身) + * [11. Parallel Inheritance Hierarchies(平行继承体系)](#11-parallel-inheritance-hierarchies平行继承体系) + * [12. Lazy Class(冗余类)](#12-lazy-class冗余类) + * [13. Speculative Generality(夸夸其谈未æ�¥æ€§ï¼‰](#13-speculative-generality夸夸其谈未æ�¥æ€§) + * [14. Temporary Field(令人迷惑的暂时字段)](#14-temporary-field令人迷惑的暂时字段) + * [15. Message Chains(过度耦å�ˆçš„æ¶ˆæ�¯é“¾ï¼‰](#15-message-chains过度耦å�ˆçš„æ¶ˆæ�¯é“¾) + * [16. Middle Man(中间人)](#16-middle-man中间人) + * [17. Inappropriate Intimacy(狎昵关系)](#17-inappropriate-intimacy狎昵关系) + * [18. Alernative Classes with Different Interfaces(异曲å�Œå·¥çš„类)](#18-alernative-classes-with-different-interfaces异曲å�Œå·¥çš„ç±») + * [19. Incomplete Library Class(ä¸�完美的类库)](#19-incomplete-library-classä¸�完美的类库) + * [20. Data Class(幼稚的数æ�®ç±»ï¼‰](#20-data-class幼稚的数æ�®ç±») + * [21. Refused Bequest(被拒ç»�的馈赠)](#21-refused-bequest被拒ç»�的馈赠) + * [22. Comments(过多的注释)](#22-comments过多的注释) +* [第四章 构筑测试体系](#第四章-构筑测试体系) +* [第五章 é‡�构列表](#第五章-é‡�构列表) +* [第六章 é‡�新组织函数](#第六章-é‡�新组织函数) + * [1. Extract Method(æ��炼函数)](#1-extract-methodæ��炼函数) + * [2. Inline Method(内è�”函数)](#2-inline-method内è�”函数) + * [3. Inline Temp(内è�”临时å�˜é‡�)](#3-inline-temp内è�”临时å�˜é‡�) + * [4. Replace Temp with Query(以查询å�–代临时å�˜é‡�)](#4-replace-temp-with-query以查询å�–代临时å�˜é‡�) + * [5. Introduce Explaining Variable(引起解释å�˜é‡�)](#5-introduce-explaining-variable引起解释å�˜é‡�) + * [6. Split Temporary Variable(分解临时å�˜é‡�)](#6-split-temporary-variable分解临时å�˜é‡�) + * [7. Remove Assigments to Parameters(移除对å�‚数的赋值)](#7-remove-assigments-to-parameters移除对å�‚数的赋值) + * [8. Replace Method with Method Object(以函数对象å�–代函数)](#8-replace-method-with-method-object以函数对象å�–代函数) + * [9. Subsititute Algorithn(替æ�¢ç®—法)](#9-subsititute-algorithn替æ�¢ç®—法) +* [第七章 在对象之间æ�¬ç§»ç‰¹æ€§](#第七章-在对象之间æ�¬ç§»ç‰¹æ€§) + * [1. Move Method(æ�¬ç§»å‡½æ•°ï¼‰](#1-move-methodæ�¬ç§»å‡½æ•°) + * [2. Move Field(æ�¬ç§»å­—段)](#2-move-fieldæ�¬ç§»å­—段) + * [3. Extract Class(æ��炼类)](#3-extract-classæ��炼类) + * [4. Inline Class(将类内è�”化)](#4-inline-class将类内è�”化) + * [5. Hide Delegate(éš�è—�“委托关系â€�)](#5-hide-delegateéš�è—�“委托关系â€�) + * [6. Remove Middle Man(移除中间人)](#6-remove-middle-man移除中间人) + * [7. Introduce Foreign Method(引入外加函数)](#7-introduce-foreign-method引入外加函数) + * [8. Introduce Local Extension(引入本地扩展)](#8-introduce-local-extension引入本地扩展) +* [第八章 é‡�新组织数æ�®](#第八章-é‡�新组织数æ�®) + * [1. Self Encapsulate Field(自å°�装字段)](#1-self-encapsulate-field自å°�装字段) + * [2. Replace Data Value with Object(以对象å�–代数æ�®å€¼ï¼‰](#2-replace-data-value-with-object以对象å�–代数æ�®å€¼) + * [3. Change Value to Reference(将值对象改æˆ�引用对象)](#3-change-value-to-reference将值对象改æˆ�引用对象) + * [4. Change Reference to value(将引用对象改为值对象)](#4-change-reference-to-value将引用对象改为值对象) + * [5. Replace Array with Object(以对象å�–代数组)](#5-replace-array-with-object以对象å�–代数组) + * [6. Duplicate Observed Data(赋值“被监视数æ�®â€�)](#6-duplicate-observed-data赋值“被监视数æ�®â€�) + * [7. Change Unidirectional Association to Bidirectional(将å�•å�‘å…³è�”改为å�Œå�‘å…³è�”)](#7-change-unidirectional-association-to-bidirectionalå°†å�•å�‘å…³è�”改为å�Œå�‘å…³è�”) + * [8. Change Bidirectional Association to Unidirectional(将å�Œå�‘å…³è�”改为å�•å�‘å…³è�”)](#8-change-bidirectional-association-to-unidirectionalå°†å�Œå�‘å…³è�”改为å�•å�‘å…³è�”) + * [9. Replace Magic Number with Symbolic Constant(以字é�¢å¸¸é‡�å�–代魔法数)](#9-replace-magic-number-with-symbolic-constant以字é�¢å¸¸é‡�å�–代魔法数) + * [10. Encapsulate Field(å°�装字段)](#10-encapsulate-fieldå°�装字段) + * [11. Encapsulate Collection(å°�装集å�ˆï¼‰](#11-encapsulate-collectionå°�装集å�ˆ) + * [12. Replace Record with Data Class(以数æ�®ç±»å�–代记录)](#12-replace-record-with-data-class以数æ�®ç±»å�–代记录) + * [13. Replace Type Code with Class(以类å�–代类型ç �)](#13-replace-type-code-with-class以类å�–代类型ç �) + * [14. Replace Type Code with Subcalsses(以å­�ç±»å�–代类型ç �)](#14-replace-type-code-with-subcalsses以å­�ç±»å�–代类型ç �) + * [15. Replace Type Code with State/Strategy (以 State/Strategy å�–代类型ç �)](#15-replace-type-code-with-statestrategy-以-statestrategy-å�–代类型ç �) + * [16. Replace Subclass with Fields(以字段å�–代å­�类)](#16-replace-subclass-with-fields以字段å�–代å­�ç±») +* [第ä¹�ç«  简化æ�¡ä»¶è¡¨è¾¾å¼�](#第ä¹�ç« -简化æ�¡ä»¶è¡¨è¾¾å¼�) + * [1. Decompose Conditional(分解æ�¡ä»¶è¡¨è¾¾å¼�)](#1-decompose-conditional分解æ�¡ä»¶è¡¨è¾¾å¼�) + * [2. Consolidate Conditional Expression(å�ˆå¹¶æ�¡ä»¶è¡¨è¾¾å¼�)](#2-consolidate-conditional-expressionå�ˆå¹¶æ�¡ä»¶è¡¨è¾¾å¼�) + * [3. Consolidate Duplicate Conditional Fragments (å�ˆå¹¶é‡�å¤�çš„æ�¡ä»¶ç‰‡æ®µï¼‰](#3-consolidate-duplicate-conditional-fragments-å�ˆå¹¶é‡�å¤�çš„æ�¡ä»¶ç‰‡æ®µ) + * [4. Remove Control Flag(移除控制标记)](#4-remove-control-flag移除控制标记) + * [5. Replace Nested Conditional with Guard Clauses (以å�«è¯­å�¥å�–代嵌套æ�¡ä»¶è¡¨è¾¾å¼�)](#5-replace-nested-conditional-with-guard-clauses-以å�«è¯­å�¥å�–代嵌套æ�¡ä»¶è¡¨è¾¾å¼�) + * [6. Replace Conditional with Polymorphism (以多æ€�å�–代æ�¡ä»¶è¡¨è¾¾å¼�)](#6-replace-conditional-with-polymorphism-以多æ€�å�–代æ�¡ä»¶è¡¨è¾¾å¼�) + * [7. Introduce Null Object(引入Null对象)](#7-introduce-null-object引入null对象) + * [8. Introduce Assertion(引入断言)](#8-introduce-assertion引入断言) +* [第å��ç«  简化函数调用](#第å��ç« -简化函数调用) + * [1. Rename Method(函数改å��)](#1-rename-method函数改å��) + * [2. Add Parameter(添加å�‚数)](#2-add-parameter添加å�‚æ•°) + * [3. Remove Parameter(移除å�‚数)](#3-remove-parameter移除å�‚æ•°) + * [4. Separate Query from Modifier(将查询函数和修改函数分离)](#4-separate-query-from-modifier将查询函数和修改函数分离) + * [5. Parameterize Method(令函数æ�ºå¸¦å�‚数)](#5-parameterize-method令函数æ�ºå¸¦å�‚æ•°) + * [6. Replace Parameter with Explicit Methods(以明确函数å�–代å�‚数)](#6-replace-parameter-with-explicit-methods以明确函数å�–代å�‚æ•°) + * [7. Preserve Whole Object(ä¿�æŒ�对象完整)](#7-preserve-whole-objectä¿�æŒ�对象完整) + * [8. Replace Parameter with Methods(以函数å�–代å�‚数)](#8-replace-parameter-with-methods以函数å�–代å�‚æ•°) + * [9. Introduce Parameter Object(引入å�‚数对象)](#9-introduce-parameter-object引入å�‚数对象) + * [10. Remove Setting Method(移除设值函数)](#10-remove-setting-method移除设值函数) + * [11. Hide Method(éš�è—�函数)](#11-hide-methodéš�è—�函数) + * [12. Replace Constructor with Factory Method (以工厂函数å�–代构造函数)](#12-replace-constructor-with-factory-method-以工厂函数å�–代构造函数) + * [13. Encapsulate Downcast(å°�装å�‘下转型)](#13-encapsulate-downcastå°�装å�‘下转型) + * [14. Replace Error Code with Exception (以异常å�–代错误ç �)](#14-replace-error-code-with-exception-以异常å�–代错误ç �) + * [15. Replace Exception with Test(以测试å�–代异常)](#15-replace-exception-with-test以测试å�–代异常) +* [第å��一章 处ç�†æ¦‚括关系](#第å��一章-处ç�†æ¦‚括关系) + * [1. Pull Up Field(字段上移)](#1-pull-up-field字段上移) + * [2. Pull Up Method(函数上移)](#2-pull-up-method函数上移) + * [3. Pull Up Constructor Body(构造函数本体上移)](#3-pull-up-constructor-body构造函数本体上移) + * [4. Push Down Method(函数下移)](#4-push-down-method函数下移) + * [5. Push Down Field(字段下移)](#5-push-down-field字段下移) + * [6. Extract Subclass(æ��炼å­�类)](#6-extract-subclassæ��炼å­�ç±») + * [7. Extract Superclass(æ��炼超类)](#7-extract-superclassæ��炼超类) + * [8. Extract Interface(æ��炼接å�£ï¼‰](#8-extract-interfaceæ��炼接å�£) + * [9. Collapse Hierarchy(折å� ç»§æ‰¿ä½“系)](#9-collapse-hierarchy折å� ç»§æ‰¿ä½“ç³») + * [10. Form Template Method(塑造模æ�¿å‡½æ•°ï¼‰](#10-form-template-method塑造模æ�¿å‡½æ•°) + * [11. Replace Inheritance with Delegation (以委托å�–代继承)](#11-replace-inheritance-with-delegation-以委托å�–代继承) + * [12. Replace Delegation with Inheritance (以继承å�–代委托)](#12-replace-delegation-with-inheritance-以继承å�–代委托) -# µÚÒ»Õ µÚÒ»¸ö°¸Àý -Èç¹ûÄã·¢ÏÖ×Ô¼ºÐèҪΪ³ÌÐòÌí¼ÓÒ»¸öÌØÐÔ£¬¶ø´úÂë½á¹¹Ê¹ÄãÎÞ·¨ºÜ·½±ãµØ´ï³ÉÄ¿µÄ£¬ÄǾÍÏÈÖØ¹¹Õâ¸ö³ÌÐò¡£ +# 第一章 第一个案例 -ÔÚÖØ¹¹Ç°£¬ÐèÒªÏȹ¹½¨ºÃ¿É¿¿µÄ²âÊÔ»·¾³£¬È·±£°²È«µØÖع¹¡£ +如果你å�‘现自己需è¦�为程åº�添加一个特性,而代ç �结构使你无法很方便地达æˆ�目的,那就先é‡�构这个程åº�。 -ÖØ¹¹ÊÇÒÔ΢СµÄ²½·¥Ð޸ijÌÐò£¬Èç¹û·¸Ï´íÎ󣬺ÜÈÝÒ×±ã¿ÉÒÔ·¢ÏÖËü¡£ +在é‡�æž„å‰�,需è¦�先构建好å�¯é� çš„æµ‹è¯•环境,确ä¿�安全地é‡�构。 -**°¸Àý·ÖÎö** +é‡�构是以微å°�的步ä¼�修改程åº�,如果犯下错误,很容易便å�¯ä»¥å�‘现它。 -ӰƬ³ö×âµêÓ¦ÓóÌÐò£¬°üÀ¨Èý¸öÀࣺMovie¡¢Rental ºÍ Customer£¬Rental °üº¬×âÁÞµÄ Movie ÒÔ¼°ÌìÊý¡£ +**案例分æž�** -![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/a758c8b2-0ac7-438f-90c2-3923ffad6328.png) +影片出租店应用程åº�,包括三个类:Movieã€�Rental å’Œ Customer,Rental 包å�«ç§Ÿèµ�çš„ Movie 以å�Šå¤©æ•°ã€‚ -×ʼµÄʵÏÖÊǰÑËùÓеļƷѴúÂë¶¼·ÅÔÚ Customer ÀàÖУ¬Ôڱ仯·¢Éúʱ£¬ÐèÒª¶ÔÕⲿ·Ö´úÂë½øÐиü¸Ä¡£±¾°¸ÀýÖпÉÄÜ·¢ÉúµÄ±ä»¯ÓУºÒ»ÖÖÀà±ðµÄ¼Æ·Ñ·½Ê½·¢Éú¸Ä±ä£»Ìí¼ÓеĵçÓ°Àà±ð¡£¿¼Âǵ½¼Æ·Ñ´úÂë¿ÉÄÜ´æÔÚÓÚ¶à´¦£¬Ò»µ©·¢Éú¸Ä±äʱ£¬¾ÍÐèÒª¶ÔËùÓмƷѴúÂë½øÐÐÐ޸ġ£ +![](https://github.com/CyC2018/InterviewNotes/blob/master/pics//a758c8b2-0ac7-438f-90c2-3923ffad6328.png) -![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/9e5e3cc6-3107-4051-b584-8ff077638fe6.png) +最开始的实现是把所有的计费代ç �都放在 Customer 类中,在å�˜åŒ–å�‘生时,需è¦�对这部分代ç �进行更改。本案例中å�¯èƒ½å�‘生的å�˜åŒ–有:一ç§�类别的计费方å¼�å�‘生改å�˜ï¼›æ·»åŠ æ–°çš„ç”µå½±ç±»åˆ«ã€‚è€ƒè™‘åˆ°è®¡è´¹ä»£ç �å�¯èƒ½å­˜åœ¨äºŽå¤šå¤„,一旦å�‘生改å�˜æ—¶ï¼Œå°±éœ€è¦�对所有计费代ç �进行修改。 -ÒÔÏÂÊǼ̳РMovie µÄ¶à̬·½°¸¡£µ«ÊÇÓÉÓÚÒ»²¿ Movie µÄÀà±ð»á¶¯Ì¬¸Ä±ä£¬Òò´ËÕâÖÖ·½°¸²»¿ÉÐС£ +![](https://github.com/CyC2018/InterviewNotes/blob/master/pics//9e5e3cc6-3107-4051-b584-8ff077638fe6.png) -![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/2a502516-5d34-4eef-8f39-916298a60035.png) +以下是继承 Movie 的多æ€�方案。但是由于一部 Movie 的类别会动æ€�改å�˜ï¼Œå› æ­¤è¿™ç§�方案ä¸�å�¯è¡Œã€‚ -ÒýÈë Price À´·´Ó¦Àà±ðÐÅÏ¢£¬Í¨¹ý×éºÏµÄ·½Ê½ÔÚ Movie ÖмÓÈë Price ¶ÔÏó£¬ÕâÑùÿÖÖÀà±ðµÄ¼Æ·Ñ·½Ê½¶¼·â×°ÔÚ²»Í¬µÄ Price ×ÓÀàÖУ¬²¢ÇÒ Movie ¶ÔÏóÒ²¿ÉÒÔ¶¯Ì¬¸Ä±äÀà±ð¡£ÕâÖÖ·½Ê½¿ÉÒԺܺõØÊÊÓ¦ÉÏÊöÌáµ½µÄ±ä»¯¡£ +![](https://github.com/CyC2018/InterviewNotes/blob/master/pics//2a502516-5d34-4eef-8f39-916298a60035.png) -![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/c02a83b8-a6b9-4d00-a509-6f0516beaf5e.png) +引入 Price æ�¥å��应类别信æ�¯ï¼Œé€šè¿‡ç»„å�ˆçš„æ–¹å¼�在 Movie 中加入 Price 对象,这样æ¯�ç§�类别的计费方å¼�都å°�装在ä¸�å�Œçš„ Price å­�类中,并且 Movie 对象也å�¯ä»¥åЍæ€�改å�˜ç±»åˆ«ã€‚è¿™ç§�æ–¹å¼�å�¯ä»¥å¾ˆå¥½åœ°é€‚应上述æ��到的å�˜åŒ–。 -ÖØ¹¹ºóµÄʱÐòͼºÍÀàͼ£º +![](https://github.com/CyC2018/InterviewNotes/blob/master/pics//c02a83b8-a6b9-4d00-a509-6f0516beaf5e.png) -![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/95f4559c-3d2a-4176-b365-4fbc46c76cf1.png) +é‡�æž„å�Žçš„æ—¶åº�图和类图: -![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/293b9326-02fc-4ad8-8c79-b4a7b5ba60d3.png) +![](https://github.com/CyC2018/InterviewNotes/blob/master/pics//95f4559c-3d2a-4176-b365-4fbc46c76cf1.png) -# µÚ¶þÕÂ ÖØ¹¹Ô­Ôò +![](https://github.com/CyC2018/InterviewNotes/blob/master/pics//293b9326-02fc-4ad8-8c79-b4a7b5ba60d3.png) -ÖØ¹¹ÊǶÔÈí¼þÄÚ²¿½á¹¹µÄÒ»ÖÖµ÷Õû£¬Ä¿µÄÊÇÔÚ²»¸Ä±äÈí¼þ¿É¹Û²ìÐÐΪµÄǰÌáÏ£¬Ìá¸ßÆä¿ÉÀí½âÐÔ£¬½µµÍÆäÐ޸ijɱ¾¡£ +# 第二章 é‡�构原则 -ÖØ¹¹µÄºÃ´¦£º¸Ä½øÈí¼þÉè¼Æ£»Ê¹Èí¼þ¸üÈÝÒ×Àí½â£»°ïÖúÕÒµ½ bug£»Ìá¸ß±à³ÌËÙ¶È¡£ +é‡�构是对软件内部结构的一ç§�调整,目的是在ä¸�改å�˜è½¯ä»¶å�¯è§‚察行为的å‰�æ��下,æ��高其å�¯ç�†è§£æ€§ï¼Œé™�低其修改æˆ�本。 -Èý´Î·¨Ôò£ºµÚÒ»´Î×öij¼þÊÂʱֻ¹ÜÈ¥×ö£»µÚ¶þ´Î×öÀàËÆÊÂÇéʱ¿ÉÒÔÈ¥×ö£»µÚÈý´ÎÔÙ×öÀàËÆµÄÊ£¬¾ÍÓ¦¸ÃÖØ¹¹¡£ +é‡�构的好处:改进软件设计;使软件更容易ç�†è§£ï¼›å¸®åŠ©æ‰¾åˆ° bugï¼›æ��高编程速度。 -¼ä½Ó²ãÓëÖØ¹¹£º¼ÆËã»ú¿ÆÑ§ÖеĺܶàÎÊÌâ¿ÉÒÔͨ¹ýÔö¼ÓÒ»¸ö¼ä½Ó²ãÀ´½â¾ö£¬¼ä½Ó²ã¾ßÓÐÒÔϼÛÖµ£ºÔÊÐíÂß¼­¹²Ïí£»·Ö¿ª½âÊÍÒâͼºÍʵÏÖ£»¸ôÀë±ä»¯£»·â×°Ìõ¼þÂß¼­¡£Öع¹¿ÉÒÔÀí½âΪÔÚÊʵ±µÄλÖòåÈë¼ä½Ó²ãÒÔ¼°ÔÚ²»ÐèÒªÊ±ÒÆ³ý¼ä½Ó²ã¡£ +三次法则:第一次å�šæŸ�件事时å�ªç®¡åŽ»å�šï¼›ç¬¬äºŒæ¬¡å�šç±»ä¼¼äº‹æƒ…æ—¶å�¯ä»¥åŽ»å�šï¼›ç¬¬ä¸‰æ¬¡å†�å�šç±»ä¼¼çš„事,就应该é‡�构。 -Ð޸Ľӿڣº¿ÉÒÔ±£Áô¾É½Ó¿Ú£¬ÈþɽӿÚÈ¥µ÷ÓÃнӿڣ¬²¢ÇÒʹÓà Java ÌṩµÄ @deprecation ½«¾É½Ó¿Ú±ê¼ÇΪÆúÓᣳý·ÇÕæÓбØÒª£¬²»Òª·¢²¼½Ó¿Ú£¬²¢ÇÒ²»Òª¹ýÔç·¢²¼½Ó¿Ú¡£ +间接层与é‡�构:计算机科学中的很多问题å�¯ä»¥é€šè¿‡å¢žåŠ ä¸€ä¸ªé—´æŽ¥å±‚æ�¥è§£å†³ï¼Œé—´æŽ¥å±‚具有以下价值:å…�许逻辑共享;分开解释æ„�图和实现;隔离å�˜åŒ–ï¼›å°�装æ�¡ä»¶é€»è¾‘。é‡�æž„å�¯ä»¥ç�†è§£ä¸ºåœ¨é€‚当的ä½�ç½®æ�’入间接层以å�Šåœ¨ä¸�需è¦�时移除间接层。 -µ±ÏÖÓдúÂë¹ýÓÚ»ìÂÒʱ£¬Ó¦µ±ÖØÐ´¶ø²»ÊÇÖØ¹¹¡£Ò»¸öÕÛÖеİ취ÊÇ£¬½«´úÂë·â×°³ÉÒ»¸ö¸ö×é¼þ£¬È»ºó¶Ô¸÷¸ö×é¼þ×öÖØÐ´»òÕßÖØ¹¹µÄ¾ö¶¨¡£ +修改接å�£ï¼šå�¯ä»¥ä¿�留旧接å�£ï¼Œè®©æ—§æŽ¥å�£åŽ»è°ƒç”¨æ–°æŽ¥å�£ï¼Œå¹¶ä¸”使用 Java æ��供的 @deprecation 将旧接å�£æ ‡è®°ä¸ºå¼ƒç”¨ã€‚除é�žçœŸæœ‰å¿…è¦�,ä¸�è¦�å�‘布接å�£ï¼Œå¹¶ä¸”ä¸�è¦�过早å�‘布接å�£ã€‚ -Èí¼þ¿ª·¢ÎÞ·¨Ô¤ÏÈÉè¼Æ£¬ÒòΪ¿ª·¢¹ý³ÌÓкܶà±ä»¯·¢Éú£¬ÔÚ×ʼ²»¿ÉÄܶ¼°ÑËùÓÐÇé¿ö¿¼ÂǽøÈ¥¡£Öع¹¿ÉÒÔ¼ò»¯Éè¼Æ£¬Öع¹ÔÚÒ»¸ö¼òµ¥µÄÉè¼ÆÉϽøÐÐÐÞÐ޸ĸ쬵±±ä»¯·¢Éúʱ£¬ÒÔÒ»ÖÖÁé»îµÄ·½Ê½È¥Ó¦¶Ô±ä»¯£¬½ø¶ø´øÀ´¸üºÃµÄÉè¼Æ¡£ +当现有代ç �过于混乱时,应当é‡�写而ä¸�是é‡�构。一个折中的办法是,将代ç �å°�装æˆ�一个个组件,然å�Žå¯¹å�„个组件å�šé‡�写或者é‡�构的决定。 -ΪÁËÈí´úÂë¸üÈÝÒ×Àí½â£¬Öع¹¿ÉÄܻᵼÖÂÐÔÄܼõµÍ¡£ÔÚ±àд´úÂëʱ£¬²»ÓöÔÐÔÄܹý¶à¹Ø×¢£¬Ö»ÓÐÔÚ×îºóÐÔÄÜÓÅ»¯½×¶ÎÔÙ¿¼ÂÇÐÔÄÜÎÊÌâ¡£Ó¦µ±Ö»¹Ø×¢¹Ø¼ü´úÂëµÄÐÔÄÜ£¬ÒòΪֻÓÐһС²¿·ÖµÄ´úÂëÊǹؼü´úÂë¡£ +软件开å�‘无法预先设计,因为开å�‘过程有很多å�˜åŒ–å�‘生,在最开始ä¸�å�¯èƒ½éƒ½æŠŠæ‰€æœ‰æƒ…况考虑进去。é‡�æž„å�¯ä»¥ç®€åŒ–设计,é‡�构在一个简å�•的设计上进行修修改改,当å�˜åŒ–å�‘生时,以一ç§�ç�µæ´»çš„æ–¹å¼�去应对å�˜åŒ–,进而带æ�¥æ›´å¥½çš„设计。 -# µÚÈýÕ ´úÂëµÄ»µÎ¶µÀ +为了软代ç �更容易ç�†è§£ï¼Œé‡�æž„å�¯èƒ½ä¼šå¯¼è‡´æ€§èƒ½å‡�低。在编写代ç �时,ä¸�用对性能过多关注,å�ªæœ‰åœ¨æœ€å�Žæ€§èƒ½ä¼˜åŒ–阶段å†�考虑性能问题。应当å�ªå…³æ³¨å…³é”®ä»£ç �的性能,因为å�ªæœ‰ä¸€å°�部分的代ç �是关键代ç �。 -## 1. Duplicated Code£¨Öظ´´úÂ룩 +# 第三章 代ç �çš„å��味é�“ -ͬһ¸öÀàµÄÁ½¸öº¯ÊýÓÐÏàͬ±í´ïʽ£¬ÔòÓà Extract Method ÌáÈ¡³öÖØ¸´´úÂ룻 +## 1. Duplicated Code(é‡�å¤�代ç �) -Á½¸ö»¥ÎªÐֵܵÄ×ÓÀຬÓÐÏàͬµÄ±í´ïʽ£¬ÏÈʹÓà Extract Method£¬È»ºó°ÑÌáÈ¡³öÀ´µÄº¯Êý Pull Up Method ÍÆÈ볬Àà¡£ +å�Œä¸€ä¸ªç±»çš„两个函数有相å�Œè¡¨è¾¾å¼�,则用 Extract Method æ��å�–出é‡�å¤�代ç �ï¼› -Èç¹ûÖ»ÊDz¿·ÖÏàͬ£¬Óà Extract Method ·ÖÀë³öÏàËÆ²¿·ÖºÍ²îÒ첿·Ö£¬È»ºóʹÓà Form Template Method ÕâÖÖÄ£°å·½·¨Éè¼ÆÄ£Ê½¡£ +两个互为兄弟的å­�ç±»å�«æœ‰ç›¸å�Œçš„表达å¼�,先使用 Extract Method,然å�ŽæŠŠæ��å�–出æ�¥çš„函数 Pull Up Method 推入超类。 -Èç¹ûÁ½¸öºÁ²»Ïà¹ØµÄÀà³öÏÖÖØ¸´´úÂ룬ÔòʹÓà Extract Class ·½·¨½«Öظ´´úÂëÌáÈ¡µ½Ò»¸ö¶ÀÁ¢ÀàÖС£ +如果å�ªæ˜¯éƒ¨åˆ†ç›¸å�Œï¼Œç”¨ Extract Method 分离出相似部分和差异部分,然å�Žä½¿ç”¨ Form Template Method è¿™ç§�模æ�¿æ–¹æ³•设计模å¼�。 -## 2. Long Method£¨¹ý³¤º¯Êý£© +如果两个毫ä¸�相关的类出现é‡�å¤�代ç �,则使用 Extract Class 方法将é‡�å¤�代ç �æ��å�–到一个独立类中。 -¼ä½Ó²ãµÄ¼ÛÖµ£º½âÊÍÄÜÁ¦¡¢¹²ÏíÄÜÁ¦¡¢Ñ¡ÔñÄÜÁ¦£» +## 2. Long Method(过长函数) -·Ö½âº¯ÊýµÄÔ­Ôò£ºµ±ÐèÒªÓÃ×¢ÊÍÀ´ËµÃ÷Ò»¶Î´úÂëʱ£¬¾ÍÐèÒª°ÑÕⲿ·Ö´úÂëдÈëÒ»¸ö¶ÀÁ¢µÄº¯ÊýÖС£ +间接层的价值:解释能力ã€�共享能力ã€�选择能力; -Extract Method »á°ÑºÜ¶à²ÎÊýºÍÁÙʱ±äÁ¿¶¼µ±×ö²ÎÊý£¬¿ÉÒÔÓà Replace Temp with Query Ïû³ýÁÙʱ±äÁ¿£¬Introduce Parameter Object ºÍ Preserve Whole Object ¿ÉÒÔ½«¹ý³¤µÄ²ÎÊýÁбäµÃ¸ü¼ò½à¡£ +分解函数的原则:当需è¦�用注释æ�¥è¯´æ˜Žä¸€æ®µä»£ç �时,就需è¦�把这部分代ç �写入一个独立的函数中。 -Ìõ¼þºÍÑ­»·ÍùÍùÒ²ÐèÒªÌáÈ¡µ½Ðµĺ¯ÊýÖС£ +Extract Method 会把很多å�‚数和临时å�˜é‡�都当å�šå�‚数,å�¯ä»¥ç”¨ Replace Temp with Query 消除临时å�˜é‡�,Introduce Parameter Object å’Œ Preserve Whole Object å�¯ä»¥å°†è¿‡é•¿çš„å�‚数列å�˜å¾—更简æ´�。 -## 3. Large Class£¨¹ý´óµÄÀࣩ +æ�¡ä»¶å’Œå¾ªçŽ¯å¾€å¾€ä¹Ÿéœ€è¦�æ��å�–到新的函数中。 -¹ý´óµÄÀà×öÁ˹ý¶àÊÂÇ飬ÐèҪʹÓà Extract Class »ò Extract Subclass¡£ +## 3. Large Class(过大的类) -ÏÈÈ·¶¨¿Í»§¶ËÈçºÎʹÓÃËüÃÇ£¬È»ºóÔËÓà Extract Interface ΪÿһÖÖʹÓ÷½Ê½ÌáÈ¡³öÒ»¸ö½Ó¿Ú¡£ +过大的类å�šäº†è¿‡å¤šäº‹æƒ…,需è¦�使用 Extract Class 或 Extract Subclass。 -## 4. Long Parameter List£¨¹ý³¤µÄ²ÎÊýÁУ© +先确定客户端如何使用它们,然å�Žè¿�用 Extract Interface 为æ¯�一ç§�使用方å¼�æ��å�–出一个接å�£ã€‚ -## 5. Divergent Change£¨·¢É¢Ê½±ä»¯£© +## 4. Long Parameter List(过长的å�‚数列) -Ò»¸öÀàÊܵ½¶àÖֱ仯µÄÓ°Ï죻 +## 5. Divergent Change(å�‘æ•£å¼�å�˜åŒ–) -Õë¶ÔijÖÖÔ­ÒòµÄ±ä»¯£¬Ê¹Óà Extract Class ½«ËüÌáÁ¶µ½Ò»¸öÀàÖС£ +一个类å�—到多ç§�å�˜åŒ–的影å“�ï¼› -## 6. Shotgun Surgery£¨É¢µ¯Ê½Ð޸ģ© +针对æŸ�ç§�原因的å�˜åŒ–,使用 Extract Class 将它æ��炼到一个类中。 -Ò»¸ö±ä»¯ÒýÆð¶à¸öÀàÐ޸ģ» +## 6. Shotgun Surgery(散弹å¼�修改) -ʹÓà Move Method ºÍ Move Field °ÑËùÓÐÐèÒªÐ޸ĵشúÂë·Åµ½Í¬Ò»¸öÀàÖС£ +一个å�˜åŒ–引起多个类修改; -## 7. Feature Envy£¨ÒÀÁµÇé½á£© +使用 Move Method å’Œ Move Field 把所有需è¦�修改地代ç �放到å�Œä¸€ä¸ªç±»ä¸­ã€‚ -Ò»¸öº¯Êý¶Ôij¸öÀàµÄÐËȤ¸ßÓÚ¶Ô×Ô¼ºËù´¦ÀàµÄÐËȤ£¬Í¨³£Êǹý¶à·ÃÎÊÆäËüÀàµÄÊý¾Ý¡£ +## 7. Feature Envy(ä¾�æ�‹æƒ…结) -ʹÓà Move Method ½«ËüÒÆµ½¸ÃÈ¥µÄµØ·½£¬Èç¹û¶Ô¶à¸öÀà¶¼ÓÐ Feature Envy£¬ÏÈÓà Extract Method ÌáÈ¡³ö¶à¸öº¯Êý¡£ +一个函数对æŸ�个类的兴趣高于对自己所处类的兴趣,通常是过多访问其它类的数æ�®ã€‚ -## 8. Data Clumps£¨Êý¾ÝÄàÍÅ£© +使用 Move Method 将它移到该去的地方,如果对多个类都有 Feature Envy,先用 Extract Method æ��å�–出多个函数。 -ÓÐЩÊý¾Ý¾­³£Ò»Æð³öÏÖ£¬±ÈÈçÁ½¸öÀà¾ßÓÐÏàͬµÄ×ֶΡ¢Ðí¶àº¯ÊýÓÐÏàͬµÄ²ÎÊý¡£Ê¹Óà Extract Class ½«ËüÃÇ·ÅÔÚÒ»Æð¡£ +## 8. Data Clumps(数æ�®æ³¥å›¢ï¼‰ -## 9. Primitive Obsession£¨»ù±¾ÀàÐÍÆ«Ö´£© +有些数æ�®ç»�常一起出现,比如两个类具有相å�Œçš„字段ã€�许多函数有相å�Œçš„å�‚数。使用 Extract Class 将它们放在一起。 -ʹÓÃÀàÍùÍù±ÈʹÓûù±¾ÀàÐ͸üºÃ£¬Ê¹Óà Replace Data Value with Object ½«Êý¾ÝÖµÌæ»»Îª¶ÔÏó¡£ +## 9. Primitive Obsession(基本类型å��执) -## 10. Switch Statements£¨switch ¾ªã¤ÏÖÉí£© +使用类往往比使用基本类型更好,使用 Replace Data Value with Object 将数æ�®å€¼æ›¿æ�¢ä¸ºå¯¹è±¡ã€‚ -## 11. Parallel Inheritance Hierarchies£¨Æ½Ðм̳ÐÌåϵ£© +## 10. Switch Statements(switch 惊悚现身) -ÿµ±ÎªÄ³¸öÀàÔö¼ÓÒ»¸ö×ÓÀ࣬±ØÐëҲΪÁíÒ»¸öÀàÏàÓ¦Ôö¼ÓÒ»¸ö×ÓÀà¡£ +## 11. Parallel Inheritance Hierarchies(平行继承体系) -ÕâÖÖ½á¹û»á´øÀ´Ò»Ð©Öظ´ÐÔ£¬Ïû³ýÖØ¸´ÐÔµÄÒ»°ã²ßÂÔ£ºÈÃÒ»¸ö¼Ì³ÐÌåϵµÄʵÀýÒýÓÃÁíÒ»¸ö¼Ì³ÐÌåϵµÄʵÀý¡£ +æ¯�当为æŸ�个类增加一个å­�类,必须也为å�¦ä¸€ä¸ªç±»ç›¸åº”增加一个å­�类。 -## 12. Lazy Class£¨ÈßÓàÀࣩ +è¿™ç§�结果会带æ�¥ä¸€äº›é‡�å¤�性,消除é‡�å¤�性的一般策略:让一个继承体系的实例引用å�¦ä¸€ä¸ªç»§æ‰¿ä½“系的实例。 -Èç¹ûÒ»¸öÀàûÓÐ×ö×ã¹»¶àµÄ¹¤×÷£¬¾ÍÓ¦¸ÃÏûʧ¡£ +## 12. Lazy Class(冗余类) -## 13. Speculative Generality£¨¿ä¿äÆä̸δÀ´ÐÔ£© +如果一个类没有å�šè¶³å¤Ÿå¤šçš„工作,就应该消失。 -ÓÐЩÄÚÈÝÊÇÓÃÀ´´¦ÀíδÀ´¿ÉÄÜ·¢ÉúµÄ±ä»¯£¬µ«ÊÇÍùÍù»áÔì³ÉϵͳÄÑÒÔÀí½âºÍά»¤£¬²¢ÇÒÔ¤²âδÀ´¿ÉÄÜ·¢ÉúµÄ¸Ä±äºÜ¿ÉÄܺÍ×ʼµÄÉèÏëÏà·´¡£Òò´Ë£¬Èç¹û²»ÊDZØÒª£¬¾Í²»ÒªÕâô×ö¡£ +## 13. Speculative Generality(夸夸其谈未æ�¥æ€§ï¼‰ -## 14. Temporary Field£¨ÁîÈËÃÔ»óµÄÔÝʱ×ֶΣ© +有些内容是用æ�¥å¤„ç�†æœªæ�¥å�¯èƒ½å�‘生的å�˜åŒ–,但是往往会造æˆ�系统难以ç�†è§£å’Œç»´æŠ¤ï¼Œå¹¶ä¸”预测未æ�¥å�¯èƒ½å�‘生的改å�˜å¾ˆå�¯èƒ½å’Œæœ€å¼€å§‹çš„设想相å��。因此,如果ä¸�是必è¦�,就ä¸�è¦�这么å�šã€‚ -ij¸ö×ֶνöΪijÖÖÌØ¶¨Çé¿ö¶øÉ裬ÕâÑùµÄ´úÂë²»Ò×Àí½â£¬ÒòΪͨ³£ÈÏΪ¶ÔÏóÔÚËùÓÐʱºò¶¼ÐèÒªËüµÄËùÓÐ×ֶΡ£ +## 14. Temporary Field(令人迷惑的暂时字段) -°ÑÕâÖÖ×ֶκÍÌØ¶¨Çé¿öµÄ´¦Àí²Ù×÷ʹÓà Extract Class ÌáÁ¶µ½Ò»¸ö¶ÀÁ¢ÀàÖС£ +æŸ�个字段仅为æŸ�ç§�特定情况而设,这样的代ç �ä¸�易ç�†è§£ï¼Œå› ä¸ºé€šå¸¸è®¤ä¸ºå¯¹è±¡åœ¨æ‰€æœ‰æ—¶å€™éƒ½éœ€è¦�它的所有字段。 -## 15. Message Chains£¨¹ý¶ÈñîºÏµÄÏûÏ¢Á´£© +把这ç§�字段和特定情况的处ç�†æ“�作使用 Extract Class æ��炼到一个独立类中。 -Ò»¸ö¶ÔÏóÇëÇóÁíÒ»¸ö¶ÔÏó£¬È»ºóÔÙÏòºóÕßÇëÇóÁíÒ»¸ö¶ÔÏó£¬È»ºó...£¬Õâ¾ÍÊÇÏûÏ¢Á´¡£²ÉÓÃÕâÖÖ·½Ê½£¬Òâζ×ſͻ§´úÂ뽫Óë¶ÔÏó¼äµÄ¹ØÏµ½ôÃÜñîºÏ¡£ +## 15. Message Chains(过度耦å�ˆçš„æ¶ˆæ�¯é“¾ï¼‰ -¸ÄÓú¯ÊýÁ´£¬Óú¯ÊýίÍÐÁíÒ»¸ö¶ÔÏóÀ´´¦Àí¡£ +一个对象请求å�¦ä¸€ä¸ªå¯¹è±¡ï¼Œç„¶å�Žå†�å�‘å�Žè€…请求å�¦ä¸€ä¸ªå¯¹è±¡ï¼Œç„¶å�Ž...,这就是消æ�¯é“¾ã€‚采用这ç§�æ–¹å¼�,æ„�味ç�€å®¢æˆ·ä»£ç �将与对象间的关系紧密耦å�ˆã€‚ -## 16. Middle Man£¨ÖмäÈË£© +改用函数链,用函数委托å�¦ä¸€ä¸ªå¯¹è±¡æ�¥å¤„ç�†ã€‚ -ÖмäÈ˸ºÔð´¦ÀíίÍиøËüµÄ²Ù×÷£¬Èç¹ûÒ»¸öÀàÖÐÓйý¶àµÄº¯Êý¶¼Î¯ÍиøÆäËüÀ࣬ÄǾÍÊǹý¶ÈÔËÓÃίÍУ¬Ó¦µ± Remove Middle Man£¬Ö±½ÓÓ븺ÔðµÄ¶ÔÏó´ò½»µÀ¡£ +## 16. Middle Man(中间人) -## 17. Inappropriate Intimacy£¨áòêǹØÏµ£© +中间人负责处ç�†å§”托给它的æ“�作,如果一个类中有过多的函数都委托给其它类,那就是过度è¿�用委托,应当 Remove Middle Man,直接与负责的对象打交é�“。 -Á½¸öÀà¶àÓÚÇ×ÃÜ£¬»¨·ÑÌ«¶àʱ¼äȥ̽ÌÖ±Ë´ËµÄ private ³É·Ö¡£ +## 17. Inappropriate Intimacy(狎昵关系) -## 18. Alernative Classes with Different Interfaces£¨ÒìÇúͬ¹¤µÄÀࣩ +两个类多于亲密,花费太多时间去探讨彼此的 private æˆ�分。 -## 19. Incomplete Library Class£¨²»ÍêÃÀµÄÀà¿â£© +## 18. Alernative Classes with Different Interfaces(异曲å�Œå·¥çš„类) -Àà¿âµÄÉè¼ÆÕß²»¿ÉÄÜÉè¼Æ³öÍêÃÀµÄÀà¿â£¬µ±ÎÒÃÇÐèÒª¶ÔÀà¿â½øÐÐһЩÐÞ¸Äʱ£¬¿ÉÒÔʹÓÃÒÔÏÂÁ½ÖÖ·½·¨£ºÈç¹ûÖ»ÊÇÐÞ¸ÄÒ»Á½¸öº¯Êý£¬Ê¹Óà Introduce Foreign Method£»Èç¹ûÒªÌí¼ÓÒ»´ó¶Ñ¶îÍâÐÐΪ£¬Ê¹Óà Introduce Local Extension¡£ +## 19. Incomplete Library Class(ä¸�完美的类库) -## 20. Data Class£¨Ó×ÖɵÄÊý¾ÝÀࣩ +类库的设计者ä¸�å�¯èƒ½è®¾è®¡å‡ºå®Œç¾Žçš„类库,当我们需è¦�对类库进行一些修改时,å�¯ä»¥ä½¿ç”¨ä»¥ä¸‹ä¸¤ç§�方法:如果å�ªæ˜¯ä¿®æ”¹ä¸€ä¸¤ä¸ªå‡½æ•°ï¼Œä½¿ç”¨ Introduce Foreign Method;如果è¦�添加一大堆é¢�外行为,使用 Introduce Local Extension。 -ËüÖ»ÓµÓÐһЩÊý¾Ý×ֶΡ£ +## 20. Data Class(幼稚的数æ�®ç±»ï¼‰ -ÕÒ³ö×Ö¶ÎʹÓõĵط½£¬È»ºó°ÑÏàÓ¦µÄ²Ù×÷ÒÆµ½ Data Class ÖС£ +它å�ªæ‹¥æœ‰ä¸€äº›æ•°æ�®å­—段。 -## 21. Refused Bequest£¨±»¾Ü¾øµÄÀ¡Ôù£© +找出字段使用的地方,然å�ŽæŠŠç›¸åº”çš„æ“�作移到 Data Class 中。 -×ÓÀà¼Ì³Ð³¬ÀàµÄËùÓк¯ÊýºÍÊý¾Ý£¬µ«ÊÇËüÖ»ÏëÒªÒ»²¿·Ö¡£ +## 21. Refused Bequest(被拒ç»�的馈赠) -Ϊ×ÓÀàн¨Ò»¸öÐÖµÜÀ࣬²»ÐèÒªµÄº¯Êý»òÊý¾ÝʹÓà Push Down Method ºÍ Push Down Field ÏÂÍÆ¸øÄǸöÐֵܡ£ +å­�类继承超类的所有函数和数æ�®ï¼Œä½†æ˜¯å®ƒå�ªæƒ³è¦�一部分。 -## 22. Comments£¨¹ý¶àµÄ×¢ÊÍ£© +为å­�类新建一个兄弟类,ä¸�需è¦�的函数或数æ�®ä½¿ç”¨ Push Down Method å’Œ Push Down Field 下推给那个兄弟。 -ʹÓà Extract Method ÌáÁ¶³öÐèҪעÊ͵IJ¿·Ö£¬È»ºóÓú¯ÊýÃûÀ´½âÊͺ¯ÊýµÄÐÐΪ¡£ +## 22. Comments(过多的注释) -# µÚËÄÕ ¹¹Öþ²âÊÔÌåϵ +使用 Extract Method æ��炼出需è¦�注释的部分,然å�Žç”¨å‡½æ•°å��æ�¥è§£é‡Šå‡½æ•°çš„行为。 -Java ¿ÉÒÔʹÓà Junit ½øÐе¥Ôª²âÊÔ¡£ +# 第四章 构筑测试体系 -µ¥Ôª²âÊԵĶÔÏóÊÇÀàµÄ·½·¨£¬¶ø¹¦ÄܲâÒÔ¿Í»§µÄ½Ç¶È±£Ö¤Èí¼þÕý³£ÔËÐС£ +Java å�¯ä»¥ä½¿ç”¨ Junit 进行å�•元测试。 -Ó¦µ±¼¯ÖвâÊÔ¿ÉÄܳö´íµÄ±ß½çÌõ¼þ¡£ +å�•元测试的对象是类的方法,而功能测以客户的角度ä¿�è¯�软件正常è¿�行。 -# µÚÎåÕÂ ÖØ¹¹Áбí +应当集中测试å�¯èƒ½å‡ºé”™çš„边界æ�¡ä»¶ã€‚ -С²½Ç°½ø£¬Æµ·±²âÊÔ¡£ +# 第五章 é‡�构列表 -# µÚÁùÕÂ ÖØÐÂ×éÖ¯º¯Êý +å°�æ­¥å‰�进,频ç¹�测试。 -## 1. Extract Method£¨ÌáÁ¶º¯Êý£© +# 第六章 é‡�新组织函数 -½«Õâ¶Î´úÂë·Å½øÒ»¸ö¶ÀÁ¢º¯ÊýÖУ¬²¢Èú¯ÊýÃû³Æ½âÊ͸ú¯ÊýµÄÓÃ;¡£ +## 1. Extract Method(æ��炼函数) -## 2. Inline Method£¨ÄÚÁªº¯Êý£© +将这段代ç �放进一个独立函数中,并让函数å��称解释该函数的用途。 -Ò»¸öº¯ÊýµÄ±¾ÌåÓëÃû³ÆÍ¬ÑùÇå³þÒ×¶®¡£ +## 2. Inline Method(内è�”函数) -ÔÚº¯Êýµ÷Óõã²åÈ뺯Êý±¾Ì壬ȻºóÒÆ³ý¸Ãº¯Êý¡£ +一个函数的本体与å��ç§°å�Œæ ·æ¸…楚易懂。 -## 3. Inline Temp£¨ÄÚÁªÁÙʱ±äÁ¿£© +在函数调用点æ�’入函数本体,然å�Žç§»é™¤è¯¥å‡½æ•°ã€‚ -Ò»¸öÁÙʱ±äÁ¿£¬Ö»±»¼òµ¥±í´ïʽ¸³ÖµÒ»´Î£¬¶øËü·Á°­ÁËÆäËüÖØ¹¹ÊÖ·¨¡£ +## 3. Inline Temp(内è�”临时å�˜é‡�) -½«ËùÓжԸñäÁ¿µÄÒýÓÃÌæ»»Îª¶ÔËü¸³ÖµµÄÄǸö±í´ïʽ×ÔÉí¡£ +一个临时å�˜é‡�,å�ªè¢«ç®€å�•表达å¼�赋值一次,而它妨ç¢�了其它é‡�构手法。 + +将所有对该å�˜é‡�的引用替æ�¢ä¸ºå¯¹å®ƒèµ‹å€¼çš„那个表达å¼�自身。 ```java double basePrice = anOrder.basePrice(); @@ -305,9 +306,9 @@ return basePrice > 1000; return anOrder.basePrice() > 1000; ``` -## 4. Replace Temp with Query£¨ÒÔ²éѯȡ´úÁÙʱ±äÁ¿£© +## 4. Replace Temp with Query(以查询å�–代临时å�˜é‡�) -ÒÔÁÙʱ±äÁ¿±£´æÄ³Ò»±í´ïʽµÄÔËËã½á¹û£¬½«Õâ¸ö±í´ïʽÌáÁ¶µ½Ò»¸ö¶ÀÁ¢º¯ÊýÖУ¬½«ËùÓжÔÁÙʱ±äÁ¿µÄÒýÓõãÌæ»»Îª¶Ôк¯ÊýµÄµ÷Óá£Replace Temp with Query ÍùÍùÊÇ Extract Method ֮ǰ±Ø²»¿ÉÉÙµÄÒ»¸ö²½Ö裬ÒòΪ¾Ö²¿±äÁ¿»áʹ´úÂëÄÑÒÔÌáÁ¶¡£ +以临时å�˜é‡�ä¿�å­˜æŸ�一表达å¼�çš„è¿�算结果,将这个表达å¼�æ��炼到一个独立函数中,将所有对临时å�˜é‡�的引用点替æ�¢ä¸ºå¯¹æ–°å‡½æ•°çš„调用。Replace Temp with Query 往往是 Extract Method 之å‰�å¿…ä¸�å�¯å°‘的一个步骤,因为局部å�˜é‡�会使代ç �难以æ��炼。 ```java double basePrice = quantity * itemPrice; @@ -329,9 +330,9 @@ double basePrice(){ } ``` -## 5. Introduce Explaining Variable£¨ÒýÆð½âÊͱäÁ¿£© +## 5. Introduce Explaining Variable(引起解释å�˜é‡�) -½«¸´ÔÓ±í´ïʽ£¨»òÆäÖÐÒ»²¿·Ö£©µÄ½á¹û·Å½øÒ»¸öÁÙʱ±äÁ¿£¬ÒԴ˱äÁ¿Ãû³ÆÀ´½âÊͱí´ïʽÓÃ;¡£ +å°†å¤�æ�‚表达å¼�(或其中一部分)的结果放进一个临时å�˜é‡�,以此å�˜é‡�å��ç§°æ�¥è§£é‡Šè¡¨è¾¾å¼�用途。 ```java if((platform.toUpperCase().indexOf("MAC") > -1) && @@ -351,15 +352,15 @@ if(isMacOS && isIEBrower && wasInitialized() && wasResized) { } ``` -## 6. Split Temporary Variable£¨·Ö½âÁÙʱ±äÁ¿£© +## 6. Split Temporary Variable(分解临时å�˜é‡�) -ij¸öÁÙʱ±äÁ¿±»¸³Öµ³¬¹ýÒ»´Î£¬Ëü¼È²»ÊÇÑ­»·±äÁ¿£¬Ò²²»ÊÇÓÃÓÚÊÕ¼¯¼ÆËã½á¹û¡£ +æŸ�个临时å�˜é‡�被赋值超过一次,它既ä¸�是循环å�˜é‡�,也ä¸�是用于收集计算结果。 -Õë¶Ôÿ´Î¸³Öµ£¬´´ÔìÒ»¸ö¶ÀÁ¢¡¢¶ÔÓ¦µÄÁÙʱ±äÁ¿£¬Ã¿¸öÁÙʱ±äÁ¿Ö»³Ðµ£Ò»¸öÔðÈΡ£ +针对æ¯�次赋值,创造一个独立ã€�对应的临时å�˜é‡�,æ¯�个临时å�˜é‡�å�ªæ‰¿æ‹…一个责任。 -## 7. Remove Assigments to Parameters£¨ÒƳý¶Ô²ÎÊýµÄ¸³Öµ£© +## 7. Remove Assigments to Parameters(移除对å�‚数的赋值) -ÒÔÒ»¸öÁÙʱ±äÁ¿È¡´ú¶Ô¸Ã²ÎÊýµÄ¸³Öµ¡£ +以一个临时å�˜é‡�å�–代对该å�‚数的赋值。 ```java int discount (int inputVal, int quentity, int yearToDate){ @@ -372,39 +373,39 @@ int discount (int inputVal, int quentity, int yearToDate){ if (inputVal > 50) result -= 2; ``` -## 8. Replace Method with Method Object£¨ÒÔº¯Êý¶ÔÏóÈ¡´úº¯Êý£© +## 8. Replace Method with Method Object(以函数对象å�–代函数) -µ±¶ÔÒ»¸ö´óÐͺ¯Êý²ÉÓà Extract Method ʱ£¬ÓÉÓÚ°üº¬Á˾ֲ¿±äÁ¿Ê¹µÃºÜÄѽøÐиòÙ×÷¡£ +当对一个大型函数采用 Extract Method 时,由于包å�«äº†å±€éƒ¨å�˜é‡�使得很难进行该æ“�作。 -½«Õâ¸öº¯Êý·Å½øÒ»¸öµ¥¶À¶ÔÏóÖУ¬Èç´ËÒ»À´¾Ö²¿±äÁ¿¾Í³ÉÁ˶ÔÏóÄÚµÄ×ֶΡ£È»ºó¿ÉÒÔÔÚͬһ¸ö¶ÔÏóÖн«Õâ¸ö´óÐͺ¯Êý·Ö½âΪ¶à¸öСÐͺ¯Êý¡£ +将这个函数放进一个å�•独对象中,如此一æ�¥å±€éƒ¨å�˜é‡�å°±æˆ�了对象内的字段。然å�Žå�¯ä»¥åœ¨å�Œä¸€ä¸ªå¯¹è±¡ä¸­å°†è¿™ä¸ªå¤§åž‹å‡½æ•°åˆ†è§£ä¸ºå¤šä¸ªå°�型函数。 -## 9. Subsititute Algorithn£¨Ìæ»»Ëã·¨£© +## 9. Subsititute Algorithn(替æ�¢ç®—法) -# µÚÆßÕ ÔÚ¶ÔÏóÖ®¼ä°áÒÆÌØÐÔ +# 第七章 在对象之间æ�¬ç§»ç‰¹æ€§ -## 1. Move Method£¨°áÒÆº¯Êý£© +## 1. Move Method(æ�¬ç§»å‡½æ•°ï¼‰ -ÀàÖеÄij¸öº¯ÊýÓëÁíÒ»¸öÀà½øÐиü¶à½»Á÷£ºµ÷ÓúóÕß»òÕß±»ºóÕßµ÷Óᣠ+类中的æŸ�个函数与å�¦ä¸€ä¸ªç±»è¿›è¡Œæ›´å¤šäº¤æµ�:调用å�Žè€…或者被å�Žè€…调用。 -½«Õâ¸öº¯Êý°áÒÆµ½ÁíÒ»¸öÀàÖС£ +将这个函数æ�¬ç§»åˆ°å�¦ä¸€ä¸ªç±»ä¸­ã€‚ -## 2. Move Field£¨°áÒÆ×ֶΣ© +## 2. Move Field(æ�¬ç§»å­—段) -ÀàÖеÄij¸ö×ֶα»ÁíÒ»¸öÀà¸ü¶àµØÓõ½£¬ÕâÀïµÄÓõ½ÊÇÖ¸µ÷ÓÃȡֵÉèÖµº¯Êý£¬Ó¦µ±°Ñ¸Ã×Ö¶ÎÒÆµ½ÁíÒ»¸öÀàÖС£ +类中的æŸ�个字段被å�¦ä¸€ä¸ªç±»æ›´å¤šåœ°ç”¨åˆ°ï¼Œè¿™é‡Œçš„用到是指调用å�–值设值函数,应当把该字段移到å�¦ä¸€ä¸ªç±»ä¸­ã€‚ -## 3. Extract Class£¨ÌáÁ¶Àࣩ +## 3. Extract Class(æ��炼类) -ij¸öÀà×öÁËÓ¦µ±ÓÉÁ½¸öÀà×öµÄÊ¡£ +æŸ�个类å�šäº†åº”当由两个类å�šçš„事。 -Ó¦µ±½¨Á¢Ò»¸öÐÂÀ࣬½«Ïà¹ØµÄ×ֶκͺ¯Êý´Ó¾ÉÀà°áÒÆµ½ÐÂÀà¡£ +应当建立一个新类,将相关的字段和函数从旧类æ�¬ç§»åˆ°æ–°ç±»ã€‚ -## 4. Inline Class£¨½«ÀàÄÚÁª»¯£© +## 4. Inline Class(将类内è�”化) -Óë Extract Class Ïà·´¡£ +与 Extract Class 相å��。 -## 5. Hide Delegate£¨Òþ²Ø¡°Î¯ÍйØÏµ¡±£© +## 5. Hide Delegate(éš�è—�“委托关系â€�) -½¨Á¢ËùÐèµÄº¯Êý£¬Òþ²ØÎ¯ÍйØÏµ¡£ +建立所需的函数,éš�è—�委托关系。 ```java class Person{ @@ -424,13 +425,13 @@ class Department{ } ``` -Èç¹û¿Í»§Ï£ÍûÖªµÀijÈ˵ľ­ÀíÊÇË­£¬±ØÐë»ñµÃ Department ¶ÔÏó£¬ÕâÑù¾Í¶Ô¿Í»§½Ò¶ÁË Department µÄ¹¤×÷Ô­Àí¡£ +如果客户希望知é�“æŸ�人的ç»�ç�†æ˜¯è°�,必须获得 Department 对象,这样就对客户æ�­éœ²äº† Department 的工作原ç�†ã€‚ ```java Person manager = john.getDepartment().getManager(); ``` -ͨ¹ýΪ Peron ½¨Á¢Ò»¸öº¯ÊýÀ´Òþ²ØÕâÖÖίÍйØÏµ¡£ +通过为 Peron 建立一个函数æ�¥éš�è—�è¿™ç§�委托关系。 ```java public Person getManager(){ @@ -438,61 +439,61 @@ public Person getManager(){ } ``` -## 6. Remove Middle Man£¨ÒƳýÖмäÈË£© +## 6. Remove Middle Man(移除中间人) -Óë Hide Delegate Ïà·´£¬±¾·½·¨ÐèÒªÒÆ³ýίÍк¯Êý£¬Èÿͻ§Ö±½Óµ÷ÓÃίÍÐÀà¡£ +与 Hide Delegate 相å��,本方法需è¦�移除委托函数,让客户直接调用委托类。 -Hide Delegate ÓкܴóºÃ´¦£¬µ«ÊÇËüµÄ´ú¼ÛÊÇ£ºÃ¿µ±¿Í»§ÒªÊ¹ÓÃÊÜÍÐÀàµÄÐÂÌØÐÔʱ£¬¾Í±ØÐëÔÚ·þÎñÆ÷¶ËÌí¼ÓÒ»¸ö¼òµ¥µÄίÍк¯Êý¡£Ëæ×ÅÊÜίÍеÄÌØÐÔÔ½À´Ô½¶à£¬·þÎñÆ÷ÀàÍêÈ«±ä³ÉÁËÒ»¸ö¡°ÖмäÈË¡±¡£ +Hide Delegate 有很大好处,但是它的代价是:æ¯�当客户è¦�使用å�—托类的新特性时,就必须在æœ�务器端添加一个简å�•的委托函数。éš�ç�€å�—委托的特性越æ�¥è¶Šå¤šï¼Œæœ�务器类完全å�˜æˆ�了一个“中间人â€�。 -## 7. Introduce Foreign Method£¨ÒýÈëÍâ¼Óº¯Êý£© +## 7. Introduce Foreign Method(引入外加函数) -ÐèҪΪÌṩ·þÎñµÄÀàÌí¼ÓÒ»¸öº¯Êý£¬µ«ÊÇÎÞ·¨ÐÞ¸ÄÕâ¸öÀà¡£ +需è¦�为æ��ä¾›æœ�务的类添加一个函数,但是无法修改这个类。 -¿ÉÒÔÔÚ¿Í»§ÀàÖн¨Á¢Ò»¸öº¯Êý£¬²¢ÒÔµÚÒ»²ÎÊýÐÎʽ´«ÈëÒ»¸ö·þÎñÀàµÄʵÀý£¬Èÿͻ§Àà×éºÏ·þÎñÆ÷ʵÀý¡£ +å�¯ä»¥åœ¨å®¢æˆ·ç±»ä¸­å»ºç«‹ä¸€ä¸ªå‡½æ•°ï¼Œå¹¶ä»¥ç¬¬ä¸€å�‚æ•°å½¢å¼�传入一个æœ�务类的实例,让客户类组å�ˆæœ�务器实例。 -## 8. Introduce Local Extension£¨ÒýÈë±¾µØÀ©Õ¹£© +## 8. Introduce Local Extension(引入本地扩展) -ºÍ Introduce Foreign Method Ä¿µÄÒ»Ñù£¬µ«ÊÇ Introduce Local Extension ͨ¹ý½¨Á¢ÐµÄÀàÀ´ÊµÏÖ¡£ÓÐÁ½ÖÖ·½Ê½£º×ÓÀà»òÕß°ü×°À࣬×ÓÀà¾ÍÊÇͨ¹ý¼Ì³ÐʵÏÖ£¬°ü×°Àà¾ÍÊÇͨ¹ý×éºÏʵÏÖ¡£ +å’Œ Introduce Foreign Method 目的一样,但是 Introduce Local Extension 通过建立新的类æ�¥å®žçŽ°ã€‚æœ‰ä¸¤ç§�æ–¹å¼�:å­�类或者包装类,å­�类就是通过继承实现,包装类就是通过组å�ˆå®žçŽ°ã€‚ -# µÚ°ËÕÂ ÖØÐÂ×éÖ¯Êý¾Ý +# 第八章 é‡�新组织数æ�® -## 1. Self Encapsulate Field£¨×Ô·â×°×ֶΣ© +## 1. Self Encapsulate Field(自å°�装字段) -Ϊ×ֶν¨Á¢È¡Öµ/ÉèÖµº¯Êý£¬²¢ÓÃÕâЩº¯ÊýÀ´·ÃÎÊ×ֶΡ£Ö»Óе±×ÓÀàÏë·ÃÎʳ¬ÀàµÄÒ»¸ö×ֶΣ¬ÓÖÏëÔÚ×ÓÀàÖн«¶ÔÕâ¸ö×ֶηÃÎʸÄΪһ¸ö¼ÆËãºóµÄÖµ£¬²ÅʹÓÃÕâÖÖ·½Ê½£¬·ñÔòÖ±½Ó·ÃÎÊ×ֶεķ½Ê½¼ò½àÃ÷ÁË¡£ +为字段建立å�–值/设值函数,并用这些函数æ�¥è®¿é—®å­—段。å�ªæœ‰å½“å­�类想访问超类的一个字段,å�ˆæƒ³åœ¨å­�类中将对这个字段访问改为一个计算å�Žçš„值,æ‰�使用这ç§�æ–¹å¼�,å�¦åˆ™ç›´æŽ¥è®¿é—®å­—段的方å¼�简æ´�明了。 -## 2. Replace Data Value with Object£¨ÒÔ¶ÔÏóÈ¡´úÊý¾ÝÖµ£© +## 2. Replace Data Value with Object(以对象å�–代数æ�®å€¼ï¼‰ -ÔÚ¿ª·¢³õÆÚ£¬ÍùÍù»áÓüòµ¥µÄÊý¾ÝÏî±íʾ¼òµ¥µÄÇé¿ö£¬µ«ÊÇËæ×Å¿ª·¢µÄ½øÐУ¬Ò»Ð©¼òµ¥Êý¾ÝÏî»á¾ßÓÐÒ»Ð©ÌØÊâÐÐΪ¡£±ÈÈçÒ»¿ªÊ¼»á°Ñµç»°ºÅÂë´æ³É×Ö·û´®£¬µ«ÊÇËæºó·¢Ïֵ绰ºÅÂëÐèÒª¡°¸ñʽ»¯¡±¡¢¡°³éÈ¡ÇøºÅ¡±Ö®ÀàµÄÌØÊâÐÐΪ¡£ +在开å�‘åˆ�期,往往会用简å�•的数æ�®é¡¹è¡¨ç¤ºç®€å�•的情况,但是éš�ç�€å¼€å�‘的进行,一些简å�•æ•°æ�®é¡¹ä¼šå…·æœ‰ä¸€äº›ç‰¹æ®Šè¡Œä¸ºã€‚比如一开始会把电è¯�å�·ç �å­˜æˆ�字符串,但是éš�å�Žå�‘现电è¯�å�·ç �需è¦�“格å¼�化â€�ã€�“抽å�–区å�·â€�之类的特殊行为。 -## 3. Change Value to Reference£¨½«Öµ¶ÔÏó¸Ä³ÉÒýÓöÔÏó£© +## 3. Change Value to Reference(将值对象改æˆ�引用对象) -½«±Ë´ËÏàµÈµÄʵÀýÌæ»»ÎªÍ¬Ò»¸ö¶ÔÏó¡£Õâ¾ÍÒªÓÃÒ»¸ö¹¤³§À´´´½¨ÕâÖÖΨһ¶ÔÏ󣬹¤³§ÀàÖÐÐèÒª±£ÁôÒ»·ÝÒѾ­´´½¨¶ÔÏóµÄÁÐ±í£¬µ±Òª´´½¨Ò»¸ö¶ÔÏóʱ£¬ÏȲéÕÒÕâ·ÝÁбíÖÐÊÇ·ñÒѾ­´æÔڸöÔÏó£¬Èç¹û´æÔÚ£¬Ôò·µ»ØÁбíÖеÄÕâ¸ö¶ÔÏó£»·ñÔò£¬Ð½¨Ò»¸ö¶ÔÏó£¬Ìí¼Óµ½ÁбíÖУ¬²¢·µ»Ø¸Ã¶ÔÏó¡£ +将彼此相等的实例替æ�¢ä¸ºå�Œä¸€ä¸ªå¯¹è±¡ã€‚这就è¦�用一个工厂æ�¥åˆ›å»ºè¿™ç§�唯一对象,工厂类中需è¦�ä¿�留一份已ç»�创建对象的列表,当è¦�创建一个对象时,先查找这份列表中是å�¦å·²ç»�存在该对象,如果存在,则返回列表中的这个对象;å�¦åˆ™ï¼Œæ–°å»ºä¸€ä¸ªå¯¹è±¡ï¼Œæ·»åŠ åˆ°åˆ—è¡¨ä¸­ï¼Œå¹¶è¿”å›žè¯¥å¯¹è±¡ã€‚ -## 4. Change Reference to value£¨½«ÒýÓöÔÏó¸ÄΪֵ¶ÔÏó£© +## 4. Change Reference to value(将引用对象改为值对象) -ÒÔ Change Value to Reference Ïà·´¡£Öµ¶ÔÏóÓиö·Ç³£ÖØÒªµÄÌØÐÔ£ºËüÊDz»¿É±äµÄ£¬²»¿É±ä±íʾÈç¹ûÒª¸Ä±äÕâ¸ö¶ÔÏ󣬱ØÐëÓÃÒ»¸öеĶÔÏóÀ´Ìæ»»¾É¶ÔÏ󣬶ø²»ÊÇÐ޸ľɶÔÏó¡£ +以 Change Value to Reference 相å��。值对象有个é�žå¸¸é‡�è¦�的特性:它是ä¸�å�¯å�˜çš„,ä¸�å�¯å�˜è¡¨ç¤ºå¦‚æžœè¦�改å�˜è¿™ä¸ªå¯¹è±¡ï¼Œå¿…须用一个新的对象æ�¥æ›¿æ�¢æ—§å¯¹è±¡ï¼Œè€Œä¸�是修改旧对象。 -ÐèҪΪֵ¶ÔÏóʵÏÖ equals() ºÍ hashCode() ·½·¨ +需è¦�为值对象实现 equals() å’Œ hashCode() 方法 -## 5. Replace Array with Object£¨ÒÔ¶ÔÏóÈ¡´úÊý×飩 +## 5. Replace Array with Object(以对象å�–代数组) -ÓÐÒ»¸öÊý×飬ÆäÖеÄÔªËØ¸÷×Ô´ú±í²»Í¬µÄ¶«Î÷¡£ +有一个数组,其中的元素å�„自代表ä¸�å�Œçš„东西。 -ÒÔ¶ÔÏóÌæ»»Êý×飬¶ÔÓÚÊý×éÖеÄÿ¸öÔªËØ£¬ÒÔÒ»¸ö×Ö¶ÎÀ´±íʾ£¬ÕâÑù·½±ã²Ù×÷£¬Ò²¸üÈÝÒ×Àí½â¡£ +以对象替æ�¢æ•°ç»„,对于数组中的æ¯�个元素,以一个字段æ�¥è¡¨ç¤ºï¼Œè¿™æ ·æ–¹ä¾¿æ“�作,也更容易ç�†è§£ã€‚ -## 6. Duplicate Observed Data£¨¸³Öµ¡°±»¼àÊÓÊý¾Ý¡±£© +## 6. Duplicate Observed Data(赋值“被监视数æ�®â€�) -һЩÁìÓòÊý¾ÝÖÃÉíÓÚ GUI ¿Ø¼þÖУ¬¶øÁìÓòº¯ÊýÐèÒª·ÃÎÊÕâЩÊý¾Ý¡£ +一些领域数æ�®ç½®èº«äºŽ GUI 控件中,而领域函数需è¦�访问这些数æ�®ã€‚ -½«¸ÃÊý¾Ý¸³Öµµ½Ò»¸öÁìÓò¶ÔÏóÖУ¬½¨Á¢Ò»¸ö Oberver ģʽ£¬ÓÃÒÔͬ²½ÁìÓò¶ÔÏóºÍ GUI ¶ÔÏóÄÚµÄÖØ¸´Êý¾Ý¡£ +将该数æ�®èµ‹å€¼åˆ°ä¸€ä¸ªé¢†åŸŸå¯¹è±¡ä¸­ï¼Œå»ºç«‹ä¸€ä¸ª Oberver 模å¼�,用以å�Œæ­¥é¢†åŸŸå¯¹è±¡å’Œ GUI 对象内的é‡�å¤�æ•°æ�®ã€‚ -![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/e024bd7e-fb4e-4239-9451-9a6227f50b00.jpg) +![](https://github.com/CyC2018/InterviewNotes/blob/master/pics//e024bd7e-fb4e-4239-9451-9a6227f50b00.jpg) -## 7. Change Unidirectional Association to Bidirectional£¨½«µ¥Ïò¹ØÁª¸ÄΪ˫Ïò¹ØÁª£© +## 7. Change Unidirectional Association to Bidirectional(将å�•å�‘å…³è�”改为å�Œå�‘å…³è�”) -µ±Á½¸öÀà¶¼ÐèÒª¶Ô·½µÄÌØÐÔʱ£¬¿ÉÒÔʹÓÃË«Ïò¹ØÁª¡£ +当两个类都需è¦�对方的特性时,å�¯ä»¥ä½¿ç”¨å�Œå�‘å…³è�”。 -ÓÐÁ½¸öÀ࣬·Ö±ðΪ¶©µ¥ Order ºÍ¿Í»§ Customer£¬Order ÒýÓÃÁË Customer£¬Customer Ò²ÐèÒªÒýÓà Order À´²é¿´ÆäËùÓж©µ¥ÏêÇé¡£ +有两个类,分别为订å�• Order 和客户 Customer,Order 引用了 Customer,Customer 也需è¦�引用 Order æ�¥æŸ¥çœ‹å…¶æ‰€æœ‰è®¢å�•详情。 ```java class Order{ @@ -517,59 +518,59 @@ class Curstomer{ } ``` -×¢Òâµ½£¬ÕâÀïÈà Curstomer ÀàÀ´¿ØÖƹØÁª¹ØÏµ¡£ÓÐÒÔÏÂÔ­ÔòÀ´¾ö¶¨ÄĸöÀàÀ´¿ØÖƹØÁª¹ØÏµ£ºÈç¹ûij¸ö¶ÔÏóÊÇ×é³ÉÁíÒ»¸ö¶ÔÏóµÄ²¿¼þ£¬ÄÇôÓɺóÕ߸ºÔð¿ØÖƹØÁª¹ØÏµ£»Èç¹ûÊÇÒ»¶Ô¶à¹ØÏµ£¬ÔòÓɵ¥Ò»ÒýÓÃÄÇÒ»·½À´¿ØÖƹØÁª¹ØÏµ¡£ +注æ„�到,这里让 Curstomer ç±»æ�¥æŽ§åˆ¶å…³è�”关系。有以下原则æ�¥å†³å®šå“ªä¸ªç±»æ�¥æŽ§åˆ¶å…³è�”关系:如果æŸ�个对象是组æˆ�å�¦ä¸€ä¸ªå¯¹è±¡çš„部件,那么由å�Žè€…负责控制关è�”关系;如果是一对多关系,则由å�•一引用那一方æ�¥æŽ§åˆ¶å…³è�”关系。 -## 8. Change Bidirectional Association to Unidirectional£¨½«Ë«Ïò¹ØÁª¸ÄΪµ¥Ïò¹ØÁª£© +## 8. Change Bidirectional Association to Unidirectional(将å�Œå�‘å…³è�”改为å�•å�‘å…³è�”) -ºÍ Change Unidirectional Association to Bidirectiona Ϊ·´²Ù×÷¡£ +å’Œ Change Unidirectional Association to Bidirectiona 为å��æ“�作。 -Ë«Ïò¹ØÁªÎ¬»¤³É±¾¸ß£¬²¢ÇÒÒ²²»Ò×ÓÚÀí½â¡£´óÁ¿µÄË«ÏòÁ¬½ÓºÜÈÝÒ×Ôì³É¡°½©Ê¬¶ÔÏó¡±£ºÄ³¸ö¶ÔÏó±¾ÉíÒѾ­ËÀÍöÁË£¬È´±£ÁôÔÚϵͳÖУ¬ÒòΪËüµÄÒýÓû¹Ã»ÓÐÈ«²¿ÍêÈ«Çå³ý¡£ +å�Œå�‘å…³è�”维护æˆ�本高,并且也ä¸�易于ç�†è§£ã€‚大é‡�çš„å�Œå�‘连接很容易造æˆ�“僵尸对象â€�:æŸ�个对象本身已ç»�死亡了,å�´ä¿�留在系统中,因为它的引用还没有全部完全清除。 -## 9. Replace Magic Number with Symbolic Constant£¨ÒÔ×ÖÃæ³£Á¿È¡´úħ·¨Êý£© +## 9. Replace Magic Number with Symbolic Constant(以字é�¢å¸¸é‡�å�–代魔法数) -´´½¨Ò»¸ö³£Á¿£¬¸ù¾ÝÆäÒâÒåΪËüÃüÃû£¬²¢½«×ÖÃæ³£Á¿»»Î»Õâ¸ö³£Á¿¡£ +创建一个常é‡�,根æ�®å…¶æ„�义为它命å��,并将字é�¢å¸¸é‡�æ�¢ä½�这个常é‡�。 -## 10. Encapsulate Field£¨·â×°×ֶΣ© +## 10. Encapsulate Field(å°�装字段) -public ×Ö¶ÎÓ¦µ±¸ÄΪ private£¬²¢ÌṩÏàÓ¦µÄ·ÃÎʺ¯Êý¡£ +public 字段应当改为 private,并æ��供相应的访问函数。 -## 11. Encapsulate Collection£¨·â×°¼¯ºÏ£© +## 11. Encapsulate Collection(å°�装集å�ˆï¼‰ -º¯Êý·µ»Ø¼¯ºÏµÄÒ»¸öÖ»¶Á¸±±¾£¬²¢ÔÚÕâ¸öÀàÖÐÌṩÌí¼Ó/ÒÆ³ý¼¯ºÏÔªËØµÄº¯Êý¡£Èç¹ûº¯Êý·µ»Ø¼¯ºÏ×ÔÉí£¬»áÈÃÓû§µÃÒÔÐ޸ļ¯ºÏÄÚÈݶø¼¯ºÏÓµÓÐÕßÈ´Ò»ÎÞËùÖª¡£ +函数返回集å�ˆçš„一个å�ªè¯»å‰¯æœ¬ï¼Œå¹¶åœ¨è¿™ä¸ªç±»ä¸­æ��供添加/移除集å�ˆå…ƒç´ çš„函数。如果函数返回集å�ˆè‡ªèº«ï¼Œä¼šè®©ç”¨æˆ·å¾—以修改集å�ˆå†…容而集å�ˆæ‹¥æœ‰è€…å�´ä¸€æ— æ‰€çŸ¥ã€‚ -## 12. Replace Record with Data Class£¨ÒÔÊý¾ÝÀàÈ¡´ú¼Ç¼£© +## 12. Replace Record with Data Class(以数æ�®ç±»å�–代记录) -## 13. Replace Type Code with Class£¨ÒÔÀàÈ¡´úÀàÐÍÂ룩 +## 13. Replace Type Code with Class(以类å�–代类型ç �) -ÀàÖÐÓÐÒ»¸öÊýÖµÀàÐÍÂ룬µ«Ëü²¢²»Ó°ÏìÀàµÄÐÐΪ£¬¾ÍÓÃÒ»¸öÐÂÀàÌæ»»¸ÃÊýÖµÀàÐÍÂë¡£Èç¹ûÀàÐÍÂë³öÏÖÔÚ switch Óï¾äÖУ¬ÐèҪʹÓà Replace Conditional with Polymorphism È¥µô switch£¬Ê×ÏȱØÐëÔËÓà Replace Type Code with Subcalss »ò Replace Type Code with State/Strategy È¥µôÀàÐÍÂë¡£ +类中有一个数值类型ç �,但它并ä¸�å½±å“�类的行为,就用一个新类替æ�¢è¯¥æ•°å€¼ç±»åž‹ç �。如果类型ç �出现在 switch 语å�¥ä¸­ï¼Œéœ€è¦�使用 Replace Conditional with Polymorphism 去掉 switch,首先必须è¿�用 Replace Type Code with Subcalss 或 Replace Type Code with State/Strategy 去掉类型ç �。 -![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/27c2e0b3-8f95-453d-bedc-6398a8566ce9.jpg) +![](https://github.com/CyC2018/InterviewNotes/blob/master/pics//27c2e0b3-8f95-453d-bedc-6398a8566ce9.jpg) -## 14. Replace Type Code with Subcalsses£¨ÒÔ×ÓÀàÈ¡´úÀàÐÍÂ룩 +## 14. Replace Type Code with Subcalsses(以å­�ç±»å�–代类型ç �) -ÓÐÒ»¸ö²»¿É±äµÄÀàÐÍÂ룬Ëü»áÓ°ÏìÀàµÄÐÐΪ£¬ÒÔ×ÓÀàÈ¡´úÕâ¸öÀàÐÍÂë¡£ +有一个ä¸�å�¯å�˜çš„类型ç �,它会影å“�类的行为,以å­�ç±»å�–代这个类型ç �。 -![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/c41d3977-e0e7-4ee4-93e1-d84f1ae3e20e.jpg) +![](https://github.com/CyC2018/InterviewNotes/blob/master/pics//c41d3977-e0e7-4ee4-93e1-d84f1ae3e20e.jpg) -## 15. Replace Type Code with State/Strategy £¨ÒÔ State/Strategy È¡´úÀàÐÍÂ룩 +## 15. Replace Type Code with State/Strategy (以 State/Strategy å�–代类型ç �) -ÓÐÒ»¸ö¿É±äµÄÀàÐÍÂ룬Ëü»áÓ°ÏìÀàµÄÐÐΪ£¬ÒÔ״̬¶ÔÏóÈ¡´úÀàÐÍÂë¡£ +有一个å�¯å�˜çš„类型ç �,它会影å“�类的行为,以状æ€�对象å�–代类型ç �。 -ºÍ Replace Type Code with Subcalsses µÄÇø±ðÊÇ Replace Type Code with State/Strategy µÄÀàÐÍÂëÊǶ¯Ì¬¿É±äµÄ£¬Ç°Õßͨ¹ý¼Ì³ÐµÄ·½Ê½À´ÊµÏÖ£¬ºóÕßͨ¹ý×éºÏµÄ·½Ê½À´ÊµÏÖ¡£ÒòΪÀàÐÍÂë¿É±ä£¬Èç¹ûͨ¹ý¼Ì³ÐµÄ·½Ê½£¬Ò»µ©Ò»¸ö¶ÔÏóµÄÀàÐÍÂë¸Ä±ä£¬ÄÇô¾ÍÒª¸Ä±äÓÃеĶÔÏóÀ´È¡´ú¾É¶ÔÏ󣬶ø¿Í»§¶ËÄÑÒԸıäеĶÔÏó¡£µ«ÊÇͨ¹ý×éºÏµÄ·½Ê½£¬¸Ä±äÒýÓõÄ״̬ÀàÊǺÜÈÝÒ׵ġ£ +å’Œ Replace Type Code with Subcalsses 的区别是 Replace Type Code with State/Strategy 的类型ç �是动æ€�å�¯å�˜çš„,å‰�者通过继承的方å¼�æ�¥å®žçŽ°ï¼Œå�Žè€…通过组å�ˆçš„æ–¹å¼�æ�¥å®žçŽ°ã€‚å› ä¸ºç±»åž‹ç �å�¯å�˜ï¼Œå¦‚果通过继承的方å¼�,一旦一个对象的类型ç �改å�˜ï¼Œé‚£ä¹ˆå°±è¦�改å�˜ç”¨æ–°çš„对象æ�¥å�–代旧对象,而客户端难以改å�˜æ–°çš„对象。但是通过组å�ˆçš„æ–¹å¼�,改å�˜å¼•用的状æ€�类是很容易的。 -![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/81fd1d6f-a3b2-4160-9a0a-1f7cb50ba440.jpg) +![](https://github.com/CyC2018/InterviewNotes/blob/master/pics//81fd1d6f-a3b2-4160-9a0a-1f7cb50ba440.jpg) -## 16. Replace Subclass with Fields£¨ÒÔ×Ö¶ÎÈ¡´ú×ÓÀࣩ +## 16. Replace Subclass with Fields(以字段å�–代å­�类) -¸÷¸ö×ÓÀàµÄΨһ²î±ðÖ»ÔÚ¡°·µ»Ø³£Á¿Êý¾Ý¡±µÄº¯ÊýÉÏ¡£ +å�„个å­�类的唯一差别å�ªåœ¨â€œè¿”回常é‡�æ•°æ�®â€�的函数上。 -![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/f2e0cee9-ecdc-4a96-853f-d9f6a1ad6ad1.jpg) +![](https://github.com/CyC2018/InterviewNotes/blob/master/pics//f2e0cee9-ecdc-4a96-853f-d9f6a1ad6ad1.jpg) -# µÚ¾ÅÕ ¼ò»¯Ìõ¼þ±í´ïʽ +# 第ä¹�ç«  简化æ�¡ä»¶è¡¨è¾¾å¼� -## 1. Decompose Conditional£¨·Ö½âÌõ¼þ±í´ïʽ£© +## 1. Decompose Conditional(分解æ�¡ä»¶è¡¨è¾¾å¼�) -¶ÔÓÚÒ»¸ö¸´ÔÓµÄÌõ¼þÓï¾ä£¬¿ÉÒÔ´Ó if¡¢then¡¢else Èý¸ö¶ÎÂäÖзֱðÌáÁ¶³ö¶ÀÁ¢º¯Êý¡£ +对于一个å¤�æ�‚çš„æ�¡ä»¶è¯­å�¥ï¼Œå�¯ä»¥ä»Ž ifã€�thenã€�else 三个段è�½ä¸­åˆ†åˆ«æ��炼出独立函数。 ```java if(data.befor(SUMMER_START) || data.after(SUMMER_END)) @@ -583,11 +584,11 @@ if(notSummer(date)) else charge = summerCharge(quantity); ``` -## 2. Consolidate Conditional Expression£¨ºÏ²¢Ìõ¼þ±í´ïʽ£© +## 2. Consolidate Conditional Expression(å�ˆå¹¶æ�¡ä»¶è¡¨è¾¾å¼�) -ÓÐһϵÁÐÌõ¼þ²âÊÔ£¬¶¼µÃµ½Ïàͬ½á¹û¡£ +有一系列æ�¡ä»¶æµ‹è¯•,都得到相å�Œç»“果。 -½«ÕâЩ²âÊԺϲ¢ÎªÒ»¸öÌõ¼þ±í´ïʽ£¬²¢½«Õâ¸öÌõ¼þ±í´ïʽÌáÁ¶³ÉΪһ¸ö¶ÀÁ¢º¯Êý¡£ +将这些测试å�ˆå¹¶ä¸ºä¸€ä¸ªæ�¡ä»¶è¡¨è¾¾å¼�,并将这个æ�¡ä»¶è¡¨è¾¾å¼�æ��炼æˆ�为一个独立函数。 ```java double disabilityAmount(){ @@ -604,11 +605,11 @@ double disabilityAmount(){ } ``` -## 3. Consolidate Duplicate Conditional Fragments £¨ºÏ²¢Öظ´µÄÌõ¼þƬ¶Î£© +## 3. Consolidate Duplicate Conditional Fragments (å�ˆå¹¶é‡�å¤�çš„æ�¡ä»¶ç‰‡æ®µï¼‰ -ÔÚÌõ¼þ±í´ïʽµÄÿ¸ö·ÖÖ§ÉÏÓÐ×ÅÏàͬµÄÒ»¶Î´úÂë¡£ +在æ�¡ä»¶è¡¨è¾¾å¼�çš„æ¯�个分支上有ç�€ç›¸å�Œçš„一段代ç �。 -½«Õâ¶ÎÖØ¸´´úÂë°áÒÆµ½Ìõ¼þ±í´ïʽ֮Íâ¡£ +将这段é‡�å¤�代ç �æ�¬ç§»åˆ°æ�¡ä»¶è¡¨è¾¾å¼�之外。 ```java if (isSpecialDeal()){ @@ -629,17 +630,17 @@ if (isSpecialDeal()) { send(); ``` -## 4. Remove Control Flag£¨ÒƳý¿ØÖƱê¼Ç£© +## 4. Remove Control Flag(移除控制标记) -ÔÚһϵÁв¼¶û±í´ïʽÖУ¬Ä³¸ö±äÁ¿´øÓС°¿ØÖƱê¼Ç¡±µÄ×÷Óᣠ+在一系列布尔表达å¼�中,æŸ�个å�˜é‡�带有“控制标记â€�的作用。 -Óà breakÓï ¾ä»ò return Óï¾äÀ´È¡´ú¿ØÖƱê¼Ç¡£ +用 break语 å�¥æˆ– return 语å�¥æ�¥å�–代控制标记。 -## 5. Replace Nested Conditional with Guard Clauses £¨ÒÔÎÀÓï¾äÈ¡´úǶÌ×Ìõ¼þ±í´ïʽ£© +## 5. Replace Nested Conditional with Guard Clauses (以å�«è¯­å�¥å�–代嵌套æ�¡ä»¶è¡¨è¾¾å¼�) -Èç¹ûij¸öÌõ¼þ¼«Æäº±¼û£¬¾ÍÓ¦¸Ãµ¥¶À¼ì²é¸ÃÌõ¼þ£¬²¢ÔÚ¸ÃÌõ¼þÎªÕæÊ±Á¢¿Ì´Óº¯ÊýÖзµ»Ø£¬ÕâÑùµÄµ¥¶À¼ì²é³£³£±»³ÆÎª¡°ÎÀÓï¾ä¡±£¨guard clauses£©¡£ +如果æŸ�个æ�¡ä»¶æž�其罕è§�,就应该å�•独检查该æ�¡ä»¶ï¼Œå¹¶åœ¨è¯¥æ�¡ä»¶ä¸ºçœŸæ—¶ç«‹åˆ»ä»Žå‡½æ•°ä¸­è¿”回,这样的å�•独检查常常被称为“å�«è¯­å�¥â€�(guard clauses)。 -Ìõ¼þ±í´ïʽͨ³£ÓÐÁ½ÖÖ±íÏÖÐÎʽ¡£µÚÒ»ÖÖÐÎʽÊÇ£ºËùÓзÖÖ§¶¼ÊôÓÚÕý³£ÐÐΪ¡£µÚ¶þÖÖÐÎʽÔòÊÇ£ºÌõ¼þ±í´ïʽÌṩµÄ´ð°¸ÖÐÖ»ÓÐÒ»ÖÖÊÇÕý³£ÐÐΪ£¬ÆäËû¶¼ÊDz»³£¼ûµÄÇé¿ö£¬¿ÉÒÔʹÓÃÎÀÓï¾ä±íÏÖËùÓÐÌØÊâÇé¿ö¡£ +æ�¡ä»¶è¡¨è¾¾å¼�通常有两ç§�表现形å¼�。第一ç§�å½¢å¼�是:所有分支都属于正常行为。第二ç§�å½¢å¼�则是:æ�¡ä»¶è¡¨è¾¾å¼�æ��供的答案中å�ªæœ‰ä¸€ç§�是正常行为,其他都是ä¸�常è§�的情况,å�¯ä»¥ä½¿ç”¨å�«è¯­å�¥è¡¨çŽ°æ‰€æœ‰ç‰¹æ®Šæƒ…å†µã€‚ ```java double getPayAmount() { @@ -665,9 +666,9 @@ double getPayAmount() { }; ``` -## 6. Replace Conditional with Polymorphism £¨ÒÔ¶à̬ȡ´úÌõ¼þ±í´ïʽ£© +## 6. Replace Conditional with Polymorphism (以多æ€�å�–代æ�¡ä»¶è¡¨è¾¾å¼�) -½«Õâ¸öÌõ¼þ±í´ïʽµÄÿ¸ö·ÖÖ§·Å½øÒ»¸ö×ÓÀàÄڵĸ²Ð´º¯ÊýÖУ¬È»ºó½«Ô­Ê¼º¯ÊýÉùÃ÷Ϊ³éÏóº¯Êý¡£ÐèÒªÏÈʹÓà Replace Type Code with Subclass »ò Replace Type Code with State/Strategy À´½¨Á¢¼Ì³Ð½á¹û¡£ +将这个æ�¡ä»¶è¡¨è¾¾å¼�çš„æ¯�个分支放进一个å­�类内的覆写函数中,然å�Žå°†åŽŸå§‹å‡½æ•°å£°æ˜Žä¸ºæŠ½è±¡å‡½æ•°ã€‚éœ€è¦�先使用 Replace Type Code with Subclass 或 Replace Type Code with State/Strategy æ�¥å»ºç«‹ç»§æ‰¿ç»“果。 ```java double getSpeed() { @@ -683,20 +684,20 @@ double getSpeed() { } ``` -![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/1c8432c8-2552-457f-b117-1da36c697221.jpg) +![](https://github.com/CyC2018/InterviewNotes/blob/master/pics//1c8432c8-2552-457f-b117-1da36c697221.jpg) -## 7. Introduce Null Object£¨ÒýÈëNull¶ÔÏó£© +## 7. Introduce Null Object(引入Null对象) -½« null ÖµÌæ»»Îª null ¶ÔÏó¡£ÕâÑù×öµÄºÃ´¦ÔÚÓÚ£¬²»ÐèҪѯÎʶÔÏóÊÇ·ñΪ¿Õ£¬Ö±½Óµ÷ÓþÍÐС£ +å°† null 值替æ�¢ä¸º null 对象。这样å�šçš„好处在于,ä¸�需è¦�询问对象是å�¦ä¸ºç©ºï¼Œç›´æŽ¥è°ƒç”¨å°±è¡Œã€‚ ```java if (customer == null) plan = BillingPlan.basic(); else plan = customer.getPlan(); ``` -## 8. Introduce Assertion£¨ÒýÈë¶ÏÑÔ£© +## 8. Introduce Assertion(引入断言) -ÒÔ¶ÏÑÔÃ÷È·±íÏÖijÖÖ¼ÙÉè¡£¶ÏÑÔÖ»ÄÜÓÃÓÚ¿ª·¢¹ý³ÌÖУ¬²úÆ·´úÂëÖв»»áÓжÏÑÔ¡£ +以断言明确表现æŸ�ç§�å�‡è®¾ã€‚断言å�ªèƒ½ç”¨äºŽå¼€å�‘过程中,产å“�代ç �中ä¸�会有断言。 ```java double getExpenseLimit() { @@ -712,25 +713,25 @@ double getExpenseLimit() { } ``` -# µÚʮՠ¼ò»¯º¯Êýµ÷Óà +# 第å��ç«  简化函数调用 -## 1. Rename Method£¨º¯Êý¸ÄÃû£© +## 1. Rename Method(函数改å��) -ʹº¯ÊýÃûÄܽâÊͺ¯ÊýµÄÓÃ;¡£ +使函数å��能解释函数的用途。 -## 2. Add Parameter£¨Ìí¼Ó²ÎÊý£© +## 2. Add Parameter(添加å�‚数) -ʹº¯Êý²»ÐèҪͨ¹ýµ÷ÓûñµÃij¸öÐÅÏ¢¡£ +使函数ä¸�需è¦�通过调用获得æŸ�个信æ�¯ã€‚ -## 3. Remove Parameter£¨ÒƳý²ÎÊý£© +## 3. Remove Parameter(移除å�‚数) -Óë Add Parameter Ïà·´£¬¸ÄÓõ÷Óõķ½Ê½À´»ñµÃij¸öÐÅÏ¢¡£ +与 Add Parameter 相å��,改用调用的方å¼�æ�¥èŽ·å¾—æŸ�个信æ�¯ã€‚ -## 4. Separate Query from Modifier£¨½«²éѯº¯ÊýºÍÐ޸ĺ¯Êý·ÖÀ룩 +## 4. Separate Query from Modifier(将查询函数和修改函数分离) -ij¸öº¯Êý¼´·µ»Ø¶ÔÏó״ֵ̬£¬ÓÖÐ޸ĶÔÏó״̬¡£ +æŸ�个函数å�³è¿”回对象状æ€�值,å�ˆä¿®æ”¹å¯¹è±¡çжæ€�。 -Ó¦µ±½¨Á¢Á½¸ö²»Í¬µÄº¯Êý£¬ÆäÖÐÒ»¸ö¸ºÔð²éѯ£¬ÁíÒ»¸ö¸ºÔðÐ޸ġ£ÈκÎÓзµ»ØÖµµÄº¯Êý£¬¶¼²»Ó¦¸ÃÓп´µÃµ½µÄ¸±×÷Óᣠ+应当建立两个ä¸�å�Œçš„函数,其中一个负责查询,å�¦ä¸€ä¸ªè´Ÿè´£ä¿®æ”¹ã€‚任何有返回值的函数,都ä¸�应该有看得到的副作用。 ```java getTotalOutstandingAndSetReadyForSummaries(); @@ -741,11 +742,11 @@ getTotalOutstanding(); setReadyForSummaries(); ``` -## 5. Parameterize Method£¨ÁÊýЯ´ø²ÎÊý£© +## 5. Parameterize Method(令函数æ�ºå¸¦å�‚数) -Èô¸Éº¯Êý×öÁËÀàËÆµÄ¹¤×÷£¬µ«ÔÚº¯Êý±¾ÌåÖÐÈ´°üº¬Á˲»Í¬µÄÖµ¡£ +若干函数å�šäº†ç±»ä¼¼çš„工作,但在函数本体中å�´åŒ…å�«äº†ä¸�å�Œçš„值。 -½¨Á¢µ¥Ò»º¯Êý£¬ÒÔ²ÎÊý±í´ïÄÇЩ²»Í¬µÄÖµ¡£ +建立å�•一函数,以å�‚数表达那些ä¸�å�Œçš„值。 ```java fivePercentRaise(); @@ -755,11 +756,11 @@ tenPercentRaise(); raise(percentage); ``` -## 6. Replace Parameter with Explicit Methods£¨ÒÔÃ÷È·º¯ÊýÈ¡´ú²ÎÊý£© +## 6. Replace Parameter with Explicit Methods(以明确函数å�–代å�‚数) -ÓÐÒ»¸öº¯Êý£¬Íêȫȡ¾öÓÚ²ÎÊýÖµ¶ø²ÉÈ¡²»Í¬ÐÐΪ¡£ +有一个函数,完全å�–决于å�‚数值而采å�–ä¸�å�Œè¡Œä¸ºã€‚ -Õë¶Ô¸Ã²ÎÊýµÄÿһ¸ö¿ÉÄÜÖµ£¬½¨Á¢Ò»¸ö¶ÀÁ¢º¯Êý¡£ +针对该å�‚æ•°çš„æ¯�一个å�¯èƒ½å€¼ï¼Œå»ºç«‹ä¸€ä¸ªç‹¬ç«‹å‡½æ•°ã€‚ ```java void setValue(String name, int value){ @@ -784,11 +785,11 @@ void setWidth(int arg){ } ``` -## 7. Preserve Whole Object£¨±£³Ö¶ÔÏóÍêÕû£© +## 7. Preserve Whole Object(ä¿�æŒ�对象完整) -´Óij¸ö¶ÔÏóÖÐÈ¡³öÈô¸ÉÖµ£¬½«ËüÃÇ×÷Ϊijһ´Îº¯Êýµ÷ÓÃʱµÄ²ÎÊý¡£ +从æŸ�个对象中å�–出若干值,将它们作为æŸ�一次函数调用时的å�‚数。 -¸ÄΪ´«µÝÕû¸ö¶ÔÏó¡£ +改为传递整个对象。 ```java int low = daysTempRange().getLow(); @@ -800,11 +801,11 @@ withinPlan = plan.withinRange(low,high); withinPlan = plan.withinRange(daysTempRange()); ``` -## 8. Replace Parameter with Methods£¨ÒÔº¯ÊýÈ¡´ú²ÎÊý£© +## 8. Replace Parameter with Methods(以函数å�–代å�‚数) -¶ÔÏóµ÷ÓÃij¸öº¯Êý£¬²¢½«ËùµÃ½á¹û×÷Ϊ²ÎÊý£¬´«µÝ¸øÁíÒ»¸öº¯Êý¡£¶ø½ÓÊܸòÎÊýµÄº¯Êý±¾ÉíÒ²Äܹ»µ÷ÓÃǰһ¸öº¯Êý¡£ +对象调用æŸ�个函数,并将所得结果作为å�‚数,传递给å�¦ä¸€ä¸ªå‡½æ•°ã€‚而接å�—该å�‚数的函数本身也能够调用å‰�一个函数。 -ÈòÎÊý½ÓÊÕÕßÈ¥³ý¸ÃÏî²ÎÊý£¬¶øÊÇÖ±½Óµ÷ÓÃǰһ¸öº¯Êý¡£ +让å�‚数接收者去除该项å�‚数,而是直接调用å‰�一个函数。 ```java int basePrice = _quantity * _itemPrice; @@ -817,37 +818,37 @@ int basePrice = _quantity * _itemPrice; double finalPrice = discountedPrice (basePrice); ``` -## 9. Introduce Parameter Object£¨ÒýÈë²ÎÊý¶ÔÏó£© +## 9. Introduce Parameter Object(引入å�‚数对象) -ijЩ²ÎÊý×ÜÊǺÜ×ÔÈ»µØÍ¬Ê±³öÏÖ£¬ÕâЩ²ÎÊý¾ÍÊÇ Data Clumps¡£ +æŸ�些å�‚数总是很自然地å�Œæ—¶å‡ºçŽ°ï¼Œè¿™äº›å�‚数就是 Data Clumps。 -ÒÔÒ»¸ö¶ÔÏóÈ¡´úÕâЩ²ÎÊý¡£ +以一个对象å�–代这些å�‚数。 -![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/08738dd0-ae8e-404a-ba78-a6b1b7d225b3.jpg) +![](https://github.com/CyC2018/InterviewNotes/blob/master/pics//08738dd0-ae8e-404a-ba78-a6b1b7d225b3.jpg) -## 10. Remove Setting Method£¨ÒƳýÉèÖµº¯Êý£© +## 10. Remove Setting Method(移除设值函数) -ÀàÖеÄij¸ö×Ö¶ÎÓ¦¸ÃÔÚ¶ÔÏó´´½¨Ê±±»ÉèÖµ£¬È»ºó¾Í²»Ôٸı䡣 +类中的æŸ�个字段应该在对象创建时被设值,然å�Žå°±ä¸�å†�改å�˜ã€‚ -È¥µô¸Ã×ֶεÄËùÓÐÉèÖµº¯Êý£¬²¢½«¸Ã×Ö¶ÎÉèΪ final¡£ +去掉该字段的所有设值函数,并将该字段设为 final。 -## 11. Hide Method£¨Òþ²Øº¯Êý£© +## 11. Hide Method(éš�è—�函数) -ÓÐÒ»¸öº¯Êý£¬´ÓÀ´Ã»Óб»ÆäËûÈκÎÀàÓõ½¡£ +有一个函数,从æ�¥æ²¡æœ‰è¢«å…¶ä»–任何类用到。 -½«Õâ¸öº¯ÊýÐÞ¸ÄΪ private¡£ +将这个函数修改为 private。 -## 12. Replace Constructor with Factory Method £¨ÒÔ¹¤³§º¯ÊýÈ¡´ú¹¹Ô캯Êý£© +## 12. Replace Constructor with Factory Method (以工厂函数å�–代构造函数) -Ï£ÍûÔÚ´´½¨¶ÔÏóʱ²»½ö½öÊÇ×ö¼òµ¥µÄ½¨¹¹¶¯×÷¡£ +希望在创建对象时ä¸�仅仅是å�šç®€å�•的建构动作。 -½«¹¹Ô캯ÊýÌæ»»Îª¹¤³§º¯Êý¡£ +将构造函数替æ�¢ä¸ºå·¥åŽ‚å‡½æ•°ã€‚ -## 13. Encapsulate Downcast£¨·â×°ÏòÏÂתÐÍ£© +## 13. Encapsulate Downcast(å°�装å�‘下转型) -ij¸öº¯Êý·µ»ØµÄ¶ÔÏó£¬ÐèÒªÓɺ¯Êýµ÷ÓÃÕßÖ´ÐÐÏòÏÂתÐÍ£¨downcast£©¡£ +æŸ�个函数返回的对象,需è¦�由函数调用者执行å�‘下转型(downcast)。 -½«ÏòÏÂתÐͶ¯×÷ÒÆµ½º¯ÊýÖС£ +å°†å�‘下转型动作移到函数中。 ```java Object lastReading(){ @@ -860,17 +861,17 @@ Reading lastReading(){ } ``` -## 14. Replace Error Code with Exception £¨ÒÔÒ쳣ȡ´ú´íÎóÂ룩 +## 14. Replace Error Code with Exception (以异常å�–代错误ç �) -ij¸öº¯Êý·µ»ØÒ»¸öÌØ¶¨µÄ´úÂ룬ÓÃÒÔ±íʾijÖÖ´íÎóÇé¿ö¡£ +æŸ�个函数返回一个特定的代ç �,用以表示æŸ�ç§�错误情况。 -¸ÄÓÃÒì³££¬Òì³£½«ÆÕͨ³ÌÐòºÍ´íÎó´¦Àí·Ö¿ª£¬Ê¹´úÂë¸üÈÝÒ×Àí½â¡£ +改用异常,异常将普通程åº�和错误处ç�†åˆ†å¼€ï¼Œä½¿ä»£ç �更容易ç�†è§£ã€‚ -## 15. Replace Exception with Test£¨ÒÔ²âÊÔÈ¡´úÒì³££© +## 15. Replace Exception with Test(以测试å�–代异常) -Ãæ¶ÔÒ»¸öµ÷ÓÃÕß¿ÉÒÔÔ¤Ïȼì²éµÄÌõ¼þ£¬ÄãÅ׳öÁËÒ»¸öÒì³£¡£ +é�¢å¯¹ä¸€ä¸ªè°ƒç”¨è€…å�¯ä»¥é¢„先检查的æ�¡ä»¶ï¼Œä½ æŠ›å‡ºäº†ä¸€ä¸ªå¼‚常。 -Ð޸ĵ÷ÓÃÕߣ¬Ê¹ËüÔÚµ÷Óú¯Êý֮ǰÏÈ×ö¼ì²é¡£ +修改调用者,使它在调用函数之å‰�å…ˆå�šæ£€æŸ¥ã€‚ ```java double getValueForPeriod(int periodNumber) { @@ -887,25 +888,25 @@ double getValueForPeriod(int periodNumber) { return values[periodNumber]; ``` -# µÚʮһÕ ´¦Àí¸ÅÀ¨¹ØÏµ +# 第å��一章 处ç�†æ¦‚括关系 -## 1. Pull Up Field£¨×Ö¶ÎÉÏÒÆ£© +## 1. Pull Up Field(字段上移) -Á½¸ö×ÓÀàÓµÓÐÏàͬµÄ×ֶΡ£ +两个å­�类拥有相å�Œçš„字段。 -½«¸Ã×Ö¶ÎÒÆÖÁ³¬Àà¡£ +将该字段移至超类。 -## 2. Pull Up Method£¨º¯ÊýÉÏÒÆ£© +## 2. Pull Up Method(函数上移) -ÓÐЩº¯Êý£¬ÔÚ¸÷¸ö×ÓÀàÖвúÉúÍêÈ«ÏàͬµÄ½á¹û¡£ +有些函数,在å�„个å­�类中产生完全相å�Œçš„结果。 -½«¸Ãº¯ÊýÒÆÖÁ³¬Àà¡£ +将该函数移至超类。 -## 3. Pull Up Constructor Body£¨¹¹Ô캯Êý±¾ÌåÉÏÒÆ£© +## 3. Pull Up Constructor Body(构造函数本体上移) -ÄãÔÚ¸÷¸ö×ÓÀàÖÐÓµÓÐһЩ¹¹Ô캯Êý£¬ËüÃǵı¾Ì弸ºõÍêȫһÖ¡£ +你在å�„个å­�类中拥有一些构造函数,它们的本体几乎完全一致。 -ÔÚ³¬ÀàÖÐн¨Ò»¸ö¹¹Ô캯Êý£¬²¢ÔÚ×ÓÀ๹Ô캯ÊýÖе÷ÓÃËü¡£ +在超类中新建一个构造函数,并在å­�类构造函数中调用它。 ```java class Manager extends Employee... @@ -924,56 +925,56 @@ public Manager(String name, String id, int grade) { } ``` -## 4. Push Down Method£¨º¯ÊýÏÂÒÆ£© +## 4. Push Down Method(函数下移) -³¬ÀàÖеÄij¸öº¯ÊýÖ»Ó벿·Ö×ÓÀàÓйء£ +超类中的æŸ�个函数å�ªä¸Žéƒ¨åˆ†å­�类有关。 -½«Õâ¸öº¯ÊýÒÆµ½Ïà¹ØµÄÄÇЩ×ÓÀàÈ¥¡£ +将这个函数移到相关的那些å­�类去。 -## 5. Push Down Field£¨×Ö¶ÎÏÂÒÆ£© +## 5. Push Down Field(字段下移) -³¬ÀàÖеÄij¸ö×Ö¶ÎÖ»±»²¿·Ö×ÓÀàÓõ½¡£ +超类中的æŸ�个字段å�ªè¢«éƒ¨åˆ†å­�类用到。 -½«Õâ¸ö×Ö¶ÎÒÆµ½ÐèÒªËüµÄÄÇЩ×ÓÀàÈ¥¡£ +将这个字段移到需è¦�它的那些å­�类去。 -## 6. Extract Subclass£¨ÌáÁ¶×ÓÀࣩ +## 6. Extract Subclass(æ��炼å­�类) -ÀàÖеÄÄ³Ð©ÌØÐÔÖ»±»Ä³Ð©ÊµÀýÓõ½¡£ +类中的æŸ�些特性å�ªè¢«æŸ�些实例用到。 -н¨Ò»¸ö×ÓÀ࣬½«ÉÏÃæËù˵µÄÄÇÒ»²¿·ÖÌØÐÔÒÆµ½×ÓÀàÖС£ +新建一个å­�类,将上é�¢æ‰€è¯´çš„那一部分特性移到å­�类中。 -## 7. Extract Superclass£¨ÌáÁ¶³¬Àࣩ +## 7. Extract Superclass(æ��炼超类) -Á½¸öÀàÓÐÏàËÆÌØÐÔ¡£ +两个类有相似特性。 -ΪÕâÁ½¸öÀཨÁ¢Ò»¸ö³¬À࣬½«ÏàÍ¬ÌØÐÔÒÆÖÁ³¬Àà¡£ +为这两个类建立一个超类,将相å�Œç‰¹æ€§ç§»è‡³è¶…类。 -## 8. Extract Interface£¨ÌáÁ¶½Ó¿Ú£© +## 8. Extract Interface(æ��炼接å�£ï¼‰ -Èô¸É¿Í»§Ê¹ÓÃÀà½Ó¿ÚÖеÄͬһ×Ó¼¯£¬»òÕßÁ½¸öÀàµÄ½Ó¿ÚÓв¿·ÖÏàͬ¡£ +若干客户使用类接å�£ä¸­çš„å�Œä¸€å­�集,或者两个类的接å�£æœ‰éƒ¨åˆ†ç›¸å�Œã€‚ -½«ÏàͬµÄ×Ó¼¯ÌáÁ¶µ½Ò»¸ö¶ÀÁ¢½Ó¿ÚÖС£ +将相å�Œçš„å­�集æ��炼到一个独立接å�£ä¸­ã€‚ -## 9. Collapse Hierarchy£¨ÕÛµþ¼Ì³ÐÌåϵ£© +## 9. Collapse Hierarchy(折å� ç»§æ‰¿ä½“系) -³¬ÀàºÍ×ÓÀàÖ®¼äÎÞÌ«´óÇø±ð¡£ +超类和å­�类之间无太大区别。 -½«ËüÃǺÏΪһÌå¡£ +将它们å�ˆä¸ºä¸€ä½“。 -## 10. Form Template Method£¨ËÜÔìÄ£°åº¯Êý£© +## 10. Form Template Method(塑造模æ�¿å‡½æ•°ï¼‰ -ÄãÓÐһЩ×ÓÀ࣬ÆäÖÐÏàÓ¦µÄijЩº¯ÊýÒÔÏàͬ˳ÐòÖ´ÐÐÀàËÆµÄ²Ù×÷£¬µ«¸÷¸ö²Ù×÷µÄϸ½ÚÉÏÓÐËù²»Í¬¡£ +你有一些å­�类,其中相应的æŸ�些函数以相å�Œé¡ºåº�执行类似的æ“�作,但å�„个æ“�作的细节上有所ä¸�å�Œã€‚ -½«ÕâЩ²Ù×÷·Ö±ð·Å½ø¶ÀÁ¢º¯ÊýÖУ¬²¢±£³ÖËüÃǶ¼ÓÐÏàͬµÄÇ©Ãû£¬ÓÚÊÇÔ­º¯ÊýÒ²¾Í±äµÃÏàͬÁË¡£È»ºó½«Ô­º¯ÊýÉÏÒÆÖÁ³¬Àà¡£(Ä£°å·½·¨Ä£Ê½) +将这些æ“�作分别放进独立函数中,并ä¿�æŒ�它们都有相å�Œçš„ç­¾å��,于是原函数也就å�˜å¾—相å�Œäº†ã€‚ç„¶å�Žå°†åŽŸå‡½æ•°ä¸Šç§»è‡³è¶…ç±»ã€‚(模æ�¿æ–¹æ³•模å¼�) -## 11. Replace Inheritance with Delegation £¨ÒÔίÍÐÈ¡´ú¼Ì³Ð£© +## 11. Replace Inheritance with Delegation (以委托å�–代继承) -ij¸ö×ÓÀàֻʹÓó¬Àà½Ó¿ÚÖеÄÒ»²¿·Ö£¬»òÊǸù±¾²»ÐèÒª¼Ì³Ð¶øÀ´µÄÊý¾Ý¡£ +æŸ�个å­�ç±»å�ªä½¿ç”¨è¶…类接å�£ä¸­çš„一部分,或是根本ä¸�需è¦�继承而æ�¥çš„æ•°æ�®ã€‚ -ÔÚ×ÓÀàÖÐн¨Ò»¸ö×Ö¶ÎÓÃÒÔ±£´æ³¬À࣬µ÷Õû×ÓÀຯÊý£¬ÁîËü¸Ä¶øÎ¯Íг¬À࣬ȻºóÈ¥µôÁ½ÕßÖ®¼äµÄ¼Ì³Ð¹ØÏµ¡£ +在å­�类中新建一个字段用以ä¿�存超类,调整å­�类函数,令它改而委托超类,然å�ŽåŽ»æŽ‰ä¸¤è€…ä¹‹é—´çš„ç»§æ‰¿å…³ç³»ã€‚ -## 12. Replace Delegation with Inheritance £¨ÒԼ̳ÐÈ¡´úίÍУ© +## 12. Replace Delegation with Inheritance (以继承å�–代委托) -ÄãÔÚÁ½¸öÀàÖ®¼äʹÓÃίÍйØÏµ£¬²¢¾­³£ÎªÕû¸ö½Ó¿Ú±àдÐí¶à¼«¼òµ¥µÄίÍк¯Êý¡£ +你在两个类之间使用委托关系,并ç»�常为整个接å�£ç¼–写许多æž�简å�•的委托函数。 -ÈÃίÍÐÀà¼Ì³ÐÊÜÍÐÀà¡£ +让委托类继承å�—托类。 diff --git a/notes/é�¢å�‘对象æ€�想.md b/notes/é�¢å�‘对象æ€�想.md index 0403888d..6e758727 100644 --- a/notes/é�¢å�‘对象æ€�想.md +++ b/notes/é�¢å�‘对象æ€�想.md @@ -1,75 +1,76 @@ * [S.O.L.I.D](#solid) - * [1. µ¥Ò»ÔðÈÎÔ­Ôò](#1-µ¥Ò»ÔðÈÎÔ­Ôò) - * [2. ¿ª·Å·â±ÕÔ­Ôò](#2-¿ª·Å·â±ÕÔ­Ôò) - * [3. ÀïÊÏÌæ»»Ô­Ôò](#3-ÀïÊÏÌæ»»Ô­Ôò) - * [4. ½Ó¿Ú·ÖÀëÔ­Ôò](#4-½Ó¿Ú·ÖÀëÔ­Ôò) - * [5. ÒÀÀµµ¹ÖÃÔ­Ôò](#5-ÒÀÀµµ¹ÖÃÔ­Ôò) -* [·â×°¡¢¼Ì³Ð¡¢¶à̬](#·â×°¼Ì³Ð¶à̬) - * [1. ·â×°](#1-·â×°) - * [2. ¼Ì³Ð](#2-¼Ì³Ð) - * [3. ¶à̬](#3-¶à̬) + * [1. å�•一责任原则](#1-å�•一责任原则) + * [2. 开放å°�闭原则](#2-开放å°�闭原则) + * [3. 里æ°�替æ�¢åŽŸåˆ™](#3-里æ°�替æ�¢åŽŸåˆ™) + * [4. 接å�£åˆ†ç¦»åŽŸåˆ™](#4-接å�£åˆ†ç¦»åŽŸåˆ™) + * [5. ä¾�赖倒置原则](#5-ä¾�赖倒置原则) +* [å°�装ã€�继承ã€�多æ€�](#å°�装继承多æ€�) + * [1. å°�装](#1-å°�装) + * [2. 继承](#2-继承) + * [3. 多æ€�](#3-多æ€�) * [UML](#uml) - * [1. Ààͼ](#1-Ààͼ) - * [2. ʱÐòͼ](#2-ʱÐòͼ) -* [²Î¿¼×ÊÁÏ](#²Î¿¼×ÊÁÏ) + * [1. 类图](#1-类图) + * [2. æ—¶åº�图](#2-æ—¶åº�图) +* [å�‚考资料](#å�‚考资料) + # S.O.L.I.D -S.O.L.I.DÊÇÃæÏò¶ÔÏóÉè¼ÆºÍ±à³Ì(OOD&OOP)Öм¸¸öÖØÒª±àÂëÔ­Ôò(Programming Priciple)µÄÊ××ÖĸËõд¡£ +S.O.L.I.D是é�¢å�‘对象设计和编程(OOD&OOP)中几个é‡�è¦�ç¼–ç �原则(Programming Priciple)的首字æ¯�缩写。 -|¼òд |ȫƴ |ÖÐÎÄ·­Òë| +|简写 |全拼 |中文翻译| | -- | -- | -- | -|SRP| The Single Responsibility Principle |µ¥Ò»ÔðÈÎÔ­Ôò| -|OCP| The Open Closed Principle | ¿ª·Å·â±ÕÔ­Ôò| -|LSP| The Liskov Substitution Principle |ÀïÊÏÌæ»»Ô­Ôò| -|ISP| The Interface Segregation Principle |½Ó¿Ú·ÖÀëÔ­Ôò| -|DIP| The Dependency Inversion Principle |ÒÀÀµµ¹ÖÃÔ­Ôò| +|SRP| The Single Responsibility Principle |å�•一责任原则| +|OCP| The Open Closed Principle | 开放å°�闭原则| +|LSP| The Liskov Substitution Principle |里æ°�替æ�¢åŽŸåˆ™| +|ISP| The Interface Segregation Principle |接å�£åˆ†ç¦»åŽŸåˆ™| +|DIP| The Dependency Inversion Principle |ä¾�赖倒置原则| -## 1. µ¥Ò»ÔðÈÎÔ­Ôò +## 1. å�•一责任原则 -µ±ÐèÒªÐÞ¸Äij¸öÀàµÄʱºòÔ­ÒòÓÐÇÒÖ»ÓÐÒ»¸ö¡£»»¾ä»°Ëµ¾ÍÊÇÈÃÒ»¸öÀàÖ»×öÒ»ÖÖÀàÐÍÔðÈΣ¬µ±Õâ¸öÀàÐèÒª³Ðµ±ÆäËûÀàÐ͵ÄÔðÈεÄʱºò£¬¾ÍÐèÒª·Ö½âÕâ¸öÀà¡£ +当需è¦�修改æŸ�个类的时候原因有且å�ªæœ‰ä¸€ä¸ªã€‚æ�¢å�¥è¯�说就是让一个类å�ªå�šä¸€ç§�类型责任,当这个类需è¦�承当其他类型的责任的时候,就需è¦�分解这个类。 -## 2. ¿ª·Å·â±ÕÔ­Ôò +## 2. 开放å°�闭原则 -Èí¼þʵÌåÓ¦¸ÃÊÇ¿ÉÀ©Õ¹£¬¶ø²»¿ÉÐ޸ĵġ£Ò²¾ÍÊÇ˵£¬¶ÔÀ©Õ¹ÊÇ¿ª·ÅµÄ£¬¶ø¶ÔÐÞ¸ÄÊÇ·â±ÕµÄ¡£ +软件实体应该是å�¯æ‰©å±•,而ä¸�å�¯ä¿®æ”¹çš„。也就是说,对扩展是开放的,而对修改是å°�闭的。 -## 3. ÀïÊÏÌæ»»Ô­Ôò +## 3. 里æ°�替æ�¢åŽŸåˆ™ -µ±Ò»¸ö×ÓÀàµÄʵÀýÓ¦¸ÃÄܹ»Ìæ»»ÈÎºÎÆä³¬ÀàµÄʵÀýʱ£¬ËüÃÇÖ®¼ä²Å¾ßÓÐ is-a ¹ØÏµ¡£ +当一个å­�类的实例应该能够替æ�¢ä»»ä½•其超类的实例时,它们之间æ‰�具有 is-a 关系。 -## 4. ½Ó¿Ú·ÖÀëÔ­Ôò +## 4. 接å�£åˆ†ç¦»åŽŸåˆ™ -²»ÄÜÇ¿ÆÈÓû§È¥ÒÀÀµÄÇЩËûÃDz»Ê¹ÓõĽӿڡ£»»¾ä»°Ëµ£¬Ê¹Óöà¸öרÃŵĽӿڱÈʹÓõ¥Ò»µÄ×ܽӿÚ×ÜÒªºÃ¡£ +ä¸�能强迫用户去ä¾�赖那些他们ä¸�使用的接å�£ã€‚æ�¢å�¥è¯�说,使用多个专门的接å�£æ¯”使用å�•一的总接å�£æ€»è¦�好。 -## 5. ÒÀÀµµ¹ÖÃÔ­Ôò +## 5. ä¾�赖倒置原则 -1. ¸ß²ãÄ£¿é²»Ó¦¸ÃÒÀÀµÓڵͲãÄ£¿é£¬¶þÕß¶¼Ó¦¸ÃÒÀÀµÓÚ³éÏó -2. ³éÏó²»Ó¦¸ÃÒÀÀµÓÚϸ½Ú£¬Ï¸½ÚÓ¦¸ÃÒÀÀµÓÚ³éÏó +1. 高层模å�—ä¸�应该ä¾�赖于低层模å�—,二者都应该ä¾�赖于抽象 +2. 抽象ä¸�应该ä¾�赖于细节,细节应该ä¾�赖于抽象 -# ·â×°¡¢¼Ì³Ð¡¢¶à̬ +# å°�装ã€�继承ã€�多æ€� -·â×°¡¢¼Ì³Ð¡¢¶à̬ÊÇÃæÏò¶ÔÏóµÄÈý´óÌØÐÔ¡£ +å°�装ã€�继承ã€�多æ€�是é�¢å�‘对象的三大特性。 -## 1. ·â×° +## 1. å°�装 -ÀûÓóéÏóÊý¾ÝÀàÐͽ«Êý¾ÝºÍ»ùÓÚÊý¾ÝµÄ²Ù×÷·â×°ÔÚÒ»Æð£¬Ê¹Æä¹¹³ÉÒ»¸ö²»¿É·Ö¸îµÄ¶ÀÁ¢ÊµÌ壬Êý¾Ý±»±£»¤ÔÚ³éÏóÊý¾ÝÀàÐ͵ÄÄÚ²¿£¬¾¡¿ÉÄܵØÒþ²ØÄÚ²¿µÄϸ½Ú£¬Ö»±£ÁôһЩ¶ÔÍâ½Ó¿Úʹ֮ÓëÍⲿ·¢ÉúÁªÏµ¡£Óû§ÊÇÎÞÐèÖªµÀ¶ÔÏóÄÚ²¿µÄϸ½Ú£¬µ«¿ÉÒÔͨ¹ý¸Ã¶ÔÏó¶ÔÍâµÄÌṩµÄ½Ó¿ÚÀ´·ÃÎʸöÔÏó¡£ +利用抽象数æ�®ç±»åž‹å°†æ•°æ�®å’ŒåŸºäºŽæ•°æ�®çš„æ“�作å°�装在一起,使其构æˆ�一个ä¸�å�¯åˆ†å‰²çš„独立实体,数æ�®è¢«ä¿�护在抽象数æ�®ç±»åž‹çš„内部,尽å�¯èƒ½åœ°éš�è—�内部的细节,å�ªä¿�留一些对外接å�£ä½¿ä¹‹ä¸Žå¤–部å�‘生è�”系。用户是无需知é�“对象内部的细节,但å�¯ä»¥é€šè¿‡è¯¥å¯¹è±¡å¯¹å¤–çš„æ��供的接å�£æ�¥è®¿é—®è¯¥å¯¹è±¡ã€‚ -·â×°ÓÐÈý´óºÃ´¦£º +å°�装有三大好处: -1. Á¼ºÃµÄ·â×°Äܹ»¼õÉÙñîºÏ¡£ +1. 良好的å°�装能够å‡�少耦å�ˆã€‚ -2. ÀàÄÚ²¿µÄ½á¹¹¿ÉÒÔ×ÔÓÉÐ޸ġ£ +2. 类内部的结构å�¯ä»¥è‡ªç”±ä¿®æ”¹ã€‚ -3. ¿ÉÒÔ¶Ô³ÉÔ±½øÐиü¾«È·µÄ¿ØÖÆ¡£ +3. å�¯ä»¥å¯¹æˆ�员进行更精确的控制。 -4. Òþ²ØÐÅÏ¢£¬ÊµÏÖϸ½Ú¡£ +4. éš�è—�ä¿¡æ�¯ï¼Œå®žçŽ°ç»†èŠ‚ã€‚ -ÒÔÏ Person Àà·â×° name¡¢gender¡¢age µÈÊôÐÔ£¬Íâ½çÖ»ÄÜͨ¹ý get() ·½·¨»ñȡһ¸ö Person ¶ÔÏóµÄ name ÊôÐÔºÍ gender ÊôÐÔ£¬¶øÎÞ·¨»ñÈ¡ age ÊôÐÔ£¬µ«ÊÇ age ÊôÐÔ¿ÉÒÔ¹© work() ·½·¨Ê¹Óᣠ+以下 Person ç±»å°�装 nameã€�genderã€�age 等属性,外界å�ªèƒ½é€šè¿‡ get() 方法获å�–一个 Person 对象的 name 属性和 gender 属性,而无法获å�– age 属性,但是 age 属性å�¯ä»¥ä¾› work() 方法使用。 -×¢Òâµ½ gender ÊôÐÔʹÓà int Êý¾ÝÀàÐͽøÐд洢£¬·âװʹµÃÓû§×¢Òâ²»µ½ÕâÖÖʵÏÖϸ½Ú¡£²¢ÇÒÔÚÐèÒªÐÞ¸ÄʹÓõÄÊý¾ÝÀàÐÍʱ£¬Ò²¿ÉÒÔÔÚ²»Ó°Ïì¿Í»§¶Ë´úÂëµÄÇé¿öϽøÐС£ +注æ„�到 gender 属性使用 int æ•°æ�®ç±»åž‹è¿›è¡Œå­˜å‚¨ï¼Œå°�装使得用户注æ„�ä¸�到这ç§�实现细节。并且在需è¦�修改使用的数æ�®ç±»åž‹æ—¶ï¼Œä¹Ÿå�¯ä»¥åœ¨ä¸�å½±å“�客户端代ç �的情况下进行。 ```java public class Person { @@ -95,25 +96,25 @@ public class Person { } ``` -## 2. ¼Ì³Ð +## 2. 继承 -¼Ì³ÐʵÏÖÁË **is-a** ¹ØÏµ£¬ÀýÈç Cat ºÍ Animal ¾ÍÊÇÒ»ÖÖ is-a ¹ØÏµ£¬Òò´Ë¿ÉÒÔ½« Cat ¼Ì³Ð×Ô Animal£¬´Ó¶ø»ñµÃ Animal ·Ç private µÄÊôÐԺͷ½·¨¡£ +继承实现了 **is-a** 关系,例如 Cat å’Œ Animal 就是一ç§� is-a 关系,因此å�¯ä»¥å°† Cat 继承自 Animal,从而获得 Animal é�ž private 的属性和方法。 -Cat ¿ÉÒÔµ±×ö Animal À´Ê¹Óã¬Ò²¾ÍÊÇ¿ÉÒÔʹÓà Animal ÒýÓà Cat ¶ÔÏó£¬ÕâÖÖ×ÓÀàת»»Îª¸¸Àà³ÆÎª **ÏòÉÏתÐÍ**¡£ +Cat å�¯ä»¥å½“å�š Animal æ�¥ä½¿ç”¨ï¼Œä¹Ÿå°±æ˜¯å�¯ä»¥ä½¿ç”¨ Animal 引用 Cat 对象,这ç§�å­�类转æ�¢ä¸ºçˆ¶ç±»ç§°ä¸º **å�‘上转型**。 -¼Ì³ÐÓ¦¸Ã×ñÑ­ÀïÊÏÌæ»»Ô­Ôò£ºµ±Ò»¸ö×ÓÀàµÄʵÀýÓ¦¸ÃÄܹ»Ìæ»»ÈÎºÎÆä³¬ÀàµÄʵÀýʱ£¬ËüÃÇÖ®¼ä²Å¾ßÓÐ is-a ¹ØÏµ¡£ +继承应该é�µå¾ªé‡Œæ°�替æ�¢åŽŸåˆ™ï¼šå½“ä¸€ä¸ªå­�类的实例应该能够替æ�¢ä»»ä½•其超类的实例时,它们之间æ‰�具有 is-a 关系。 ```java Animal animal = new Cat(); ``` -## 3. ¶à̬ +## 3. 多æ€� -¶à̬·ÖΪ±àÒëʱ¶à̬ºÍÔËÐÐʱ¶à̬¡£±àÒëʱ¶à̬Ö÷ÒªÖ¸·½·¨µÄ֨װ£¬ÔËÐÐʱ¶àָ̬³ÌÐòÖж¨ÒåµÄ¶ÔÏóÒýÓÃËùÖ¸ÏòµÄ¾ßÌåÀàÐÍÔÚÔËÐÐÆÚ¼ä²ÅÈ·¶¨¡£ +多æ€�分为编译时多æ€�å’Œè¿�行时多æ€�。编译时多æ€�主è¦�指方法的é‡�装,è¿�行时多æ€�指程åº�中定义的对象引用所指å�‘的具体类型在è¿�行期间æ‰�确定。 -¶à̬ÓÐÈý¸öÌõ¼þ£º1. ¼Ì³Ð£»2. ¸²¸Ç¸¸Àà·½·¨£»3. ÏòÉÏתÐÍ¡£ +多æ€�有三个æ�¡ä»¶ï¼š1. 继承;2. 覆盖父类方法;3. å�‘上转型。 -ÏÂÃæµÄ´úÂëÖУ¬ÀÖÆ÷ÀࣨInstrument£©ÓÐÁ½¸ö×ÓÀࣺWind ºÍ Percussion£¬ËüÃǶ¼¸²¸ÇÁË play() ·½·¨£¬²¢ÇÒÔÚ main() ·½·¨ÖÐʹÓø¸Àà Instrument À´ÒýÓà Wind ºÍ Percussion ¶ÔÏó¡£ÔÚ Instrument ÒýÓõ÷Óà play() ·½·¨Ê±£¬»áÖ´ÐÐʵ¼ÊÒýÓöÔÏóËùÔÚÀàµÄ play() ·½·¨£¬¶ø²»ÊÇ Instrument ÀàµÄ·½·¨¡£ +下é�¢çš„代ç �中,ä¹�器类(Instrument)有两个å­�类:Wind å’Œ Percussion,它们都覆盖了 play() 方法,并且在 main() 方法中使用父类 Instrument æ�¥å¼•用 Wind å’Œ Percussion 对象。在 Instrument 引用调用 play() 方法时,会执行实际引用对象所在类的 play() 方法,而ä¸�是 Instrument 类的方法。 ```java public class Instrument { @@ -151,157 +152,157 @@ public class Music { # UML -## 1. Ààͼ +## 1. 类图 -**1.1 ¼Ì³ÐÏà¹Ø** +**1.1 继承相关** -¼Ì³ÐÓÐÁ½ÖÖÐÎʽ: ·º»¯£¨generalize£©ºÍʵÏÖ£¨realize£©£¬±íÏÖΪ is-a ¹ØÏµ¡£ +继承有两ç§�å½¢å¼�: 泛化(generalize)和实现(realize),表现为 is-a 关系。 -¢Ù ·º»¯¹ØÏµ(generalization) +â‘  泛化关系(generalization) -´Ó¾ßÌåÀàÖм̳Р+从具体类中继承 -![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/29badd92-109f-4f29-abb9-9857f5973928.png) +![](https://github.com/CyC2018/InterviewNotes/blob/master/pics//29badd92-109f-4f29-abb9-9857f5973928.png) -¢Ú ʵÏÖ¹ØÏµ(realize) +â‘¡ 实现关系(realize) -´Ó³éÏóÀà»òÕß½Ó¿ÚÖм̳Р+从抽象类或者接å�£ä¸­ç»§æ‰¿ -![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/4b16e1d3-3a60-472c-9756-2f31b1c48abe.png) +![](https://github.com/CyC2018/InterviewNotes/blob/master/pics//4b16e1d3-3a60-472c-9756-2f31b1c48abe.png) -**1.2 ÕûÌåºÍ²¿·Ö** +**1.2 整体和部分** -¢Ù ¾ÛºÏ¹ØÏµ(aggregation) +â‘  è�šå�ˆå…³ç³»(aggregation) -±íʾÕûÌåÓɲ¿·Ö×é³É£¬µ«ÊÇÕûÌåºÍ²¿·Ö²»ÊÇÇ¿ÒÀÀµµÄ£¬ÕûÌå²»´æÔÚÁ˲¿·Ö»¹ÊÇ»á´æÔÚ¡£ÒÔϱíʾ B ÓÉ A ×é³É£º +表示整体由部分组æˆ�,但是整体和部分ä¸�是强ä¾�赖的,整体ä¸�存在了部分还是会存在。以下表示 B ç”± A 组æˆ�: -![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/34259bb8-ca3a-4872-8771-9e946782d9c3.png) +![](https://github.com/CyC2018/InterviewNotes/blob/master/pics//34259bb8-ca3a-4872-8771-9e946782d9c3.png) -¢Ú ×éºÏ¹ØÏµ(composition) +â‘¡ 组å�ˆå…³ç³»(composition) -ºÍ¾ÛºÏ²»Í¬£¬×éºÏÖÐÕûÌåºÍ²¿·ÖÊÇÇ¿ÒÀÀµµÄ£¬ÕûÌå²»´æÔÚÁ˲¿·ÖÒ²²»´æÔÚÁË¡£±ÈÈ繫˾ºÍ²¿ÃÅ£¬¹«Ë¾Ã»Á˲¿ÃžͲ»´æÔÚÁË¡£µ«Êǹ«Ë¾ºÍÔ±¹¤¾ÍÊôÓھۺϹØÏµÁË£¬ÒòΪ¹«Ë¾Ã»ÁËÔ±¹¤»¹ÔÚ¡£ +å’Œè�šå�ˆä¸�å�Œï¼Œç»„å�ˆä¸­æ•´ä½“和部分是强ä¾�赖的,整体ä¸�存在了部分也ä¸�存在了。比如公å�¸å’Œéƒ¨é—¨ï¼Œå…¬å�¸æ²¡äº†éƒ¨é—¨å°±ä¸�存在了。但是公å�¸å’Œå‘˜å·¥å°±å±žäºŽè�šå�ˆå…³ç³»äº†ï¼Œå› ä¸ºå…¬å�¸æ²¡äº†å‘˜å·¥è¿˜åœ¨ã€‚ -![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/7dda050d-ac35-4f47-9f51-18f18ed6fa9a.png) +![](https://github.com/CyC2018/InterviewNotes/blob/master/pics//7dda050d-ac35-4f47-9f51-18f18ed6fa9a.png) -**1.3 Ï໥ÁªÏµ** +**1.3 相互è�”ç³»** -¢Ù ¹ØÁª¹ØÏµ(association) +â‘  å…³è�”关系(association) -±íʾ²»Í¬Àà¶ÔÏóÖ®¼äÓйØÁª£¬ÕâÊÇÒ»ÖÖ¾²Ì¬¹ØÏµ£¬ÓëÔËÐйý³ÌµÄ״̬Î޹أ¬ÔÚ×ʼ¾Í¿ÉÒÔÈ·¶¨¡£Òò´ËÒ²¿ÉÒÔÓà 1 ¶Ô 1¡¢¶à¶Ô 1¡¢¶à¶Ô¶àÕâÖÖ¹ØÁª¹ØÏµÀ´±íʾ¡£±ÈÈçѧÉúºÍѧУ¾ÍÊÇÒ»ÖÖ¹ØÁª¹ØÏµ£¬Ò»¸öѧУ¿ÉÒÔÓкܶàѧÉú£¬µ«ÊÇÒ»¸öѧÉúÖ»ÊôÓÚÒ»¸öѧУ£¬Òò´ËÕâÊÇÒ»ÖÖ¶à¶ÔÒ»µÄ¹ØÏµ£¬ÔÚÔËÐпªÊ¼Ö®Ç°¾Í¿ÉÒÔÈ·¶¨¡£ +表示ä¸�å�Œç±»å¯¹è±¡ä¹‹é—´æœ‰å…³è�”,这是一ç§�é�™æ€�关系,与è¿�行过程的状æ€�无关,在最开始就å�¯ä»¥ç¡®å®šã€‚因此也å�¯ä»¥ç”¨ 1 对 1ã€�多对 1ã€�多对多这ç§�å…³è�”关系æ�¥è¡¨ç¤ºã€‚比如学生和学校就是一ç§�å…³è�”关系,一个学校å�¯ä»¥æœ‰å¾ˆå¤šå­¦ç”Ÿï¼Œä½†æ˜¯ä¸€ä¸ªå­¦ç”Ÿå�ªå±žäºŽä¸€ä¸ªå­¦æ ¡ï¼Œå› æ­¤è¿™æ˜¯ä¸€ç§�多对一的关系,在è¿�行开始之å‰�å°±å�¯ä»¥ç¡®å®šã€‚ -![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/4ccd294c-d6b2-421b-839e-d88336ff5fb7.png) +![](https://github.com/CyC2018/InterviewNotes/blob/master/pics//4ccd294c-d6b2-421b-839e-d88336ff5fb7.png) -¢Ú ÒÀÀµ¹ØÏµ(dependency) +â‘¡ ä¾�赖关系(dependency) -ºÍ¹ØÁª¹ØÏµ²»Í¬µÄÊÇ, ÒÀÀµ¹ØÏµÊÇÔÚÔËÐйý³ÌÖÐÆð×÷Óõġ£Ò»°ãÒÀÀµ×÷ΪÀàµÄ¹¹ÔìÆ÷»òÕß·½·¨µÄ²ÎÊý´«È롣˫ÏòÒÀÀµÊ±Ò»ÖÖ²»ºÃµÄÉè¼Æ¡£ +和关è�”关系ä¸�å�Œçš„æ˜¯, ä¾�赖关系是在è¿�行过程中起作用的。一般ä¾�赖作为类的构造器或者方法的å�‚数传入。å�Œå�‘ä¾�赖时一ç§�ä¸�好的设计。 -![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/47ca2614-509f-476e-98fc-50ec9f9d43c0.png) +![](https://github.com/CyC2018/InterviewNotes/blob/master/pics//47ca2614-509f-476e-98fc-50ec9f9d43c0.png) -## 2. ʱÐòͼ +## 2. æ—¶åº�图 -**2.1 ¶¨Òå** +**2.1 定义** -ʱÐòͼÃèÊöÁ˶ÔÏóÖ®¼ä´«µÝÏûÏ¢µÄʱ¼ä˳Ðò£¬ËüÓÃÀ´±íʾÓÃÀýµÄÐÐΪ˳Ðò¡£ËüµÄÖ÷Òª×÷ÓÃÊÇͨ¹ý¶ÔÏó¼äµÄ½»»¥À´ÃèÊöÓÃÀý£¨×¢ÒâÊǶÔÏ󣩣¬´Ó¶øÑ°ÕÒÀàµÄ²Ù×÷¡£ +æ—¶åº�图æ��述了对象之间传递消æ�¯çš„æ—¶é—´é¡ºåº�,它用æ�¥è¡¨ç¤ºç”¨ä¾‹çš„行为顺åº�。它的主è¦�作用是通过对象间的交互æ�¥æ��述用例(注æ„�是对象),从而寻找类的æ“�作。 -**2.2 ³à±Ú֮սʱÐòͼ** +**2.2 赤å£�之战时åº�图** -´ÓÐéÏß´ÓÉÏÍùϱíʾʱ¼äµÄÍÆ½ø¡£ +从虚线从上往下表示时间的推进。 -![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/80c5aff8-fc46-4810-aeaa-215b5c60a003.png) +![](https://github.com/CyC2018/InterviewNotes/blob/master/pics//80c5aff8-fc46-4810-aeaa-215b5c60a003.png) -¿É¼û£¬Í¨¹ýʱÐòͼ¿ÉÒÔÖªµÀÿ¸öÀà¾ßÓÐÒÔϲÙ×÷£º +å�¯è§�,通过时åº�图å�¯ä»¥çŸ¥é�“æ¯�个类具有以下æ“�作: ```java -publc class Áõ±¸ { - public void Ó¦Õ½(); +publc class 刘备 { + public void 应战(); } -publc class ¿×Ã÷ { - public void Äⶨ²ßÂÔ(); - public void ÁªºÏËïȨ(); - private void ½è¶«·ç»ð¹¥(); +publc class 孔明 { + public void 拟定策略(); + public void è�”å�ˆå­™æ�ƒ(); + private void 借东风ç�«æ”»(); } -public class ¹ØÓð { - public void ·ÀÊØÇGÖÝ(); +public class 关羽 { + public void 防守è�Šå·ž(); } -public class ÕÅ·É { - public void ·ÀÊØ¾£ÖÝǰÏß(); +public class 张飞 { + public void 防守è�†å·žå‰�线(); } -public class ËïȨ { - public void Áì±øÏàÖú(); +public class å­™æ�ƒ { + public void 领兵相助(); } ``` -**2.3 »î¶¯Í¼¡¢Ê±Ðòͼ֮¼äµÄ¹ØÏµ** +**2.3 活动图ã€�æ—¶åº�图之间的关系** -»î¶¯Í¼Ê¾´ÓÓû§µÄ½Ç¶ÈÀ´ÃèÊöÓÃÀý£» +活动图示从用户的角度æ�¥æ��述用例; -ʱÐòͼÊÇ´Ó¼ÆËã»úµÄ½Ç¶È£¨¶ÔÏó¼äµÄ½»»¥£©ÃèÊöÓÃÀý¡£ +æ—¶åº�图是从计算机的角度(对象间的交互)æ��述用例。 -**2.4 ÀàͼÓëʱÐòͼµÄ¹ØÏµ** +**2.4 类图与时åº�图的关系** -ÀàͼÃèÊöϵͳµÄ¾²Ì¬½á¹¹£¬Ê±ÐòͼÃèÊöϵͳµÄ¶¯Ì¬ÐÐΪ¡£ +类图æ��述系统的é�™æ€�结构,时åº�图æ��述系统的动æ€�行为。 -**2.5 ʱÐòͼµÄ×é³É** +**2.5 æ—¶åº�图的组æˆ�** -¢Ù ¶ÔÏó +â‘  对象 -ÓÐÈýÖÖ±íÏÖÐÎʽ +有三ç§�表现形å¼� -![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/25b8adad-2ef6-4f30-9012-c306b4e49897.png) +![](https://github.com/CyC2018/InterviewNotes/blob/master/pics//25b8adad-2ef6-4f30-9012-c306b4e49897.png) -ÔÚ»­Í¼Ê±£¬Ó¦¸Ã×ñÑ­ÒÔÏÂÔ­Ôò£º +在画图时,应该é�µå¾ªä»¥ä¸‹åŽŸåˆ™ï¼š -1. °Ñ½»»¥Æµ·±µÄ¶ÔÏ󾡿ÉÄܵؿ¿Â£¡£ +1. 把交互频ç¹�的对象尽å�¯èƒ½åœ°é� æ‹¢ã€‚ -2. °Ñ³õʼ»¯Õû¸ö½»»¥»î¶¯µÄ¶ÔÏó£¨ÓÐʱÊÇÒ»¸ö²ÎÓëÕߣ©·ÅÖÃÔÚ×î×ó±ß¡£ +2. 把åˆ�始化整个交互活动的对象(有时是一个å�‚与者)放置在最左边。 -¢Ú ÉúÃüÏß +â‘¡ 生命线 -ÉúÃüÏß´Ó¶ÔÏóµÄ´´½¨¿ªÊ¼µ½¶ÔÏóÏú»ÙʱÖÕÖ¹ +生命线从对象的创建开始到对象销æ¯�时终止 -![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/b7b0eac6-e7ea-4fb6-8bfb-95fec6f235e2.png) +![](https://github.com/CyC2018/InterviewNotes/blob/master/pics//b7b0eac6-e7ea-4fb6-8bfb-95fec6f235e2.png) -¢Û ÏûÏ¢ +â‘¢ 消æ�¯ -¶ÔÏóÖ®¼äµÄ½»»¥Ê½Í¨¹ý·¢ËÍÏûÏ¢À´ÊµÏֵġ£ +对象之间的交互å¼�通过å�‘é€�消æ�¯æ�¥å®žçŽ°çš„ã€‚ -ÏûÏ¢ÓÐ4ÖÖÀàÐÍ£º +消æ�¯æœ‰4ç§�类型: -1\. ¼òµ¥ÏûÏ¢£¬²»Çø·Öͬ²½Òì²½¡£ +1\. 简å�•消æ�¯ï¼Œä¸�区分å�Œæ­¥å¼‚步。 -![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/a13b62da-0fa8-4224-a615-4cadacc08871.png) +![](https://github.com/CyC2018/InterviewNotes/blob/master/pics//a13b62da-0fa8-4224-a615-4cadacc08871.png) -2\. ͬ²½ÏûÏ¢£¬·¢ËÍÏûÏ¢Ö®ºóÐèÒªÔÝÍ£»î¶¯À´µÈ´ý»ØÓ¦¡£ +2\. å�Œæ­¥æ¶ˆæ�¯ï¼Œå�‘é€�消æ�¯ä¹‹å�Žéœ€è¦�æš‚å�œæ´»åЍæ�¥ç­‰å¾…回应。 -![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/33821037-dc40-4266-901c-e5b38e618426.png) +![](https://github.com/CyC2018/InterviewNotes/blob/master/pics//33821037-dc40-4266-901c-e5b38e618426.png) -3\. Òì²½ÏûÏ¢£¬·¢ËÍÏûÏ¢Ö®ºó²»ÐèÒªµÈ´ý¡£ +3\. 异步消æ�¯ï¼Œå�‘é€�消æ�¯ä¹‹å�Žä¸�需è¦�等待。 -![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/dec6c6cc-1b5f-44ed-b8fd-464fcf849dac.png) +![](https://github.com/CyC2018/InterviewNotes/blob/master/pics//dec6c6cc-1b5f-44ed-b8fd-464fcf849dac.png) -4\. ·µ»ØÏûÏ¢£¬¿ÉÑ¡¡£ +4\. 返回消æ�¯ï¼Œå�¯é€‰ã€‚ -¢Ü ¼¤»î +â‘£ 激活 -ÉúÃüÏßÉϵķ½¿ò±íʾ¼¤»î״̬£¬ÆäËüʱ¼ä´¦ÓÚÐÝÃß״̬¡£ +生命线上的方框表示激活状æ€�,其它时间处于休眠状æ€�。 -![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/6ab5de9b-1c1e-4118-b2c3-fb6c7ed7de6f.png) +![](https://github.com/CyC2018/InterviewNotes/blob/master/pics//6ab5de9b-1c1e-4118-b2c3-fb6c7ed7de6f.png) -# ²Î¿¼×ÊÁÏ +# å�‚考资料 -- Java ±à³Ì˼Ïë +- Java 编程æ€�想 -- [ÃæÏò¶ÔÏóÉè¼ÆµÄSOLIDÔ­Ôò](http://www.cnblogs.com/shanyou/archive/2009/09/21/1570716.html) +- [é�¢å�‘对象设计的SOLID原则](http://www.cnblogs.com/shanyou/archive/2009/09/21/1570716.html) -- [¿´¶®UMLÀàͼºÍʱÐòͼ](http://design-patterns.readthedocs.io/zh_CN/latest/read_uml.html#generalization) +- [看懂UML类图和时åº�图](http://design-patterns.readthedocs.io/zh_CN/latest/read_uml.html#generalization) -- [UMLϵÁСª¡ªÊ±Ðòͼ£¨Ë³Ðòͼ£©sequence diagram](http://www.cnblogs.com/wolf-sun/p/UML-Sequence-diagram.html) +- [UML系列——时åº�图(顺åº�图)sequence diagram](http://www.cnblogs.com/wolf-sun/p/UML-Sequence-diagram.html) -- [ÃæÏò¶ÔÏó±à³ÌÈý´óÌØÐÔ------·â×°¡¢¼Ì³Ð¡¢¶à̬](http://blog.csdn.net/jianyuerensheng/article/details/51602015) +- [é�¢å�‘对象编程三大特性------å°�装ã€�继承ã€�多æ€�](http://blog.csdn.net/jianyuerensheng/article/details/51602015)