<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Blog Khoa Học Máy Tính</title>
	<atom:link href="http://www.procul.org/blog/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.procul.org/blog</link>
	<description>Tầm nhìn ta thật ngắn mà đã thấy bao thứ để làm -- Alan Turing</description>
	<lastBuildDate>Wed, 16 May 2012 15:36:44 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	
		<item>
		<title>Khoe</title>
		<link>http://www.procul.org/blog/2012/05/16/khoe/</link>
		<comments>http://www.procul.org/blog/2012/05/16/khoe/#comments</comments>
		<pubDate>Wed, 16 May 2012 14:44:03 +0000</pubDate>
		<dc:creator>NQH</dc:creator>
				<category><![CDATA[Cơ sở dữ liệu]]></category>
		<category><![CDATA[conjunctive join]]></category>
		<category><![CDATA[Khoe]]></category>

		<guid isPermaLink="false">http://www.procul.org/blog/?p=4581</guid>
		<description><![CDATA[Được cái này, nhờ bài báo này. Như bạn mlteppi đã loan báo từ trước. Bài báo &#8220;Worst-case optimal join algorithms&#8221; có một lịch sử thú vị liên quan đến blog KHMT. Số là năm ngoái bọn tôi làm một vấn đề về giải mã tín hiệu trong compressed sensing. (Bài ở STACS 2012.) Một [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://www.sigmod.org/the-pods-pages/pods-best-paper-awards">Được cái này</a>, nhờ <a href="http://arxiv.org/abs/1203.1952">bài báo này</a>. Như bạn mlteppi <a href="http://www.procul.org/blog/g-ri-t-long/#comment-321582">đã loan báo</a> từ trước.</p>
<p>Bài báo &#8220;<em>Worst-case optimal join algorithms</em>&#8221; có một lịch sử thú vị liên quan đến blog KHMT. Số là năm ngoái bọn tôi làm một vấn đề về giải mã tín hiệu trong compressed sensing. (<a href="http://drops.dagstuhl.de/opus/volltexte/2012/3401/">Bài ở STACS 2012</a>.) Một trong những kết quả tìm được là một thuật toán cho <a href="http://www.procul.org/blog/2011/03/01/tia/">bài lính bắn tia laser</a>. Bài lính bắn laser vốn là một bất đẳng thức hình học, và do có cấu trúc khá chặt chẽ tôi thấy rất khó chịu khi thuật toán chỉ làm cho trường hợp 3-chiều. Tôi có viết <a href="http://www.procul.org/blog/2011/03/01/tia/#comment-199638">trong một lời bình</a> ngày 1 tháng 3, 2011 là</p>
<blockquote><p>Tôi tin là có chứng minh tốt hơn cái CM tôi có, và có lẽ đây là trường hợp đặc biệt của cái gì đó đã biết, nhưng tôi không biết là cái gì.</p></blockquote>
<p><strong>Bài học 1:</strong> luôn không thoả mãn với các trường hợp đặc biệt. Nếu kết quả của mình có vẻ cơ bản thì nó phải là một ví dụ của cái gì đó tổng quát hơn, đẹp hơn!</p>
<p><span id="more-4581"></span></p>
<p>May có bác Xuân Long <a href="http://www.procul.org/blog/2011/03/01/tia/#comment-199644">cho ngay câu trả lời</a>: đó là trường hợp đặc biệt của <a href="http://www.procul.org/blog/2011/03/04/ch%E1%BB%A9ng-minh-d%E1%BB%8Bnh-ly-loomis-whitney-dung-entropy/">bất đẳng thức Loomis-Whitney</a>. Từ đó bọn tôi đi tìm hiểu xem cách chứng minh bài laser của mình có dùng để chứng minh BĐT Loomis-Whitney hay không. Đây là chứng minh bằng thuật toán: cho các hình chiếu, xây dựng lại bộ tập điểm ban đầu, chứ không phải chứng minh BĐT toán học tuần tuý. Nếu chỉ chứng minh toán học thuần tuý thì cái chứng minh dùng entropy là tuyệt hảo rồi.</p>
<p>Sau một tháng, ngày 8 tháng 4, tôi ghi lại <a href="http://www.procul.org/blog/2011/04/08/m%E1%BB%99t-ch%E1%BB%A9ng-minh-khac-c%E1%BB%A7a-loomis-whitney/">một chứng minh khác</a> của BĐT Loomis-Whitney không dùng entropy cũng trên blog này. Lúc đó bác Nguyễn Tiến Zũng có <a href="http://www.procul.org/blog/2011/04/08/m%e1%bb%99t-ch%e1%bb%a9ng-minh-khac-c%e1%bb%a7a-loomis-whitney/#comment-202246">bình luận</a> là &#8220;<em>chứng minh entropy có gì phù thuỷ đâu</em>&#8220;?</p>
<p><strong>Bài học 2:</strong> có sự khác biệt giữa tư duy toán học và tư duy KHMT. Dân KHMT thường nên nghĩ về thuật toán chứ không chỉ một chứng minh toán học thuần tuý.</p>
<p>Một trong những thứ mà tôi nhận ra ngay từ bài lính bắn laser là đây là một bài toán <a href="http://en.wikipedia.org/wiki/Conjunctive_query">conjunctive join</a> trong cơ sở dữ liệu quan hệ (relational database). Sau một vài tháng suy nghĩ thì bọn tôi tìm được một thuật toán &#8220;chứng minh&#8221; BĐT Loomis-Whitney. Tuy nhiên cái chứng minh (bằng thuật toán) này chứng minh được một BĐT yếu hơn Loomis-Whitney một chút. Dù sao, nó cũng là một kết quả thú vị về conjunctive query evaluation và bọn tôi viết lại, nộp vào SODA 2012. Các bác referees cũng khá thích kết quả này, nhưng họ càm ràm rằng lớp các conjunctive queries mà BĐT Loomis-Whitney đại diện <em>quá</em> đặc biệt; cần kết quả mạnh hơn. Thế là bài báo không được nhận dù review khá tốt.</p>
<p><strong>Bài học 3:</strong> đôi khi một bài báo bị từ chối là một điều tốt.</p>
<p>Lẽ tất nhiên, bọn tôi lại phải quay lại với bút chì và giấy nháp; cố gắng thử xem thuật toán của mình có dùng để evaluate các conjunctive queries tổng quát hơn hay không. Nhưng cũng chằng đi đến đâu. </p>
<p>Trước đó, tôi gọi điện hỏi bác An Hải &#8212; nói cho bác ấy biết là bọn tôi có một thuật toán mới cho conjunctive join. Bác AH bảo: &#8220;không có thằng nào đi implement thuật toán mới đâu, đừng có nằm mơ, các RDBMS engines có mấy chục năm heuristics ở trong đó, inertia rất lớn, blah blah blah. Tuy nhiên, ở Wisconsin có chú Chris Ré làm lý thuyết, hay liên lạc với chú ấy xem sao.&#8221;</p>
<p><strong>Bài học 4:</strong> gọi điện hỏi, nhưng đừng nghe lời bác An Hải.</p>
<p>Trùng hợp là một đồng tác giả của tôi, Atri Rudra, học cùng trường với Chris Ré. Sau khi liên lạc thì Chris rất thích kết quả (yếu) về BĐT Loomis-Whitney và đi hỏi các chuyên gia về join optimization. Cuối cùng, bọn tôi khám phá rất một <a href="http://www.lsi.upc.edu/~atserias/papers/joins/queries.pdf">bài báo tuyệt vời</a> của Atserias-Grohe-Marx ở FOCS 2008. Bài báo này chứng minh một bất đẳng thức tổng quát cho mọi (full) conjunctive queries, mà trong đó Loomis-Whitney là một trường hợp đặc biệt. Hãy gọi bất đẳng thức này là BĐT AGM. BĐT AGM cũng được chứng minh bằng entropy như BĐT Loomis-Whitney.</p>
<p>Thế là bọn tôi chuyển hướng nghiên cứu thuật toán chứng minh BĐT AGM &#8212; và cũng là thuật toán evaluate conjunctive queries. Thuật toán trước đó cho LW không giải quyết được trường hợp tổng quát này. Do thuật toán được thiết kế cho LW, một trường hợp đặc biệt, nó tận dụng quá nhiều cấu trúc của trường hợp đặc biệt và do đó không thể tổng quát hoá nó lên.</p>
<p><strong>Bài học 5:</strong> giải trường hợp tổng quát có thể &#8220;dễ&#8221; hơn trường hợp đặc biệt, và thường là sẽ cho lời giải &#8220;đúng&#8221; hơn với bản chất vấn đề.</p>
<p>Cuối cùng, sau khoảng 3, 4 tháng bí rị, trong vòng 1 tuần bọn tôi tìm ra thuật toán vừa chứng minh BĐT AGM, vừa là một thuật toán tối ưu cho conjunctive join. Lý do có thể &#8220;đục thủng&#8221; được sự bí rị là vì thuật toán trước chứng minh một phiên bản yếu của LW, và rất không đẹp. Cho nên quyết định chứng minh lại Loomis-Whitney một cách chặt chẽ dùng một thuật toán mới. Sau đó tổng quát hoá thuật toán mới này lên AGM.</p>
<p><strong>Bài học 6:</strong> luôn luôn cảm thấy khó chịu với các lời giải không đẹp.</p>
<p>Lúc đó gần tháng 11. Định nộp vào STOC nhưng viết không kịp; vả lại PODS là hội nghị DB nên có lẽ là người ta &#8220;appreciate&#8221; kết quả này hơn. </p>
<p>Thuật toán cuối cùng phức tạp hơn thuật toán ban đầu cho LW nhiều, nhưng mặt khác nó cũng thoáng hơn vì nó giải quyết trường hợp tổng quát nên ta không bị gò bó vào các cấu trúc lắt nhắt. </p>
<p>OK, khoe đã xong, khi nào rảnh rỗi sẽ viết lại kỹ hơn về conjunctive joins, thuật toán NPRR, và các ứng dụng (nhiều vô kể) của conjunctive join query evaluation.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.procul.org/blog/2012/05/16/khoe/feed/</wfw:commentRss>
		<slash:comments>7</slash:comments>
		</item>
		<item>
		<title>Khoa học vị nhân xinh</title>
		<link>http://www.procul.org/blog/2012/05/08/khoa-h%e1%bb%8dc-v%e1%bb%8b-nhan-xinh/</link>
		<comments>http://www.procul.org/blog/2012/05/08/khoa-h%e1%bb%8dc-v%e1%bb%8b-nhan-xinh/#comments</comments>
		<pubDate>Wed, 09 May 2012 03:01:20 +0000</pubDate>
		<dc:creator>Nguyễn Xuân Long</dc:creator>
				<category><![CDATA[Vui - Giải Trí]]></category>

		<guid isPermaLink="false">http://www.procul.org/blog/?p=4576</guid>
		<description><![CDATA[Chẳng mấy khi thấy một bài báo của mình lại được nhắc chung với một tạp chí uy tín như People Magazine hay những người nổi tiếng như ở bài báo sâu sắc này . Vui!]]></description>
			<content:encoded><![CDATA[<p>Chẳng mấy khi thấy một bài báo của mình lại được nhắc chung với một tạp chí uy tín như People Magazine hay những người nổi tiếng như ở <a href="http://dimatura.net/sigbovik_2012.pdf"> bài báo sâu sắc này </a>. Vui!</p>
]]></content:encoded>
			<wfw:commentRss>http://www.procul.org/blog/2012/05/08/khoa-h%e1%bb%8dc-v%e1%bb%8b-nhan-xinh/feed/</wfw:commentRss>
		<slash:comments>7</slash:comments>
		</item>
		<item>
		<title>Làm an toàn thông tin thì học gì?</title>
		<link>http://www.procul.org/blog/2012/05/02/lam-an-toan-thong-tin-thi-h%e1%bb%8dc-gi/</link>
		<comments>http://www.procul.org/blog/2012/05/02/lam-an-toan-thong-tin-thi-h%e1%bb%8dc-gi/#comments</comments>
		<pubDate>Wed, 02 May 2012 21:31:13 +0000</pubDate>
		<dc:creator>thaidn</dc:creator>
				<category><![CDATA[Bảo mật và mật mã học]]></category>
		<category><![CDATA[Giáo dục]]></category>
		<category><![CDATA[Giới thiệu sách]]></category>

		<guid isPermaLink="false">http://www.procul.org/blog/?p=4552</guid>
		<description><![CDATA[1 Giới thiệu Tôi nhận được thư từ của nhiều bạn hỏi về việc nên học gì và như thế nào để có thể tìm được việc làm và làm được việc trong ngành an toàn thông tin (information security). Tôi nghĩ việc đầu tiên bạn cần phải làm là in toàn bộ bài viết &#8220;Làm [...]]]></description>
			<content:encoded><![CDATA[<p><strong><strong>1 Giới thiệu</strong></strong></p>
<p>Tôi nhận được thư từ của nhiều bạn hỏi về việc nên học gì và như thế nào để có thể tìm được việc làm và làm được việc trong ngành an toàn thông tin (information security). Tôi nghĩ việc đầu tiên bạn cần phải làm là in toàn bộ bài viết &#8220;<a href="http://www.hvaonline.net/hvaonline/posts/list/621.hva">Làm thế nào để trở thành white hat hacker</a>&#8221; ra giấy, nhưng đừng đọc, mà hãy để chúng trong toilet khi nào cần thì xài dần.</p>
<p>Quay trở lại câu hỏi. An toàn thông tin là một ngành rộng lớn với rất nhiều lĩnh vực. Những gì tôi biết và làm được chỉ gói gọn trong một hai lĩnh vực. Có rất nhiều mảng kiến thức cơ bản mà tôi không nắm vững và cũng có nhiều kỹ năng mà tôi không thạo. Hack tài khoản Yahoo! Mail là một trong số đó. Tôi cũng không biết cách tìm địa chỉ IP của bạn chat <img src='http://www.procul.org/blog/wp-includes/images/smilies/icon_sad.gif' alt=':-(' class='wp-smiley' /> .</p>
<p><span id="more-4552"></span></p>
<p>Xét theo <a href="http://www.procul.org/blog/2005/09/01/nnm-m%E1%BB%A9c-ngu-d%E1%BB%91t/">năm mức ngu dốt</a> thì tôi nằm ở mức &#8220;1OI &#8211; thiếu kiến thức&#8221; ở hầu hết các lĩnh vực trong an toàn thông tin. Cũng có lĩnh vực tôi nằm ở mức &#8220;2OI &#8211; thiếu nhận thức&#8221;. Nhiều lần đọc sách vở hoặc nói chuyện với đồng nghiệp, tôi hay nhận ra rằng có nhiều thứ tôi không biết là tôi không biết. Theo ý của anh Ngô Quang Hưng thì đây là chuyện bình thường:</p>
<blockquote><p>Dân máy tính thường phải đọc/học rất nhiều để theo kịp sự phát triển với tốc độ ánh sáng của ngành mình. Trong quá trình này, với mỗi vấn đề X của ngành, ta sẽ chuyển dần dần từ 3OI xuống 1OI. Sau đó, nếu X là cái mà ta thật sự thích hoặc cần cho công việc thì sẽ chuyển nó lên 0OI.</p></blockquote>
<blockquote><p>Rất nhiều sinh viên và nghiên cứu sinh KHMT ở mức 3OI khi mới bắt đầu đi học. Sau đó họ tìm hiểu về quá trình nghiên cứu, quá trình tìm các vấn đề và hướng nghiên cứu mới, quá trính cập nhật kiến thức về ngành của mình, và chuyển dần các thứ lên 2OI. Để có một quá trình hiệu quả từ 3OI lên 2OI không dễ chút nào. Ví dụ đơn giản: các journals, conference nào trong ngành mình là có giá trị, làm thế nào để tìm đọc các bài trong chúng, phương pháp lọc bài đọc thế nào, vân vân.</p></blockquote>
<p>Tôi thấy anh Hưng nói có lý, nên mục tiêu chính của bài viết này là cung cấp một quá trình hiệu quả để bớt ngu về an toàn thông tin.<br />
<strong><br />
<strong>2 Làm an toàn thông tin là làm gì?</strong></strong></p>
<p>Tôi muốn viết phần này vì nhiều người tưởng tôi làm bảo vệ khi tôi nói tôi làm security. Ngoài ra có lẽ là do thị trường việc làm an toàn thông tin ở Việt Nam không phong phú nên hầu hết đều nghĩ rằng làm an toàn thông tin nghĩa là đảm bảo an toàn hệ thống mạng (network/system security), trong khi thực tế đây chỉ là một trong số rất nhiều công việc trong ngành.</p>
<p>Trong bốn phần nhỏ tiếp theo, tôi sẽ giới thiệu bốn nhóm công việc chính trong ngành. Đối với mỗi nhóm công việc, tôi sẽ bàn một chút về triển vọng nghề nghiệp ở Việt Nam và Mỹ, hai nơi mà tôi có dịp được quan sát. Nếu bạn không biết bạn thích làm gì thì cứ chọn một công việc rồi làm thử. Các công việc này đều có liên quan nhau, nên kiến thức mà bạn học được trong quá trình thử vẫn hữu ích cho những nghề khác.<br />
<strong><br />
<em>2.1 An toàn sản phẩm (product security)</em></strong></p>
<p>Công việc chính của nhóm này là làm việc với các đội phát triển sản phẩm để đảm bảo sản phẩm làm ra an toàn cho người dùng và an toàn cho hệ thống của công ty, cụ thể là:</p>
<ul>
<li>Kiểm định mã nguồn và thiết kế của sản phẩm</li>
</ul>
<ul>
<li>Phát triển các giải pháp kỹ thuật và quy trình phát triển phần mềm an toàn để phát hiện và ngăn chặn những kỹ thuật tấn công đã biết</li>
</ul>
<ul>
<li>Đào tạo nhân lực để nâng cao nhận thức về an toàn thông tin cũng như kỹ năng viết mã an toàn</li>
</ul>
<ul>
<li>Nghiên cứu các hướng tấn công mới có thể ảnh hưởng hệ thống sản phẩm và dịch vụ của công ty</li>
</ul>
<p>Tóm gọn lại thì nhóm này chuyên <a href="http://vnhacker.blogspot.com/2011/11/tim-lo-lay-tien.html">tìm lỗ hổng</a> và kỹ thuật tấn công mới. Đây là công việc của tôi và tôi thấy đây là công việc thú vị nhất trong ngành <img src='http://www.procul.org/blog/wp-includes/images/smilies/icon_smile.gif' alt=':-)' class='wp-smiley' /> .</p>
<p>Ở Mỹ thì thông thường thì chỉ có các hãng có phần mềm và dịch vụ lớn như Facebook, Google, Microsoft, Oracle, v.v. hay các tập đoàn tài chính ngân hàng lớn mới có đội ngũ tại chỗ để đảm nhiệm công việc này. Các công ty nhỏ thường chỉ thuê dịch vụ của các công ty tư vấn. IBM và Big Four đều có cung cấp dịch vụ tư vấn này. Dẫu vậy nếu được chọn lựa thì tôi sẽ chọn làm cho các công ty chuyên sâu như Matasano, iSec, Leviathan, Gotham, IOActive, Immunity, v.v.</p>
<p>Ở Việt Nam thì thị trường việc làm cho người làm an toàn sản phẩm có vẻ ảm đạm hơn. Cho đến nay tôi biết chỉ có một vài công ty ở Việt Nam là có nhân viên chuyên trách lĩnh vực này. Các công ty khác (nếu có quan tâm đến an toàn thông tin) thì hầu như chỉ tập trung vào an toàn vận hành. Các công ty tư vấn an toàn thông tin ở Việt Nam cũng không tư vấn an toàn sản phẩm, mà chỉ tập trung tư vấn chung chung về các quy trình và tiêu chuẩn an toàn thông tin.</p>
<p><strong><em>2.2 An toàn vận hành (operations security)</em></strong></p>
<p>Công việc chính của nhóm này là đảm bảo sự an toàn cho toàn bộ hệ thống thông tin của doanh nghiệp, với ba nhiệm vụ chính:</p>
<ul>
<li>Ngăn chặn: đưa ra các chính sách, quy định, hướng dẫn về an toàn vận hành; kiện toàn toàn bộ hệ thống thông tin, từ các vành đai cho đến máy tính của người dùng cuối; cấp và thu hồi quyền truy cập hệ thống; quét tìm lỗ hổng trong hệ thống, theo dõi thông tin lỗ hổng mới và làm việc với các bên liên quan để vá lỗi, v.v.</li>
</ul>
<ul>
<li>Theo dõi và phát hiệ: <a href="http://vnhacker.blogspot.com/2009/12/giam-sat-ninh-mang-hay-la-lam-nao-e.html">giám sát an ninh mạng</a>.</li>
</ul>
<ul>
<li>Xử lý: phản hồi (incident response) và điều tra số (digital forensics) khi xảy ra sự cố an toàn thông tin, từ tài khoản của nhân viên bị đánh cắp, rò rỉ thông tin sản phẩm mới cho đến tấn công từ chối dịch vụ.</li>
</ul>
<p>Đây là công việc khó nhất, nhưng lại ít <a href="http://vnhacker.blogspot.com/2007/01/phn-thng-no-dnh-cho-ngi-lm-bo-mt.html">phần thưởng</a> nhất của ngành an toàn thông tin.</p>
<p>Tương tự như trên, chỉ có các hãng lớn của Mỹ mới có đội ngũ tại chỗ để phụ trách toàn bộ khối lượng công việc đồ sộ này, nhất là mảng xử lý và điều tra. Đa số các công ty chỉ tập trung vào ngăn chặn và sử dụng dịch vụ của bên thứ ba cho hai mảng còn lại. Các hãng như Mandiant, Netwitness hay HBGary cung cấp dịch vụ điều tra các vụ xâm nhập và có rất nhiều hãng khác cung cấp dịch vụ giám sát an ninh mạng.</p>
<p>Ở Việt Nam thì thị trường việc làm cho người làm an toàn vận hành tương đối phong phú hơn so với an toàn sản phẩm. Các công ty và tổ chức tài chính lớn đều có một vài vị trí chuyên trách về an toàn vận hành. Đa số người làm về an toàn thông tin ở Việt Nam mà tôi biết là làm trong lĩnh vực này. Dẫu vậy hầu như chưa có ai và công ty tư vấn nào làm về phản hồi và điều tra sự cố.<br />
<strong><br />
<em>2.3 Phát triển công cụ (applied security)</em></strong></p>
<p>Công việc chính của nhóm này là phát triển và cung cấp các công cụ, dịch vụ và thư viện phần mềm có liên quan đến an toàn thông tin cho các nhóm phát triển sản phẩm sử dụng lại.</p>
<p>Nhóm này bao gồm các kỹ sư nhiều năm kinh nghiệm và có kiến thức vững chắc về an toàn thông tin, viết mã an toàn và mật mã học. Họ phát triển các thư viện và dịch vụ dùng chung như phân tích mã tĩnh &#8211; phân tích mã động (static &#8211; dynamic code analysis), hộp cát (sandboxing), xác thực (authentication), kiểm soát truy cập (authorization), mã hóa (encryption) và quản lý khóa (key management), v.v.</p>
<p>Đây là dạng công việc dành cho những ai đang viết phần mềm chuyên nghiệp và muốn chuyển qua làm về an toàn thông tin. Đây cũng là công việc của những người thích làm an toàn sản phẩm nhưng muốn tập trung vào việc xây dựng sản phẩm hơn là tìm lỗ hổng.</p>
<p>Rõ ràng loại công việc này chỉ xuất hiện ở các công ty phần mềm lớn. Ở các công ty phần mềm nhỏ hơn thì các kỹ sư phần mềm thường phải tự cáng đáng công việc này mà ít có sự hỗ trợ từ nguồn nào khác. Ở Việt Nam thì tôi không biết có ai làm dạng công việc này không.<br />
<strong><br />
<em>2.4 Tìm diệt mã độc và các nguy cơ khác (threat analysis)</em></strong></p>
<p>Ngoài an toàn sản phẩm ra thì đây là một lĩnh vực mà tôi muốn làm. Công việc chính của nhóm này là phân tích, truy tìm nguồn gốc và tiêu diệt tận gốc mã độc và các tấn công có chủ đích (targeted attack). Mã độc ở đây có thể là virút, sâu máy tính, hay mã khai thác các lỗ hổng đã biết hoặc chưa được biết đến mà phần mềm diệt virút thông thường chưa phát hiện được. Các loại mã độc này thường được sử dụng trong các tấn công có chủ đích vào <a href="http://googleblog.blogspot.com/2010/01/new-approach-to-china.html">doanh nghiệp</a>.</p>
<p>Tôi nghĩ rằng sau hàng loạt vụ tấn công vừa rồi thì chắc hẳn các công ty lớn với nhiều tài sản trí tuệ giá trị đều muốn có những chuyên gia trong lĩnh vực này trong đội ngũ của họ. Ngoài ra các công ty chuyên về điều tra và xử lý sự cố như Mandiant, HBGary hay Netwitness mà tôi đề cập ở trên đều đang ăn nên làm ra và lúc nào cũng cần người. Các công ty sản xuất phần mềm diệt virút dĩ nhiên cũng là một lựa chọn.</p>
<p>Ở Việt Nam thì tôi nghĩ hầu hết doanh nghiệp vẫn chưa thấy được nguy cơ đến từ các cuộc tấn công có chủ đích, thành ra họ sẽ không tuyển người chuyên trách vấn đề này. Tôi cũng không biết có công ty tư vấn nào ở Việt Nam chuyên về điều tra và xử lý sự cố hay không. Tôi nghĩ lựa chọn khả dĩ nhất cho những người thích mảng công việc này là các công ty phần mềm diệt virút.</p>
<p>Tuy nhiên cũng cần lưu ý rằng trong vài năm gần đây ở <a href="http://googleonlinesecurity.blogspot.com/2010/03/chilling-effects-of-malware.html">Việt Nam</a> còn xuất hiện những loại mã độc nhắm vào đông đảo người dùng máy tính bình thường. Vấn nạn này có lẽ sẽ còn kéo dài trong nhiều năm tới và lẽ đương nhiên &#8220;phe ta&#8221; lúc nào cũng cần thêm những chiến sĩ lành nghề như anh <a href="http://www.hvaonline.net/hvaonline/posts/list/38818.hva">TQN</a>. Thành ra dẫu triển vọng nghề nghiệp không sáng sủa cho lắm, nhưng tôi rất hi vọng sẽ ngày càng nhiều người tham gia vào việc phân tích các mã độc nhắm vào người dùng máy tính ở Việt Nam. Đối với tôi họ là những người hùng thầm lặng, chiến đấu đêm ngày với các &#8220;thế lực thù địch&#8221; để bảo vệ tất cả chúng ta.<br />
<strong><br />
<strong>3 Học như thế nào?</strong></strong></p>
<p>Đa số những bạn viết thư cho tôi đều đang học đại học ngành CNTT và tất cả đều than rằng chương trình học quá chán, không có những thứ mà các bạn muốn học. Tôi nghĩ đây là một ngộ nhận.</p>
<p>Hối tiếc lớn thứ nhì trong sự nghiệp học tập mấy chục năm của tôi là đã không học nghiêm túc khi còn là sinh viên (hối tiếc lớn nhất là tôi đã không nghỉ hẳn, nhưng đó là một câu chuyện dài khác). Tôi cũng đã nghĩ rằng chương trình học ở đại học là lạc hậu và không cần thiết. Bây giờ nhìn lại thì tôi thấy nội dung và cách dạy của từng môn học thì đúng là lạc hậu (chỉ có mấy môn triết học Mác-Lênin là bắt kịp <a href="http://www.ou.edu.vn/dtn/Pages/Moi-ban-tham-gia-cuoc-thi-Anh-sang-thoi-dai-2012.aspx">ánh sáng thời đại</a>), nhưng toàn bộ giáo trình đại học vẫn cung cấp được một cái sườn kiến thức rất cần thiết cho một kỹ sư an toàn thông tin.</p>
<p>Ở đại học người ta có cách tiếp cận top-down, nghĩa là dạy từ đầu đến cuối những kiến thức nằm trong chương trình. Điều này dễ dẫn đến tình trạng là người học phải học những kiến thức mà họ không thấy cần thiết. Nếu chương trình học cũ kỹ và không có nhiều thực hành, hoặc người dạy không chỉ ra được bức tranh toàn cảnh, vị trí hiện tại của người học và bước tiếp theo họ nên làm là gì thì người học sẽ dễ cảm thấy rằng họ đang phí thời gian học những kiến thức vô bổ.</p>
<p>Trong khi khi đi làm thì cách tiếp cận là bottom-up, nghĩa là lao vào làm, thấy thiếu kiến thức chỗ nào thì học để bù vào chỗ đó. Lúc này tôi hoàn toàn chủ động trong việc học và tôi cũng hiểu rõ tôi cần học cái gì và tại sao. Điều thú vị là mỗi khi truy ngược lại nguồn gốc của những kiến thức tôi cần phải có, tôi thường thấy chúng nằm trong chương trình đại học.</p>
<p>Ví dụ như tôi muốn luyện kỹ năng dịch ngược mã phần mềm (reverse code engineering &#8211; RCE) thì tôi thấy rằng tôi cần phải có kiến thức về tổ chức và cấu trúc máy tính. Hoặc nếu tôi muốn học về mật mã học thì tôi phải học lý thuyết tính toán, mà khởi nguồn là lý thuyết automata. Nhưng tại sao trước đó tôi cũng đi làm nhưng không thấy được những lỗ hổng kiến thức này? Tôi nghĩ là do tôi làm không đủ sâu. Ví dụ như nếu bạn suốt ngày chỉ lập trình PHP thì bạn sẽ không thể hiểu được tại sao phải nắm vững tổ chức và kiến trúc máy tính. Hoặc giả như công việc của bạn là sysadmin thì cũng sẽ rất khó để bạn thấy được tại sao cần phải học lý thuyết automata.</p>
<p>Những gì tôi nói lan man ở trên có thể tóm gọn lại thế này:</p>
<ul>
<li>Học dựa theo chương trình đại học. Nếu bạn đang học đại học các ngành công nghệ thông tin, khoa học máy tính hay toán tin thì nên tập trung vào việc học các môn trong trường. Các học liệu trong phần 4 cũng được soạn theo các đại học lớn trên thế giới.</li>
</ul>
<ul>
<li>Học kiến thức căn bản thật vững (cái gì là căn bản thì xem phần 4), những món còn lại khi nào cần (căn cứ vào nhu cầu công việc) thì hẵng học.</li>
</ul>
<ul>
<li>Tìm dự án lề (side project) mà bạn thích để làm để có thể nhanh chóng nhận ra những mảng kiến thức còn thiếu.</li>
</ul>
<ul>
<li>Thời điểm tốt nhất để học một cái gì đó là khi bạn đang là sinh viên. Thời điểm tốt thứ hai là ngay bây giờ!</li>
</ul>
<p>Các lớp mà tôi liệt kê trong phần 4 đa số là của đại học Stanford. Bạn không cần phải đến tận nơi, ngồi trong lớp mới có thể học được. Tôi thấy trong nhiều trường hợp thì bạn chỉ cần đọc lecture notes, sách giáo khoa mà lớp sử dụng rồi làm bài tập đầy đủ thì vẫn sẽ tiếp thu đủ kiến thức. Một số lớp mà tôi liệt kê dưới đây được dạy miễn phí rộng rãi trên <a href="https://www.coursera.org/">Coursera</a>.Bạn có thể tham khảo chương trình <a href="http://scpd.stanford.edu/">SCPD</a> nếu muốn học chung với các sinh viên Stanford khác. Đây là chương trình học từ xa thông qua video. Buổi sáng lớp diễn ra thì buổi chiều bạn đã có video để xem. Thi cử như các sinh viên chính quy khác và điểm phải trên B mới được học tiếp. Đây là chương trình mà tôi theo học. Điểm thú vị là mỗi học kỳ bạn chỉ cần lấy một lớp, nhưng Stanford vẫn sẽ cho bạn xem video của tất cả các lớp khác.</p>
<p>Ngoài Stanford và Coursera ra, bạn cũng có thể tham khảo các lớp trên <a href="http://www.udacity.com/">Udacity</a>, <a href="http://ocw.mit.edu/index.htm">OCW</a> và <a href="http://mitx.mit.edu/">MITx</a>. Khi tôi đang viết những dòng này thì MIT và Harvard công bố dự án <a href="http://web.mit.edu/press/2012/mit-harvard-edx-announcement.html">edX</a>. Chúng ta đang sống trong một thời đại cực kỳ thú vị! Bây giờ chỉ cần bạn chịu học thì muốn học cái gì cũng có lớp và học liệu miễn phí. Nhưng mà học cái gì bây giờ?</p>
<p><strong><strong>4 Học cái gì?</strong></strong></p>
<p>Có ba món quan trọng cần phải học: lập trình, lập trình và lập trình! Để làm việc được trong ngành này, bạn phải yêu thích lập trình. Không có cách nào khác. Thề luôn!</p>
<p>Tôi dành khá nhiều thời gian tìm hiểu giáo trình khoa học máy tính của các trường đại học lớn trên thế giới và tôi thấy tất cả các môn học đều có phần bài tập là lập trình. Học cái gì viết phần mềm cho cái đó. Học về hệ điều hành thì phần bài tập là viết một hệ điều hành. Học về mạng thì viết phần mềm giả lập router, switch hay firewall. Cá nhân tôi cũng thấy rằng lập trình là cách tốt nhất để tiếp thu kiến thức một môn học nào đó, biến nó thành của mình. Nói cách khác, lập trình là một cách <a href="http://www.procul.org/blog/2007/06/12/ma-hoa-tri-th%E1%BB%A9c-nh%C6%B0-th%E1%BA%BF-nao/">mã hóa tri thức</a> khá hiệu quả.</p>
<p>Ngoài ra nhìn vào mô tả công việc ở phần 2, bạn cũng có thể thấy kỹ năng lập trình quan trọng đến dường nào, bởi hầu hết các vấn đề và giải pháp của an toàn thông tin là đến từ phần mềm. Rõ ràng muốn tìm lỗi của phần mềm thì bạn phải hiểu được phần mềm thông qua mã nguồn trực tiếp hay trung gian của nó. Rất có thể bạn sẽ không phải lập trình hàng ngày, nhưng bạn phải viết được những công cụ nhỏ hay những thư viện hỗ trợ cho công việc và các lập trình viên khác.</p>
<p>Vậy làm thế nào để lập trình giỏi? Câu hỏi này làm tôi nhớ đến câu chuyện cười về ông lập trình viên không thể ra khỏi phòng tắm vì trên chai dầu gội có ghi hướng dẫn sử dụng là &#8220;cho vào tay, xoa lên đầu, xả nước và lập lại&#8221;. Từ khóa trong câu chuyện này là &#8220;lập lại&#8221;: muốn giỏi lập trình thì cách tốt nhất là lập trình nhiều vô!</p>
<p>Nhưng mà lập trình bằng ngôn ngữ gì bây giờ? Đây là câu hỏi dễ làm cho các lập trình viên oánh nhau nhất <img src='http://www.procul.org/blog/wp-includes/images/smilies/icon_wink.gif' alt=';-)' class='wp-smiley' /> . Cá nhân tôi thấy rằng người làm an toàn thông tin bây giờ cần phải thông thạo C, x86 Assembly, Python (hoặc Ruby) và JavaScript. Tôi có nói lý do tại sao trong phần giới thiệu sách tiếp theo.<br />
<strong><br />
<em><strong>Lập trình</strong></em><br />
</strong></p>
<ul>
<li>Brian Kernighan, Dennis Ritchie, <em>The C Programming Language (2nd Edition)</em>: kinh điển và phải-đọc cho tất cả những ai muốn học C! Linus Torvalds từng nói rằng &#8220;[...] <em>all right-thinking people know that (a) K&amp;R are _right_ and (b) K&amp;R are right</em>&#8220;. Tôi đã từng rất sợ C (vì nghĩ nó phức tạp), và cuốn này giúp tôi không còn sợ nữa.</li>
</ul>
<ul>
<li>Randal Bryant, David O&#8217;Hallaron, <em>Computer Systems: A Programmer&#8217;s Perspective</em>: cuốn này được dùng cho lớp <a href="http://cs107.stanford.edu/">CS107</a>. Đọc cuốn này và làm bài tập của lớp CS107 sẽ rèn cho bạn kỹ năng lập trình C và x86 Assembly. Sau khi đọc cuốn này, bạn sẽ biết tại sao có lỗi tràn bộ đệm và cách khai thác chúng. Tôi rất thích các chương nói về x86 và sự liên kết giữa các công cụ như preprocessor, compiler và linker.</li>
</ul>
<ul>
<li>David Hanson, <em>C Interfaces and Implementations</em>: muốn mau &#8220;lên cơ&#8221; bida thì phải thường xuyên xem người khác chơi để mà học &#8220;đường&#8221; mới. Tương tự, muốn giỏi lập trình thì phải thường xuyên đọc mã của những cao thủ. David Hanson là một cao thủ C và cuốn sách này sẽ chỉ cho bạn nhiều &#8220;đường&#8221; mới trong việc sử dụng C. Tôi thích các bài tập của cuốn sách này. Tôi nghĩ chỉ cần luyện các bài này là đủ để trở thành một lập trình viên C hạng lông.</li>
</ul>
<ul>
<li>Justin Seitz, <em>Gray Hat Python: Python Programming for Hackers and Reverse Engineers</em>: cuốn này sẽ giúp bạn sử dụng Python để viết những công cụ nho nhỏ mà bất kỳ ai làm an toàn thông tin cũng sẽ phải viết một vài lần trong đời.</li>
</ul>
<ul>
<li>Douglas Crockford, <em>JavaScript: The Good Parts</em>: JavaScript là ngôn ngữ thống trị WWW. Nếu bạn muốn làm an toàn (ứng dụng và trình duyệt) web thì bắt buộc phải thành thạo ngôn ngữ. Cuốn sách rất mỏng này của tác giả JSON giới thiệu đầy đủ những vấn đề mà người làm an toàn ứng dụng cần phải biết về JavaScript. Cuốn này có thể dùng làm sách giáo khoa thay cho cuốn &#8220;Javascript: The Definitive Guide&#8221; trong lớp <a href="http://crypto.stanford.edu/cs142/">CS142</a> (xem bên dưới). Đọc cuốn này tôi mới hiểu closure là gì và bản chất prototypal của JavaScript.</li>
</ul>
<ul>
<li>Sẽ đọc: những cuốn được giới thiệu ở <a href="https://sites.google.com/site/cinterfacesimplementations/recommended-books">đây</a>.</li>
</ul>
<p><em><strong>Hệ điều hành</strong></em></p>
<ul>
<li>Abraham Silberschatz, Peter Galvin, and Greg Gagne, <em>Operating System Concepts, 8th Edition Update</em>: cuốn này là giáo trình của lớp <a href="http://www.stanford.edu/~ouster/cgi-bin/cs140-winter12/index.php">CS140</a>. Tôi nghĩ không cần đọc cuốn này, chỉ cần đọc notes và làm bài tập (viết các phần khác nhau của một hệ điều hành!) là đủ. Đây là một lớp nặng. Tôi theo đuổi lớp CS140 này giữa chừng thì phải dừng lại do không có đủ thời gian.</li>
</ul>
<ul>
<li>Intel Software Developer Manuals: tôi thấy nên đọc tài liệu của <a href="http://www.scs.stanford.edu/05au-cs240c/lab/i386/toc.htm">80386</a> trước, rồi sau đó hẵng đọc tài liệu của các <a href="http://www.intel.com/content/www/us/en/processors/architectures-software-developer-manuals.html">CPU mới hơn</a>.</li>
</ul>
<ul>
<li>Red Hat, <em>Introduction to System Administration</em>: tôi rất thích chương nói về &#8220;philosophy of sysadmin&#8221; của cuốn này và tôi nghĩ kỹ năng quản trị hệ thống là cực kỳ cần thiết khi muốn nghiên cứu các kỹ thuật tấn công/phòng thủ mới. Không thể làm an toàn vận hành nếu không có kỹ năng quản trị hệ thống.</li>
</ul>
<ul>
<li>Sẽ đọc: Mark Russinovich, David Solomon, Alex Ionescu, <em>Windows Internals, Part 1: Covering Windows Server 2008 R2 and Windows 7.</em></li>
</ul>
<p><em><strong>Mạng máy tính</strong></em></p>
<ul>
<li>Richard Stevens, <em>TCP/IP Illustrated Vol I</em>: cuốn sách này quá nổi tiếng rồi nên tôi nghĩ không cần phải giới thiệu. Tôi chưa đọc Vol II, III nhưng nhất định sẽ tìm đọc trong thời gian tới. Lớp <a href="http://cs144.stanford.edu/">CS144</a> dùng một cuốn sách khác. Tôi chưa học lớp này, nhưng tôi thấy bài tập của họ khá thú vị.</li>
</ul>
<ul>
<li>Stephen Northcutt, Lenny Zeltser, Scott Winters, Karen Kent, Ronald W. Ritchey, <em>Inside Network Perimeter Security, 2nd Edition</em>: tôi thích cuốn này vì nó viết rất dễ hiểu về các vấn đề  và công cụ thường gặp trong an toàn mạng.</li>
</ul>
<ul>
<li>Sẽ đọc: Fyodor, <em>Nmap Network Scanning</em>.</li>
</ul>
<p>Sau khi đã có những kiến thức cơ bản ở trên, bạn có thể theo đuổi lớp <a href="http://cs155.stanford.edu/">CS155</a>. Lớp này có trên Coursera với tên <a href="http://www.security-class.org/">Computer Security</a>. Song song với lớp CS155, bạn có thể tìm đọc các sách sau:</p>
<p><em><strong>Tìm lỗi phầm mềm</strong></em></p>
<ul>
<li>Mark Dowd, John McDonald, Justin Schuh, <em>The Art of Software Security Assessment: Identifying and Preventing Software Vulnerabilities</em>: Kinh điển và phải-đọc! Cuốn này là kinh thánh của lĩnh vực an ninh ứng dụng. Tôi thích nhất phần nói về tràn số nguyên và những vấn đề của ngôn ngữ C trong cuốn này.</li>
</ul>
<ul>
<li>Dafydd Stuttard, Marcus Pinto, <em>The Web Application Hacker&#8217;s Handbook: Discovering and Exploiting Security Flaws</em>: cuốn này tập trung vào ứng dụng web. Tôi không đọc cuốn này kỹ lắm, mà chỉ thường dùng nó để tham khảo. Dẫu vậy tôi nghĩ nó là một cuốn giới thiệu tốt cho những ai mới bắt đầu.</li>
</ul>
<ul>
<li>Michal Zalewski, <em>The Tangled Web</em>: cuốn này mới xuất bản gần đây nhưng đã ngay lập tức trở thành kinh điển! Cuốn này đúc kết quá trình nghiên cứu về an ninh web trong vài năm trời của một trong những hacker xuất sắc nhất thế giới. Tôi nghĩ chỉ cần đọc cuốn này là bạn đã có thể bắt đầu tìm lỗ kiếm tiền được rồi. Cuốn này và cuốn ở trên được dùng làm sách giáo khoa của lớp <a href="http://crypto.stanford.edu/cs142/">CS142</a>.</li>
</ul>
<ul>
<li>Sẽ đọc: Tobias Klein, <em>A Bug Hunter&#8217;s Diary: A Guided Tour Through the Wilds of Software Security</em></li>
</ul>
<p><em><strong>Dịch ngược mã phần mềm</strong></em></p>
<ul>
<li>Eldad Eilam, <em>Reversing: Secrets of Reverse Engineering</em>: mặc dù có rất nhiều người viết về RCE nhưng tôi thấy đây là cuốn duy nhất hệ thống hóa được các bước quan trọng cần phải làm khi cần dịch ngược mã của một tệp chương trình nào đó.</li>
</ul>
<ul>
<li>Chris Eagle, <em>The IDA Pro Book: The Unofficial Guide to the World&#8217;s Most Popular Disassembler</em>: IDA Pro là công cụ tốt nhất để làm RCE và đây là cuốn sách tốt nhất về IDA Pro. Nắm vững C và x86 Assembly thì chỉ cần đọc cuốn này là bạn có thể bắt đầu RCE các phần mềm phức tạp.</li>
</ul>
<ul>
<li>Tham khảo các tài liệu về <a href="http://pentest.cryptocity.net/reverse-engineering/">dịch ngược mã phần mềm</a> của lớp PenTest của đại học NYU.</li>
</ul>
<ul>
<li>Sẽ đọc: Christian Collberg, <em>Surreptitious Software: Obfuscation, Watermarking, and Tamperproofing for Software Protection: Obfuscation, Watermarking, and Tamperproofing for Software Protection</em></li>
</ul>
<ul>
<li>Sẽ đọc: Michael Sikorski, Andrew Honig, <em>Practical Malware Analysis: The Hands-On Guide to Dissecting Malicious Software</em></li>
</ul>
<p><em><strong>Điều tra số (digital forensics)</strong></em></p>
<ul>
<li>Brian Carrier, <em>File System Forensic Analysis</em>: Brian Carrier là tác giả của bộ công cụ forensic nổi tiếng <a href="http://www.sleuthkit.org/">The Sleuth Kit</a>. Cuốn này đã giúp tôi &#8220;khai quật&#8221; được một đoạn video bị xóa lưu trong một máy camera quay lén các máy ATM.</li>
</ul>
<ul>
<li>Sẽ đọc: Cory Altheide, Harlan Carvey, <em>Digital Forensics with Open Source Tools</em></li>
</ul>
<p><em><strong>Mật mã hóa</strong></em></p>
<ul>
<li>Niels Ferguson, Bruce Schneier, <em>Practical Cryptography</em>: tôi có nhiều kỷ niệm đẹp với cuốn này <img src='http://www.procul.org/blog/wp-includes/images/smilies/icon_wink.gif' alt=';-)' class='wp-smiley' /> . Hầu hết các kết quả làm việc của tôi trong vài năm vừa rồi là nhờ vào việc đọc cuốn này. Tôi chép lại đây giới thiệu rất hay của một người bạn: &#8220;<em>The best security books, you can read &#8220;inside out&#8221;, taking any recommendation on what to do and looking for people to do the opposite to find flaws. &#8220;Firewalls and Internet Security&#8221; was like that. So was &#8220;Practical Unix Security&#8221;, and so is TOASSA. This is that book for crypto. It&#8217;s also the one book on crypto you should allow yourself to read until you start actually finding crypto flaws.</em>&#8220;</li>
</ul>
<ul>
<li>Jonathan Katz, Yehuda Lindell, <em>Introduction to Modern Cryptography: Principles and Protocols</em>: đây là sách giáo khoa của lớp <a href="http://cs255.stanford.edu/">CS255</a>. Lớp này là lớp <a href="https://www.coursera.org/course/crypto">Cryptography</a> trên Coursera.</li>
</ul>
<ul>
<li>Sẽ đọc: Adam Young, Moti Yung, <em>Malicious Cryptography: Exposing Cryptovirology</em></li>
</ul>
<p>Chú ý đây là những cuốn sách tập trung vào công việc hàng ngày và sở thích của tôi &#8212; nói cách khác, còn thiếu nhiều sách của các mảng công việc khác. Dẫu vậy tôi nghĩ những cuốn sách này sẽ giúp bạn có được một kiến thức nền tảng vững chắc để từ đó theo đuổi các nghề nghiệp khác nhau trong ngành an toàn thông tin. Trong thời gian tới tôi sẽ cập nhật thêm những cuốn sách mà tôi đang và sẽ đọc. Nếu bạn biết sách nào hay thì hãy giới thiệu cho tôi.</p>
<p>Ngoài ra trong các sách mà tôi vừa liệt kê không có cuốn sách toán (và lý thuyết khoa học máy tính) nào cả. Tôi nghĩ bạn sẽ tự có câu trả lời cho câu hỏi &#8220;Có nên học toán hay không?&#8221; khi bắt đầu học mật mã. Về hai mảng này thì tôi rất thích lớp &#8220;Great Ideas in Theoretical Computer Science&#8221; của <a href="http://www.scottaaronson.com/blog/">Scott Aaronson</a> và cuốn &#8220;<a href="http://shoup.net/ntb/">A Computational Introduction to Number Theory and Algebra</a>&#8221; của Victor Shoup. Thích đến nỗi tôi phải viết đoạn này chỉ để nhắc đến chúng <img src='http://www.procul.org/blog/wp-includes/images/smilies/icon_wink.gif' alt=';-)' class='wp-smiley' /> . Tôi cũng đã từng dành ra nhiều tháng để đánh vật với <a href="http://www-math.mit.edu/~sipser/">Introduction to the Theory of Computation</a> của Michael Sipser. Nhưng thôi, tôi không muốn giới thiệu sách toán nữa vì tôi rất dốt món này!</p>
<p><strong>5 Bắt đầu nói nhảm và hết</strong></p>
<p>Phew! Không ngờ là tôi cũng viết được cho đến đây (hi vọng là bạn vẫn đang đọc!). Tôi định viết dông dài về thái độ học tập này nọ, nhưng thôi bài đã dài và nhiều thông tin rồi, nên tôi chỉ nói ngắn gọn thế này:</p>
<p>Cái mà tôi vừa &#8220;vẽ&#8221; ra là một con đường. Thú thật là tôi không biết đích đến của nó là gì &#8212; tôi chỉ biết rằng hành trình mà tôi đã đi qua (và hi vọng là những chặng đường sắp tới) đã mang đến cho tôi rất nhiều niềm vui &#8212; niềm vui của một con người đi khám phá thế giới, chinh phục những thử thách, để rồi chia sẻ những câu chuyện hay ho với tất cả mọi người.Mỗi ngày tôi đều dành thời gian đọc sách, làm bài tập, viết mã hoặc chứng minh một cái gì đó. Không ai bắt tôi phải làm những chuyện đó. Có những thứ tôi học cũng không (hoặc chưa) có liên quan gì đến công việc. Tôi học chỉ vì tôi thích và tò mò. Tôi học vì tôi muốn hiểu thêm những thứ mà tôi cho là hay ho. Tôi học vì tôi muốn đi mãi, đi mãi, đi đến tận cùng những cái mà người ta viết trong sách, để xem ở đó có gì hay không.</p>
<p>Hôm rồi tôi đọc một mẩu chuyện về Richard Feynman, trong đó có đoạn kể về lúc Feynman bị bệnh gần đất xa trời, ông tâm sự rằng, &#8220;[I'm going to die but I'm not as sad as you think because] when you get as old as I am, you start to realize that you&#8217;ve told most of the good stuff you know to other people anyway&#8221;. Đương nhiên những gì tôi biết làm sao mà &#8220;good&#8221; bằng những gì Feynman biết, nhưng dẫu sao thì tôi cũng sẽ học theo Feynman: có biết chuyện gì hay ho thì kể cho nhiều người khác cùng biết. Bài này là một chuyện như thế.</p>
<p>Happy hacking!</p>
<p><em>(cảm ơn đại ca M. đã đọc và sửa bản nháp của bài này)</em></p>
]]></content:encoded>
			<wfw:commentRss>http://www.procul.org/blog/2012/05/02/lam-an-toan-thong-tin-thi-h%e1%bb%8dc-gi/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>Con sãi ở chùa thì đi săn lỗ</title>
		<link>http://www.procul.org/blog/2012/04/24/con-sai-%e1%bb%9f-chua-thi-di-san-l%e1%bb%97/</link>
		<comments>http://www.procul.org/blog/2012/04/24/con-sai-%e1%bb%9f-chua-thi-di-san-l%e1%bb%97/#comments</comments>
		<pubDate>Tue, 24 Apr 2012 06:58:49 +0000</pubDate>
		<dc:creator>thaidn</dc:creator>
				<category><![CDATA[Bảo mật và mật mã học]]></category>
		<category><![CDATA[Tin tức đó đây]]></category>

		<guid isPermaLink="false">http://www.procul.org/blog/?p=4539</guid>
		<description><![CDATA[Chương trình tìm lỗ lấy tiền của Google vừa mới nâng giá giải thưởng: $20,000 for qualifying vulnerabilities that the reward panel determines will allow code execution on our production systems. $10,000 for SQL injection and equivalent vulnerabilities; and for certain types of information disclosure, authentication, and authorization bypass bugs. Up to $3,133.7 for many [...]]]></description>
			<content:encoded><![CDATA[<p>Chương trình <a href="http://www.procul.org/blog/2011/11/04/4084/">tìm lỗ lấy tiền</a> của Google vừa mới <a href="http://googleonlinesecurity.blogspot.com/2012/04/spurring-more-vulnerability-research.html">nâng giá giải thưởng</a>:</p>
<blockquote><p>$20,000 for qualifying vulnerabilities that the reward panel determines will allow code execution on our production systems.</p>
<p>$10,000 for SQL injection and equivalent vulnerabilities; and for certain types of information disclosure, authentication, and authorization bypass bugs.</p>
<p>Up to $3,133.7 for many types of XSS, XSRF, and other high-impact flaws in highly sensitive applications.</p></blockquote>
<p>3.000 Mỹ kim cho một lỗ hổng <a href="http://en.wikipedia.org/wiki/Cross-site_scripting">XSS</a>, quá ngon! Với số lượng ứng dụng khổng lồ của Google, việc tìm được những lỗi như XSS hay <a href="http://en.wikipedia.org/wiki/Cross-site_request_forgery">XSRF</a>, vốn không đòi hỏi kiến thức hay kinh nghiệm gì cao siêu cả, là không quá khó. Thực tế là kể từ khi chương trình này bắt đầu cho đến nay, đã có hơn hai trăm người gửi lỗi và được Google thưởng cho hơn 460.000 Mỹ kim. Nhưng <a href="http://www.google.com/about/company/halloffame.html">chưa</a> có con sãi nào đến từ Việt Nam cả!</p>
<p>Nếu không săn lỗ thì đi <a href="http://nhipsongso.tuoitre.vn/Nhip-song-so/488331/Sinh-vien-%E2%80%9Ctrieu-phu%E2%80%9D-nho-viet-phan-mem.html">viết app</a> cũng được.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.procul.org/blog/2012/04/24/con-sai-%e1%bb%9f-chua-thi-di-san-l%e1%bb%97/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Con sãi ở chùa lại đánh bi-da</title>
		<link>http://www.procul.org/blog/2012/04/20/con-sai-%e1%bb%9f-chua-l%e1%ba%a1i-danh-bi-da/</link>
		<comments>http://www.procul.org/blog/2012/04/20/con-sai-%e1%bb%9f-chua-l%e1%ba%a1i-danh-bi-da/#comments</comments>
		<pubDate>Fri, 20 Apr 2012 12:34:13 +0000</pubDate>
		<dc:creator>NQH</dc:creator>
				<category><![CDATA[Vui - Giải Trí]]></category>
		<category><![CDATA[Bi da]]></category>
		<category><![CDATA[Con sãi]]></category>
		<category><![CDATA[Vui]]></category>

		<guid isPermaLink="false">http://www.procul.org/blog/?p=4535</guid>
		<description><![CDATA[Năm 24 tuổi, hầu hết thời gian trong đời tớ dùng vào việc đánh bi da. À không, hình như lúc đó đang lui cui học lệnh cd, ls, cp trên một máy SGI. Đánh bi da là năm 18-22 tuổi. Năm 24 tuổi, cô gái này đi &#8220;đến thăm, động viên đội ngũ cán [...]]]></description>
			<content:encoded><![CDATA[<p>Năm 24 tuổi, hầu hết thời gian trong đời tớ dùng vào việc đánh bi da. À không, hình như lúc đó đang lui cui học lệnh <code>cd, ls, cp</code> trên một máy SGI. Đánh bi da là năm 18-22 tuổi.</p>
<p>Năm 24 tuổi, <a href="http://www.bbc.co.uk/vietnamese/vietnam/2012/04/120420_politburo_daughter_ceo.shtml">cô gái này</a> đi &#8220;<em>đến thăm, động viên đội ngũ cán bộ, công nhân đang thi công &#8230;  chỉ đạo Ban quản lý chu đáo các vấn đề liên quan đến việc làm lán, trại, chỗ ở cho công nhân để anh em yên tâm làm việc và đảm bảo sức khỏe</em>&#8220;. </p>
<p>Thiệt là hậu sinh khả uý.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.procul.org/blog/2012/04/20/con-sai-%e1%bb%9f-chua-l%e1%ba%a1i-danh-bi-da/feed/</wfw:commentRss>
		<slash:comments>23</slash:comments>
		</item>
		<item>
		<title>Hàm băm FNV</title>
		<link>http://www.procul.org/blog/2012/04/18/ham-bam-fnv/</link>
		<comments>http://www.procul.org/blog/2012/04/18/ham-bam-fnv/#comments</comments>
		<pubDate>Thu, 19 Apr 2012 01:33:25 +0000</pubDate>
		<dc:creator>NQH</dc:creator>
				<category><![CDATA[Cấu trúc dữ liệu]]></category>
		<category><![CDATA[FVN]]></category>
		<category><![CDATA[Hàm băm]]></category>
		<category><![CDATA[Võ Kiềm Phong]]></category>

		<guid isPermaLink="false">http://www.procul.org/blog/?p=4508</guid>
		<description><![CDATA[Khi xây dựng bảng băm, ví dụ bảng băm cho một bộ tự điển, đầu tiên ta cần tính mã băm (hash codes) của các từ trong tự điển. Mỗi mã băm của một từ là một số nguyên dài 4 bytes chẳng hạn. Sau đó ta dùng một hàm băm nữa gọi là hàm [...]]]></description>
			<content:encoded><![CDATA[<p>Khi xây dựng bảng băm, ví dụ bảng băm cho một bộ tự điển, đầu tiên ta cần tính mã băm (hash codes) của các từ trong tự điển. Mỗi mã băm của một từ là một số nguyên dài 4 bytes chẳng hạn. Sau đó ta dùng một hàm băm nữa gọi là hàm nén (compression function) chuyển số nguyên này xuống miền nhỏ hơn, cỡ vài trăm ngàn tuỳ tự điển. Tóm lại, một hàm băm từ tập các từ thường là composition của hai hàm băm &#8212; một hàm chuyển về miền số nguyên dài 32 bits, hàm thứ hai từ miền số nguyên đến miền nhỏ cỡ trăm ngàn, tuỳ theo load factor của bảng băm.</p>
<p>Có rất nhiều cách tính mã băm chuyển chuỗi ký tự thành số nguyên dài 32 bits. Các sách giáo khoa thường nói đến mã băm đa thức (<em>polynomial hash codes</em>). Ví dụ, với một chuỗi bytes <code>s = s[0]...s[k-1]</code> với chiều dài <code>k</code> ta có thể dùng hash code sau:</p>
<p><center><img src='http://s.wordpress.com/latex.php?latex=%5Ctext%7Bhashcode%28s%29%7D%20%3D%20%5Csum_%7Bi%3D0%7D%5E%7Bk-1%7Ds%5Bi%5D%2Aa%5Ei&#038;bg=ffffff&#038;fg=000000&#038;s=0' alt='\text{hashcode(s)} = \sum_{i=0}^{k-1}s[i]*a^i' title='\text{hashcode(s)} = \sum_{i=0}^{k-1}s[i]*a^i' class='latex' /></center></p>
<p>trong đó <img src='http://s.wordpress.com/latex.php?latex=a&#038;bg=ffffff&#038;fg=000000&#038;s=0' alt='a' title='a' class='latex' /> thường được chọn là một số nguyên tố. Hàm <code>hashCode()</code> strong trong lớp <code>string</code> của Java <a href="http://www.ibm.com/developerworks/java/library/j-jtp05273/index.html">dùng</a> mã băm đa thức với <img src='http://s.wordpress.com/latex.php?latex=a%3D31&#038;bg=ffffff&#038;fg=000000&#038;s=0' alt='a=31' title='a=31' class='latex' />. Một lợi điểm của mã băm đa thức là nó có thể tính đương đối nhanh được dùng luật Horner: </p>
<p><center><img src='http://s.wordpress.com/latex.php?latex=%5Ctext%7Bhashcode%28s%29%7D%20%3D%20s%5B0%5D%20%2B%20a%2A%28s%5B1%5D%20%2B%20a%2A%28%5Cdots%20%28s%5Bk-2%5D%20%2B%20a%20%2A%20s%5Bk-1%5D%29%5Cdots%29&#038;bg=ffffff&#038;fg=000000&#038;s=0' alt='\text{hashcode(s)} = s[0] + a*(s[1] + a*(\dots (s[k-2] + a * s[k-1])\dots)' title='\text{hashcode(s)} = s[0] + a*(s[1] + a*(\dots (s[k-2] + a * s[k-1])\dots)' class='latex' /></center></p>
<p><span id="more-4508"></span></p>
<p>Dịch ra C++ (đảo thứ tự các bytes lại cho đơn giản) là</p>
<pre class="brush: cpp; title: ; notranslate">
uint32_t poly(string s, uint32_t base) {
    uint32_t ret = static_cast&lt;uint32_t&gt;(s[0]); // assumes s.length() &gt; 0
    for (size_t i=1; i&lt;s.length(); ++i) {
        ret += base*ret + static_cast&lt;uint32_t&gt;(s[i]);
    }
    return ret;
}
</pre>
<p>Nếu <code>base</code> là 33 hoặc 31 thì ta có thể thay <code>base*ret</code> bằng <code>base + (base << 5)</code> hoặc <code>(base << 5) - base</code>: nhanh hơn nhiều. Do đó, 33 và 31 thường được giới thiệu dùng.</p>
<p>Một hàm khác cũng thường được gợi ý thì thay phép nhân với một <code>base</code> bằng một phép <code>shift</code> đi vài bits, ví dụ <code>7</code> bits:</p>
<pre class="brush: cpp; title: ; notranslate">
uint32_t shift7(string s) {
    uint32_t ret=0;
    for (size_t i=0; i&lt;s.length(); ++i) {
            ret = (ret &lt;&lt; 7) | (ret &gt;&gt; 25); // cyclic shift
            ret += static_cast&lt;uint32_t&gt;(s[i]);
    }
    return ret;
}
</pre>
<p>Năm 97, Bob Jenkins viết một <a href="http://burtleburtle.net/bob/hash/doobs.html">bài báo</a> trên tạp chí kỹ thuật Dr. Doob có liệt kê ra khá nhiều hàm phổ dụng cùng với các lợi điểm, yếu điểm của chúng. Sau đó đến khoảng 2006 ông ta <a href="http://burtleburtle.net/bob/hash/doobs.html">cập nhật</a> bài báo này với một số hàm mới. Đáng lưu ý là các hàm sau đây:</p>
<ul>
<li> <a href="http://isthe.com/chongo/tech/comp/fnv/">Hàm FNV</a> (viết tắt của <a href="http://en.wikipedia.org/wiki/Fowler_Noll_Vo_hash">Fowler–Noll–Vo</a>). Hàm này có vẻ như được dùng rất phổ biến trong các phần mềm hiện đại. (Ví dụ, dùng để cải tiến fragment cache của Twitter.) Điều có liên quan đến blog này là chữ Vo thuộc về <a href="http://www.research.att.com/people/Vo_Kiem-phong/index.html?fbid=nwJ3C7xGU2L">bác Võ Kiềm Phong</a> của AT&#038;T lab. Bác Phong cũng là đồng tác giả của <a href="http://www2.research.att.com/~gsf/download/ref/sfio/sfio.html">thư viện SFIO</a>, và nhiều <a href="http://nices.com/www-att-com/attlabs/reputation/fellows/vo.html">hàm thư viện Unix khác</a>.
<li> <a href="http://code.google.com/p/smhasher/">MurmurHash</a>
<li> Và một <a href="http://burtleburtle.net/bob/hash/doobs.html">vài hàm</a> của Jenkins và <a href="http://www.azillionmonkeys.com/qed/hash.html">của Paul Hsieh</a>
</ul>
<p>FNV hash bản 32-bit có thể viết như sau:</p>
<pre class="brush: cpp; title: ; notranslate">
uint32_t FNV32(string s)
{
    static const uint32_t FNV_PRIME_32  = 16777619;
    static const uint32_t FNV_OFFSET_32 = 2166136261;

    uint32_t hash = FNV_OFFSET_32, i;
    for(int i = 0; i &lt; s.length(); i++) {
        hash  = hash^(s[i]);  // hash = hash XOR s[i]
        hash *= FNV_PRIME_32; // hash = hash * (fixed prime)
    }
    return hash;
}
</pre>
<p>Tôi download <a href="http://wordlist.sourceforge.net/">một tự điển nhỏ</a> của phần mềm ispell, gồm khoảng 47 nghìn từ tiếng Anh thông dụng, và thí nghiệm với vài biến thể của các hàm băm trên. Kết quả như sau:</p>
<pre>
HC Name             Total # colliding values   Max bucket size
FNV32               0                           0
poly31              22                          1
poly33              22                          1
poly37              22                          1
poly7               2276                        18
poly91              19                          1
shift5              27                          2
shift7              56                          1
sum                 45579                       175
xoring              560                         2
</pre>
<p>Có thể thấy FVN32 rất tốt. Chúc mừng bác Võ! Kết quả này cũng tương tự với 3 bộ từ khác gồm gần 100 nghìn từ mà tôi đã thử. Chất lượng của một hàm băm nằm ở xác suất đụng độ và cả tốc độ của hàm băm. Trong thí nghiệm trên tôi chưa đo tốc độ.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.procul.org/blog/2012/04/18/ham-bam-fnv/feed/</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
		<item>
		<title>Các câu hỏi phỏng vấn [43]</title>
		<link>http://www.procul.org/blog/2012/04/18/cac-cau-h%e1%bb%8fi-ph%e1%bb%8fng-v%e1%ba%a5n-43/</link>
		<comments>http://www.procul.org/blog/2012/04/18/cac-cau-h%e1%bb%8fi-ph%e1%bb%8fng-v%e1%ba%a5n-43/#comments</comments>
		<pubDate>Wed, 18 Apr 2012 22:27:44 +0000</pubDate>
		<dc:creator>thaidn</dc:creator>
				<category><![CDATA[Dành cho du học sinh]]></category>
		<category><![CDATA[Lý thuyết số]]></category>
		<category><![CDATA[Mật mã học]]></category>
		<category><![CDATA[Đố]]></category>

		<guid isPermaLink="false">http://www.procul.org/blog/?p=4506</guid>
		<description><![CDATA[113. Tính cube root modulo : cho và , tính nhanh sao cho . Thiệt ra đây không phải câu hỏi phỏng vấn (có nơi nào phỏng vấn mà hỏi những câu dạng này không nhỉ?) mà là của một anh đồng nghiệp hỏi tôi hôm nay. Tôi thấy nó thú vị và thích hợp [...]]]></description>
			<content:encoded><![CDATA[<p>113. Tính cube root modulo <img src='http://s.wordpress.com/latex.php?latex=2%5En&#038;bg=ffffff&#038;fg=000000&#038;s=0' alt='2^n' title='2^n' class='latex' />: cho <img src='http://s.wordpress.com/latex.php?latex=a&#038;bg=ffffff&#038;fg=000000&#038;s=0' alt='a' title='a' class='latex' /> và <img src='http://s.wordpress.com/latex.php?latex=n&#038;bg=ffffff&#038;fg=000000&#038;s=0' alt='n' title='n' class='latex' />, tính nhanh <img src='http://s.wordpress.com/latex.php?latex=x&#038;bg=ffffff&#038;fg=000000&#038;s=0' alt='x' title='x' class='latex' /> sao cho <img src='http://s.wordpress.com/latex.php?latex=a%20%3D%20x%5E3%20%28mod%5C%3B2%5En%29&#038;bg=ffffff&#038;fg=000000&#038;s=0' alt='a = x^3 (mod\;2^n)' title='a = x^3 (mod\;2^n)' class='latex' />.</p>
<p>Thiệt ra đây không phải câu hỏi phỏng vấn (có nơi nào phỏng vấn mà hỏi những câu dạng này không nhỉ?) mà là của một anh đồng nghiệp hỏi tôi hôm nay. Tôi thấy nó thú vị và thích hợp với những ai đang theo học lớp <a href="http://crypto-class.org">crypto</a> của Stanford nên gửi lên đây.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.procul.org/blog/2012/04/18/cac-cau-h%e1%bb%8fi-ph%e1%bb%8fng-v%e1%ba%a5n-43/feed/</wfw:commentRss>
		<slash:comments>12</slash:comments>
		</item>
		<item>
		<title>Câu hỏi về câu hỏi về câu hỏi &#8230;</title>
		<link>http://www.procul.org/blog/2012/04/14/cau-h%e1%bb%8fi-v%e1%bb%81-cau-h%e1%bb%8fi-v%e1%bb%81-cau-h%e1%bb%8fi/</link>
		<comments>http://www.procul.org/blog/2012/04/14/cau-h%e1%bb%8fi-v%e1%bb%81-cau-h%e1%bb%8fi-v%e1%bb%81-cau-h%e1%bb%8fi/#comments</comments>
		<pubDate>Sun, 15 Apr 2012 00:55:20 +0000</pubDate>
		<dc:creator>Administrator</dc:creator>
				<category><![CDATA[Thông báo]]></category>
		<category><![CDATA[Đổi tên]]></category>

		<guid isPermaLink="false">http://www.procul.org/blog/?p=4498</guid>
		<description><![CDATA[]]></description>
			<content:encoded><![CDATA[Note: There is a poll embedded within this post, please visit the site to participate in this post's poll.
]]></content:encoded>
			<wfw:commentRss>http://www.procul.org/blog/2012/04/14/cau-h%e1%bb%8fi-v%e1%bb%81-cau-h%e1%bb%8fi-v%e1%bb%81-cau-h%e1%bb%8fi/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Drama</title>
		<link>http://www.procul.org/blog/2012/04/13/drama/</link>
		<comments>http://www.procul.org/blog/2012/04/13/drama/#comments</comments>
		<pubDate>Fri, 13 Apr 2012 14:56:24 +0000</pubDate>
		<dc:creator>NQH</dc:creator>
				<category><![CDATA[Vui - Giải Trí]]></category>
		<category><![CDATA[Drama]]></category>

		<guid isPermaLink="false">http://www.procul.org/blog/?p=4494</guid>
		<description><![CDATA[]]></description>
			<content:encoded><![CDATA[<p><iframe width="560" height="315" src="http://www.youtube.com/embed/9OIJRMqYAA0" frameborder="0" allowfullscreen></iframe></p>
]]></content:encoded>
			<wfw:commentRss>http://www.procul.org/blog/2012/04/13/drama/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Các cây tìm kiếm cân bằng: AVL, đỏ đen, (2,4), và cây loe</title>
		<link>http://www.procul.org/blog/2012/04/06/cac-cay-tim-ki%e1%ba%bfm-can-b%e1%ba%b1ng-avl-d%e1%bb%8f-den-24-va-cay-loe/</link>
		<comments>http://www.procul.org/blog/2012/04/06/cac-cay-tim-ki%e1%ba%bfm-can-b%e1%ba%b1ng-avl-d%e1%bb%8f-den-24-va-cay-loe/#comments</comments>
		<pubDate>Fri, 06 Apr 2012 05:15:49 +0000</pubDate>
		<dc:creator>NQH</dc:creator>
				<category><![CDATA[C++]]></category>
		<category><![CDATA[Cấu trúc dữ liệu]]></category>
		<category><![CDATA[2-4 tree]]></category>
		<category><![CDATA[amortized analysis]]></category>
		<category><![CDATA[avl tree]]></category>
		<category><![CDATA[phân tích khấu hao]]></category>
		<category><![CDATA[red-black tree]]></category>
		<category><![CDATA[splay tree]]></category>

		<guid isPermaLink="false">http://www.procul.org/blog/?p=4477</guid>
		<description><![CDATA[Bài giảng cho lớp cấu trúc dữ liệu. Bạn nào rảnh đọc thì góp ý giùm, nhất là phần C++. Bài trước: Cây nhị phân và cây tìm kiếm nhị phân Bài sau: bảng băm. In the previous lecture we have discussed binary search trees (BSTs) and several basic results such as the number of [...]]]></description>
			<content:encoded><![CDATA[<blockquote><p>
Bài giảng cho lớp cấu trúc dữ liệu. Bạn nào rảnh đọc thì góp ý giùm, nhất là phần C++.</p>
<p><strong>Bài trước</strong>: <a href="http://www.procul.org/blog/2012/03/20/cay-nh%e1%bb%8b-phan-va-cay-tim-ki%e1%ba%bfm-nh%e1%bb%8b-phan/">Cây nhị phân và cây tìm kiếm nhị phân</a><br />
<strong>Bài sau</strong>: bảng băm.
</p></blockquote>
<p>In the previous lecture we have discussed binary search trees (BSTs) and several basic results such as the number of BSTs with <code>n</code> keys and the height of a random BST with <code>n</code> node. Perhaps the most important result is that in a BST the three basic operations &#8212; search, insert, and delete &#8212; take <code>O(h)</code> time where <code>h</code> is the height of the tree (at the time an operation is performed). Since the average height of a random BST is <code>O(log n)</code> (with a small variance), these operations are pretty fast on average. However, the run-time in the worst case could be bad.</p>
<blockquote><p>
<strong>Exercise:</strong> come up with a sequence of <code>n</code> inserts such that the tree height is <img src='http://s.wordpress.com/latex.php?latex=%5COmega%28n%29&#038;bg=ffffff&#038;fg=000000&#038;s=0' alt='\Omega(n)' title='\Omega(n)' class='latex' />.
</p></blockquote>
<p>In this lecture, we describe several schemes for maintaining BSTs such that the height of the tree is (about) logarithmic in the number of nodes. One of the main ideas is to ensure that for each node in the tree the height of the left sub-tree and the height of the right-subtree are roughly equal. For a visual illustration of three of the trees described in this lecture, you can make use of the Java applet on <a href="http://webdiis.unizar.es/asignaturas/EDA/AVLTree/avltree.html">this page</a>.</p>
<p><span id="more-4477"></span></p>
<h3>1. AVL Trees</h3>
<p><a href="http://en.wikipedia.org/wiki/AVL_tree">AVL Trees</a> are probably the earliest balanced BST, proposed by two Russians (Soviet) G. M. Adelson-Velskii and E. M. Landis in 1962. The main idea is intuitive: we call a node <em>balanced</em> if its two subtrees have heights differ by at most 1. A BST is an <em>AVL</em> tree if all nodes are balanced. This property is called the <em>AVL property</em>. There are two things we have to do to turn this idea into a theoretically sound data structure:</p>
<ol>
<li> Prove that if a tree is an AVL tree, then its height is <code>O(log n)</code> where <code>n</code> is the number of keys in the tree.
<li> Show how to do <code>insert</code> and <code>delete</code> in <code>O(log n)</code>-time <em>while</em> maintaining the AVL property.
</ol>
<h4>1.1. AVL property implies logarithmic height</h4>
<blockquote><p>
<strong>Theorem:</strong> an AVL tree on <code>n</code> nodes has <code>O(log n)</code> height.
</p></blockquote>
<p><em>Proof.</em> Let <img src='http://s.wordpress.com/latex.php?latex=h%28n%29&#038;bg=ffffff&#038;fg=000000&#038;s=0' alt='h(n)' title='h(n)' class='latex' /> be the maximum height of an AVL tree with <img src='http://s.wordpress.com/latex.php?latex=n&#038;bg=ffffff&#038;fg=000000&#038;s=0' alt='n' title='n' class='latex' /> nodes. We want to show that <img src='http://s.wordpress.com/latex.php?latex=h%28n%29%20%5Cleq%20c%5Clog%20n&#038;bg=ffffff&#038;fg=000000&#038;s=0' alt='h(n) \leq c\log n' title='h(n) \leq c\log n' class='latex' /> where <img src='http://s.wordpress.com/latex.php?latex=c&#038;bg=ffffff&#038;fg=000000&#038;s=0' alt='c' title='c' class='latex' /> is some constant. It turns out that proving the contra-positive is a little easier. Let <img src='http://s.wordpress.com/latex.php?latex=n%28h%29&#038;bg=ffffff&#038;fg=000000&#038;s=0' alt='n(h)' title='n(h)' class='latex' /> be the <em>minimum</em> number of nodes in an AVL tree with height <img src='http://s.wordpress.com/latex.php?latex=h&#038;bg=ffffff&#038;fg=000000&#038;s=0' alt='h' title='h' class='latex' />, we will derive a lower bound for <img src='http://s.wordpress.com/latex.php?latex=n%28h%29&#038;bg=ffffff&#038;fg=000000&#038;s=0' alt='n(h)' title='n(h)' class='latex' /> in terms of <img src='http://s.wordpress.com/latex.php?latex=h&#038;bg=ffffff&#038;fg=000000&#038;s=0' alt='h' title='h' class='latex' />, which will then lead to an upper bound of <img src='http://s.wordpress.com/latex.php?latex=h%28n%29&#038;bg=ffffff&#038;fg=000000&#038;s=0' alt='h(n)' title='h(n)' class='latex' /> in terms of <img src='http://s.wordpress.com/latex.php?latex=n&#038;bg=ffffff&#038;fg=000000&#038;s=0' alt='n' title='n' class='latex' />.<br />
For simplicity, we will count all of the <code>NULL</code> pointers as leaves of the tree. Thus, a BST is a full binary tree: each non-NULL node has 2 children. It is not hard to see that <img src='http://s.wordpress.com/latex.php?latex=n%281%29%20%3D%201&#038;bg=ffffff&#038;fg=000000&#038;s=0' alt='n(1) = 1' title='n(1) = 1' class='latex' /> and <img src='http://s.wordpress.com/latex.php?latex=n%282%29%20%3D%202&#038;bg=ffffff&#038;fg=000000&#038;s=0' alt='n(2) = 2' title='n(2) = 2' class='latex' />. Now, consider an AVL tree with height <img src='http://s.wordpress.com/latex.php?latex=h%3E2&#038;bg=ffffff&#038;fg=000000&#038;s=0' alt='h&gt;2' title='h&gt;2' class='latex' /> with the minimum possible number of nodes <img src='http://s.wordpress.com/latex.php?latex=n%28h%29&#038;bg=ffffff&#038;fg=000000&#038;s=0' alt='n(h)' title='n(h)' class='latex' />. Then, it must be the case that one of the sub-trees of the root has height <img src='http://s.wordpress.com/latex.php?latex=h-1&#038;bg=ffffff&#038;fg=000000&#038;s=0' alt='h-1' title='h-1' class='latex' /> with <img src='http://s.wordpress.com/latex.php?latex=n%28h-1%29&#038;bg=ffffff&#038;fg=000000&#038;s=0' alt='n(h-1)' title='n(h-1)' class='latex' /> nodes and the other sub-tree has height <img src='http://s.wordpress.com/latex.php?latex=h-2&#038;bg=ffffff&#038;fg=000000&#038;s=0' alt='h-2' title='h-2' class='latex' /> with <img src='http://s.wordpress.com/latex.php?latex=n%28h-2%29&#038;bg=ffffff&#038;fg=000000&#038;s=0' alt='n(h-2)' title='n(h-2)' class='latex' /> nodes. Thus, we have the following recurrence:</p>
<p><center><img src='http://s.wordpress.com/latex.php?latex=n%28h%29%20%3D%201%20%2B%20n%28h-1%29%20%2B%20n%28h-2%29%2C%20%5Ctext%7B%20for%20%7D%20h%20%5Cgeq%203&#038;bg=ffffff&#038;fg=000000&#038;s=0' alt='n(h) = 1 + n(h-1) + n(h-2), \text{ for } h \geq 3' title='n(h) = 1 + n(h-1) + n(h-2), \text{ for } h \geq 3' class='latex' /></center></p>
<p>Define <img src='http://s.wordpress.com/latex.php?latex=g%28h%29%20%3D%20n%28h%29%20%2B%201&#038;bg=ffffff&#038;fg=000000&#038;s=0' alt='g(h) = n(h) + 1' title='g(h) = n(h) + 1' class='latex' />, then we have <img src='http://s.wordpress.com/latex.php?latex=g%281%29%20%3D%202&#038;bg=ffffff&#038;fg=000000&#038;s=0' alt='g(1) = 2' title='g(1) = 2' class='latex' />, <img src='http://s.wordpress.com/latex.php?latex=g%282%29%20%3D%203&#038;bg=ffffff&#038;fg=000000&#038;s=0' alt='g(2) = 3' title='g(2) = 3' class='latex' />, and</p>
<img src='http://s.wordpress.com/latex.php?latex=g%28h%29%20%3D%20g%28h-1%29%20%2B%20g%28h-2%29%2C%20%5Ctext%7B%20for%20%7D%20h%20%5Cgeq%203&#038;bg=ffffff&#038;fg=000000&#038;s=0' alt='g(h) = g(h-1) + g(h-2), \text{ for } h \geq 3' title='g(h) = g(h-1) + g(h-2), \text{ for } h \geq 3' class='latex' />
<p>Because <img src='http://s.wordpress.com/latex.php?latex=g%281%29%20%3D%20F_3&#038;bg=ffffff&#038;fg=000000&#038;s=0' alt='g(1) = F_3' title='g(1) = F_3' class='latex' />, <img src='http://s.wordpress.com/latex.php?latex=g%282%29%20%3D%20F_4&#038;bg=ffffff&#038;fg=000000&#038;s=0' alt='g(2) = F_4' title='g(2) = F_4' class='latex' />, the third and fourth Fibonacci numbers, and beause <img src='http://s.wordpress.com/latex.php?latex=g%28n%29&#038;bg=ffffff&#038;fg=000000&#038;s=0' alt='g(n)' title='g(n)' class='latex' /> obeys the same recurrence as the Fibonnaci recurrence, we conclude that <img src='http://s.wordpress.com/latex.php?latex=g%28n%29%20%3D%20F_%7Bn%2B2%7D&#038;bg=ffffff&#038;fg=000000&#038;s=0' alt='g(n) = F_{n+2}' title='g(n) = F_{n+2}' class='latex' />. Consequently,</p>
<p><center><img src='http://s.wordpress.com/latex.php?latex=n%28h%29%20%3D%20%5Cfrac%7B%5Cvarphi%5E%7Bh%2B2%7D%20-%20%28-1%2F%5Cvarphi%29%5E%7Bh%2B2%7D%7D%7B%5Csqrt%205%7D%20-%201%20%3D%20%5COmega%28%5Cvarphi%5Eh%29&#038;bg=ffffff&#038;fg=000000&#038;s=0' alt='n(h) = \frac{\varphi^{h+2} - (-1/\varphi)^{h+2}}{\sqrt 5} - 1 = \Omega(\varphi^h)' title='n(h) = \frac{\varphi^{h+2} - (-1/\varphi)^{h+2}}{\sqrt 5} - 1 = \Omega(\varphi^h)' class='latex' /></center></p>
<p>where <img src='http://s.wordpress.com/latex.php?latex=%5Cvarphi%20%3D%20%5Cfrac%7B1%2B%5Csqrt%205%7D%7B2%7D%20%5Capprox%201.618&#038;bg=ffffff&#038;fg=000000&#038;s=0' alt='\varphi = \frac{1+\sqrt 5}{2} \approx 1.618' title='\varphi = \frac{1+\sqrt 5}{2} \approx 1.618' class='latex' /> is the golden ratio. Taking log on both sides of the inequality, we obtain <img src='http://s.wordpress.com/latex.php?latex=h%20%3D%20O%28%5Clog%20n%28h%29%29&#038;bg=ffffff&#038;fg=000000&#038;s=0' alt='h = O(\log n(h))' title='h = O(\log n(h))' class='latex' />. Since <img src='http://s.wordpress.com/latex.php?latex=n%28h%29&#038;bg=ffffff&#038;fg=000000&#038;s=0' alt='n(h)' title='n(h)' class='latex' /> is the minimum possible number of nodes in any AVL tree with height <img src='http://s.wordpress.com/latex.php?latex=h&#038;bg=ffffff&#038;fg=000000&#038;s=0' alt='h' title='h' class='latex' />, we conclude that for <em>any</em> AVL tree on <img src='http://s.wordpress.com/latex.php?latex=n&#038;bg=ffffff&#038;fg=000000&#038;s=0' alt='n' title='n' class='latex' /> nodes with height <img src='http://s.wordpress.com/latex.php?latex=h&#038;bg=ffffff&#038;fg=000000&#038;s=0' alt='h' title='h' class='latex' />, we have <img src='http://s.wordpress.com/latex.php?latex=h%20%3D%20O%28%5Clog%20n%29&#038;bg=ffffff&#038;fg=000000&#038;s=0' alt='h = O(\log n)' title='h = O(\log n)' class='latex' /> as desired.</p>
<h4>1.2. Maintaining the AVL property</h4>
<p><strong>After an insert</strong> (using the same algorithm as in a normal BST), some subtree might be 2 taller than its sibling subtree. We thus will have to readjust the tree to rebalance it. One important property to note is that the only nodes which might become unbalanced after a new node <code>v</code> is inserted are the nodes along the path from <code>v</code> back up to the root of the tree. Because, those are the nodes whose heights might be affected by the insertion.</p>
<p>To keep track of which nodes are balanced or not, we will add an extra field to each node called the <code>balance</code> field, which is defined to be the height of the left subtree minus the height of the right subtree of that node.</p>
<pre class="brush: cpp; title: ; notranslate">
    struct AVLNode {
        // can also use static const instead of enum
        enum { LEFT_HEAVY = 1, BALANCED = 0, RIGHT_HEAVY = -1};
        int balance;
        Key key;
        Value value;
        AVLNode* left;
        AVLNode* right;
        AVLNode* parent;

        AVLNode(const Key&amp; k, const Value&amp; v)
        : key(k), value(v), parent(NULL), left(NULL), right(NULL),
          balance(BALANCED) {}

        std::string to_string() const {
            std::ostringstream oss;
            oss &lt;&lt; key &lt;&lt; &quot;(&quot; &lt;&lt; balance &lt;&lt; &quot;)&quot;;
            return oss.str();
        }
    };
</pre>
<p>We want a node&#8217;s balance to be 1, 0, or -1. After inserting a node <code>v</code> into the tree, let <code>a</code> be the first node on the path from <code>v</code> back to the root that is unbalanced. Note that <code>a</code>&#8216;s balance factor has to be 2 or -2. Let <code>b</code> be the ancestor of <code>v</code> which is the child of <code>a</code>. Note that <code>v</code>&#8216;s parent cannot be unbalanced after <code>v</code>&#8216;s insert, and thus <code>a</code> has to be at the very least <code>v</code>&#8216;s grandparent. Node <code>b</code> might be <code>v</code>&#8216;s parent. </p>
<p>We look for <code>a</code> by moving up the tree from <code>v</code>, readjusting the nodes&#8217; balance fields along the way. If we don&#8217;t find <code>a</code> then we are done, no rebalancing needed. If we do find <code>a</code>, then there are four cases to consider: the right-right case, the right-left case, the left-left case, and the left-right case. </p>
<p>Below is the picture for the right-right case, which should be self-explanatory:</p>
<p><a href="http://cse250.files.wordpress.com/2012/04/avl-rr-case.png"><img src="http://cse250.files.wordpress.com/2012/04/avl-rr-case.png" alt="" title="AVL-RR-case" width="630" height="334" class="aligncenter size-full wp-image-600" /></a></p>
<p>We readjust the tree by doing a <em>left rotation</em> about node <code>a</code> as shown in the picture. For the <em>right-left</em> case, we perform a <em>double rotation</em>: imagine doing a right-rotate about node <code>c</code> first to bring <code>b</code> up, and then a left-rotate about node <code>a</code> to bring <code>b</code> one more step up. Note that the new node can be in either T2 or T3 in the following picture.</p>
<p><a href="http://cse250.files.wordpress.com/2012/04/avl-rl-case.png"><img src="http://cse250.files.wordpress.com/2012/04/avl-rl-case.png" alt="" title="AVL-RL-case" width="630" height="319" class="aligncenter size-full wp-image-604" /></a></p>
<p>The left-left and the left-right cases are symmetric to the above two cases. A very important point to notice is that after doing the rotation (double or single), we no longer have to fix the balance fields of nodes further up the tree! </p>
<blockquote><p>
<strong>Exercise:</strong> argue why after a single or double rotation, all nodes higher up in the tree are balanced.
</p></blockquote>
<p>Here is a simple interface for AVL tree:</p>
<pre class="brush: cpp; title: ; notranslate">
/**
 * *****************************************************************************
 *  AVLTree.h: a simple implementation of the AVL Tree
 *  Author:      Hung Q. Ngo
 * *****************************************************************************
 */
#ifndef AVLTREE_H_
#define AVLTREE_H_

#include &lt;iostream&gt;
#include &lt;sstream&gt;

template &lt;typename Key, typename Value&gt;
class AVLTree {
public:
    AVLTree() : root(NULL) { }

    void  inorder_print()  { inorder_print(root); std::cout &lt;&lt; std::endl; }
    void  preorder_print() { preorder_print(root); std::cout &lt;&lt; std::endl; }
    void  postorder_print() { postorder_print(root); std::cout &lt;&lt; std::endl; }

    bool  insert(Key, Value);
    bool  find(Key key) { return search(root, key) != NULL; }
    const Value&amp; get(Key);
    const Value&amp; minimum();
    const Value&amp; maximum();
    bool  remove(Key);
    void  clear() { clear(root); }

private:
    // The node is similar to a BSTNode; use parent pointer to simplify codes
    // A tree is simply a pointer to a BSTNode, we will assume that variables of
    // type Key are comparable using &lt;, &lt;=, ==, &gt;=, and &gt;
    // we do not allow default keys and values
    struct AVLNode {
        enum { LEFT_HEAVY = 1, BALANCED = 0, RIGHT_HEAVY = -1};
        int balance;
        Key key;
        Value value;
        AVLNode* left;
        AVLNode* right;
        AVLNode* parent;

        AVLNode(const Key&amp; k, const Value&amp; v)
        : key(k), value(v), parent(NULL), left(NULL), right(NULL),
          balance(BALANCED) {}

        std::string to_string() const {
            std::ostringstream oss;
            oss &lt;&lt; key &lt;&lt; &quot;(&quot; &lt;&lt; balance &lt;&lt; &quot;)&quot;;
            return oss.str();
        }
    };

    AVLNode* root;
    AVLNode* successor(AVLNode* node);
    AVLNode* predecessor(AVLNode* node);
    AVLNode* search(AVLNode*, Key);

    void rebalance(AVLNode*);
    void right_rotate(AVLNode*&amp;);
    void left_rotate(AVLNode*&amp;);

    void inorder_print(AVLNode*);
    void preorder_print(AVLNode*);
    void postorder_print(AVLNode*);

    void clear(AVLNode*&amp;);
};

#include &quot;AVLTree.cpp&quot; // only done for template classes

#endif
</pre>
<p>And here is the implementation of the insertion strategy just described.</p>
<pre class="brush: cpp; title: ; notranslate">
/**
 * -----------------------------------------------------------------------------
 *  insert a new key, value pair, return
 *    true if the insertion was successful
 *    false if the key is found already
 * -----------------------------------------------------------------------------
 */
template &lt;typename Key, typename Value&gt;
bool AVLTree&lt;Key, Value&gt;::insert(Key key, Value value) {
    AVLNode* p   = NULL;
    AVLNode* cur = root;
    while (cur != NULL) {
        p = cur;
        if (key &lt; cur-&gt;key)
            cur = cur-&gt;left;
        else if (key &gt; cur-&gt;key)
            cur = cur-&gt;right;
        else
            return false; // key found, no insertion
    }

    // insert new node at a leaf position
    AVLNode* node = new AVLNode(key, value);
    node-&gt;parent = p;
    if (p == NULL) // empty tree to start with
        root = node;
    else if (node-&gt;key &lt; p-&gt;key)
        p-&gt;left = node;
    else
        p-&gt;right = node;

    // readjust balance of all nodes up to the root if necessary
    rebalance(node);
    return true;
}

/**
 * -----------------------------------------------------------------------------
 *  left rotate around node c
 *                       c             b
 *                      / \           / \
 *                     C   b  --&gt;    c   B
 *                        / \       / \
 *                       A   B     C   A
 * adjust parent pointers accordingly
 * -----------------------------------------------------------------------------
 */
template &lt;typename Key, typename Value&gt;
void AVLTree&lt;Key, Value&gt;::left_rotate(AVLNode*&amp; node) {
    if (node == NULL || node-&gt;right == NULL) return;

    AVLNode* c = node;
    AVLNode* b = c-&gt;right;
    AVLNode* p = c-&gt;parent;

    // first, adjust all parent pointers
    b-&gt;parent = p;
    c-&gt;parent = b;
    if (b-&gt;left != NULL) b-&gt;left-&gt;parent = c;

    // make sure c's parent points to b now
    if (p != NULL) {
        if (p-&gt;right == c) p-&gt;right = b;
        else p-&gt;left = b;
    }

    // finally, adjust downward pointers
    c-&gt;right = b-&gt;left;
    b-&gt;left  = c;

    node = b;                // new local root
    if (root == c) root = b; // new root if necessary
}

/**
 * -----------------------------------------------------------------------------
 *  right rotate around node c
 *                       c             b
 *                      / \           /  \
 *                     b   C  --&gt;    A    c
 *                    / \                / \
 *                   A   B              B   C
 * adjust parent pointers accordingly
 * -----------------------------------------------------------------------------
 */
template &lt;typename Key, typename Value&gt;
void AVLTree&lt;Key, Value&gt;::right_rotate(AVLNode*&amp; node) {
    if (node == NULL || node-&gt;left == NULL) return;

    AVLNode* c = node;
    AVLNode* b = c-&gt;left;
    AVLNode* p = c-&gt;parent;

    // first, adjust all parent pointers
    b-&gt;parent = p;
    c-&gt;parent = b;
    if (b-&gt;right != NULL) b-&gt;right-&gt;parent = c;

    // next, make sure c's parent points to b
    if (p != NULL) {    // make sure c's parent points to b now
        if (p-&gt;right == c) p-&gt;right = b;
        else p-&gt;left = b;
    }

    // finally, adjust the downward pointers
    c-&gt;left  = b-&gt;right;
    b-&gt;right = c;

    node = b;                // new local root
    if (root == c) root = b; // new root if necessary
}

/**
 * -----------------------------------------------------------------------------
 *  node points to the root of a sub-tree which just had a height increase
 *  we assume the invariance that node's parent is not unbalanced, which
 *  certainly holds for the first node that got inserted
 *  the 'balance' field of the parent may not be correct and we have to
 *  adjust that too
 * -----------------------------------------------------------------------------
 */
template &lt;typename Key, typename Value&gt;
void AVLTree&lt;Key, Value&gt;::rebalance(AVLNode* node) {
    AVLNode* p = node-&gt;parent;
    if (p == NULL) return;

    // first, recompute 'balance' of the parent; node got a heigh increase
    if (p-&gt;left == node)
        p-&gt;balance++;
    else
        p-&gt;balance--;

    // if there's no grandparent or if the parent is balanced then we're done
    AVLNode* gp = p-&gt;parent; // the grand parent
    if (gp == NULL || p-&gt;balance == AVLNode::BALANCED) return;

    // if we get here then the parent p just got a height increase
    // next, see if the grand parent is unbalanced
    if (node == p-&gt;left) {
        if (p == gp-&gt;left) {
            if (gp-&gt;balance == AVLNode::LEFT_HEAVY) {
                // this is the LL case
                //        gp(+2)          p (0)
                //       /   \           /  \
                //      p(+1) B  --&gt;   node  gp (0)
                //     / \                  / \
                //   node A                A   B
                p-&gt;balance = gp-&gt;balance = AVLNode::BALANCED;
                right_rotate(gp);
                return;
            }
        } else { // p == gp-&gt;right
            if (gp-&gt;balance == AVLNode::RIGHT_HEAVY) { // the RL case
                // this is the RL case
                //        gp(-2)               node(0)
                //       /   \                 /   \
                //      A    p(+1)    --&gt;     gp(x) p(y)
                //           / \              /\   / \
                //         node D            A  B C   D
                //         / \
                //        B   C
                //  computing the new balance is a little trickier, depending on
                //  with of B &amp; C is heavier
                switch (node-&gt;balance) {
                case AVLNode::LEFT_HEAVY:
                    p-&gt;balance  = AVLNode::RIGHT_HEAVY;
                    gp-&gt;balance = AVLNode::BALANCED;
                    break;
                case AVLNode::BALANCED: // only happens if B &amp; C are NULL
                    p-&gt;balance  = AVLNode::BALANCED;
                    gp-&gt;balance = AVLNode::BALANCED;;
                    break;
                case AVLNode::RIGHT_HEAVY:
                    p-&gt;balance  = AVLNode::BALANCED;;
                    gp-&gt;balance = AVLNode::LEFT_HEAVY;
                    break;
                }
                node-&gt;balance = AVLNode::BALANCED;
                right_rotate(p);
                left_rotate(gp);
                return;
            }
        }
    } else { // node == p-&gt;right
        if (p == gp-&gt;right) {
            if (gp-&gt;balance == AVLNode::RIGHT_HEAVY) {
                // this is the RR case
                //        gp(-2)              p(0)
                //       /   \               /  \
                //      A   p(-1)    --&gt;  gp(0) node
                //           / \          / \   / \
                //          B  node      A   B
                p-&gt;balance = gp-&gt;balance = AVLNode::BALANCED;
                left_rotate(gp);
                return;
            }
        } else { // p == gp-&gt;left
            if (gp-&gt;balance == AVLNode::LEFT_HEAVY) {
                // this is the LR case
                //        gp(+2)          node(0)
                //       /   \            /   \
                //     p(-1)  D   --&gt;   p(x)   gp(y)
                //     /  \             /\     / \
                //    A    node        A  B   C   D
                //         / \
                //        B   C
                //  computing the new balance is a little trickier, depending on
                //  with of B &amp; C is heavier
                switch (node-&gt;balance) {
                case AVLNode::LEFT_HEAVY:
                    p-&gt;balance  = AVLNode::BALANCED;
                    gp-&gt;balance = AVLNode::RIGHT_HEAVY;
                    break;
                case AVLNode::BALANCED: // only happens if B &amp; C are NULL
                    p-&gt;balance  = AVLNode::BALANCED;
                    gp-&gt;balance = AVLNode::BALANCED;;
                    break;
                case AVLNode::RIGHT_HEAVY:
                    p-&gt;balance  = AVLNode::LEFT_HEAVY;
                    gp-&gt;balance = AVLNode::BALANCED;;
                    break;
                }
                node-&gt;balance = AVLNode::BALANCED;
                left_rotate(p);
                right_rotate(gp);
                return;
            }
        }
    }

    rebalance(p);
}
</pre>
<p>Insertion as desribed above runs in time O(log n) because it involves one pass down and one pass up the tree&#8217;s height. Also, we use the node structure which has a parent pointer to simplify the code. We do not need parent pointers, but without them we will then probably have to use a stack to move up after an insertion.</p>
<p><strong>Removing a node</strong> from an AVL tree has two steps:</p>
<ul>
<li> The first step is done in the same way as a normal BST. If the node has at most one child then we splice it. Let <code>v</code> be its child (or NULL). If the node has two children, we find its successor (which is the minimum node on the right subtree) and splice the successor, put the successor&#8217;s payload in the node&#8217;s payload. In this case, let <code>v</code> be the successor&#8217;s other child (which could be <code>NULL</code>).
<li> In the second step, we fix the balances of all nodes from <code>v</code> up to the root and perform rotations accordingly. The strategy is exactly the same as that in the insertion case with one key difference: we might have to do more than one single/double rotations, all the way up to the root. In this case, the subtree rooted at <code>v</code> just lost 1 from its height.
<p> Consider, for instance, the case when <code>v</code> is the left child of its parent. We will have to rebalance at <code>v</code>&#8216;s parent if it was already right-leaning. Let <code>u</code> be <code>v</code>&#8216;s sibling. If <code>u</code> is left leaning then we do a double rotation. Otherwise, a single rotation at the parent node will suffice. Then, we repeat the strategy if there is an overal height reduction at the parent node.
</ul>
<blockquote><p>
<strong>Exercise:</strong> complete the <code>AVLTREE::remove()</code> function.
</p></blockquote>
<h3>2. Red-Black Trees</h3>
<p><a href="http://en.wikipedia.org/wiki/Red%E2%80%93black_tree">Red Black trees</a> were <a href="http://www.springerlink.com/content/qh41m2014673513j/">proposed</a> by Rudolf Bayer in 1972, and refined by Leonidas J. Guibas and Robert Sedgewick in 1978. Guibas and Redgewick presented the coloring scheme and the name RB tree sticks. RB trees are found in many practical search structures. C++&#8217;s <code>std::map</code> and <code>std::set</code> are typically implemented with a red-black tree, so are symbol tables in many operating systems and other languages.</p>
<p>One way to describe the intuition behind a RB tree is as follows. In a perfectly balanced tree all the paths from a node to its leaves have the same length. However, this property is way too strong to be maintainable. Hence, we will design a balanced BST by keeping a &#8220;skeleton&#8221; of black nodes which have the aforementioned property of a perfectly balanced tree. At the same time, we cut the tree some slack by allowing some other nodes to be red, positioned at various placed in the tree so that the constraint is looser. However, we cannot give the red nodes too much freedom because they will destroy the balance maintained by the black skeleton. Thus, we will enforce the property that red nodes can not have red children. This way, red nodes are positioned scatteredly throughout the tree giving the &#8220;right&#8221; amount of slack while keeping the tree mostly balanced.</p>
<p>Rigorously, a <em>red-black tree</em> is a BST with the following properties:</p>
<ul>
<li> (<strong>Bicolor property</strong>) All nodes are colored red or black
<li> (<strong>Black root and leaves</strong>) The root and the leaves (the NULL nodes) are colored black
<li> (<strong>Black height property</strong>) For every internal node <code>v</code>, the number of black nodes we encounter on <em>any</em> path from <code>v</code> down to one of its leaves are the same. This number is called the <em>black height</em> of <code>v</code>. Note that the black height of a node does not count the node&#8217;s own color.
<li> (<strong>Black parent property</strong>) A red node must have a black parent. Or, equivalently, every red node must have two black children. This is the property that ensures the sparsity of red nodes.
</ul>
<p>Here is an example of what a RB tree looks like.</p>
<p><a href="http://cse250.files.wordpress.com/2012/04/rbtree.png"><img src="http://cse250.files.wordpress.com/2012/04/rbtree.png" alt="" title="RBTree" width="630" height="399" class="aligncenter size-full wp-image-608" /></a></p>
<h4>2.1. RB trees have logarithmic heights</h4>
<p>Consider any RB tree <code>T</code>. Suppose we lump together every red node with its parent (which must be black); then, we obtain a tree <code>T'</code> which is no longer a binary tree. The tree <code>T'</code> will be a (2,4)-tree (or 2-3-4 tree), where each internal node has 2, 3, or 4 children. If the RB tree shown above is <code>T</code>, then its 2-3-4 counterpart is</p>
<p><a href="http://cse250.files.wordpress.com/2012/04/rb234.png"><img src="http://cse250.files.wordpress.com/2012/04/rb234.png" alt="" title="RB234" width="630" height="278" class="aligncenter size-full wp-image-609" /></a><br />
Let <code>h</code> be the height of <code>T</code> and <code>h'</code> be the height of <code>T'</code>. Also, let <code>n</code> be the number of keys in <code>T</code>. First of all, we claim that the number of black leaves (squares in the pictures) is exactly <code>n+1</code>. This is because the RB tree is a full binary tree and from that we can prove this claim by induction. (Sketch: if the left subtree of the root has <code>a</code> keys and the right subtree has <code>b</code> keys, then there are totally <code>a+b+1</code> keys in the tree and <code>(a+1)+(b+1)</code> leaves by the induction hypothesis.)</p>
<p>Now, due to the 2 to 4 branching factors, the number of leaves varies between <code>2<sup>h'</sup></code> and <code>4<sup>h'</sup></code>: <img src='http://s.wordpress.com/latex.php?latex=2%5E%7Bh%27%7D%20%5Cleq%20n%2B1%20%5Cleq%204%5E%7Bh%27%7D&#038;bg=ffffff&#038;fg=000000&#038;s=0' alt='2^{h&#039;} \leq n+1 \leq 4^{h&#039;}' title='2^{h&#039;} \leq n+1 \leq 4^{h&#039;}' class='latex' />. By the black parent property, the height of <code>T'</code> is at least half the height of <code>T</code>. Hence, </p>
<p><center><img src='http://s.wordpress.com/latex.php?latex=h%20%5Cleq%202h%27%20%5Cleq%202%5Clog_2%28n%2B1%29&#038;bg=ffffff&#038;fg=000000&#038;s=0' alt='h \leq 2h&#039; \leq 2\log_2(n+1)' title='h \leq 2h&#039; \leq 2\log_2(n+1)' class='latex' /></center></p>
<h4>2.2. How to maintain the RB properties</h4>
<p><strong>After an insert</strong>. We will always color the newly inserted node <code>red</code>, unless it is the root in which case we color it black. Call the newly inserted node <code>z</code>.</p>
<p>If <code>z</code> or its parent is black, then there is nothing to do. All properties are still satisfied.</p>
<p>Now, suppose <code>z</code>&#8216;s parent is red. Then, we have the <em>double red</em> problem. We fix this problem by considering the following cases.</p>
<ul>
<li> If <code>z</code>&#8216;s uncle is red, then we recolor <code>z</code>&#8216;s parent and uncle black, grandparent red (it had to be black before), and consider the grandparent the new <code>z</code>. We potentially have a new double red problem but it is now higher up in the tree. If <code>z</code>&#8216;s grand parent is the root then we color it black and we are done. The following picture illustrates this case.
<p><a href="http://cse250.files.wordpress.com/2012/04/zuncleisred.png"><img src="http://cse250.files.wordpress.com/2012/04/zuncleisred.png" alt="" title="zuncleisred" width="630" height="357" class="aligncenter size-full wp-image-613" /></a></p>
<li> If <code>z</code>&#8216;s uncle is black then there are two subcases which can be resolved with either a single rotation or a double rotation as seen in the following pictures.
<p><a href="http://cse250.files.wordpress.com/2012/04/zuncleblack1.png"><img src="http://cse250.files.wordpress.com/2012/04/zuncleblack1.png" alt="" title="zuncleblack1" width="630" height="317" class="aligncenter size-full wp-image-614" /></a></p>
<p><a href="http://cse250.files.wordpress.com/2012/04/zuncleblack2.png"><img src="http://cse250.files.wordpress.com/2012/04/zuncleblack2.png" alt="" title="zuncleblack2" width="630" height="308" class="aligncenter size-full wp-image-616" /></a></p>
</ul>
<p><strong>After a delete</strong>. When we delete a node from a BST, we either splice it or splice its successor. Let <code>z</code> be the children of the node that got spliced. If we spliced a red node, then we&#8217;re done; there is nothing to fix. Suppose we spliced a black node. In this case, we will violate the black height property of all ancestors of <code>z</code> (except for the trivial case when <code>z</code> is the root or when <code>z</code>&#8216;s parent is the root).</p>
<p>Conceptually, if <code>z</code> was allowed to have &#8220;double blackness&#8221; then the black height property is not violated. Note that <code>z</code>&#8216;s sibling cannot be a leaf node; thus, the sibling must have two children. We consider three cases as follows.</p>
<ul>
<li> <code>z</code>&#8216;s sibling is black with a red child. In this case, we do a single or double rotation and color that child black. In essence we give that red child one of <code>z</code>&#8216;s &#8220;blackness&#8221;. The fact that <code>z</code> is double black also indicates that the subtree rooted at <code>z</code> is a little short on height; and, the fact that the sibling&#8217;s side has a red node means that side has extra height to spare. Overall, a rotation toward <code>z</code>&#8216;s side makes sense. The following pictures illustrate the two sub-cases:
<p><a href="http://cse250.files.wordpress.com/2012/04/zsiblingblackredchild.png"><img src="http://cse250.files.wordpress.com/2012/04/zsiblingblackredchild.png" alt="" title="zsiblingblackredchild" width="630" height="290" class="aligncenter size-full wp-image-617" /></a></p>
<p><a href="http://cse250.files.wordpress.com/2012/04/zsiblingblackredchild2.png"><img src="http://cse250.files.wordpress.com/2012/04/zsiblingblackredchild2.png" alt="" title="zsiblingblackredchild2" width="630" height="294" class="aligncenter size-full wp-image-618" /></a></p>
<li> <code>z</code>&#8216;s sibling is black with both black children <em>and</em> the parent is red. In this case, we color the sibling red, parent black, and we are done:
<p><a href="http://cse250.files.wordpress.com/2012/04/zsiblingblackparentred.png"><img src="http://cse250.files.wordpress.com/2012/04/zsiblingblackparentred.png" alt="" title="zsiblingblackparentred" width="630" height="247" class="aligncenter size-full wp-image-619" /></a></p>
<li> <code>z</code>&#8216;s sibling is black with both black children <em>and</em> the parent is black. In this case, we color the sibling red, parent double black, and move the double black problem up the tree.
<p><a href="http://cse250.files.wordpress.com/2012/04/zsiblingblackparentblack.png"><img src="http://cse250.files.wordpress.com/2012/04/zsiblingblackparentblack.png" alt="" title="zsiblingblackparentblack" width="630" height="247" class="aligncenter size-full wp-image-620" /></a></p>
<li> Finally, if <code>z</code>&#8216;s sibling is red we perform a single rotation, give the sibling the parent&#8217;s color, and the parent red color. As <code>z</code>&#8216;s new sibling is black, we are back to one of the previous cases.
<p><a href="http://cse250.files.wordpress.com/2012/04/zsiblingred1.png"><img src="http://cse250.files.wordpress.com/2012/04/zsiblingred1.png" alt="" title="zsiblingred" width="630" height="286" class="aligncenter size-full wp-image-640" /></a></p>
</ul>
<h3>3. (2,4)-Trees</h3>
<p>A (2,4)-tree, also called a <a href="http://en.wikipedia.org/wiki/2-3-4_tree">2-3-4 tree</a> was invented by Rodolf Bayer in 1972. It is a special case of B-trees and multiway search trees. So let&#8217;s talk about a multiway search tree first. </p>
<p>In a multiway search tree, nodes no longer are restricted to having 2 children and holding one key. Nodes can hold multiple keys. A <em>d-node</em> is a node that holds <code>d-1</code> keys and have <code>d</code> children. Let <code>K<sub>1</sub> &le; K<sub>2</sub> &le; ...  &le; K<sub>d-1</sub></code> be the keys stored at this node. And, let <code>v<sub>1</sub></code>, <code>v<sub>2</sub></code> &#8230;  <code>v<sub>d</sub></code> be the <code>d</code> children pointers. Then, in a multiway search tree, for every <code>d-node</code>, it must hold that the keys of the <code>v<sub>i</sub></code> subtree is in between <code>K<sub>i-1</sub></code> and <code>K<sub>i</sub></code> as shown in the following picture. (We implicitly understand that <code>K<sub>0</sub></code> is minus infinity and <code>K<sub>d</sub></code> is plus infinity.) </p>
<p><a href="http://cse250.files.wordpress.com/2012/04/d-node.png"><img src="http://cse250.files.wordpress.com/2012/04/d-node.png" alt="" title="d-node" width="630" height="318" class="aligncenter size-full wp-image-627" /></a></p>
<p>Here&#8217;s an example of a multiway search tree.</p>
<p><a href="http://cse250.files.wordpress.com/2012/04/mway.png"><img src="http://cse250.files.wordpress.com/2012/04/mway.png" alt="" title="mway" width="630" height="243" class="aligncenter size-full wp-image-626" /></a></p>
<p>Searching in a multiway search tree is straightforward: to search for key <code>K</code>, we find the index <code>i</code> such that <code>K<sub>i-1</sub> &lt; K &lt; K<sub>i</sub></code> and follow link <code>v<sub>i</sub></code>. </p>
<blockquote><p>
<strong>Exercise:</strong> Similarly, you should think of the algorithms for finding the maximum, minimum, successor, and predecessor.
</p></blockquote>
<blockquote><p>
<strong>Exercise:</strong> Does a pre/in/post-order traversal of a multiway search tree make sense? How about a levelorder traversal? How do you write codes for a levelorder traversal of a multiway search tree?
</p></blockquote>
<p>A <em>(2,4)-tree</em> is a multiway search tree with two additional properties:</p>
<ul>
<li><strong>Size property:</strong> all internal nodes in the tree are 2-, 3-, or 4-nodes. In particular, every internal node holds 1, 2, or 3 keys.
<li><strong>Depth property:</strong> every leaf of a (2,4)-tree are at the same depth, called the depth of the tree.
</ul>
<p>Here is a sample (2,4)-tree:</p>
<p><a href="http://cse250.files.wordpress.com/2012/04/24-tree.png"><img src="http://cse250.files.wordpress.com/2012/04/24-tree.png" alt="" title="24-tree" width="630" height="215" class="aligncenter size-full wp-image-628" /></a></p>
<h4>3.1. A (2,4)-tree has logarithmic height</h4>
<p>First, we show that the number of leaves of a (2,4)-tree is precisely <code>n+1</code> where <code>n</code> is the number of keys stored in the tree. This holds for any &#8220;branching trees&#8221;, which are trees in which every internal node has at least 2 children. So, we prove this fact for branching trees. The proof is by induction on the height of the tree.</p>
<p>If the tree has height 0 then the root is a leaf which stores no key.  If the tree has height 1 then this is certainly the case because when the root is a <code>d-node</code> it has <code>d</code> children (which are leaves) and stores <code>d-1</code> keys.  If the tree has height at least 2, again suppose the root is a <code>d-node</code>. Let <img src='http://s.wordpress.com/latex.php?latex=n_1%2C%20%5Ccdots%2C%20n_d&#038;bg=ffffff&#038;fg=000000&#038;s=0' alt='n_1, \cdots, n_d' title='n_1, \cdots, n_d' class='latex' /> be the number of keys stored in the <code>d</code> subtrees of the root. Since all sub-trees of the root are also branching trees, by the induction hypothesis the total number of leaves is <img src='http://s.wordpress.com/latex.php?latex=%28n_1%2B1%29%2B%28n_2%2B1%29%2B%5Ccdots%2B%28n_d%2B1%29%20%3D%20%5Csum_%7Bi%3D1%7D%5Ed%20n_i%2Bd%20%3D%20n%2B1&#038;bg=ffffff&#038;fg=000000&#038;s=0' alt='(n_1+1)+(n_2+1)+\cdots+(n_d+1) = \sum_{i=1}^d n_i+d = n+1' title='(n_1+1)+(n_2+1)+\cdots+(n_d+1) = \sum_{i=1}^d n_i+d = n+1' class='latex' /> where <img src='http://s.wordpress.com/latex.php?latex=n&#038;bg=ffffff&#038;fg=000000&#038;s=0' alt='n' title='n' class='latex' /> is the total number of keys in the entire tree. Here, we used the fact that the root stores <img src='http://s.wordpress.com/latex.php?latex=d-1&#038;bg=ffffff&#038;fg=000000&#038;s=0' alt='d-1' title='d-1' class='latex' /> keys.</p>
<p>Next, let <img src='http://s.wordpress.com/latex.php?latex=h&#038;bg=ffffff&#038;fg=000000&#038;s=0' alt='h' title='h' class='latex' /> be the height of a (2,4)-tree, by the same reasoning as in the RB tree case we have <img src='http://s.wordpress.com/latex.php?latex=2%5Eh%20%5Cleq%20n%2B1&#038;bg=ffffff&#038;fg=000000&#038;s=0' alt='2^h \leq n+1' title='2^h \leq n+1' class='latex' /> which implies <img src='http://s.wordpress.com/latex.php?latex=h%20%5Cleq%20%5Clog_2%28n%2B1%29&#038;bg=ffffff&#038;fg=000000&#038;s=0' alt='h \leq \log_2(n+1)' title='h \leq \log_2(n+1)' class='latex' />.</p>
<h4>3.2. How to maintain the (2,4)-tree properties</h4>
<p>We will assume that we do not store duplicate keys.</p>
<p><strong>After an insert</strong>. We insert a new key into a (2,4)-tree in the following way. We search for it in the tree. If the new key is found then we do nothing because duplicate keys are not allowed. If the new key is not found, then we will end up at a leaf node. Let <code>v</code> be the parent of that leaf node. We insert the key into the correct relative position in that node <code>v</code>.</p>
<p>Prior to the insertion of the new key, if <code>v</code> was a 2-node or a 3-node, then we are OK because after the insertion of a new key <code>v</code> is at worst a 4-node. However, if <code>v</code> was already a 4-node then we have the <em>overflow</em> problem we need to resolve. The solution is intuitive: we split the node into two, bring a middle key up one level as shown in the following picture:</p>
<p><a href="http://cse250.files.wordpress.com/2012/04/insertoverflow.png"><img src="http://cse250.files.wordpress.com/2012/04/insertoverflow.png" alt="" title="insertoverflow" width="630" height="332" class="aligncenter size-full wp-image-629" /></a></p>
<p>In the worst-case, the updates are propagated up to the root and we have an increase in tree height</p>
<p><a href="http://cse250.files.wordpress.com/2012/04/rootupgrade.png"><img src="http://cse250.files.wordpress.com/2012/04/rootupgrade.png" alt="" title="rootupgrade" width="630" height="233" class="aligncenter size-full wp-image-630" /></a></p>
<p>The run time is proportional to the height of the tree which is logarithmic, and both the size property and the depth property are still satisfied.</p>
<p><strong>After a delete</strong>. To delete a key from a (2,4)-tree, we use the strategy similar to that of the BST case. If the key is at the lowest level, we simply remove it. If the key is at some node higher up, we find the successor key which is the left most key on the right subtree (of the key to be removed), replace the key with its successor, and remove the successor.</p>
<p>The problem occurs when we try to remove a 2-node (which is at the lowest level, next to the leaves): the problem is called an <em>underflow</em> problem. To solve the underflow problem, we consider the following cases.</p>
<ul>
<li> If the node to be removed has an adjacent sibling which is a 3-node or a 4-node, we perform a &#8220;transfer&#8221; as shown in the following picture, which hopefuly is self-explanatory:
<p> <a href="http://cse250.files.wordpress.com/2012/04/transfer.png"><img src="http://cse250.files.wordpress.com/2012/04/transfer.png" alt="" title="transfer" width="630" height="380" class="aligncenter size-full wp-image-633" /></a></p>
<li> If the node to be removed has only one adjacent sibling which is a 2-node, or has 2 adjacent siblings both of which are 2-nodes, then we perform a fusion as shown in the following picture:
<p><a href="http://cse250.files.wordpress.com/2012/04/fusion11.png"><img src="http://cse250.files.wordpress.com/2012/04/fusion11.png" alt="" title="fusion1" width="630" height="354" class="aligncenter size-full wp-image-657" /></a></p>
<p> The fusion might cause an underflow at the parent node, in which case we repeat the process:</p>
<p><a href="http://cse250.files.wordpress.com/2012/04/fusion2.png"><img src="http://cse250.files.wordpress.com/2012/04/fusion2.png" alt="" title="fusion2" width="630" height="199" class="aligncenter size-full wp-image-635" /></a></p>
<p> The fusion may propagate all the way up to the root, in which case we have a height reduction of the tree.
</ul>
<h3>4. Splay trees</h3>
<p><a href="http://en.wikipedia.org/wiki/Splay_tree">Splay trees</a> are a self-adjusting binary search trees invented by Dan Sleator and Bob Tarjan in 1985. It does not require any additional field in each node such as color or balance. All operations have amortized cost <code>O(log n)</code>. In addition, frequently accessed nodes are closer to the root. </p>
<p>In a splay tree, insertion,  deletion,  and search are done exactly in the same way as in a normal BST, with one additional <em>splay(<code>c</code>)</em> step, where <code>c</code> is a node to be defined later.</p>
<h4>4.1. Splaying</h4>
<p>To &#8220;splay&#8221; a node <code>c</code>, we perform <code>O(height of tree)</code> <em>baby steps</em>. Each of these baby steps is either a <code>zig-zig</code>, <code>zig-zag</code>, or <code>zig</code> defined as follows.</p>
<ul>
<li><code>zig-zig</code> is performed when <code>c</code> has a grandparent and its side (left or right) with respect to its parent is the same as its parent&#8217;s side with respect to its grandparent.
<p><a href="http://cse250.files.wordpress.com/2012/04/zigzig2.png"><img src="http://cse250.files.wordpress.com/2012/04/zigzig2.png?w=300" alt="" title="zigzig" width="300" height="174" class="aligncenter size-medium wp-image-662" /></a></p>
<li><code>zig-zag</code> is performed when <code>c</code> has a grandparent and it is on a different side of its parent than its parent is with respect to the grandparent.
<p><a href="http://cse250.files.wordpress.com/2012/04/zigzag2.png"><img src="http://cse250.files.wordpress.com/2012/04/zigzag2.png?w=300" alt="" title="zigzag" width="300" height="176" class="aligncenter size-medium wp-image-663" /></a></p>
<li><code>zig</code> is performed when <code>c</code>&#8216;s parent is the root.
<p><a href="http://cse250.files.wordpress.com/2012/04/zig3.png"><img src="http://cse250.files.wordpress.com/2012/04/zig3.png?w=300" alt="" title="zig" width="300" height="161" class="aligncenter size-medium wp-image-670" /></a>
</ul>
<p>To splay a node <code>c</code>, we repeatedly perform the baby steps until the node is floated up all the way to the root. The cost of splaying is proportional to the height of the splayed node.</p>
<h4>4.2. Which node to splay and why it works</h4>
<p>After a search, we splay the node whose key is found; or, if the key is not found then we splay the last non-NULL  node seen in the search.</p>
<p>After an insert, we splay the newly inserted node.</p>
<p>After a delete, we splay the child of the spliced node.</p>
<p>The main question is, why does this work, even just on average? It is conceivable that the tree will become so unbalanced that its height is <img src='http://s.wordpress.com/latex.php?latex=%5COmega%28n%29&#038;bg=ffffff&#038;fg=000000&#038;s=0' alt='\Omega(n)' title='\Omega(n)' class='latex' /> and thus a search might take linear time. How can we then say that on average an operation takes logarithmic time? Let&#8217;s actually construct a sequence of insertions and such that a later search takes linear time. Suppose we insert the keys 1, 2, &#8230;, n in that order. After each insertion, the key ends up on the right node of the root, and a zig operation brings it up top. </p>
<pre>
Insert 1:
1
Insert 2:
1                  2
 \    -- zig --&gt;  /
  2              1
Insert 3:
  2                3
 / \  -- zig --&gt;  /
1   3            2
                /
               1
and so on
</pre>
<p>Now, after <code>n</code> insertions as described, when we search for key <code>1</code>, we will have to take about <code>n</code> steps to get down to the left-most branch, and then about <code>n/2</code> splaying baby steps to bring <code>1</code> up all the way to the root. Overall, we spent <code>cn</code> units of time where <code>c</code> is some constant. What is going for us is that the price we paid for all of the previous insertions were also some constants. And thus, when we distribute the total cost over <code>n+1</code> operations we will still have a small cost <em>per</em> operation. </p>
<p>For example, if each of the inserts took <code>d</code> units of times, then the total price we pay per operation is <img src='http://s.wordpress.com/latex.php?latex=%28nd%20%2B%20nc%29%2Fn%20%3D%20d%2Bc&#038;bg=ffffff&#038;fg=000000&#038;s=0' alt='(nd + nc)/n = d+c' title='(nd + nc)/n = d+c' class='latex' /> which is a constant! We will transfer this intuition into an (amortized) analysis by giving each operation a budget of <img src='http://s.wordpress.com/latex.php?latex=O%28%5Clog%20n%29&#038;bg=ffffff&#038;fg=000000&#038;s=0' alt='O(\log n)' title='O(\log n)' class='latex' /> &#8220;dollars.&#8221; Then, we show that the money left in the accounts of all the nodes plus the <img src='http://s.wordpress.com/latex.php?latex=O%28%5Clog%20n%29&#038;bg=ffffff&#038;fg=000000&#038;s=0' alt='O(\log n)' title='O(\log n)' class='latex' /> new dollars are always sufficient to pay for any of the operations. If an operation costs less money, we will deposit the residual amount to the accounts to pay for future and potentially more expensive operations. </p>
<h4>4.3. Analysis</h4>
<p>Define the &#8220;size&#8221; of a node <code>v</code>, denoted by <code>n(v)</code>, in a splay tree to be the number of keys in its subtree. And, call the &#8220;rank&#8221; of a node, denoted by <code>r(v)</code>, the value <code>log<sub>2</sub>(2n(v)+1)</code>. Note that the ranks and the sizes will change over time.</p>
<p>Let P be an operation to be performed: search, insert, or delete. Let <code>cost(P)</code> denote the cost of performing P. Our strategy is to make a &#8220;deposit&#8221; <code>D(P)</code> (in &#8220;miliseconds&#8221;, or &#8220;dollars&#8221;) for operation P in such away that the deposit plus what ever amount of &#8220;money&#8221; we still have in the tree is sufficient to pay for the cost of the operation. Our ultimate objective is to prove that</p>
<blockquote><p>
If each operation P has a deposit of <code>D(P)  = c*log(n)</code> dollars, then the splay tree &#8220;bank&#8221; will always have sufficient fund to pay for all operations. In particular, the amortized cost of search, insert, and delete in a splay tree is <code>O(log n)</code>
</p></blockquote>
<p>The splay tree bank is organized as follows. The bank maintains a strict accounting policy:</p>
<blockquote><p>
<strong>The invariant</strong>: Every node <code>v</code> in the tree will have an account that has <img src='http://s.wordpress.com/latex.php?latex=r%28v%29%20%3D%20%5Clog_2%282n%28v%29%2B1%29&#038;bg=ffffff&#038;fg=000000&#038;s=0' alt='r(v) = \log_2(2n(v)+1)' title='r(v) = \log_2(2n(v)+1)' class='latex' /> dollars in it.
</p></blockquote>
<p>We will make sure that each operation P on the tree deposits an amount <code>D(P)</code> sufficient for the invariant to hold. The invariant certainly holds when the tree is empty, i.e. when it has only 1 NULL node whose rank <code>r(v) = 0</code>.</p>
<p>Let <code>r(T)</code> denote the total amount of money the bank <code>T</code> (i.e. a splay tree) possesses, called the banking reserve:</p>
<p><center><img src='http://s.wordpress.com/latex.php?latex=r%28T%29%20%3D%20%5Csum_%7Bv%20%5Cin%20T%7D%20r%28v%29&#038;bg=ffffff&#038;fg=000000&#038;s=0' alt='r(T) = \sum_{v \in T} r(v)' title='r(T) = \sum_{v \in T} r(v)' class='latex' /></center></p>
<p>In order to maintain the invariant after an operation P is performed on the tree, we must make sure that the deposit <code>D(P)</code> is sufficiently large so that</p>
<p><center><img src='http://s.wordpress.com/latex.php?latex=r%28T%29%2BD%28P%29-%5Ctext%7Bcost%7D%28P%29%20%5Cgeq%20r%28T%27%29&#038;bg=ffffff&#038;fg=000000&#038;s=0' alt='r(T)+D(P)-\text{cost}(P) \geq r(T&#039;)' title='r(T)+D(P)-\text{cost}(P) \geq r(T&#039;)' class='latex' /></center></p>
<p>where <code>T'</code> is the tree resulted from performing operation <code>P</code> on <code>T</code>. In other words, we want the variation in bank reserves to be small relative to the newly deposited amount:</p>
<p><center><img src='http://s.wordpress.com/latex.php?latex=r%28T%27%29%20-%20r%28T%29%20%5Cleq%20D%28P%29-%5Ctext%7Bcost%7D%28P%29&#038;bg=ffffff&#038;fg=000000&#038;s=0' alt='r(T&#039;) - r(T) \leq D(P)-\text{cost}(P)' title='r(T&#039;) - r(T) \leq D(P)-\text{cost}(P)' class='latex' /></center></p>
<p>Thus, in order to determine how much <code>D(P)</code> should be, we need to determine the variation <img src='http://s.wordpress.com/latex.php?latex=r%28T%27%29%20-%20r%28T%29&#038;bg=ffffff&#038;fg=000000&#038;s=0' alt='r(T&#039;) - r(T)' title='r(T&#039;) - r(T)' class='latex' /> after each pair of operations: P = insert + splay, P = delete + splay, P = search + splay. For example, an insert changes the tree from <code>T</code> to <code>T<sub>in</sub></code>, and then the splaying changes the tree from <code>T<sub>in</sub></code> to <code>T'</code>. And, because</p>
<p><center><img src='http://s.wordpress.com/latex.php?latex=r%28T%27%29%20-%20r%28T%29%20%3D%20%28r%28T%27%29%20-%20r%28T_%7B%5Ctext%7Bin%7D%7D%29%29%20%2B%20%28r%28T_%7B%5Ctext%7Bin%7D%7D%29%20-%20r%28T%29%29&#038;bg=ffffff&#038;fg=000000&#038;s=0' alt='r(T&#039;) - r(T) = (r(T&#039;) - r(T_{\text{in}})) + (r(T_{\text{in}}) - r(T))' title='r(T&#039;) - r(T) = (r(T&#039;) - r(T_{\text{in}})) + (r(T_{\text{in}}) - r(T))' class='latex' /></center></p>
<p>we can assess the variations separately instead of assessing the variations for each pair insert + splay, delete + splay, and search + splay.</p>
<p>In what follows, let <code>T'</code> be the tree after an operation was performed (search, insert, delete, splay, or baby step), and <code>T</code> be the tree before the operation.</p>
<p><strong>After a delete</strong>: <code>r(T')</code> can only be smaller than <code>r(T)</code> because the ranks of all nodes from the deleted node up to the root are reduced. Hence, in this case <code>r(T') - r(T) &le; 0</code>.</p>
<p><strong>After a search</strong>: <code>r(T')-r(T)=0</code>.</p>
<p><strong>After an insert</strong>: suppose we just inserted node <img src='http://s.wordpress.com/latex.php?latex=v_0&#038;bg=ffffff&#038;fg=000000&#038;s=0' alt='v_0' title='v_0' class='latex' /> at depth <img src='http://s.wordpress.com/latex.php?latex=d&#038;bg=ffffff&#038;fg=000000&#038;s=0' alt='d' title='d' class='latex' />, and <img src='http://s.wordpress.com/latex.php?latex=v_0%2C%20v_1%2C%20%5Ccdots%2C%20v_d&#038;bg=ffffff&#038;fg=000000&#038;s=0' alt='v_0, v_1, \cdots, v_d' title='v_0, v_1, \cdots, v_d' class='latex' /> is the path from <img src='http://s.wordpress.com/latex.php?latex=v_0&#038;bg=ffffff&#038;fg=000000&#038;s=0' alt='v_0' title='v_0' class='latex' /> up to the root of the tree. Then, the difference in bank reserve amounts is</p>
<p><center><img src='http://s.wordpress.com/latex.php?latex=r%28T%27%29%20-%20r%28T%29%20%3D%20%5Csum_%7Bi%3D0%7D%5Ed%20r%27%28v_0%29%20-%20%5Csum_%7Bj%3D1%7D%5Ed%20r%28v_j%29&#038;bg=ffffff&#038;fg=000000&#038;s=0' alt='r(T&#039;) - r(T) = \sum_{i=0}^d r&#039;(v_0) - \sum_{j=1}^d r(v_j)' title='r(T&#039;) - r(T) = \sum_{i=0}^d r&#039;(v_0) - \sum_{j=1}^d r(v_j)' class='latex' /></center></p>
<p>where <img src='http://s.wordpress.com/latex.php?latex=r%27%28v_i%29&#038;bg=ffffff&#038;fg=000000&#038;s=0' alt='r&#039;(v_i)' title='r&#039;(v_i)' class='latex' /> is the rank of node <img src='http://s.wordpress.com/latex.php?latex=v_i&#038;bg=ffffff&#038;fg=000000&#038;s=0' alt='v_i' title='v_i' class='latex' /> after the insertion. Also, let <img src='http://s.wordpress.com/latex.php?latex=n%27%28v_i%29&#038;bg=ffffff&#038;fg=000000&#038;s=0' alt='n&#039;(v_i)' title='n&#039;(v_i)' class='latex' /> be the size of node <img src='http://s.wordpress.com/latex.php?latex=v_i&#038;bg=ffffff&#038;fg=000000&#038;s=0' alt='v_i' title='v_i' class='latex' /> after the insertion. Then, <img src='http://s.wordpress.com/latex.php?latex=n%27%28v_0%29%20%5Cleq%20n%28v_1%29&#038;bg=ffffff&#038;fg=000000&#038;s=0' alt='n&#039;(v_0) \leq n(v_1)' title='n&#039;(v_0) \leq n(v_1)' class='latex' />, <img src='http://s.wordpress.com/latex.php?latex=n%27%28v_1%29%20%5Cleq%20n%28v_2%29&#038;bg=ffffff&#038;fg=000000&#038;s=0' alt='n&#039;(v_1) \leq n(v_2)' title='n&#039;(v_1) \leq n(v_2)' class='latex' />, and so on, up to <img src='http://s.wordpress.com/latex.php?latex=n%27%28v_%7Bd-1%7D%29%20%5Cleq%20n%28v_d%29&#038;bg=ffffff&#038;fg=000000&#038;s=0' alt='n&#039;(v_{d-1}) \leq n(v_d)' title='n&#039;(v_{d-1}) \leq n(v_d)' class='latex' />. Thus, <img src='http://s.wordpress.com/latex.php?latex=r%27%28v_i%29%20%5Cleq%20r%28v_%7Bi%2B1%7D%29&#038;bg=ffffff&#038;fg=000000&#038;s=0' alt='r&#039;(v_i) \leq r(v_{i+1})' title='r&#039;(v_i) \leq r(v_{i+1})' class='latex' /> for every <img src='http://s.wordpress.com/latex.php?latex=i%20%5Cin%20%5C%7B0%2C%201%2C%20%5Cdots%2C%20d-1%5C%7D&#038;bg=ffffff&#038;fg=000000&#038;s=0' alt='i \in \{0, 1, \dots, d-1\}' title='i \in \{0, 1, \dots, d-1\}' class='latex' />. Consequently,</p>
<p><center><img src='http://s.wordpress.com/latex.php?latex=r%28T%27%29-r%28T%29%20%5Cleq%20r%27%28v_d%29%20%5Cleq%20%5Clog_2%282n%2B1%29&#038;bg=ffffff&#038;fg=000000&#038;s=0' alt='r(T&#039;)-r(T) \leq r&#039;(v_d) \leq \log_2(2n+1)' title='r(T&#039;)-r(T) \leq r&#039;(v_d) \leq \log_2(2n+1)' class='latex' /></center></p>
<p><strong>After a splay</strong>: since a splay operation consists of many baby steps, let us estimate the banking reserve difference after each baby step. Please refer to the pictures above in the following derivation. We will use the fact that, for any two real numbers <img src='http://s.wordpress.com/latex.php?latex=a%2C%20b%3E0&#038;bg=ffffff&#038;fg=000000&#038;s=0' alt='a, b&gt;0' title='a, b&gt;0' class='latex' />, </p>
<p><center><img src='http://s.wordpress.com/latex.php?latex=%5Clog_2%20a%20%2B%20%5Clog_2%20b%20%5Cleq%202%5Clog_2%28a%2Bb%29-2&#038;bg=ffffff&#038;fg=000000&#038;s=0' alt='\log_2 a + \log_2 b \leq 2\log_2(a+b)-2' title='\log_2 a + \log_2 b \leq 2\log_2(a+b)-2' class='latex' /> (*)</center></p>
<p>Because, the inequality is equivalent to <img src='http://s.wordpress.com/latex.php?latex=ab%20%5Cleq%20%28a%2Bb%29%5E2%2F4&#038;bg=ffffff&#038;fg=000000&#038;s=0' alt='ab \leq (a+b)^2/4' title='ab \leq (a+b)^2/4' class='latex' /> which is equivalent to <img src='http://s.wordpress.com/latex.php?latex=%28a-b%29%5E2%5Cgeq%200&#038;bg=ffffff&#038;fg=000000&#038;s=0' alt='(a-b)^2\geq 0' title='(a-b)^2\geq 0' class='latex' />.</p>
<ul>
<li><strong>zig-zig</strong>: after zig-ziging node <code>c</code> up two levels, from inequality (*) we can see that <img src='http://s.wordpress.com/latex.php?latex=r%28c%29%2Br%27%28y%29%20%5Cleq%202r%27%28c%29-2&#038;bg=ffffff&#038;fg=000000&#038;s=0' alt='r(c)+r&#039;(y) \leq 2r&#039;(c)-2' title='r(c)+r&#039;(y) \leq 2r&#039;(c)-2' class='latex' />. The banking reserve difference can then be bounded by:
<p><center><img src='http://s.wordpress.com/latex.php?latex=%5Cbegin%7Barray%7D%7Brcl%7Dr%28T%27%29-r%28T%29%26%3D%26r%27%28c%29%2Br%27%28x%29%2Br%27%28y%29-r%28c%29-r%28x%29-r%28y%29%5C%5C%26%3D%26r%27%28x%29%2Br%27%28y%29-r%28c%29-r%28x%29%5C%5C%26%5Cleq%262r%27%28c%29-2r%28c%29-2%2Br%27%28x%29-r%28x%29%5C%5C%26%5Cleq%263%28r%27%28c%29-r%28c%29%29-2%5Cend%7Barray%7D&#038;bg=ffffff&#038;fg=000000&#038;s=0' alt='\begin{array}{rcl}r(T&#039;)-r(T)&amp;=&amp;r&#039;(c)+r&#039;(x)+r&#039;(y)-r(c)-r(x)-r(y)\\&amp;=&amp;r&#039;(x)+r&#039;(y)-r(c)-r(x)\\&amp;\leq&amp;2r&#039;(c)-2r(c)-2+r&#039;(x)-r(x)\\&amp;\leq&amp;3(r&#039;(c)-r(c))-2\end{array}' title='\begin{array}{rcl}r(T&#039;)-r(T)&amp;=&amp;r&#039;(c)+r&#039;(x)+r&#039;(y)-r(c)-r(x)-r(y)\\&amp;=&amp;r&#039;(x)+r&#039;(y)-r(c)-r(x)\\&amp;\leq&amp;2r&#039;(c)-2r(c)-2+r&#039;(x)-r(x)\\&amp;\leq&amp;3(r&#039;(c)-r(c))-2\end{array}' class='latex' /></center></p>
<p>The last inequality follows from the fact that <img src='http://s.wordpress.com/latex.php?latex=r%27%28x%29%20%5Cleq%20r%27%28c%29&#038;bg=ffffff&#038;fg=000000&#038;s=0' alt='r&#039;(x) \leq r&#039;(c)' title='r&#039;(x) \leq r&#039;(c)' class='latex' /> and <img src='http://s.wordpress.com/latex.php?latex=r%28x%29%20%5Cgeq%20r%28c%29&#038;bg=ffffff&#038;fg=000000&#038;s=0' alt='r(x) \geq r(c)' title='r(x) \geq r(c)' class='latex' />.</p>
<li><strong>zig-zag</strong>: after zig-zaging node <code>c</code>, from inequality (*) we know <img src='http://s.wordpress.com/latex.php?latex=r%27%28x%29%2Br%27%28y%29%20%5Cleq%202r%27%28c%29-2&#038;bg=ffffff&#038;fg=000000&#038;s=0' alt='r&#039;(x)+r&#039;(y) \leq 2r&#039;(c)-2' title='r&#039;(x)+r&#039;(y) \leq 2r&#039;(c)-2' class='latex' />. Thus, the difference can be bounded by
<p><center><img src='http://s.wordpress.com/latex.php?latex=%5Cbegin%7Barray%7D%7Brcl%7Dr%28T%27%29-r%28T%29%26%3D%26r%27%28c%29%2Br%27%28x%29%2Br%27%28y%29-r%28c%29-r%28x%29-r%28y%29%5C%5C%26%3D%26r%27%28x%29%2Br%27%28y%29-r%28c%29-r%28x%29%5C%5C%26%5Cleq%262r%27%28c%29-2-r%28x%29-r%28c%29%5C%5C%26%5Cleq%262%28r%27%28c%29-r%28c%29%29-2%5C%5C%26%5Cleq%263%28r%27%28c%29-r%28c%29%29-2%5Cend%7Barray%7D&#038;bg=ffffff&#038;fg=000000&#038;s=0' alt='\begin{array}{rcl}r(T&#039;)-r(T)&amp;=&amp;r&#039;(c)+r&#039;(x)+r&#039;(y)-r(c)-r(x)-r(y)\\&amp;=&amp;r&#039;(x)+r&#039;(y)-r(c)-r(x)\\&amp;\leq&amp;2r&#039;(c)-2-r(x)-r(c)\\&amp;\leq&amp;2(r&#039;(c)-r(c))-2\\&amp;\leq&amp;3(r&#039;(c)-r(c))-2\end{array}' title='\begin{array}{rcl}r(T&#039;)-r(T)&amp;=&amp;r&#039;(c)+r&#039;(x)+r&#039;(y)-r(c)-r(x)-r(y)\\&amp;=&amp;r&#039;(x)+r&#039;(y)-r(c)-r(x)\\&amp;\leq&amp;2r&#039;(c)-2-r(x)-r(c)\\&amp;\leq&amp;2(r&#039;(c)-r(c))-2\\&amp;\leq&amp;3(r&#039;(c)-r(c))-2\end{array}' class='latex' /></center></p>
<li><strong>zig</strong>: in this case,
<p><center><img src='http://s.wordpress.com/latex.php?latex=%5Cbegin%7Barray%7D%7Brcl%7Dr%28T%27%29-r%28T%29%26%3D%26r%27%28x%29%2Br%27%28y%29-r%28c%29-r%28x%29%5C%5C%26%3D%26r%27%28y%29-r%28c%29%5C%5C%26%5Cleq%26%20r%27%28c%29-r%28c%29%5C%5C%26%5Cleq%263%28r%27%28c%29-r%28c%29%29%5Cend%7Barray%7D&#038;bg=ffffff&#038;fg=000000&#038;s=0' alt='\begin{array}{rcl}r(T&#039;)-r(T)&amp;=&amp;r&#039;(x)+r&#039;(y)-r(c)-r(x)\\&amp;=&amp;r&#039;(y)-r(c)\\&amp;\leq&amp; r&#039;(c)-r(c)\\&amp;\leq&amp;3(r&#039;(c)-r(c))\end{array}' title='\begin{array}{rcl}r(T&#039;)-r(T)&amp;=&amp;r&#039;(x)+r&#039;(y)-r(c)-r(x)\\&amp;=&amp;r&#039;(y)-r(c)\\&amp;\leq&amp; r&#039;(c)-r(c)\\&amp;\leq&amp;3(r&#039;(c)-r(c))\end{array}' class='latex' /></center></p>
</ul>
<p>In conclusion, after a zig-zig or zig-zag, the banking reserve difference is at most <img src='http://s.wordpress.com/latex.php?latex=3%28r%27%28c%29-r%28c%29%29-2&#038;bg=ffffff&#038;fg=000000&#038;s=0' alt='3(r&#039;(c)-r(c))-2' title='3(r&#039;(c)-r(c))-2' class='latex' />, and after a zig the difference is at most <img src='http://s.wordpress.com/latex.php?latex=3%28r%27%28c%29-r%28c%29%29&#038;bg=ffffff&#038;fg=000000&#038;s=0' alt='3(r&#039;(c)-r(c))' title='3(r&#039;(c)-r(c))' class='latex' />. Now, when we splay node <img src='http://s.wordpress.com/latex.php?latex=c&#038;bg=ffffff&#038;fg=000000&#038;s=0' alt='c' title='c' class='latex' /> at depth <img src='http://s.wordpress.com/latex.php?latex=d&#038;bg=ffffff&#038;fg=000000&#038;s=0' alt='d' title='d' class='latex' /> all the way to the root, there will be <img src='http://s.wordpress.com/latex.php?latex=%5Clceil%20d%2F2%20%5Crceil&#038;bg=ffffff&#038;fg=000000&#038;s=0' alt='\lceil d/2 \rceil' title='\lceil d/2 \rceil' class='latex' /> baby steps all of which are zig-zig or zig-zag except for possibly the last step. </p>
<p>Let <img src='http://s.wordpress.com/latex.php?latex=r_0%28c%29&#038;bg=ffffff&#038;fg=000000&#038;s=0' alt='r_0(c)' title='r_0(c)' class='latex' /> be the rank of <img src='http://s.wordpress.com/latex.php?latex=c&#038;bg=ffffff&#038;fg=000000&#038;s=0' alt='c' title='c' class='latex' /> before any baby step is done, <img src='http://s.wordpress.com/latex.php?latex=r_i%28c%29&#038;bg=ffffff&#038;fg=000000&#038;s=0' alt='r_i(c)' title='r_i(c)' class='latex' /> be the rank of <img src='http://s.wordpress.com/latex.php?latex=c&#038;bg=ffffff&#038;fg=000000&#038;s=0' alt='c' title='c' class='latex' /> after the <img src='http://s.wordpress.com/latex.php?latex=i&#038;bg=ffffff&#038;fg=000000&#038;s=0' alt='i' title='i' class='latex' />th baby step for <img src='http://s.wordpress.com/latex.php?latex=i%5Cin%20%5C%7B1%2C2%2C%5Cdots%2C%20%5Clceil%20d%2F2%20%5Crceil%5C%7D&#038;bg=ffffff&#038;fg=000000&#038;s=0' alt='i\in \{1,2,\dots, \lceil d/2 \rceil\}' title='i\in \{1,2,\dots, \lceil d/2 \rceil\}' class='latex' />. Then, the net banking reserve difference is at most</p>
<p><center><img src='http://s.wordpress.com/latex.php?latex=%5Cbegin%7Barray%7D%7Brcl%7D%20r%28T%27%29-r%28T%29%20%26%5Cleq%26%20%5Csum_%7Bi%3D1%7D%5E%7B%5Clceil%20d%2F2%20%5Crceil%7D%20%5B3%28r_i%28c%29-r_%7Bi-1%7D%28c%29%29-2%5D%20%2B%202%5C%5C%26%3D%26%203%28r_%7B%5Clceil%20d%2F2%20%5Crceil%7D%20%28c%29-r_0%28c%29%29-2%5Clceil%20d%2F2%20%5Crceil%20%2B%202%5C%5C%20%26%5Cleq%26%203%28r_%7B%5Clceil%20d%2F2%20%5Crceil%7D%20%28c%29-r_0%28c%29%29%2B2-d%5Cend%7Barray%7D&#038;bg=ffffff&#038;fg=000000&#038;s=0' alt='\begin{array}{rcl} r(T&#039;)-r(T) &amp;\leq&amp; \sum_{i=1}^{\lceil d/2 \rceil} [3(r_i(c)-r_{i-1}(c))-2] + 2\\&amp;=&amp; 3(r_{\lceil d/2 \rceil} (c)-r_0(c))-2\lceil d/2 \rceil + 2\\ &amp;\leq&amp; 3(r_{\lceil d/2 \rceil} (c)-r_0(c))+2-d\end{array}' title='\begin{array}{rcl} r(T&#039;)-r(T) &amp;\leq&amp; \sum_{i=1}^{\lceil d/2 \rceil} [3(r_i(c)-r_{i-1}(c))-2] + 2\\&amp;=&amp; 3(r_{\lceil d/2 \rceil} (c)-r_0(c))-2\lceil d/2 \rceil + 2\\ &amp;\leq&amp; 3(r_{\lceil d/2 \rceil} (c)-r_0(c))+2-d\end{array}' class='latex' /></center></p>
<p>Now, recall the inequality </p>
<p><center><img src='http://s.wordpress.com/latex.php?latex=r%28T%27%29%20-%20r%28T%29%20%5Cleq%20D%28P%29-%5Ctext%7Bcost%7D%28P%29&#038;bg=ffffff&#038;fg=000000&#038;s=0' alt='r(T&#039;) - r(T) \leq D(P)-\text{cost}(P)' title='r(T&#039;) - r(T) \leq D(P)-\text{cost}(P)' class='latex' /></center></p>
<p>that we wanted to maintain after each pair search + splay, insert + splay, and delete + splay. We need to determine the deposit <code>D(P)</code> to be made for operation <code>P</code>. </p>
<p>Consider first the pair <code>P = search + splay</code>. Let <code>d</code> be the depth of the splayed node. Then, the cost of this operation is proportional to <code>d</code>; and, by a change of currency we can assume that it costs exactly <code>d</code> dollars. We have shown that the net banking reserve difference after <code>search + splay</code> is bounded by</p>
<p><center><img src='http://s.wordpress.com/latex.php?latex=%5Cbegin%7Barray%7D%7Brcl%7D%20r%28T%27%29-r%28T%29%20%26%5Cleq%26%203%28r_%7B%5Clceil%20d%2F2%20%5Crceil%7D%20%28c%29-r_0%28c%29%29%2B2-d%5C%5C%26%3D%263%28r_%7B%5Clceil%20d%2F2%20%5Crceil%7D%20%28c%29-r_0%28c%29%29%2B2%20-%20%5Ctext%7Bcost%7D%28P%29%5Cend%7Barray%7D&#038;bg=ffffff&#038;fg=000000&#038;s=0' alt='\begin{array}{rcl} r(T&#039;)-r(T) &amp;\leq&amp; 3(r_{\lceil d/2 \rceil} (c)-r_0(c))+2-d\\&amp;=&amp;3(r_{\lceil d/2 \rceil} (c)-r_0(c))+2 - \text{cost}(P)\end{array}' title='\begin{array}{rcl} r(T&#039;)-r(T) &amp;\leq&amp; 3(r_{\lceil d/2 \rceil} (c)-r_0(c))+2-d\\&amp;=&amp;3(r_{\lceil d/2 \rceil} (c)-r_0(c))+2 - \text{cost}(P)\end{array}' class='latex' /></center></p>
<p>Hence, if we deposit an amount <img src='http://s.wordpress.com/latex.php?latex=D%28P%29%20%3D%203%28r_%7B%5Clceil%20d%2F2%20%5Crceil%7D%20%28c%29-r_0%28c%29%29%2B2%20%3D%20O%28%5Clog%20n%29&#038;bg=ffffff&#038;fg=000000&#038;s=0' alt='D(P) = 3(r_{\lceil d/2 \rceil} (c)-r_0(c))+2 = O(\log n)' title='D(P) = 3(r_{\lceil d/2 \rceil} (c)-r_0(c))+2 = O(\log n)' class='latex' /> we would have enough to cover the cost plus the extra banking reserve needed. Note that <img src='http://s.wordpress.com/latex.php?latex=r_%7B%5Clceil%20d%2F2%20%5Crceil%7D%20%28c%29%20%3D%20%5Clog%282n%2B1%29&#038;bg=ffffff&#038;fg=000000&#038;s=0' alt='r_{\lceil d/2 \rceil} (c) = \log(2n+1)' title='r_{\lceil d/2 \rceil} (c) = \log(2n+1)' class='latex' />.</p>
<p>The analysis for the pair <code>delete + splay</code> is similar.</p>
<p>For <code>insert + splay</code>, the net difference is</p>
<p><center><img src='http://s.wordpress.com/latex.php?latex=%5Cbegin%7Barray%7D%7Brcl%7D%20r%28T%27%29-r%28T%29%20%26%5Cleq%26%20%5Clog%282n%2B1%29%20%2B%203%28r_%7B%5Clceil%20d%2F2%20%5Crceil%7D%20%28c%29-r_0%28c%29%29%2B2-d%5C%5C%26%3D%26%5Clog%282n%2B1%29%2B3%28r_%7B%5Clceil%20d%2F2%20%5Crceil%7D%20%28c%29-r_0%28c%29%29%2B2%20-%20%5Ctext%7Bcost%7D%28P%29%5Cend%7Barray%7D&#038;bg=ffffff&#038;fg=000000&#038;s=0' alt='\begin{array}{rcl} r(T&#039;)-r(T) &amp;\leq&amp; \log(2n+1) + 3(r_{\lceil d/2 \rceil} (c)-r_0(c))+2-d\\&amp;=&amp;\log(2n+1)+3(r_{\lceil d/2 \rceil} (c)-r_0(c))+2 - \text{cost}(P)\end{array}' title='\begin{array}{rcl} r(T&#039;)-r(T) &amp;\leq&amp; \log(2n+1) + 3(r_{\lceil d/2 \rceil} (c)-r_0(c))+2-d\\&amp;=&amp;\log(2n+1)+3(r_{\lceil d/2 \rceil} (c)-r_0(c))+2 - \text{cost}(P)\end{array}' class='latex' /></center></p>
<p>and thus a <img src='http://s.wordpress.com/latex.php?latex=O%28%5Clog%20n%29&#038;bg=ffffff&#038;fg=000000&#038;s=0' alt='O(\log n)' title='O(\log n)' class='latex' /> deposit is also sufficient.</p>
<h3>5. Experimental performance analysis of balanced search trees</h3>
<p>We have analyzed some of the most important balanced BSTs. They perform well theoretically by ensuring that each operation takes logarithmic time (worst-case or on average). With theoretically identical performance like this, we do not have a good basis for picking which data structure to use in a real-world problems. In such case, the only choice is to implement them all and see which one fits best for the problem at hand.</p>
<p>Fortunately, Ben Pfaff has done an set of experiments like that. Here&#8217;s <a href="http://www.stanford.edu/~blp/papers/libavl.pdf">the report</a>. There are many interesting conclusions drawn from the experiments; the following is probably more relevant to this course:</p>
<blockquote><p>
We found that in selecting data structures, unbalanced BSTs are best when randomly ordered input can be relied upon; if random ordering is the norm but occasional runs of sorted order are expected, then red-black trees should be chosen. On the other hand, if insertions often occur in a sorted order, AVL trees excel when later accesses tend to be random, and splay trees perform best when later accesses are sequential or clustered.  </p>
<p>For node representation, we found that parent pointers are generally fastest, so they should be preferred as long as the cost of an additional pointer ﬁeld per node is not important. If space is at a premium, threaded representations conserve memory and lag only slightly behind parent pointers in speed.
</p></blockquote>
]]></content:encoded>
			<wfw:commentRss>http://www.procul.org/blog/2012/04/06/cac-cay-tim-ki%e1%ba%bfm-can-b%e1%ba%b1ng-avl-d%e1%bb%8f-den-24-va-cay-loe/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

