<?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>推导 &#8211; 编码无悔 /  Intent &amp; Focused</title>
	<atom:link href="https://www.codelast.com/tag/%E6%8E%A8%E5%AF%BC/feed/" rel="self" type="application/rss+xml" />
	<link>https://www.codelast.com</link>
	<description>最优化之路</description>
	<lastBuildDate>Tue, 28 Apr 2020 02:07:20 +0000</lastBuildDate>
	<language>zh-Hans</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=7.1.3</generator>
	<item>
		<title>[原创] 如何用「归纳假设法」求归并排序的时间复杂度</title>
		<link>https://www.codelast.com/%e5%8e%9f%e5%88%9b-%e5%a6%82%e4%bd%95%e7%94%a8%e3%80%8c%e5%bd%92%e7%ba%b3%e5%81%87%e8%ae%be%e6%b3%95%e3%80%8d%e6%b1%82%e5%bd%92%e5%b9%b6%e6%8e%92%e5%ba%8f%e7%9a%84%e6%97%b6%e9%97%b4%e5%a4%8d/</link>
					<comments>https://www.codelast.com/%e5%8e%9f%e5%88%9b-%e5%a6%82%e4%bd%95%e7%94%a8%e3%80%8c%e5%bd%92%e7%ba%b3%e5%81%87%e8%ae%be%e6%b3%95%e3%80%8d%e6%b1%82%e5%bd%92%e5%b9%b6%e6%8e%92%e5%ba%8f%e7%9a%84%e6%97%b6%e9%97%b4%e5%a4%8d/#respond</comments>
		
		<dc:creator><![CDATA[learnhard]]></dc:creator>
		<pubDate>Mon, 15 Sep 2014 17:36:26 +0000</pubDate>
				<category><![CDATA[Algorithm]]></category>
		<category><![CDATA[原创]]></category>
		<category><![CDATA[O(nlogn)]]></category>
		<category><![CDATA[归并排序]]></category>
		<category><![CDATA[归纳假设法]]></category>
		<category><![CDATA[推导]]></category>
		<category><![CDATA[时间复杂度]]></category>
		<guid isPermaLink="false">http://www.codelast.com/?p=8322</guid>

					<description><![CDATA[<p>
分析归并排序算法的时间复杂度，可以根据算法的逻辑，分析每一个步骤的最坏情况，然后得到总体的时间复杂度；也可以利用数学中的『归纳假设法』，用几乎纯数学的方式来得到它的时间复杂度。而后者比前者好理解得多，所以，我认为要推导归并排序的时间复杂度的话，归纳假设的方法是不二之选。<br />
<span id="more-8322"></span><br />
<span style="background-color:#00ff00;">『1』</span>时间复杂度递推公式<br />
将待排序的数组记为a。假设这里是用递归的方式实现的归并排序（易于理解）。<br />
归并排序将a分为两半，分别排序，再把排序后的这两半归并为一个数组。对这两半，还是用归并排序的方法，把它们分别再分成两半来排序、归并。这样一直拆分下去，直到最后拆成的&#8220;两半&#8221;已经是两个单独的元素，就算是&#8220;到头&#8221;了（没得拆了）。<br />
因此，在每一次递归的过程中，需要做两个递归调用（分别排序拆成的那&#8220;两半&#8221;数组），以及一个归并操作。<br />
<span style="color: rgb(255, 255, 255);">文章来源：</span><a href="http://www.codelast.com/" target="_blank" rel="noopener noreferrer"><span style="color: rgb(255, 255, 255);">http://www.codelast.com/</span></a><br />
归并操作的时间复杂度是 <span class='MathJax_Preview'>\(O\left( n \right)\)</span><script type='math/tex'>O\left( n \right)</script> ，而两个递归调用的时间复杂度是多少呢？<br />
这里先假设一次递归调用的过程所耗费的时间是 <span class='MathJax_Preview'>\(t(n)\)</span><script type='math/tex'>t(n)</script> ，则在问题的规模减半后（数组拆成了两半，所以规模减半了），递归调用耗费的时间就是 <span class='MathJax_Preview'>\(t\left( {\frac{n}{2}} \right)\)</span><script type='math/tex'>t\left( {\frac{n}{2}} \right)</script> 了。<br />
因此，归并排序耗费的时间的递推公式就是：<br />
 <span class='MathJax_Preview'>\(t(n) = t\left( {\frac{n}{2}} \right) + t\left( {\frac{n}{2}} \right) + n = 2t\left( {\frac{n}{2}} \right) + n,\;n 1\)</span><script type='math/tex'>t(n) = t\left( {\frac{n}{2}} \right) + t\left( {\frac{n}{2}} \right) + n = 2t\left( {\frac{n}{2}} \right) + n,\;n 1</script> <br />
根据这个式子，我们如何用归纳假设法，求出归并排序的时间复杂度？<br />
<span style="color: rgb(255, 255, 255);">文章来源：</span><a href="http://www.codelast.com/" target="_blank" rel="noopener noreferrer"><span style="color: rgb(255, 255, 255);">http://www.codelast.com/</span></a>&#8230; <a href="https://www.codelast.com/%e5%8e%9f%e5%88%9b-%e5%a6%82%e4%bd%95%e7%94%a8%e3%80%8c%e5%bd%92%e7%ba%b3%e5%81%87%e8%ae%be%e6%b3%95%e3%80%8d%e6%b1%82%e5%bd%92%e5%b9%b6%e6%8e%92%e5%ba%8f%e7%9a%84%e6%97%b6%e9%97%b4%e5%a4%8d/" class="read-more">Read More </a></p>]]></description>
										<content:encoded><![CDATA[<p>
分析归并排序算法的时间复杂度，可以根据算法的逻辑，分析每一个步骤的最坏情况，然后得到总体的时间复杂度；也可以利用数学中的『归纳假设法』，用几乎纯数学的方式来得到它的时间复杂度。而后者比前者好理解得多，所以，我认为要推导归并排序的时间复杂度的话，归纳假设的方法是不二之选。<br />
<span id="more-8322"></span><br />
<span style="background-color:#00ff00;">『1』</span>时间复杂度递推公式<br />
将待排序的数组记为a。假设这里是用递归的方式实现的归并排序（易于理解）。<br />
归并排序将a分为两半，分别排序，再把排序后的这两半归并为一个数组。对这两半，还是用归并排序的方法，把它们分别再分成两半来排序、归并。这样一直拆分下去，直到最后拆成的&ldquo;两半&rdquo;已经是两个单独的元素，就算是&ldquo;到头&rdquo;了（没得拆了）。<br />
因此，在每一次递归的过程中，需要做两个递归调用（分别排序拆成的那&ldquo;两半&rdquo;数组），以及一个归并操作。<br />
<span style="color: rgb(255, 255, 255);">文章来源：</span><a href="http://www.codelast.com/" target="_blank" rel="noopener noreferrer"><span style="color: rgb(255, 255, 255);">http://www.codelast.com/</span></a><br />
归并操作的时间复杂度是 <span class='MathJax_Preview'>\(O\left( n \right)\)</span><script type='math/tex'>O\left( n \right)</script> ，而两个递归调用的时间复杂度是多少呢？<br />
这里先假设一次递归调用的过程所耗费的时间是 <span class='MathJax_Preview'>\(t(n)\)</span><script type='math/tex'>t(n)</script> ，则在问题的规模减半后（数组拆成了两半，所以规模减半了），递归调用耗费的时间就是 <span class='MathJax_Preview'>\(t\left( {\frac{n}{2}} \right)\)</span><script type='math/tex'>t\left( {\frac{n}{2}} \right)</script> 了。<br />
因此，归并排序耗费的时间的递推公式就是：<br />
 <span class='MathJax_Preview'>\(t(n) = t\left( {\frac{n}{2}} \right) + t\left( {\frac{n}{2}} \right) + n = 2t\left( {\frac{n}{2}} \right) + n,\;n > 1\)</span><script type='math/tex'>t(n) = t\left( {\frac{n}{2}} \right) + t\left( {\frac{n}{2}} \right) + n = 2t\left( {\frac{n}{2}} \right) + n,\;n > 1</script> <br />
根据这个式子，我们如何用归纳假设法，求出归并排序的时间复杂度？<br />
<span style="color: rgb(255, 255, 255);">文章来源：</span><a href="http://www.codelast.com/" target="_blank" rel="noopener noreferrer"><span style="color: rgb(255, 255, 255);">http://www.codelast.com/</span></a><br />
<span style="background-color:#00ff00;">『2』</span>归纳<br />
归纳就是总结出归并排序的时间复杂度公式，说白了根据几个已知的计算结果来猜。<br />
根据前面的递推公式，我们可以计算出：</p>
<div>
	 <span class='MathJax_Preview'>\(t(2) = 2t(1) + 2 = 2 = 2 \cdot {\log _2}2\)</span><script type='math/tex'>t(2) = 2t(1) + 2 = 2 = 2 \cdot {\log _2}2</script> <br />
	 <span class='MathJax_Preview'>\(t(4) = 2t(2) + 4 = 8 = 4 \cdot {\log _2}4\)</span><script type='math/tex'>t(4) = 2t(2) + 4 = 8 = 4 \cdot {\log _2}4</script> <br />
	 <span class='MathJax_Preview'>\(t(8) = 2t(4) + 8 = 24 = 8 \cdot {\log _2}8\)</span><script type='math/tex'>t(8) = 2t(4) + 8 = 24 = 8 \cdot {\log _2}8</script> <br />
	计算到这里，规律已经非常明显了： <span class='MathJax_Preview'>\(t(n) = n{\log _2}n\)</span><script type='math/tex'>t(n) = n{\log _2}n</script> <br />
	我们知道，在描述算法复杂度的时候，对数的底数无关紧要，通常省略它，因此这里我们就记为： <span class='MathJax_Preview'>\(t(n) = n\log n\)</span><script type='math/tex'>t(n) = n\log n</script> <br />
	所以我们就归纳（也就是猜测）出了归并排序的时间复杂度。<br />
	<span style="color: rgb(255, 255, 255);">文章来源：</span><a href="http://www.codelast.com/" target="_blank" rel="noopener noreferrer"><span style="color: rgb(255, 255, 255);">http://www.codelast.com/</span></a><br />
	<span style="background-color:#00ff00;">『3』</span>假设 ＆ 证明<br />
	假设什么呢？<br />
	我们当然是要假设上面归纳出的时间复杂度公式是正确的。在这样的假设下，来看看可以怎样证明归并排序的时间复杂度确实是 <span class='MathJax_Preview'>\(O\left( {n\log n} \right)\)</span><script type='math/tex'>O\left( {n\log n} \right)</script> 。<br />
	由算法效率的定义，若一个算法的时间复杂度为 <span class='MathJax_Preview'>\(O\left( {n\log n} \right)\)</span><script type='math/tex'>O\left( {n\log n} \right)</script> ，则存在正常数 <span class='MathJax_Preview'>\(c\)</span><script type='math/tex'>c</script> 和 <span class='MathJax_Preview'>\(N\)</span><script type='math/tex'>N</script> ，使得 <span class='MathJax_Preview'>\(f(n) \le c\left( {n\log n} \right)\)</span><script type='math/tex'>f(n) \le c\left( {n\log n} \right)</script> 对所有 <span class='MathJax_Preview'>\(n \ge N\)</span><script type='math/tex'>n \ge N</script> 成立。那么，由上面的假设，可得：<br />
	 <span class='MathJax_Preview'>\(t(n) = 2t\left( {\frac{n}{2}} \right) + n \le c \cdot \left[ {\frac{n}{2}\log \left( {\frac{n}{2}} \right)} \right] + n\)</span><script type='math/tex'>t(n) = 2t\left( {\frac{n}{2}} \right) + n \le c \cdot \left[ {\frac{n}{2}\log \left( {\frac{n}{2}} \right)} \right] + n</script> <br />
	在这里，我们根据假设的正确的时间复杂度公式，用算法效率的定义，得到了上面的不等式，我们下面要做的，就是继续推导这个不等式，使之满足： <span class='MathJax_Preview'>\(t(n) \le c\cdot\left( {n\log n} \right)\)</span><script type='math/tex'>t(n) \le c\cdot\left( {n\log n} \right)</script> ，那么根据算法效率的定义，就可知归并排序算法的时间复杂度确实是 <span class='MathJax_Preview'>\(O\left( {n\log n} \right)\)</span><script type='math/tex'>O\left( {n\log n} \right)</script> 了。<br />
	<span style="color: rgb(255, 255, 255);">文章来源：</span><a href="http://www.codelast.com/" target="_blank" rel="noopener noreferrer"><span style="color: rgb(255, 255, 255);">http://www.codelast.com/</span></a><br />
	看推导：</p>
<div>
		 <span class='MathJax_Preview'>\(\begin{array}{l}t(n) = 2t\left( {\frac{n}{2}} \right) + n \le c \cdot \left[ {\frac{n}{2}\log \left( {\frac{n}{2}} \right)} \right] + n \le cn\log \left( {\frac{n}{2}} \right) + n\\ = cn(\log n - \log 2) + n = cn\log n - cn + n = cn\log n + (1 - c)n\end{array}\)</span><script type='math/tex'>\begin{array}{l}t(n) = 2t\left( {\frac{n}{2}} \right) + n \le c \cdot \left[ {\frac{n}{2}\log \left( {\frac{n}{2}} \right)} \right] + n \le cn\log \left( {\frac{n}{2}} \right) + n\\ = cn(\log n - \log 2) + n = cn\log n - cn + n = cn\log n + (1 - c)n\end{array}</script> <br />
		此时，我们只要取 <span class='MathJax_Preview'>\(c \ge 1\)</span><script type='math/tex'>c \ge 1</script> ，便可使得上面的式子 <span class='MathJax_Preview'>\( \le cn\log n\)</span><script type='math/tex'> \le cn\log n</script> ，即： <span class='MathJax_Preview'>\(t(n) \le c \cdot \left( {n\log n} \right)\)</span><script type='math/tex'>t(n) \le c \cdot \left( {n\log n} \right)</script> <br />
		所以到这里，我们就成功地利用假设，证明了归并排序的时间复杂度确实是 <span class='MathJax_Preview'>\(O\left( {n\log n} \right)\)</span><script type='math/tex'>O\left( {n\log n} \right)</script> 。</p>
<p style="font-size: 16px; margin: 5px 0px; clear: both; font-family: sans-serif;">
			<span style="color: rgb(255, 255, 255);">文章来源：</span><a href="https://www.codelast.com/" rel="noopener noreferrer" target="_blank"><span style="color: rgb(255, 255, 255);">https://www.codelast.com/</span></a><br />
			<span style="color: rgb(255, 0, 0);">➤➤</span>&nbsp;版权声明&nbsp;<span style="color: rgb(255, 0, 0);">➤➤</span>&nbsp;<br />
			转载需注明出处：<u><a href="https://www.codelast.com/" rel="noopener noreferrer" target="_blank"><em><span style="color: rgb(0, 0, 255);"><strong><span style="font-family: arial, helvetica, sans-serif;">codelast.com</span></strong></span></em></a></u>&nbsp;<br />
			感谢关注我的微信公众号（微信扫一扫）：</p>
<p style="border: 0px; font-size: 13px; margin: 0px 0px 9px; outline: 0px; padding: 0px; color: rgb(77, 77, 77);">
			<img decoding="async" alt="wechat qrcode of codelast" src="https://www.codelast.com/codelast_wechat_qr_code.jpg" style="width: 200px; height: 200px;" /></p>
</p></div>
</div>
]]></content:encoded>
					
					<wfw:commentRss>https://www.codelast.com/%e5%8e%9f%e5%88%9b-%e5%a6%82%e4%bd%95%e7%94%a8%e3%80%8c%e5%bd%92%e7%ba%b3%e5%81%87%e8%ae%be%e6%b3%95%e3%80%8d%e6%b1%82%e5%bd%92%e5%b9%b6%e6%8e%92%e5%ba%8f%e7%9a%84%e6%97%b6%e9%97%b4%e5%a4%8d/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
	</channel>
</rss>
