<?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>阅微堂 &#187; 算法分析</title>
	<atom:link href="http://zhiqiang.org/blog/tag/%e7%ae%97%e6%b3%95%e5%88%86%e6%9e%90/feed" rel="self" type="application/rss+xml" />
	<link>http://zhiqiang.org/blog</link>
	<description>理工科背景的证券从业人员</description>
	<lastBuildDate>Sun, 05 Feb 2012 03:59:13 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.1</generator>
		<item>
		<title>递归算法的复杂度</title>
		<link>http://zhiqiang.org/blog/science/computer-science/complexity-of-recursive-algorithm.html</link>
		<comments>http://zhiqiang.org/blog/science/computer-science/complexity-of-recursive-algorithm.html#comments</comments>
		<pubDate>Sat, 27 Sep 2008 06:26:46 +0000</pubDate>
		<dc:creator>zhiqiang</dc:creator>
				<category><![CDATA[计算机科学]]></category>
		<category><![CDATA[动态规划]]></category>
		<category><![CDATA[算法分析]]></category>
		<category><![CDATA[递归]]></category>

		<guid isPermaLink="false">http://zhiqiang.org/blog/?p=852</guid>
		<description><![CDATA[博客 » 计算机科学 » 算法分析 » 递归算法的复杂度通常很难衡量，一般都认为是每次递归分支数的递归深度次方。但通常情况下没有这个大，如果我们可以保存每次子递归的结果的话，递归算法的复杂性等于不同的节点个数。这也是动态规划算法思想的由来。 看一下下面这个算法题目，据称是百度的笔试题： 简述：实现一个函数，对一个正整数n，算得到1需要的最少操作次...]]></description>
			<content:encoded><![CDATA[<p id="breadcrumb" class="breadcrumb"><a href="http://zhiqiang.org/blog/">博客</a> » <a href="http://zhiqiang.org/blog/category/science/computer-science">计算机科学</a> » <a href='http://zhiqiang.org/blog/tag/%e7%ae%97%e6%b3%95%e5%88%86%e6%9e%90'>算法分析</a>  » </p><p>递归算法的复杂度通常很难衡量，一般都认为是每次递归分支数的递归深度次方。但通常情况下没有这个大，如果我们可以保存每次子递归的结果的话，递归算法的复杂性等于不同的节点个数。这也是动态规划算法思想的由来。</p>
<p>看一下下面这个算法题目，据称是百度的笔试题：</p>
<blockquote><p>简述：实现一个函数，对一个正整数n，算得到1需要的最少操作次数：</p>
<p>如果n为偶数，将其处以2；如果n为奇数，可以加1或减1；一直处理下去。</p>
<p>要求：实现函数（实现尽可能高效）int func(unsigned int n)；n为输入，返回最小的运算次数。</p></blockquote>
<p>我不确定是不是对n的操作次数有一个简单的刻画，尝试着想了一会儿，似乎不太容易想到。但后来发现这个题目本质上不是算法题，而是算法分析题。因为仔细分析可以发现，题目中给的递归构造本身就是非常高效的。</p>
<p>直接按照题目中的操作描述可以写出函数：</p>
<blockquote><p><code>int function(unsigned int n) {<br />
  if (n == 1) return 0;<br />
  if (n%2 == 0) return 1 + function(n/2);<br />
  return 2 + min(function((n + 1)/2), function((n - 1)/2));<br />
} </code></p></blockquote>
<p>在递归过程中，每个节点可以引出一条或两条分支，递归深度为<span class='MathJax_Preview'><img src='http://zhiqiang.org/blog/wp-content/plugins/latex/cache/tex_0d2e858bd7f89eed5461e5637d6e0a50.gif' style='vertical-align: middle; border: none; ' class='tex' alt="\log n" /></span><script type='math/tex'>\log n</script>，所以总节点数为<span class='MathJax_Preview'><img src='http://zhiqiang.org/blog/wp-content/plugins/latex/cache/tex_7b8b965ad4bca0e41ab51de7b31363a1.gif' style='vertical-align: middle; border: none; padding-bottom:2px;' class='tex' alt="n" /></span><script type='math/tex'>n</script>级别的，但为何还说此递归本身是非常高效的呢？</p>
<p>理解了动态规划的思想，就很容易理解这里面的问题。因为动态规划本质上就是保存运算结果的递归，虽然递归算法经常会有指数级别的搜索节点，但这些节点往往重复率特别高，当保存每次运算的节点结果后，在重复节点的计算时，就可以直接使用已经保存过的结果，这样就大大提高了速度（每次不仅减少一个节点，而且同时消灭了这个节点后面的所有分支节点）。</p>
<p>在这个问题里是什么情况呢？仔细分析就会发现，在整个搜索数中，第<span class='MathJax_Preview'><img src='http://zhiqiang.org/blog/wp-content/plugins/latex/cache/tex_8ce4b16b22b58894aa86c421e8759df3.gif' style='vertical-align: middle; border: none; padding-bottom:1px;' class='tex' alt="k" /></span><script type='math/tex'>k</script>层的节点只有两种可能性<span class='MathJax_Preview'><img src='http://zhiqiang.org/blog/wp-content/plugins/latex/cache/tex_cfa2e6ed7549ad14e8e9a6b23bae3350.gif' style='vertical-align: middle; border: none; ' class='tex' alt="n>>k" /></span><script type='math/tex'>n>>k</script>和<span class='MathJax_Preview'><img src='http://zhiqiang.org/blog/wp-content/plugins/latex/cache/tex_27672e0fe4bb1f6992a9354f8ddb41dd.gif' style='vertical-align: middle; border: none; ' class='tex' alt="n>>k - 1" /></span><script type='math/tex'>n>>k - 1</script>。这意味着整个搜索树事实上只有<span class='MathJax_Preview'><img src='http://zhiqiang.org/blog/wp-content/plugins/latex/cache/tex_def698af2f32b60b8fccb63d54603305.gif' style='vertical-align: middle; border: none; ' class='tex' alt="2\log n" /></span><script type='math/tex'>2\log n</script>个节点。所以这个递归算法本质上的运算复杂度只有<span class='MathJax_Preview'><img src='http://zhiqiang.org/blog/wp-content/plugins/latex/cache/tex_0ca47d9a481af371d1210a620c1945db.gif' style='vertical-align: middle; border: none; ' class='tex' alt="O(\log n)" /></span><script type='math/tex'>O(\log n)</script>。这已经是最优的了。</p>
<div><h4>相关文章</h4><ul><li><a href="http://zhiqiang.org/blog/science/computer-science/inverse-square-root-algorithm-analysis.html">求平方根倒数的算法</a></li></ul></div>    <p></p>
    <hr noshade style="margin:0;height:1px" />
    <p>&copy; zhiqiang for <a href="http://zhiqiang.org/blog">阅微堂</a>, 2008. | <a href="http://zhiqiang.org/blog/science/computer-science/complexity-of-recursive-algorithm.html">&#38142;&#25509;</a> | <a href="http://zhiqiang.org/blog/science/computer-science/complexity-of-recursive-algorithm.html#comments">20 &#26465;&#35780;&#35770;</a></p>]]></content:encoded>
			<wfw:commentRss>http://zhiqiang.org/blog/science/computer-science/complexity-of-recursive-algorithm.html/feed</wfw:commentRss>
		<slash:comments>20</slash:comments>
		</item>
		<item>
		<title>求平方根倒数的算法</title>
		<link>http://zhiqiang.org/blog/science/computer-science/inverse-square-root-algorithm-analysis.html</link>
		<comments>http://zhiqiang.org/blog/science/computer-science/inverse-square-root-algorithm-analysis.html#comments</comments>
		<pubDate>Fri, 19 Sep 2008 04:10:28 +0000</pubDate>
		<dc:creator>zhiqiang</dc:creator>
				<category><![CDATA[计算机科学]]></category>
		<category><![CDATA[算法]]></category>
		<category><![CDATA[算法分析]]></category>

		<guid isPermaLink="false">http://zhiqiang.org/blog/posts/inverse-square-root-algorithm-analysis.html</guid>
		<description><![CDATA[博客 » 计算机科学 » 算法 » 下面这个求的函数号称比直接调用sqrt库函数快4倍，来自游戏Quake III的源代码。 float InvSqrt (float x){ float xhalf = 0.5f*x; int i = *(int*)&#38;x; i = 0x5f3759df - (i&#62;&#62;1); y = *(float*)&#38;i; y = y*(1.5f - xhalf*x*x); return x; } 我们这里分析一下它的原理（指程序的正确性，而不是解释为何快）。 分析程序之前，我们必须解释一下float数据在计算机里的表示方式。一般而...]]></description>
			<content:encoded><![CDATA[<p id="breadcrumb" class="breadcrumb"><a href="http://zhiqiang.org/blog/">博客</a> » <a href="http://zhiqiang.org/blog/category/science/computer-science">计算机科学</a> » <a href='http://zhiqiang.org/blog/tag/%e7%ae%97%e6%b3%95'>算法</a>  » </p><p>下面这个求<span class='MathJax_Preview'><img src='http://zhiqiang.org/blog/wp-content/plugins/latex/cache/tex_c316ab9d453dd89c01a6fdb29cfb28de.gif' style='vertical-align: middle; border: none; ' class='tex' alt="1/\sqrt{x}" /></span><script type='math/tex'>1/\sqrt{x}</script>的函数号称比直接调用sqrt库函数快4倍，来自游戏Quake III的源代码。</p>
<blockquote>
<pre><span style="color: #0000ff;">float</span> InvSqrt (<span style="color: #0000ff;">float</span> x){
    <span style="color: #0000ff;">float</span> xhalf = 0.5f*x;
    <span style="color: #0000ff;">int</span> i = *(<span style="color: #0000ff;">int</span>*)&amp;x;
    i = 0x5f3759df - (i&gt;&gt;1);
    y = *(<span style="color: #0000ff;">float</span>*)&amp;i;
    y = y*(1.5f - xhalf*x*x);
    <span style="color: #0000ff;">return</span> x;
}</pre>
</blockquote>
<p>我们这里分析一下它的原理（指程序的正确性，而不是解释为何快）。</p>
<p>分析程序之前，我们必须解释一下float数据在计算机里的表示方式。一般而言，一个float数据<span class='MathJax_Preview'><img src='http://zhiqiang.org/blog/wp-content/plugins/latex/cache/tex_9dd4e461268c8034f5c8564e155c67a6.gif' style='vertical-align: middle; border: none; padding-bottom:2px;' class='tex' alt="x" /></span><script type='math/tex'>x</script>共32个bit，和int数据一样。其中前23位为有效数字<span class='MathJax_Preview'><img src='http://zhiqiang.org/blog/wp-content/plugins/latex/cache/tex_832cab6245118c67b73c5ef0be7cf7e8.gif' style='vertical-align: middle; border: none; ' class='tex' alt="M_x" /></span><script type='math/tex'>M_x</script>，后面接着一个8位数据<span class='MathJax_Preview'><img src='http://zhiqiang.org/blog/wp-content/plugins/latex/cache/tex_893be2279f4c4bc665184cf9f87da90c.gif' style='vertical-align: middle; border: none; ' class='tex' alt="E_x" /></span><script type='math/tex'>E_x</script>表示指数，最后一位表示符号，由于这里被开方的数总是大于0，所以我们暂不考虑最后一个符号位。此时</p>
<p><p style='text-align:center;'><span class='MathJax_Preview'><img src='http://zhiqiang.org/blog/wp-content/plugins/latex/cache/tex_1e4110c15e61979363c8a50c9be6667c.gif' style='vertical-align: middle; border: none;' class='tex' alt="x=1.M_x 2^{E_x-127} " /></span><script type='math/tex; mode=display'>x=1.M_x 2^{E_x-127} </script></p></p>
<p>如果我们把计算机内的浮点数<span class='MathJax_Preview'><img src='http://zhiqiang.org/blog/wp-content/plugins/latex/cache/tex_9dd4e461268c8034f5c8564e155c67a6.gif' style='vertical-align: middle; border: none; padding-bottom:2px;' class='tex' alt="x" /></span><script type='math/tex'>x</script>看做一个整数<span class='MathJax_Preview'><img src='http://zhiqiang.org/blog/wp-content/plugins/latex/cache/tex_e0c12d615090d3574f32ebeab63f5601.gif' style='vertical-align: middle; border: none; ' class='tex' alt="I_x" /></span><script type='math/tex'>I_x</script>，那么<p style='text-align:center;'><span class='MathJax_Preview'><img src='http://zhiqiang.org/blog/wp-content/plugins/latex/cache/tex_104440c83c5fffbe38f981757bd33978.gif' style='vertical-align: middle; border: none;' class='tex' alt="I_x = 2^{23}E_x+M_x " /></span><script type='math/tex; mode=display'>I_x = 2^{23}E_x+M_x </script></p></p>
<p>现在开始逐步分析函数。这个函数的主体有四个语句，分别的功能是：</p>
<blockquote><p><span style="color: #0000ff;">int</span> i = *(<span style="color: #0000ff;">int</span>*)&amp;x; 这条语句把<span class='MathJax_Preview'><img src='http://zhiqiang.org/blog/wp-content/plugins/latex/cache/tex_9dd4e461268c8034f5c8564e155c67a6.gif' style='vertical-align: middle; border: none; padding-bottom:2px;' class='tex' alt="x" /></span><script type='math/tex'>x</script>转成<span class='MathJax_Preview'><img src='http://zhiqiang.org/blog/wp-content/plugins/latex/cache/tex_1efc275e97e02ac108c7836caad83cc0.gif' style='vertical-align: middle; border: none; ' class='tex' alt="i=I_x" /></span><script type='math/tex'>i=I_x</script>。</p>
<p>i = 0x5f3759df - (i&gt;&gt;1); 这条语句从<span class='MathJax_Preview'><img src='http://zhiqiang.org/blog/wp-content/plugins/latex/cache/tex_e0c12d615090d3574f32ebeab63f5601.gif' style='vertical-align: middle; border: none; ' class='tex' alt="I_x" /></span><script type='math/tex'>I_x</script>计算<span class='MathJax_Preview'><img src='http://zhiqiang.org/blog/wp-content/plugins/latex/cache/tex_ed49444b7e57c2fc4dfc8f056fae6bc4.gif' style='vertical-align: middle; border: none; ' class='tex' alt="I_{1/\sqrt{x}}" /></span><script type='math/tex'>I_{1/\sqrt{x}}</script>。</p>
<p>y = *(<span style="color: #0000ff;">float</span>*)&amp;i; 这条语句将<span class='MathJax_Preview'><img src='http://zhiqiang.org/blog/wp-content/plugins/latex/cache/tex_ed49444b7e57c2fc4dfc8f056fae6bc4.gif' style='vertical-align: middle; border: none; ' class='tex' alt="I_{1/\sqrt{x}}" /></span><script type='math/tex'>I_{1/\sqrt{x}}</script>转换为<span class='MathJax_Preview'><img src='http://zhiqiang.org/blog/wp-content/plugins/latex/cache/tex_c316ab9d453dd89c01a6fdb29cfb28de.gif' style='vertical-align: middle; border: none; ' class='tex' alt="1/\sqrt{x}" /></span><script type='math/tex'>1/\sqrt{x}</script>。</p>
<p>y = y*(1.5f - xhalf*y*y); 这时候的y是近似解；此步就是经典的牛顿迭代法。迭代次数越多越准确。</p></blockquote>
<p>关键是第二步 i = 0x5f3759df - (i&gt;&gt;1); 这条语句从<span class='MathJax_Preview'><img src='http://zhiqiang.org/blog/wp-content/plugins/latex/cache/tex_e0c12d615090d3574f32ebeab63f5601.gif' style='vertical-align: middle; border: none; ' class='tex' alt="I_x" /></span><script type='math/tex'>I_x</script>计算<span class='MathJax_Preview'><img src='http://zhiqiang.org/blog/wp-content/plugins/latex/cache/tex_ed49444b7e57c2fc4dfc8f056fae6bc4.gif' style='vertical-align: middle; border: none; ' class='tex' alt="I_{1/\sqrt{x}}" /></span><script type='math/tex'>I_{1/\sqrt{x}}</script>，原理:</p>
<p>令<span class='MathJax_Preview'><img src='http://zhiqiang.org/blog/wp-content/plugins/latex/cache/tex_aa1b97bb7383597663a51e7ad5b0da35.gif' style='vertical-align: middle; border: none; ' class='tex' alt="y=1/\sqrt{x}" /></span><script type='math/tex'>y=1/\sqrt{x}</script>，用<span class='MathJax_Preview'><img src='http://zhiqiang.org/blog/wp-content/plugins/latex/cache/tex_1759e9f3f5a3125e49343a92a2b7cf7c.gif' style='vertical-align: middle; border: none; ' class='tex' alt="x=(1+m_x)2^{e_x}" /></span><script type='math/tex'>x=(1+m_x)2^{e_x}</script>和<span class='MathJax_Preview'><img src='http://zhiqiang.org/blog/wp-content/plugins/latex/cache/tex_8a525bf37b169a440892a25eb7403799.gif' style='vertical-align: middle; border: none; ' class='tex' alt="y=(1+m_y)2^{e_y}" /></span><script type='math/tex'>y=(1+m_y)2^{e_y}</script>带入之后两边取对数，再利用近似表示<span class='MathJax_Preview'><img src='http://zhiqiang.org/blog/wp-content/plugins/latex/cache/tex_ea3d4f8b071da0aba0556f4b7de23443.gif' style='vertical-align: middle; border: none; ' class='tex' alt="\log_2(1+z)\sim z+\delta" /></span><script type='math/tex'>\log_2(1+z)\sim z+\delta</script>，算一算就得到</p>
<p><p style='text-align:center;'><span class='MathJax_Preview'><img src='http://zhiqiang.org/blog/wp-content/plugins/latex/cache/tex_97c1e31a970b3aae9c98ba334dd4c151.gif' style='vertical-align: middle; border: none;' class='tex' alt="I_y = \frac{2}{3}(127-\delta)2^{23}-I_x/2 " /></span><script type='math/tex; mode=display'>I_y = \frac{2}{3}(127-\delta)2^{23}-I_x/2 </script></p></p>
<p>若取<span class='MathJax_Preview'><img src='http://zhiqiang.org/blog/wp-content/plugins/latex/cache/tex_322863072b22b9062d0ad72cb98692f7.gif' style='vertical-align: middle; border: none; ' class='tex' alt="\delta=0.0450465679168701171875" /></span><script type='math/tex'>\delta=0.0450465679168701171875</script>，<span class='MathJax_Preview'><img src='http://zhiqiang.org/blog/wp-content/plugins/latex/cache/tex_5c30a3072abd9f51847218d4ddede824.gif' style='vertical-align: middle; border: none; ' class='tex' alt="\frac{2}{3}(127-\delta)2^{23}" /></span><script type='math/tex'>\frac{2}{3}(127-\delta)2^{23}</script>就是程序里所用的常量0x5f3759df。至于为何选择这个<span class='MathJax_Preview'><img src='http://zhiqiang.org/blog/wp-content/plugins/latex/cache/tex_77a3b715842b45e440a5bee15357ad29.gif' style='vertical-align: middle; border: none; ' class='tex' alt="\delta" /></span><script type='math/tex'>\delta</script>，则应该是曲线拟合实验的结果。</p>
<div><h4>相关文章</h4><ul><li><a href="http://zhiqiang.org/blog/science/computer-science/complexity-of-recursive-algorithm.html">递归算法的复杂度</a></li><li><a href="http://zhiqiang.org/blog/science/computer-science/preliminary-computer-theory-algorithms-and-calculation-model.html">理论计算机初步：算法和计算模型</a></li><li><a href="http://zhiqiang.org/blog/science/computer-science/graph-isomorphism-is-polynomial.html">图同构问题属于P？</a></li><li><a href="http://zhiqiang.org/blog/science/computer-science/programs-depend-on-date-struct-not-algorithm.html">编程的核心是数据结构，而不是算法</a></li><li><a href="http://zhiqiang.org/blog/science/computer-science/complexity-of-prime-sieve.html">素数筛法的复杂度</a></li><li><a href="http://zhiqiang.org/blog/science/computer-science/another-perfect-shuffle-algorithm.html">Perfect Shuffle的算法</a></li><li><a href="http://zhiqiang.org/blog/science/computer-science/download-encyclopedia-of-algorithm.html">算法百科全书 - Encyclopedia of Algorithms</a></li><li><a href="http://zhiqiang.org/blog/science/computer-science/3-color-a-simple-graph.html">一个简单图的三染色算法问题</a></li><li><a href="http://zhiqiang.org/blog/science/computer-science/how-google-search-similar-images.html">图片搜索的原理</a></li><li><a href="http://zhiqiang.org/blog/science/computer-science/max-drawdown-algorithm.html">最大回撤和最大短期回撤的线性算法</a></li></ul></div>    <p></p>
    <hr noshade style="margin:0;height:1px" />
    <p>&copy; zhiqiang for <a href="http://zhiqiang.org/blog">阅微堂</a>, 2008. | <a href="http://zhiqiang.org/blog/science/computer-science/inverse-square-root-algorithm-analysis.html">&#38142;&#25509;</a> | <a href="http://zhiqiang.org/blog/science/computer-science/inverse-square-root-algorithm-analysis.html#comments">25 &#26465;&#35780;&#35770;</a></p>]]></content:encoded>
			<wfw:commentRss>http://zhiqiang.org/blog/science/computer-science/inverse-square-root-algorithm-analysis.html/feed</wfw:commentRss>
		<slash:comments>25</slash:comments>
		</item>
	</channel>
</rss>

