Matrix42 - 读书
type: channel
link: http://www.sundeqiang.cn/category/reading
items: 成为专业程序员路上用到的各种优秀资料、神器及框架
items: 名词解释
items: 位运算(四) : 实战篇
items: 位运算(三) : 进阶篇(2)
items: 位运算(二) : 进阶篇(1)
items: 位运算(一) : 基础篇
items: 原码,反码和补码
items: RAID详解
items: Effective Java读书笔记
items: 专业书书单

成为专业程序员路上用到的各种优秀资料、神器及框架
type: item
date: 2017-10-13T15:01:35+08:00
description: 前言 成为一名专业程序员的道路上，需要坚持练习、学习与积累，技术方面既要有一定的广度，更要有自己的深度。 笔者作为一位tool mad，将工作以来用到的各种优秀资料、神器及框架整理在此，毕竟好记性不如烂键盘，此项目可以作为自己的不时之需。 本人喜欢折腾，记录的东西也比较杂，各方面都会有一些，内容按重要等级排序，大家各取所需。 这里的东西会持续积累下去，欢迎Star，也欢迎发PR给我。 Thonatos.Yang整理的GitBook版本，阅读体验更佳：https://thonatos.gitbooks.io/be-a-professional-programmer/ 目录 资料篇 技术站点 必看书籍 大牛博客 GitHub篇 工具篇 平台工具 常用工具 第三方服务 爬虫相关(好玩的工具) 安全相关 Web服务器性能/压力测试工具/负载均衡器 大数据处理/数据分析/分布式工具 Web前端 语言篇 Scala Java Python Swift .NET C & C++ 其他 游戏开发相关 日志聚合，分布式日志收集 RTP,实时传输协议与音视频 资料篇 技术站点 在线学习：Coursera、edX、Udacity、MIT公开课、MOOC学院、慕课网 Hacker News：非常棒的针对编程的链接聚合网站 Techmeme：美国知名科技新闻和博客聚集网站，类似的还有（Panda, Hacker & Designer News） Reddit - Programming板块：同上 Java牛人必备：Program Creek Stack Overflow：IT技术问答网站 SegmentFault：中文的技术问答社区 GitHub：全球最大的源代码管理平台，很多知名开源项目都在上面，如Linux内核，OpenStack等 码云：支持中文可免费创建私有项目的代码托管平台，可作为备选 LeetCode：来做做这些题吧，看看自己的算法水平如何？这可比什么面试宝典强多了。 LintCode：支持中文的编程题在线训练平台，可作为备选 Kaggle,Topcoder: 机器学习、大数据竞赛 掘金：高质量的技术社区 开发者头条 InfoQ：企业级应用，关注软件开发领域 V2EX: way to explore 国内老牌技术社区：OSChina、博客园、CSDN、51CTO 免费的it电子书：http://it-ebooks.info/ 在线学习：http://www.udemy.com/ 优质学习资源：http://plus.mojiax.com/ 代码练习：http://exercism.io/ and https://www.codingame.com DevStore:开发者服务商店 MSDN：微软相关的官方技术集中地，主要是文档类 谷歌开发者 码库 - 收录了实用的开源项目及资源 Coding 基于Git的国内代码托管平台，支持私有项目，有项目管理相关功能 必看书籍 SICP(Structure and Interpretation of Computer Programs) 深入理解计算机系统 代码大全2 人件 人月神话 软件随想录 算法导论（麻省理工学院出版社） 离散数学及其应用 设计模式 编程之美 黑客与画家 编程珠玑 The Little Schemer Simply Scheme_Introducing_Computer_Science C++ Prime Effective C++ TCP/IP详解 Unix 编程艺术 技术的本质 软件随想录 计算机程序设计艺术 程序员的自我修养：链接、装载与库 程序员修炼之道 高效能程序员的修炼 《精神分析引论》弗洛伊德 《失控》《科技想要什么》《技术元素》凯文凯利 程序开发心理学 天地一沙鸥 搞定：无压力工作的艺术 大牛博客 awesome-programmers - 各领域大牛，值得纪念的程序员们 云风（游戏界大牛）: http://blog.codingnow.com/ 王垠（不少文章喷到蛮有道理）：http://www.yinwang.org/ 冰河-伞哥(Lisp大牛)：http://tianchunbinghe.blog.163.com/ R大【干货满满】RednaxelaFX写的文章/回答的导航帖 陈皓-左耳朵耗子：http://coolshell.cn/ Jeff Atwood（国外知名博主）: https://blog.codinghorror.com/ 阮一峰（黑客与画家译者，Web）：http://www.ruanyifeng.com/ 廖雪峰（他的Python、Git教程不少人都看过）：http://www.liaoxuefeng.com/ 道哥的黑板报（安全）：http…

名词解释
type: item
date: 2017-10-13T14:15:00+08:00
description: 数据仓库 数据仓库，英文名称为Data Warehouse，可简写为DW或DWH。是一种资讯系统的资料储存理论，此理论强调利用某些特殊资料储存方式，让所包含的资料，特别有利于分析处理，以产生有价值的资讯并依此作决策。 利用数据仓库方式所存放的资料，具有一但存入，便不随时间而更动的特性，同时存入的资料必定包含时间属性，通常一个数据仓库皆会含有大量的历史性资料，并利用特定分析方式，自其中发掘出特定资讯。 数据仓库的特性 主题导向（Subject-Oriented） 有别于一般OLTP系统，数据仓库的资料模型设计，着重将资料按其意义归类至相同的主题区（subject area），因此称为主题导向。举例如Party、Arrangement、Event、Product等。 集成性（Integrated） 资料来自企业各OLTP系统，在数据仓库中是集成过且一致的。 时间差异性（Time-Variant） 资料的变动，在数据仓库中是能够被纪录以及追踪变化的，有助于能反映出能随着时间变化的资料轨迹。 不变动性（Nonvolatile） 资料一旦确认写入后是不会被取代或删除的，即使资料是错误的亦同。（i.e.错误的后续修正，便可因上述时间差异性的特性而被追踪） ETL ETL，是英文 Extract-Transform-Load 的缩写，用来描述将数据从来源端经过抽取（extract）、转换（transform）、加载（load）至目的端的过程。ETL一词较常用在数据仓库，但其对象并不限于数据仓库。 ETL是构建数据仓库的重要一环，用户从数据源抽取出所需的数据，经过数据清洗,最终按照预先定义好的数据仓库模型，将数据加载到数据仓库中去。 BI BI（Business Intelligence）即商务智能 广义上讲，BI包括ETL, DW和相应的Reporting System. 因为现在一般的公司动不动说上个BI系统，都是要从DW建模开始做，然后做ETL，最后做对应的Reporting System. 虽然最终领导们只看到了他们想要的报表，但是这一套系统是需要DW和ETL的支持的。 狭义的BI就仅仅指Reporting System, 就是基于DW设计的报表系统，是领导们想要看的报表的展现。通过DW中的维度表和事实表，来从不同的维度看领导想要的数据。比如大中华区销售了多少，每个省的KPI怎么样等等。常用的工具有OBIEE，BO，Cognos等等。 OLTP 联机事务处理OLTP（on-line transaction processing） 主要是执行基本日常的事务处理，比如数据库记录的增删查改。比如在银行的一笔交易记录，就是一个典型的事务。 OLTP的特点一般有： 实时性要求高。我记得之前上大学的时候，银行异地汇款，要隔天才能到账，而现在是分分钟到账的节奏，说明现在银行的实时处理能力大大增强。 数据量不是很大，生产库上的数据量一般不会太大，而且会及时做相应的数据处理与转移。 交易一般是确定的，比如银行存取款的金额肯定是确定的，所以OLTP是对确定性的数据进行存取 高并发，并且要求满足ACID原则。比如两人同时操作一个银行卡账户，比如大型的购物网站秒杀活动时上万的QPS请求。 OLAP 联机分析处理OLAP（On-Line Analytical Processing） 是数据仓库系统的主要应用，支持复杂的分析操作，侧重决策支持，并且提供直观易懂的查询结果。典型的应用就是复杂的动态的报表系统。 OLAP的特点一般有： 实时性要求不是很高，比如最常见的应用就是天级更新数据，然后出对应的数据报表。 数据量大，因为OLAP支持的是动态查询，所以用户也许要通过将很多数据的统计后才能得到想要知道的信息，例如时间序列分析等等，所以处理的数据量很大; OLAP系统的重点是通过数据提供决策支持，所以查询一般都是动态，自定义的。所以在OLAP中，维度的概念特别重要。一般会将用户所有关心的维度数据，存入对应数据平台。 总结： OLTP即联机事务处理，就是我们经常说的关系数据库，增删查改就是我们经常应用的东西，这是数据库的基础；TPCC(Transaction Processing Performance Council)属于此类。 OLAP即联机分析处理，是数据仓库的核心部心，所谓数据仓库是对于大量已经由OLTP形成的数据的一种分析型的数据库，用于处理商业智能、决策支持等重要的决策信息；数据仓库是在数据库应用到一定程序之后而对历史数据的加工与分析，读取较多，更新较少，TPCH属于此类。 随着大数据时代的到来，对于OLAP，列存储模式或者说nosql模式比传统意义的行存储模式可能更具优势。 ACID ACID，指数据库事务正确执行的四个基本要素的缩写。包含：原子性（At…

位运算(四) : 实战篇
type: item
date: 2017-07-28T10:55:00+08:00
description: Problem : 费解的开关 题目来源:06年NOIp模拟赛（一） by Matrix67 第四题 问题描述 你玩过“拉灯”游戏吗？25盏灯排成一个5x5的方形。每一个灯都有一个开关，游戏者可以改变它的状态。每一步，游戏者可以改变某一个灯的状态。游戏者改变一个灯的状态会产生连锁反应：和这个灯上下左右相邻的灯也要相应地改变其状态。 我们用数字“1”表示一盏开着的灯，用数字“0”表示关着的灯。下面这种状态 10111 01101 10111 10000 11011 在改变了最左上角的灯的状态后将变成： 01111 11101 10111 10000 11011 再改变它正中间的灯后状态将变成： 01111 11001 11001 10100 11011 给定一些游戏的初始状态，编写程序判断游戏者是否可能在6步以内使所有的灯都变亮。 输入格式 第一行有一个正整数n，代表数据中共有n个待解决的游戏初始状态。 以下若干行数据分为n组，每组数据有5行，每行5个字符。每组数据描述了一个游戏的初始状态。各组数据间用一个空行分隔。 对于30%的数据，n<=5； 对于100%的数据，n<=500。 输出格式 输出数据一共有n行，每行有一个小于等于6的整数，它表示对于输入数据中对应的游戏状态最少需要几步才能使所有灯变亮。 对于某一个游戏初始状态，若6步以内无法使所有灯变亮，请输出“-1”。 样例输入 3 00111 01011 10001 11010 11100 11101 11101 11110 11111 11111 01111 11111 11111 11111 11111 样例输出 3 2 -1 程序代码 const BigPrime=3214567; MaxStep=6; type pointer=^rec; rec=record v:longint; step:integer; next:pointer; end; var total:longint; hash:array[0..BigPrime-1]of pointer; q:array[1..400000]of rec; function update(a:longint;p:integer):longint; begin a:=a xor (1 shl p); if p mod 5<>0 then a:=a xor (1 shl (p-1)); if (p+1) mod 5<>0 then a:=a xor (1 shl (p+1)); if p<20 then a:=a xor (1 shl (p+5)); if p>4 then a:=a xor (1 shl (p-5)); exit(a); end; function find(a:longint;step:integer):boolean; var now:pointer; begin now:=hash[a mod BigPrime]; while now<>nil do begin if now^.v=a then exit(true); now:=now^.next; end; new(now); now^.v:=a; now^.step:=step; now^.next:=hash[a mod BigPrime]; hash[a mod BigPrime]:=now; total:=total+1; exit(false); end; procedure solve; var p:integer; close:longint=0; open:longint=1; begin find(1 shl 25-1,0); q[1].v:=1 shl 25-1; q[1].step:=0; repeat inc(close); for p:=0 to 24 do if not find(update(q[close].v,p),q[close].step+1) and (q[close].step+1<MaxStep) then begin open:=open+1; q[open].v:=update(q[close].v,p); q[open].step:=q[close].step+1; end; until close>=open; end; procedure print(a:longint); var now:pointer; begin now:=hash[a mod BigPrime]; while now<>nil do begin if now^.v=a then begin writeln(now^.step); exit; end; now:=now^.next; end; writeln(-1)…

位运算(三) : 进阶篇(2)
type: item
date: 2017-07-28T10:51:00+08:00
description: n皇后问题位运算版 n皇后问题是啥我就不说了吧，学编程的肯定都见过。下面的十多行代码是n皇后问题的一个高效位运算程序，看到过的人都夸它牛。初始时，upperlim:=(1 shl n)-1。主程序调用test(0,0,0)后sum的值就是n皇后总的解数。拿这个去交USACO，0.3s，暴爽。 procedure test(row,ld,rd:longint); var pos,p:longint; begin { 1} if row<>upperlim then { 2} begin { 3} pos:=upperlim and not (row or ld or rd); { 4} while pos<>0 do { 5} begin { 6} p:=pos and -pos; { 7} pos:=pos-p; { 8} test(row+p,(ld+p)shl 1,(rd+p)shr 1); { 9} end; {10} end {11} else inc(sum); end; 乍一看似乎完全摸不着头脑，实际上整个程序是非常容易理解的。这里还是建议大家自己单步运行一探究竟，实在没研究出来再看下面的解说。 和普通算法一样，这是一个递归过程，程序一行一行地寻找可以放皇后的地方。过程带三个参数，row、ld和rd，分别表示在纵列和两个对角线方向的限制条件下这一行的哪些地方不能放。我们以6×6的棋盘为例，看看程序是怎么工作的。假设现在已经递归到第四层，前三层放的子已经标在左图上了。红色、蓝色和绿色的线分别表示三个方向上有冲突的位置，位于该行上的冲突位置就用row、ld和rd中的1来表示。把它们三个并起来，得到该行所有的禁位，取反后就得到所有可以放的位置（用pos来表示）。前面说过-a相当于not a + 1，这里的代码第6行就相当于pos and (not pos + 1)，其结果是取出最右边的那个1。这样，p就表示该行的某个可以放子的位置，把它从pos中移除并递归调用test过程。注意递归调用时三个参数的变化，每个参数都加上了一个禁位，但两个对角线方向的禁位对下一行的影响需要平移一位。最后，如果递归到某个时候发现row=111111了，说明六个皇后全放进去了，此时程序从第1行跳到第11行，找到的解的个数加一。 Gray码 假如我有4个潜在的GF，我需要决定最终到底和谁在一起。一个简单的办法就是，依次和每个MM交往一段时间，最后选择给我带来的“满意度”最大的MM。但看了dd牛的理论后，事情开始变得复杂了：我可以选择和多个MM在一起。这样，需要考核的状态变成了2^4=16种（当然包括0000这一状态，因为我有可能是玻璃）。现在的问题就是，我应该用什么顺序来遍历这16种状态呢？ 传统的做法是，用二进制数的顺序来遍历所有可能的组合。也就是说，我需要以0000->0001->0010->0011->0100->…->1111这样的顺序对每种状态进行测试。这个顺序很不科学，很多时候状态的转移都很耗时。比如从0111到1000时我需要暂时甩掉当前所有的3个MM，然后去把第4个MM。同时改变所有MM与我的关系是一件何等巨大的工程啊。因此，我希望知道，是否有一种方法可以使得，从没有MM这一状态出发，每次只改变我和一个MM的关系（追或者甩），15次操作后恰好遍历完所有可能的组合（最终状态不一定是1111）。大家自己先试一试看行不行。 解决这个问题的方法很巧妙。我们来说明，假如我们已经知道了n=2时的合法遍历顺序，我们如何得到n=3的遍历顺序。显然，n=2的遍历顺序如下： 00 01 11 10 你可能已经想到了如何把上面的遍历顺序扩展到n=3的情况。n=3时一共有8种状态，其中前面4个把n=2的遍历顺序照搬下来，然后把它们对称翻折下去并在最前面加上1作为后面4个状态： 000 001 011 010 ↑ ——– 110 ↓ 111 101 100 用这种方法得到的遍历顺序显然符合要求。首先，上面8个状态恰好是n=3时的所有8种组合，因为它们是在n=2的全部四种组合的基础上考虑选不选第3个元素所得到的。然后我们看到，后面一半的状态应该和前面一半一样满足“相邻状态间仅一位不同”的限制，而“镜面”处则是最前面那一位数不同。再次翻折三阶遍历顺序，我们就得到了刚才的问题的答案： 0000 0001 0011 0010 0110 0111 0101 0100 1100 1101 1111 1110 1010 1011 1001 1000 这种遍历顺序作为一种编码方式存在，叫做Gray码（写个中文让蜘蛛来抓：格雷码）。它的应用范围很广。比如，n阶的Gray码相当于在n维立方体上的Hamilton回路，因为沿着立方体上的边走一步，n维坐标中只会有一个值改变。再比如…

位运算(二) : 进阶篇(1)
type: item
date: 2017-07-28T10:43:00+08:00
description: 二进制中的1有奇数个还是偶数个 我们可以用下面的代码来计算一个32位整数的二进制中1的个数的奇偶性，当输入数据的二进制表示里有偶数个数字1时程序输出0，有奇数个则输出1。例如，1314520的二进制101000000111011011000中有9个1，则x=1314520时程序输出1。 var i,x,c:longint; begin readln(x); c:=0; for i:=1 to 32 do begin c:=c + x and 1; x:=x shr 1; end; writeln( c and 1 ); end. 但这样的效率并不高，位运算的神奇之处还没有体现出来。 同样是判断二进制中1的个数的奇偶性，下面这段代码就强了。你能看出这个代码的原理吗？ var x:longint; begin readln(x); x:=x xor (x shr 1); x:=x xor (x shr 2); x:=x xor (x shr 4); x:=x xor (x shr 8); x:=x xor (x shr 16); writeln(x and 1); end. 为了说明上面这段代码的原理，我们还是拿1314520出来说事。1314520的二进制为101000000111011011000，第一次异或操作的结果如下： 00000000000101000000111011011000 XOR 0000000000010100000011101101100 --------------------------------------- 00000000000111100000100110110100 得到的结果是一个新的二进制数，其中右起第i位上的数表示原数中第i和i+1位上有奇数个1还是偶数个1。比如，最右边那个0表示原数末两位有偶数个1，右起第3位上的1就表示原数的这个位置和前一个位置中有奇数个1。对这个数进行第二次异或的结果如下： 00000000000111100000100110110100 XOR 000000000001111000001001101101 --------------------------------------- 00000000000110011000101111011001 结果里的每个1表示原数的该位置及其前面三个位置中共有奇数个1，每个0就表示原数对应的四个位置上共偶数个1。一直做到第五次异或结束后，得到的二进制数的最末位就表示整个32位数里有多少个1，这就是我们最终想要的答案。 计算二进制中的1的个数 同样假设x是一个32位整数。经过下面五次赋值后，x的值就是原数的二进制表示中数字1的个数。比如，初始时x为1314520（网友抓狂：能不能换一个数啊），那么最后x就变成了9，它表示1314520的二进制中有9个1。 x := (x and $55555555) + ((x shr 1) and $55555555); x := (x and $33333333) + ((x shr 2) and $33333333); x := (x and $0F0F0F0F) + ((x shr 4) and $0F0F0F0F); x := (x and $00FF00FF) + ((x shr 8) and $00FF00FF); x := (x and $0000FFFF) + ((x shr 16) and $0000FFFF); 为了便于解说，我们下面仅说明这个程序是如何对一个8位整数进行处理的。我们拿数字211（我们班某MM的生日）来开刀。211的二进制为11010011。 +---+---+---+---+---+---+---+---+ | 1 | 1 | 0 | 1 | 0 | 0 | 1 | 1 | <---原数 +---+---+---+---+---+---+---+---+ | 1 0 | 0 1 | 0 0 | 1 0 | <---第一次运算后 +-------+-------+-------+-------+ | 0 0 1 1 | 0 0 1 0 | <---第二次运算后 +---------------+---------------+ | 0 0 0 0 0 1 0 1 | <---第三次运算后，得数为5 +-------------------------------+ 整个程序是一个分治的思想。第一次我们把每相邻的两位加起来，得到每两位里1的个数，比如前两位10就表示原数的前两位有2个1。第二次我们继续两两相加，10+01=11，00+10=10，得到的结果是00110010，它表示原数前4位有3个1，末4位有2个1。最后一次我们把0011和0010加…

位运算(一) : 基础篇
type: item
date: 2017-07-27T18:59:00+08:00
description: 什么是位运算？ 程序中的所有数在计算机内存中都是以二进制的形式储存的。位运算说穿了，就是直接对整数在内存中的二进制位进行操作。比如，and运算本来是一个逻辑运算符，但整数与整数之间也可以进行and运算。举个例子，6的二进制是110，11的二进制是1011，那么6 and 11的结果就是2，它是二进制对应位进行逻辑运算的结果。由于位运算直接对内存数据进行操作，不需要转成十进制，因此处理速度非常快。 各种位运算的使用 1. 与运算(&) 与运算通常用于二进制取位操作，例如一个数 & 1的结果就是取二进制的最末位。这可以用来判断一个整数的奇偶，二进制的最末位为0表示该数为偶数，最末位为1表示该数为奇数. 2. 或运算(|) 或运算通常用于二进制特定位上的无条件赋值，例如一个数 | 1的结果就是把二进制最末位强行变成1。如果需要把二进制最末位变成0，对这个数 | 1之后再减一就可以了，其实际意义就是把这个数强行变成最接近的偶数。 3. 异或运算(^) 异或运算通常用于对二进制的特定一位进行取反操作，因为异或可以这样定义：0和1异或0都不变，异或1则取反。 异或运算的逆运算是它本身，也就是说两次异或同一个数最后结果不变，即(a ^ b) ^ b = a。所以异或运算可以用于简单的加密。 下面我们看另外一个东西。定义两个符号#和@，这两个符号互为逆运算，也就是说(x # y) @ y = x。现在依次执行下面三条命令，结果是什么？ x <- x # y y <- x @ y x <- x @ y 执行了第一句后x变成了x # y。那么第二句实质就是y <- x # y @ y，由于#和@互为逆运算，那么此时的y变成了原来的x。第三句中x实际上被赋值为(x # y) @ x，如果#运算具有交换律，那么赋值后x就变成最初的y了。这三句话的结果是，x和y的位置互换了。 加法和减法互为逆运算，并且加法满足交换律。把#换成+，把@换成-，我们可以写出一个不需要临时变量的swap过程： a = a + b; b = a - b; a = a - b; 好了，刚才不是说^的逆运算是它本身吗？于是我们就有了一个看起来非常诡异的swap过程： a = a ^ b; b = a ^ b; a = a ^ b; 4. 非运算(~) 非运算的定义是把内存中的0和1全部取反。使用~运算时要格外小心，你需要注意整数类型有没有符号。如果!的对象是无符号整数（不能表示负数），那么得到的值就是它与该类型上界的差，因为无符号类型的数是用0x0000到0xFFFF依次表示的。下面的程序返回65435。 #include <stdio.h> int main() { unsigned short a=100; a = ~a; printf( "%dn", a ); return 0; } 5. 左移运算(<<) a << b就表示把a转为二进制后左移b位（在后面添b个0）。例如100的二进制为1100100，而110010000转成十进制是400，那么100 << 2 = 400。可以看出，a << b的值实际上就是a乘以2的b次方，因为在二进制数后添一个0就相当于该数乘以2。 通常认为a << 1比a * 2更快，因为前者是更底层一些的操作。因此程序中乘以2的操作请尽量用左移一位来代替。 定义一些常量可能会用到shl运算。你可以方便地用1 << 16 – 1来表示65535。很多算法和数据结构要求数据规模必须是2的幂，此时可以用shl来定义Max_N等常量。 6. 右移运算(>>) 和左移相似，a >> b表示二进制右移b位（去掉末b位），相当于a除以2的b次方（取整）。我们也经常用>> 1来代替除2，比如二分查找、堆的插入操作等等。想办法用右移代替除法运算可以使程序效率大大提高。最大公约数的二进制算法用除以2操作来代替慢得出奇的取余运算，效率可以提高60%。 位运算的简单应用 有时我们的程序需要一个规模不大的Hash表来记录状态。比如，做数独时我们需要27个Hash表来统计每一行、每一列和每一个小九宫格里已经有哪些数了。此时，我们可以用27个小于2^9的整数进行记录。例如，一个只填了2和5的小九宫格就用数字18表示（二进制为000010010），而某一行的状态为511则表示这一行已经填满。需要改变状态时我们不需要把这个数转成二进制修改后再转回去，而是直接进行位操作。在搜索时，把状态表示成整数可以更好地进行判重等操作。 下面列举了一些常见的二进制位的变换操作。 功能 | 示例 | 位运算 去掉最后一位 | (101101->10110) | x >> 1 在最后加一个0 | (101101->1011010) | x << 1 在最后加一个1 | (101101->10110…

原码,反码和补码
type: item
date: 2017-07-27T16:36:00+08:00
description: 一. 机器数和真值 1、机器数 一个数在计算机中的二进制表示形式, 叫做这个数的机器数。机器数是带符号的，在计算机用一个数的最高位存放符号, 正数为0, 负数为1. 比如，十进制中的数 +3 , 计算机字长为8位, 转换成二进制就是00000011。如果是 -3 , 就是 10000011 。 那么，这里的 00000011 和 10000011 就是机器数。 2、真值 因为第一位是符号位，所以机器数的形式值就不等于真正的数值。例如上面的有符号数 10000011，其最高位1代表负，其真正数值是 -3 而不是形式值131（10000011转换成十进制等于131）。所以，为区别起见，将带符号位的机器数对应的真正数值称为机器数的真值。 例：0000 0001的真值 = +000 0001 = +1，1000 0001的真值 = –000 0001 = –1 二. 原码, 反码, 补码的基础概念和计算方法 在探求为何机器要使用补码之前, 让我们先了解原码, 反码和补码的概念.对于一个数, 计算机要使用一定的编码方式进行存储. 原码, 反码, 补码是机器存储一个具体数字的编码方式. 1. 原码 原码就是符号位加上真值的绝对值, 即用第一位表示符号, 其余位表示值. 比如如果是8位二进制: [+1]原 = 0000 0001 [-1]原 = 1000 0001 第一位是符号位. 因为第一位是符号位, 所以8位二进制数的取值范围就是: [1111 1111 , 0111 1111] 即 [-127 , 127] 原码是人脑最容易理解和计算的表示方式. 2. 反码 反码的表示方法是: 正数的反码是其本身 负数的反码是在其原码的基础上, 符号位不变，其余各个位取反. [+1] = [00000001]原 = [00000001]反 [-1] = [10000001]原 = [11111110]反 可见如果一个反码表示的是负数, 人脑无法直观的看出来它的数值. 通常要将其转换成原码再计算. 3. 补码 补码的表示方法是: 正数的补码就是其本身 负数的补码是在其原码的基础上, 符号位不变, 其余各位取反, 最后+1. (即在反码的基础上+1) [+1] = [00000001]原 = [00000001]反 = [00000001]补 [-1] = [10000001]原 = [11111110]反 = [11111111]补 对于负数, 补码表示方式也是人脑无法直观看出其数值的. 通常也需要转换成原码在计算其数值. 三. 为何要使用原码, 反码和补码 现在我们知道了计算机可以有三种编码方式表示一个数. 对于正数因为三种编码方式的结果都相同: [+1] = [00000001]原 = [00000001]反 = [00000001]补 所以不需要过多解释. 但是对于负数: [-1] = [10000001]原 = [11111110]反 = [11111111]补 可见原码, 反码和补码是完全不同的. 既然原码才是被人脑直接识别并用于计算表示方式, 为何还会有反码和补码呢? 首先, 因为人脑可以知道第一位是符号位, 在计算的时候我们会根据符号位, 选择对真值区域的加减. (真值的概念在本文最开头). 但是对于计算机, 加减乘数已经是最基础的运算, 要设计的尽量简单. 计算机辨别"符号位"显然会让计算机的基础电路设计变得十分复杂! 于是人们想出了将符号位也参与运算的方法. 我们知道, 根据运算法则减去一个正数等于加上一个负数, 即: 1-1 = 1 + (-1) = 0 , 所以机器可以只有加法而没有减法, 这样计算机运算的设计就更简单了. 于是人们开始探索 将符号位参与运算, 并且只保留加法的方法. 首先来看原码: 计算十进制的表达式: 1-1=0 1 - 1 = 1 + (-1) = [00000001]原 + [10000001]原 = [10000010]原 = -2 如果用原码表示, 让符号位也参与计算, 显然对于减法来说, 结果是不正确的.这也就是为何计算机内部不使用原码表示一个数. 为了解决原码做减法的问题, 出现了反码: 计算十进制的表达式: 1-1=0 1 - 1 = 1 + (-1) = [0000 0001]原 + [1000 0001]原= [0000 0001]反 + [1111 1110]反 = [1111 1111]反 = [1000 0000]原 = -0 发现用反码计算减法, 结果的真值部分是正确的. 而唯一的问题其实就出现在"0"这个特殊的数值上. 虽然人们理解上+0和-0是一样的, 但是0带符号是没有任何意义的. 而且会有[0000 0000]原和[1000 0000]原两个编码表示0. 于是补码的出现, 解决…

RAID详解
type: item
date: 2017-07-27T10:34:37+08:00
description: 一．RAID定义 RAID(Redundant Array of Independent Disk 独立冗余磁盘阵列)技术是加州大学伯克利分校1987年提出，最初是为了组合小的廉价磁盘来代替大的昂贵磁盘，同时希望磁盘失效时不会使对数据的访问受损 失而开发出一定水平的数据保护技术。RAID就是一种由多块廉价磁盘构成的冗余阵列，在操作系统下是作为一个独立的大型存储设备出现。RAID可以充分发 挥出多块硬盘的优势，可以提升硬盘速度，增大容量，提供容错功能够确保数据安全性，易于管理的优点，在任何一块硬盘出现问题的情况下都可以继续工作，不会 受到损坏硬盘的影响。 二、 RAID的几种工作模式（仅讨论 RAID0，RAID1，RAID5，RAID10这四种，这四种比较典型） 1、RAID0 （又称为Stripe或Striping－－分条） 即Data Stripping数据分条技术。RAID 0可以把多块硬盘连成一个容量更大的硬盘群，可以提高磁 盘的性能和吞吐量。RAID 0没有冗余或错误修复能力，成本低，要求至少两个磁盘，一般只是在那些对数 据安全性要求不高的情况下才被使用。 2、RAID 1 （又称为Mirror或Mirroring－－镜像） RAID 1称为磁盘镜像：把一个磁盘的数据镜像到另一个磁盘上，在不影响性能情况下最大限度的保证系统的可靠性和可修复性上，具有很高的数据冗余能力，但磁盘利用 率为50%，故成本最高，多用在保存关键性的重要数据的场合。RAID 1的操作方式是把用户写入硬盘的数据百分之百地自动复制到另外一个硬盘上。 3、RAID 5 （可以理解为是RAID 0和RAID 1的折衷方案，但没有完全使用RAID 1镜像理念，而是使用了“奇偶校验信息”来作为数据恢复的方式，与下面的RAID10不同。） RAID 5 是一种存储性能、数据安全和存储成本兼顾的存储解决方案。 以四个硬盘组成的RAID 5为例，其数据存储方式如图4所示：图中，Ap为A1，A2和A3的奇偶校验信息，其它以此类推。由图中可以看出，RAID 5不对存储的数据进行备份，而是把数据和相对应的奇偶校验信息存储到组成RAID5的各个磁盘上，并且奇偶校验信息和相对应的数据分别存储于不同的磁盘 上。当RAID5的一个磁盘数据发生损坏后，利用剩下的数据和相应的奇偶校验信息去恢复被损坏的数据。 RAID 5可以理解为是RAID 0和RAID 1的折衷方案。RAID 5可以为系统提供数据安全保障，但保障程度要比Mirror低而磁盘空间利用率要比Mirror高。RAID 5具有和RAID 0相近似的数据读取速度，只是多了一个奇偶校验信息，写入数据的速度比对单个磁盘进行写入操作稍慢。同时由于多个数据对应一个奇偶校验信息，RAID 5的磁盘空间利用率要比RAID 1高，存储成本相对较低。 4、 RAID 10 （是RAID 0和RAID 1的组合方案） RAID10也被称为镜象阵列条带。象RAID0一样，数据跨磁盘抽取；象RAID1一样，每个磁盘都有一个镜象磁盘, 所以RAID 10的另一种会说法是 RAID 0+1。RAID10提供100%的数据冗余，支持更大的卷尺寸，但价格也相对较高。对大多数只要求具有冗余度而不必考虑价格的应用来说，RAID10提 供最好的性能。使用RAID10，可以获得更好的可靠性，因为即使两个物理驱动器发生故障（每个阵列中一个），数据仍然可以得到保护。RAID10需要4 + 2*N 个磁盘驱动器（N >=0)， 而且只能使用其中一半(或更小, 如果磁盘大小不一)的磁盘用量, 例如 4 个 250G 的硬盘使用RAID10 阵列， 实际容量是 500G。

Effective Java读书笔记
type: item
date: 2017-06-01T11:55:00+08:00
description: 第一章 创建和销毁对象 1.1 考虑用静态工厂方法替换构造器 1.2 用私有构造器或者枚举类型强化Singleton属性 1.3 避免创建不必要的对象 1.4 消除过期的对象引用 import java.util.Arrays; import java.util.EmptyStackException; public class Stack { private Object[] elements; private int size = 0; private static final int DEFAULT_INITIAL_CAPACITY = 16; public Stack() { elements = new Object[DEFAULT_INITIAL_CAPACITY]; } public void push(Object e){ ensureCapaciy(); elements[size++] = e; } public Object pop(){ if(size == 0){ throw new EmptyStackException(); } return elements[--size]; } private void ensureCapaciy(){ if(elements.length == size){ elements = Arrays.copyOf(elements, 2 * size + 1); } } } 在本例中,凡是数组下标小于size的那些元素都是过期引用 在支持垃圾回收的语言中,内存泄露是很隐蔽的 这类问题的修复方法很简单:一旦对象引用以及过期,只需要清空这些引用即可 public Object pop(){ if(size == 0){ throw new EmptyStackException(); } Object result = elements[--size]; elements[size] = null; return result; } 一般而言,只要类是自己管理内存,程序员就应该警惕内存泄露的问题 内存泄露的另一个常见的来源是缓存 内存泄露的第三个常见来源是监听器和其他回调.如果你实现了一个API,客户端在这个API中注册回调,却没有显式地取消注册,那么除非你采取某些动作,否则他们就会积聚.确保回调立即被当成垃圾回收的最佳方法是只保存它们的弱引用（weak reference）,例如，只将它们保存成WeakHashMap中的键. 第二章 对于所有对象都通用的方法 2.1 覆盖equals时总要覆盖hashCode 2.2 始终覆盖toString 2.3 考虑实现Compareable接口 第三章 类和接口 3.1 使类和成员的可访问行最小化 3.2 使可变性最小化 3.3 组合、继承 组 合 关 系 继 承 关 系 优点：不破坏封装，整体类与局部类之间松耦合，彼此相对独立 缺点：破坏封装，子类与父类之间紧密耦合，子类依赖于父类的实现，子类缺乏独立性 优点：具有较好的可扩展性 缺点：支持扩展，但是往往以增加系统结构的复杂度为代价 优点：支持动态组合。在运行时，整体对象可以选择不同类型的局部对象 缺点：不支持动态继承。在运行时，子类无法选择不同的父类 优点：整体类可以对局部类进行包装，封装局部类的接口，提供新的接口 缺点：子类不能改变父类的接口 缺点：整体类不能自动获得和局部类同样的接口 优点：子类能自动继承父类的接口 缺点：创建整体类的对象时，需要创建所有局部类的对象 优点：创建子类的对象时，无须创建父类的对象 请记住下面两句话： 继承要慎用，其使用场合仅限于你确信使用该技术有效的情况。一个判断方法是，问一问自己是否需要从新类向基类进行向上转型。如果是必须的，则继承是必要的。反之则应该好好考虑是否需要继承。《Java编程思想》 只有当子类真正是超类的子类型时，才适合用继承。换句话说，对于两个类A和B，只有当两者之间确实存在is-a关系的时候，类B才应该继续类A。《Effective Java》 3.4.接口只用于定义类型。 3.5 常量接口不值得效仿，接口应该只被用来定义类型，不应该被用来导出常量。 3.6 对于常量的使用我们应该遵循如下规则：如果常量与某个现有的类或者接口紧密相关，就应该把这些常量添加到这个类或者接口中；如果常量最好被看做枚举类型的成员，则应该用枚举类型来导出这些常量；否则应该使用不可实例化的工具类来导出这些常量。 第四章 泛型 推荐使用泛型，虽然他在运行时会被擦除。 尽可能地消除每一个非受检警告。如果无法消除警告，同时可以证明引起警告的代码是类型安全的，则可以使用@SuppressWarnings("unchecked")注解来禁止这条警告，同时我们…

专业书书单
type: item
date: 2017-05-26T21:07:50+08:00
description: Java编程思想 Effective Java 深入理解Java虚拟机 HotSpot实战 重构 改善既有代码的设计 设计模式 Hadoop权威指南 深入分析Java Web技术内幕 Fundamental networking in java Java并发编程实战 Java多线程编程核心技术 Expert One-on-One J2EE Design and Development Software Architecture in Practice,2nd Edition--软件构架实践(第2版) Documenting Software Architectures --软件构架编档 Applied Software Architecture --实用软件体系结构 企业应用架构模式 敏捷软件开发原则、模式与实践 Patterns of Enterprise Application Architecture --企业应用架构模式 Effective Enterprise Java--中文版 大型网站技术架构 核心原理与案例分析 大型网站技术架构 核心原理与案例分析 从Paxos到ZooKeeper 分布式一致性原理与实践 UML精粹 快速软件开发 敏捷软件开发 Agile Java 面向对象分析与设计 OO设计必读 Unix编程艺术 打开你的眼界 人月神话 卓有成效的程序员 算法导论 深入理解计算机系统 编译原理