<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="3.10.0">Jekyll</generator><link href="https://forge-jian.github.io/feed.xml" rel="self" type="application/atom+xml" /><link href="https://forge-jian.github.io/" rel="alternate" type="text/html" /><updated>2026-02-26T08:59:05+00:00</updated><id>https://forge-jian.github.io/feed.xml</id><title type="html">Jian Shi’s Blog</title><subtitle>A Blog Record My Tech Life</subtitle><author><name>Jian Shi</name></author><entry><title type="html">字符串匹配算法</title><link href="https://forge-jian.github.io/algorithm/String-Matching-Algorithm/" rel="alternate" type="text/html" title="字符串匹配算法" /><published>2019-09-17T00:00:00+00:00</published><updated>2019-09-17T00:00:00+00:00</updated><id>https://forge-jian.github.io/algorithm/String-Matching-Algorithm</id><content type="html" xml:base="https://forge-jian.github.io/algorithm/String-Matching-Algorithm/"><![CDATA[<h1 id="string-matching-algorithm字符串匹配算法">String Matching Algorithm(字符串匹配算法)</h1>

<blockquote>
  <p>在编辑文本程序的过程中，我们经常需要在文本中找到某个模式的所有出现位置。有效地解决这个问题的算法叫做字符串匹配算法。我在此记录了3种常见的字符串匹配算法供自己留作记录参考，分别是从最简单的暴力求解的朴素算法入手，至两个优化过复杂度的算法Hospool和KMP。</p>
</blockquote>

<h2 id="naïve-pattern-searching-algorithm">Naïve Pattern Searching Algorithm</h2>
<blockquote>
  <p>一个简单的 Brute Force 的寻求子字符串的匹配解法。</p>
</blockquote>

<h3 id="1算法说明">1.算法说明</h3>
<p>在Text上不断滑动 Pattern，如果不匹配，继续滑动 Pattern 到下一个 Index，如果匹配，返回Text上第一个匹配到 Pattern 的起始位置。</p>

<h3 id="2算法表现">2.算法表现</h3>
<p>Text: 长度 N; Pattern: 长度 M; <br />
Worst Case: 总共比较次数为 ((N-M)+1)*M <br />
Average: <em>Θ(N * M)</em> <br /></p>

<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">public</span> <span class="kd">static</span> <span class="nc">List</span><span class="o">&lt;</span><span class="nc">Integer</span><span class="o">&gt;</span> <span class="nf">naiveMatching</span><span class="o">(</span><span class="nc">String</span> <span class="n">text</span><span class="o">,</span> <span class="nc">String</span> <span class="n">pattern</span><span class="o">)</span> <span class="o">{</span>
    <span class="nc">List</span><span class="o">&lt;</span><span class="nc">Integer</span><span class="o">&gt;</span> <span class="n">result</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">ArrayList</span><span class="o">&lt;&gt;();</span>
    <span class="c1">// 一个循环在Text上一个一个Index的进行滑动</span>
    <span class="k">for</span> <span class="o">(</span><span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="o">;</span> <span class="n">i</span> <span class="o">&lt;=</span> <span class="n">text</span><span class="o">.</span><span class="na">length</span><span class="o">()</span> <span class="o">-</span> <span class="n">pattern</span><span class="o">.</span><span class="na">length</span><span class="o">();</span> <span class="n">i</span><span class="o">++)</span> <span class="o">{</span>
        <span class="c1">// 在当前Index，检查Pattern是否匹配Text</span>
        <span class="k">for</span> <span class="o">(</span><span class="kt">int</span> <span class="n">j</span> <span class="o">=</span> <span class="mi">0</span><span class="o">;</span> <span class="n">j</span> <span class="o">&lt;</span> <span class="n">pattern</span><span class="o">.</span><span class="na">length</span><span class="o">();</span> <span class="n">j</span><span class="o">++)</span> <span class="o">{</span>
            <span class="k">if</span> <span class="o">(</span><span class="n">text</span><span class="o">.</span><span class="na">charAt</span><span class="o">(</span><span class="n">i</span> <span class="o">+</span> <span class="n">j</span><span class="o">)</span> <span class="o">!=</span> <span class="n">pattern</span><span class="o">.</span><span class="na">charAt</span><span class="o">(</span><span class="n">j</span><span class="o">))</span> <span class="k">break</span><span class="o">;</span>
            <span class="k">if</span> <span class="o">(</span><span class="n">j</span> <span class="o">==</span> <span class="n">pattern</span><span class="o">.</span><span class="na">length</span><span class="o">()</span> <span class="o">-</span> <span class="mi">1</span><span class="o">)</span> <span class="n">result</span><span class="o">.</span><span class="na">add</span><span class="o">(</span><span class="n">i</span><span class="o">);</span>
        <span class="o">}</span>
    <span class="o">}</span>
    <span class="k">return</span> <span class="n">result</span><span class="o">;</span>
<span class="o">}</span>
</code></pre></div></div>

<h2 id="boyermoorehorspool-algorithm-horspools-algorithm">Boyer–Moore–Horspool algorithm (Horspool’s algorithm)</h2>

<blockquote>
  <p>一个用空间换取时间来获取一个 Average-case Complexity O(n) 的子字符串匹配算法。</p>
</blockquote>

<h3 id="1算法说明-1">1.算法说明</h3>
<ol>
  <li>
    <p><strong>首先处理 Pattern，建立一个 Shift Table</strong></p>

    <ul>
      <li>
        <p>Shift Table 理论上应该包含所有字符，Java 用了Unicode 集，一个 char 可以包含65536个不同字符，一般情况，只做字母的匹配话，包含字母即可，我折中选取了 ASCII 表，使 Shift Table 包含128个元素，也方便了在 Java 中 char 直接转换为在 ASCII 中对应的 Index。</p>
      </li>
      <li>
        <p>对 Shift Table 中的元素（<strong>除最后一位末尾</strong>）移动距离的构建：
①非在 Pattern 中出现的 char，则移动位置为 Pattern 长度。
②在 Pattern 中出现的 char，根据当前 char 距离最后一个元素的距离决定，如果有重复的元素,则右边的元素覆盖左边的元素，以右边距离最后一个元素的距离为准。</p>
      </li>
      <li>
        <p>直观上对移动 Pattern 距离的理解，就是以 Pattern 末尾元素对应的 Text 中的元素 TAIL 为基准，
①如果 TAIL 没出现在 Pattern 末尾之前的元素里，则把整个 Pattern 往后移动整个 Pattern 的距离
②如果 TAIL 出现在 Pattern 末尾之前的元素里，则把 Pattern 移动到使最靠近末尾的和 TAIL 相同的元素和 TAIL 相对应的位置上。</p>
      </li>
    </ul>
  </li>
  <li>
    <p><strong>Pattern 的检索过程</strong>
首先将 Pattern 放在 Text 最开始位置，然后每次从 Pattern 的最右端（即末尾）开始进行匹配，如果不匹配，根据 Pattern 末尾元素对应的 Text 中的元素在 Shift Table 中的 Value 进行移动 Pattern.直到找到匹配位置，或者检索完整个 Text。</p>
  </li>
</ol>

<h3 id="2算法表现-1">2.算法表现</h3>

<p>Text: 长度 N; Pattern: 长度 M; <br />
Worst Case: <em>O(N * M)</em> Best Case: <em>O(N / M)</em> <br />
Average Case: <em>O(N)</em> <br /></p>

<p><strong>引用</strong></p>

<p><a href="https://www.youtube.com/watch?v=PHXAOKQk2dw">YouTube用户Mike Slade讲解</a> <br />
<a href="https://www.wikiwand.com/en/Boyer%E2%80%93Moore%E2%80%93Horspool_algorithm">Wikipidea Boyer–Moore–Horspool_algorithm</a></p>

<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">public</span> <span class="kd">static</span> <span class="nc">List</span><span class="o">&lt;</span><span class="nc">Integer</span><span class="o">&gt;</span> <span class="nf">holspoolMatching</span><span class="o">(</span><span class="nc">String</span> <span class="n">text</span><span class="o">,</span> <span class="nc">String</span> <span class="n">pattern</span><span class="o">)</span> <span class="o">{</span>
    <span class="nc">List</span><span class="o">&lt;</span><span class="nc">Integer</span><span class="o">&gt;</span> <span class="n">result</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">ArrayList</span><span class="o">&lt;&gt;();</span>
    <span class="c1">//构建移动Pattern距离的一个移位表，只考虑ASCII编码的128位</span>
    <span class="c1">//Java用了Unicode集，前128位即采用了ASCII编码</span>
    <span class="kt">int</span><span class="o">[]</span> <span class="n">shiftTable</span> <span class="o">=</span> <span class="n">buildShiftTable</span><span class="o">(</span><span class="n">pattern</span><span class="o">);</span>
    <span class="kt">int</span> <span class="n">searchIndex</span> <span class="o">=</span> <span class="mi">0</span><span class="o">;</span>
    <span class="k">while</span> <span class="o">(</span><span class="n">searchIndex</span> <span class="o">&lt;=</span> <span class="n">text</span><span class="o">.</span><span class="na">length</span><span class="o">()</span> <span class="o">-</span> <span class="n">pattern</span><span class="o">.</span><span class="na">length</span><span class="o">())</span> <span class="o">{</span>
        <span class="c1">//从pattern右侧开始往左侧匹配</span>
        <span class="kt">int</span> <span class="n">patternIndex</span> <span class="o">=</span> <span class="n">pattern</span><span class="o">.</span><span class="na">length</span><span class="o">()</span> <span class="o">-</span> <span class="mi">1</span><span class="o">;</span>
        <span class="k">while</span> <span class="o">(</span><span class="n">text</span><span class="o">.</span><span class="na">charAt</span><span class="o">(</span><span class="n">searchIndex</span> <span class="o">+</span> <span class="n">patternIndex</span><span class="o">)</span> <span class="o">==</span> <span class="n">pattern</span><span class="o">.</span><span class="na">charAt</span><span class="o">(</span><span class="n">patternIndex</span><span class="o">))</span> <span class="o">{</span>
            <span class="c1">//如果匹配到Pattern的头部，说明完全匹配，则返回Text中相对应的Index，</span>
            <span class="k">if</span> <span class="o">(</span><span class="n">patternIndex</span> <span class="o">==</span> <span class="mi">0</span><span class="o">)</span> <span class="n">result</span><span class="o">.</span><span class="na">add</span><span class="o">(</span><span class="n">searchIndex</span><span class="o">);</span>
            <span class="c1">//不断往左匹配</span>
            <span class="n">patternIndex</span><span class="o">--;</span>
        <span class="o">}</span>
        <span class="c1">//根据起始匹配位置（即Pattern最右侧匹配的对应)的那个Text中的char来决定右移的长度</span>
        <span class="n">searchIndex</span> <span class="o">+=</span> <span class="n">shiftTable</span><span class="o">[</span><span class="n">text</span><span class="o">.</span><span class="na">charAt</span><span class="o">(</span><span class="n">searchIndex</span> <span class="o">+</span> <span class="n">pattern</span><span class="o">.</span><span class="na">length</span><span class="o">()</span> <span class="o">-</span> <span class="mi">1</span><span class="o">)];</span>
    <span class="o">}</span>
    <span class="k">return</span> <span class="n">result</span><span class="o">;</span>
<span class="o">}</span>


<span class="cm">/**
 * 构建移动 Pattern 距离的一个移位表，只考虑 ASCII 编码的128位
 * Java 用了 Unicode 集，前128位即采用了 ASCII 编码
 *
 * @param pattern 需要匹配的子字符串
 * @return 根据Pattern来构建的Shift Table
 */</span>
<span class="kd">private</span> <span class="kd">static</span> <span class="kt">int</span><span class="o">[]</span> <span class="nf">buildShiftTable</span><span class="o">(</span><span class="nc">String</span> <span class="n">pattern</span><span class="o">)</span> <span class="o">{</span>
    <span class="kt">int</span><span class="o">[]</span> <span class="n">shiftTable</span> <span class="o">=</span> <span class="k">new</span> <span class="kt">int</span><span class="o">[</span><span class="mi">128</span><span class="o">];</span>
    <span class="c1">//非在Pattern中出现的char，则移动位置为Pattern长度</span>
    <span class="nc">Arrays</span><span class="o">.</span><span class="na">fill</span><span class="o">(</span><span class="n">shiftTable</span><span class="o">,</span> <span class="n">pattern</span><span class="o">.</span><span class="na">length</span><span class="o">());</span>
    <span class="c1">//将每个出现在Pattern中的char在数组中的位置里填充上移动距离(除最后一位)</span>
    <span class="k">for</span> <span class="o">(</span><span class="kt">int</span> <span class="n">j</span> <span class="o">=</span> <span class="mi">0</span><span class="o">;</span> <span class="n">j</span> <span class="o">&lt;</span> <span class="n">pattern</span><span class="o">.</span><span class="na">length</span><span class="o">()</span> <span class="o">-</span> <span class="mi">1</span><span class="o">;</span> <span class="n">j</span><span class="o">++)</span> <span class="o">{</span>
        <span class="c1">//char自动通过ASCII编码转码到对应的Int值，即shiftTable中对应Index</span>
        <span class="c1">//shift的距离根据当前char距离最后一个元素的距离决定，如果有重复的元素，则右边</span>
        <span class="c1">//的元素覆盖左边的元素，以右边距离最后一个元素的距离为准</span>
        <span class="n">shiftTable</span><span class="o">[</span><span class="n">pattern</span><span class="o">.</span><span class="na">charAt</span><span class="o">(</span><span class="n">j</span><span class="o">)]</span> <span class="o">=</span> <span class="o">(</span><span class="n">pattern</span><span class="o">.</span><span class="na">length</span><span class="o">()</span> <span class="o">-</span> <span class="mi">1</span><span class="o">)</span> <span class="o">-</span> <span class="n">j</span><span class="o">;</span>
    <span class="o">}</span>
    <span class="k">return</span> <span class="n">shiftTable</span><span class="o">;</span>
<span class="o">}</span>
</code></pre></div></div>

<h2 id="knuth-morris-prattkmp-algorithm">Knuth-Morris-Pratt(KMP) Algorithm</h2>
<blockquote>
  <p>此算法通过运用对这个词在不匹配时本身就包含足够的信息来确定下一个匹配将在哪里开始的发现，从而避免重新检查先前匹配的字符。</p>
</blockquote>

<h3 id="1算法说明-2">1.算法说明</h3>
<ol>
  <li>
    <p>首先 Pattern 和 Pattern 自己进行比较，来建立一个 Prefix Table，其中如何建立在核心解释中说明。</p>
  </li>
  <li>
    <p>然后 Text 和 Pattern 进行比较，通过刚建立的 Prefix Table，在当前位置不匹配的时候回退 Pattern，继续比较，直到匹配到完整的 Pattern。在 Text 和 Pattern 进行比较时，运用的回退思想和建立 Prefix Table 时的回退是一个原理，都是不断回退到次一级长度的最长前缀。这也是为什么两个函数的代码格式看起来几乎一样，这次相当于把整个 Pattern 当作了一个前缀，去匹配 Text, 在 Text中出现 Pattern 长度的后缀时候，则说明匹配到。</p>
  </li>
  <li>
    <p><strong>核心解释</strong><br />
创建最长前缀长度表的核心回退语句的示例分析，
Prefix Table 中的数字代表在字符串[0..i]中相匹配的前缀与后缀中，最长的字符串的长度。<br />
<strong>例子：<br />
下标 Index:           [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]<br />
子字符串 Pattern:     [a, b, a, b, z, a, b, a, b, a]<br />
最终 Prefix Table:     [0, 0, 1, 2, 0, 1, 2, 3, 4, 3]</strong></p>

    <p>前面的 Index 较好理解，主要考虑 Index=9 时候的最终结果为什么等于3来理解函数中嵌套在 for 循环中的 while 循环，从 Index=5 开始 maxPrefixLength=1，而后到 Index=8 为止，之间的元素都与前缀匹配，所以 maxPrefixLength=4, 然而 Index=9 时，与 Index=4 的前缀不匹配，则需要进行回退，接下来主要分析<strong>如何回退</strong>.</p>

    <ul>
      <li>
        <p>可以很明显的发现，在字符串 ababzabab(0-8) 中，后缀的最长前缀为abab(0-3)，然而当下一  个 Index 不匹配的时候，需要去找一个这样的新后缀，让这个后缀在当前范围内(0-8)有一个前缀，且对应的这个前缀(0-2) + 下一个 Index(3) 构成的新前缀(0-3)可以等于这个后缀(7-8) + Index(9) 构成的新后缀(7-9)。</p>
      </li>
      <li>
        <p>显而易见的，这个后缀越长越好，在例子，这个后缀为 Index7-8 构成的长度为2的后缀，也正好是次最长前缀长度。然而如果这个次最长前缀 + 新Index不符合要求，则再往下找新的更小的前缀，直到退到前缀长度为0，则下一个 Index 的 maxPrefixLength 从0再开始计算。</p>
      </li>
      <li>
        <p>最终，我们要用代码来快速的不断找次一级的最长前缀长度，当前例子中，Index0-8 之间，后缀的最长前缀为”abab”(0-3)，次一级为”ab”(0-2),再次一级为“”(0),可以看出次一级的前缀永远都是上一级的子集，即可以不断在上一级的前缀里找到下一级前缀，同时，在PrefixTable中，已经都存取了每一段子字符串的最长前缀的长度：</p>

        <p>比如 ababzabab(0-8), 在 Index=8 的 PrefixTable 中，最长前缀长度为4(abab),</p>

        <p>往前找 abab(0-3), 在 Index=3 的 PrefixTable 中，最长前缀长度为2(ab),</p>

        <p>往前找 ab(0-1), 在 Index=1 的 PrefixTable 中，最长前缀长度为0,</p>

        <p>所以，在代码中，如果字符串的下一个 Index 不符合 Prefix 的下一个 Index，则通过 PrefixTable 中记录的最长前缀长度不断的回退，直到匹配要求。</p>
      </li>
    </ul>
  </li>
</ol>

<h3 id="2算法表现-2">2.算法表现</h3>
<p>Text: 长度 N; Pattern: 长度 M; <br />
<em>O(N+M)</em> <br />
建立最长前缀长度表<em>O(M)</em>, 搜索<em>O(N)</em> <br /></p>

<p><strong>引用</strong></p>

<p><a href="https://www.zhihu.com/question/21923021">知乎用户逍遥行答案</a><br />
算法导论</p>

<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">public</span> <span class="kd">static</span> <span class="nc">List</span><span class="o">&lt;</span><span class="nc">Integer</span><span class="o">&gt;</span> <span class="nf">KMPMatching</span><span class="o">(</span><span class="nc">String</span> <span class="n">text</span><span class="o">,</span> <span class="nc">String</span> <span class="n">pattern</span><span class="o">)</span> <span class="o">{</span>
    <span class="nc">List</span><span class="o">&lt;</span><span class="nc">Integer</span><span class="o">&gt;</span> <span class="n">result</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">ArrayList</span><span class="o">&lt;&gt;();</span>
    <span class="kt">int</span><span class="o">[]</span> <span class="n">prefixTable</span> <span class="o">=</span> <span class="n">buildPrefixTable</span><span class="o">(</span><span class="n">pattern</span><span class="o">);</span>
    <span class="kt">int</span> <span class="n">matchedCharacter</span> <span class="o">=</span> <span class="mi">0</span><span class="o">;</span>
    <span class="k">for</span> <span class="o">(</span><span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="o">;</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="n">text</span><span class="o">.</span><span class="na">length</span><span class="o">();</span> <span class="n">i</span><span class="o">++)</span> <span class="o">{</span>
        <span class="c1">//不匹配，根据prefixTable回退到相对应的位置，</span>
        <span class="k">while</span> <span class="o">(</span><span class="n">matchedCharacter</span> <span class="o">&gt;</span> <span class="mi">0</span> <span class="o">&amp;&amp;</span> <span class="n">pattern</span><span class="o">.</span><span class="na">charAt</span><span class="o">(</span><span class="n">matchedCharacter</span><span class="o">)</span> <span class="o">!=</span> <span class="n">text</span><span class="o">.</span><span class="na">charAt</span><span class="o">(</span><span class="n">i</span><span class="o">))</span> <span class="o">{</span>
            <span class="n">matchedCharacter</span> <span class="o">=</span> <span class="n">prefixTable</span><span class="o">[</span><span class="n">matchedCharacter</span> <span class="o">-</span> <span class="mi">1</span><span class="o">];</span> <span class="c1">//核心回退语句</span>
        <span class="o">}</span>
        <span class="c1">//匹配，匹配数量+1</span>
        <span class="k">if</span> <span class="o">(</span><span class="n">pattern</span><span class="o">.</span><span class="na">charAt</span><span class="o">(</span><span class="n">matchedCharacter</span><span class="o">)</span> <span class="o">==</span> <span class="n">text</span><span class="o">.</span><span class="na">charAt</span><span class="o">(</span><span class="n">i</span><span class="o">))</span> <span class="o">{</span>
            <span class="n">matchedCharacter</span><span class="o">++;</span>
        <span class="o">}</span>
        <span class="k">if</span> <span class="o">(</span><span class="n">matchedCharacter</span> <span class="o">==</span> <span class="n">pattern</span><span class="o">.</span><span class="na">length</span><span class="o">())</span> <span class="o">{</span>
            <span class="n">result</span><span class="o">.</span><span class="na">add</span><span class="o">(</span><span class="n">i</span> <span class="o">-</span> <span class="n">matchedCharacter</span> <span class="o">+</span> <span class="mi">1</span><span class="o">);</span>
            <span class="n">matchedCharacter</span> <span class="o">=</span> <span class="n">prefixTable</span><span class="o">[</span><span class="n">matchedCharacter</span> <span class="o">-</span> <span class="mi">1</span><span class="o">];</span>
        <span class="o">}</span>
    <span class="o">}</span>
    <span class="k">return</span> <span class="n">result</span><span class="o">;</span>
<span class="o">}</span>
    
<span class="kd">private</span> <span class="kd">static</span> <span class="kt">int</span><span class="o">[]</span> <span class="nf">buildPrefixTable</span><span class="o">(</span><span class="nc">String</span> <span class="n">pattern</span><span class="o">)</span> <span class="o">{</span>
    <span class="kt">int</span><span class="o">[]</span> <span class="n">prefixTable</span> <span class="o">=</span> <span class="k">new</span> <span class="kt">int</span><span class="o">[</span><span class="n">pattern</span><span class="o">.</span><span class="na">length</span><span class="o">()];</span>
    <span class="kt">int</span> <span class="n">maxPrefixLength</span> <span class="o">=</span> <span class="mi">0</span><span class="o">;</span>
    <span class="c1">//遍历Pattern，对每一个Char创建一个对应的最长前缀长度表</span>
    <span class="k">for</span> <span class="o">(</span><span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">1</span><span class="o">;</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="n">prefixTable</span><span class="o">.</span><span class="na">length</span><span class="o">;</span> <span class="n">i</span><span class="o">++)</span> <span class="o">{</span>
        <span class="k">while</span> <span class="o">(</span><span class="n">maxPrefixLength</span> <span class="o">&gt;</span> <span class="mi">0</span> <span class="o">&amp;&amp;</span> <span class="n">pattern</span><span class="o">.</span><span class="na">charAt</span><span class="o">(</span><span class="n">maxPrefixLength</span><span class="o">)</span> <span class="o">!=</span> <span class="n">pattern</span><span class="o">.</span><span class="na">charAt</span><span class="o">(</span><span class="n">i</span><span class="o">))</span> <span class="o">{</span>
            <span class="c1">//当前index的char和prefix的char对应不上，则不断去找去掉当前位置得char的</span>
            <span class="c1">//之前的所有的text的后缀的“次一级最长前缀长度”，直到</span>
            <span class="c1">//①Length为0，从头再开始匹配，</span>
            <span class="c1">//②匹配到相对应的prefix，往下运行。具体可以看例子来理解这句话</span>
            <span class="n">maxPrefixLength</span> <span class="o">=</span> <span class="n">prefixTable</span><span class="o">[</span><span class="n">maxPrefixLength</span> <span class="o">-</span> <span class="mi">1</span><span class="o">];</span>    <span class="c1">//核心回退语句</span>
        <span class="o">}</span>
        <span class="k">if</span> <span class="o">(</span><span class="n">pattern</span><span class="o">.</span><span class="na">charAt</span><span class="o">(</span><span class="n">maxPrefixLength</span><span class="o">)</span> <span class="o">==</span> <span class="n">pattern</span><span class="o">.</span><span class="na">charAt</span><span class="o">(</span><span class="n">i</span><span class="o">))</span> <span class="o">{</span>
            <span class="n">maxPrefixLength</span><span class="o">++;</span>
        <span class="o">}</span>
        <span class="n">prefixTable</span><span class="o">[</span><span class="n">i</span><span class="o">]</span> <span class="o">=</span> <span class="n">maxPrefixLength</span><span class="o">;</span>
    <span class="o">}</span>
    <span class="k">return</span> <span class="n">prefixTable</span><span class="o">;</span>
<span class="o">}</span>    
</code></pre></div></div>]]></content><author><name>Jian Shi</name></author><category term="Algorithm" /><category term="Algorithm" /><category term="Java" /><category term="String" /><summary type="html"><![CDATA[String Matching Algorithm(字符串匹配算法)]]></summary></entry><entry><title type="html">排序算法(比较排序)</title><link href="https://forge-jian.github.io/algorithm/Sorting-Algorithm-Comparison-Sorts/" rel="alternate" type="text/html" title="排序算法(比较排序)" /><published>2019-08-12T00:00:00+00:00</published><updated>2019-08-12T00:00:00+00:00</updated><id>https://forge-jian.github.io/algorithm/Sorting-Algorithm-Comparison-Sorts</id><content type="html" xml:base="https://forge-jian.github.io/algorithm/Sorting-Algorithm-Comparison-Sorts/"><![CDATA[<h1 id="sorting-algorithm---comparison-sorts">Sorting Algorithm - Comparison Sorts</h1>

<blockquote>
  <p>比较排序 (<a href="https://www.wikiwand.com/en/Comparison_sort">Comparison Sorts</a>) 是排序算法的一种，通过一个抽象的内容比较操作（通常是“小于或等于”操作或者一个 <a href="https://www.wikiwand.com/en/Three-way_comparison">three-way comparison</a>）来确定两个元素中哪个应该放在序列前面。</p>
</blockquote>

<h2 id="properties3个基础属性">Properties(3个基础属性)</h2>

<ul>
  <li>
    <p>In-place: It does not require additional memory (except a few units of memory). (基本上不需要额外辅助的数据结构,然而,允许少量额外的辅助变量来转换数据)</p>
  </li>
  <li>Stable: It preserves the relative order of elements that have identical keys. (原本有相等键值的纪录维持相对次序。也就是如果一个排序算法是<strong>稳定</strong>的，当有两个相等键值的纪录<strong>R</strong>和<strong>S</strong>，且在原本的串列中<strong>R</strong>出现在<strong>S</strong>之前，在排序过的串列中<strong>R</strong>也将会是在<strong>S</strong>之前。)</li>
  <li>Input-insensitive: Its running time is fairly independent of input properties other than size</li>
</ul>

<h2 id="summary总结">Summary(总结)</h2>

<table>
  <thead>
    <tr>
      <th style="text-align: right"> </th>
      <th style="text-align: center">In-place</th>
      <th style="text-align: center">Stable</th>
      <th style="text-align: center">Worst-case</th>
      <th style="text-align: center">Average-case</th>
      <th style="text-align: center">Best-case</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td style="text-align: right">Selection Sort</td>
      <td style="text-align: center">√</td>
      <td style="text-align: center">×</td>
      <td style="text-align: center">О(<em>n</em><sup>2</sup>)</td>
      <td style="text-align: center">О(<em>n</em><sup>2</sup>)</td>
      <td style="text-align: center">О(<em>n</em><sup>2</sup>)</td>
    </tr>
    <tr>
      <td style="text-align: right">Insertion Sort</td>
      <td style="text-align: center">√</td>
      <td style="text-align: center">√</td>
      <td style="text-align: center">О(<em>n</em><sup>2</sup>)</td>
      <td style="text-align: center">О(<em>n</em><sup>2</sup>)</td>
      <td style="text-align: center">О(<em>n</em>)</td>
    </tr>
    <tr>
      <td style="text-align: right">Shell Sort</td>
      <td style="text-align: center">√</td>
      <td style="text-align: center">×</td>
      <td style="text-align: center">О(<em>n</em><sup>2</sup>)</td>
      <td style="text-align: center">Depends</td>
      <td style="text-align: center">O(<em>n</em> log <em>n</em>)</td>
    </tr>
    <tr>
      <td style="text-align: right">Heap Sort</td>
      <td style="text-align: center">√</td>
      <td style="text-align: center">×</td>
      <td style="text-align: center">O(<em>n</em> log <em>n</em>)</td>
      <td style="text-align: center">O(<em>n</em> log <em>n</em>)</td>
      <td style="text-align: center">O(<em>n</em> log <em>n</em>) (distinct keys)</td>
    </tr>
    <tr>
      <td style="text-align: right">Quick Sort</td>
      <td style="text-align: center">√</td>
      <td style="text-align: center">×</td>
      <td style="text-align: center">О(<em>n</em><sup>2</sup>)</td>
      <td style="text-align: center">O(<em>n</em> log <em>n</em>)</td>
      <td style="text-align: center">O(<em>n</em> log <em>n</em>)</td>
    </tr>
    <tr>
      <td style="text-align: right">Merge Sort</td>
      <td style="text-align: center">×</td>
      <td style="text-align: center">√</td>
      <td style="text-align: center">O(<em>n</em> log <em>n</em>)</td>
      <td style="text-align: center">O(<em>n</em> log <em>n</em>)</td>
      <td style="text-align: center">O(<em>n</em> log <em>n</em>)</td>
    </tr>
  </tbody>
</table>

<p><em>注：附Wikipedia中的<a href="https://www.wikiwand.com/en/Sorting_algorithm#/Comparison_sorts">Comparison Sorts的表格的链接</a> (更加全面详细)</em></p>

<h2 id="selection-sort选择排序">Selection Sort(选择排序)</h2>

<p>排序数列分为2部分，①已排序的部分和②未排序的部分，从index = 0开始，总是选择(Select) ②未排序部分的最小(大)值放到①已排序部分的末端，直至index = array.length - 1，完成排序。</p>

<table>
  <thead>
    <tr>
      <th style="text-align: left">In-place</th>
      <th>Stable</th>
      <th>Worst-case</th>
      <th>Average-case</th>
      <th>Best-case</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td style="text-align: left">√</td>
      <td>×</td>
      <td>О(<em>n</em><sup>2</sup>)</td>
      <td>О(<em>n</em><sup>2</sup>)</td>
      <td>О(<em>n</em><sup>2</sup>)</td>
    </tr>
  </tbody>
</table>

<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">public</span> <span class="kd">static</span> <span class="kt">void</span> <span class="nf">selectionSort</span><span class="o">(</span><span class="kt">int</span><span class="o">[]</span> <span class="n">arr</span><span class="o">)</span> <span class="o">{</span>    
    <span class="kt">int</span> <span class="n">length</span> <span class="o">=</span> <span class="n">arr</span><span class="o">.</span><span class="na">length</span><span class="o">;</span>    
    <span class="kt">int</span> <span class="n">min</span><span class="o">;</span>    
    <span class="k">for</span> <span class="o">(</span><span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="o">;</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="n">length</span> <span class="o">-</span> <span class="mi">1</span><span class="o">;</span> <span class="n">i</span><span class="o">++)</span> <span class="o">{</span>        
        <span class="n">min</span> <span class="o">=</span> <span class="n">i</span><span class="o">;</span>        
        <span class="c1">//找到并选择(select)最小的Index        </span>
        <span class="k">for</span> <span class="o">(</span><span class="kt">int</span> <span class="n">k</span> <span class="o">=</span> <span class="n">i</span> <span class="o">+</span> <span class="mi">1</span><span class="o">;</span> <span class="n">k</span> <span class="o">&lt;</span> <span class="n">length</span><span class="o">;</span> <span class="n">k</span><span class="o">++)</span> <span class="o">{</span>            
            <span class="k">if</span> <span class="o">(</span><span class="n">arr</span><span class="o">[</span><span class="n">k</span><span class="o">]</span> <span class="o">&lt;</span> <span class="n">arr</span><span class="o">[</span><span class="n">min</span><span class="o">])</span> <span class="o">{</span>                
                <span class="n">min</span> <span class="o">=</span> <span class="n">k</span><span class="o">;</span>            
            <span class="o">}</span>        
        <span class="o">}</span>        
        <span class="c1">//交换 arr[i] 和 arr[min]        </span>
        <span class="kt">int</span> <span class="n">temp</span> <span class="o">=</span> <span class="n">arr</span><span class="o">[</span><span class="n">i</span><span class="o">];</span>        
        <span class="n">arr</span><span class="o">[</span><span class="n">i</span><span class="o">]</span> <span class="o">=</span> <span class="n">arr</span><span class="o">[</span><span class="n">min</span><span class="o">];</span>        
        <span class="n">arr</span><span class="o">[</span><span class="n">min</span><span class="o">]</span> <span class="o">=</span> <span class="n">temp</span><span class="o">;</span>    
    <span class="o">}</span>
<span class="o">}</span>
</code></pre></div></div>

<h2 id="insertion-sort插入排序">Insertion Sort(插入排序)</h2>

<p>排序数列分为2部分，①已排序的部分和②未排序的部分，从index = 1开始，总是将当前index的item插入(insert)到①已排序部分相对应的位置，直至index = array.length - 1，完成排序。</p>

<p>对<strong>小</strong>的Array较好（比如几百个元素）</p>

<table>
  <thead>
    <tr>
      <th>In-place</th>
      <th>Stable</th>
      <th>Worst-case</th>
      <th>Average-case</th>
      <th>Best-case</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>√</td>
      <td>√</td>
      <td>О(<em>n</em><sup>2</sup>)</td>
      <td>О(<em>n</em><sup>2</sup>)</td>
      <td>О(<em>n</em>)</td>
    </tr>
  </tbody>
</table>

<p><em>注：最好情况的 О( n )是在输入数组基本就是已排序的状态下，比如说用别的高效率的排序算法先排序一个混乱数组到差不多排序的状态下，让Insertion Sort接手继续排序。</em></p>

<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">public</span> <span class="kd">static</span> <span class="kt">void</span> <span class="nf">insertionSort</span><span class="o">(</span><span class="kt">int</span><span class="o">[]</span> <span class="n">arr</span><span class="o">)</span> <span class="o">{</span>
    <span class="kt">int</span> <span class="n">length</span> <span class="o">=</span> <span class="n">arr</span><span class="o">.</span><span class="na">length</span><span class="o">;</span>
    <span class="k">for</span> <span class="o">(</span><span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">1</span><span class="o">;</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="n">length</span><span class="o">;</span> <span class="n">i</span><span class="o">++)</span> <span class="o">{</span>
        <span class="kt">int</span> <span class="n">item</span> <span class="o">=</span> <span class="n">arr</span><span class="o">[</span><span class="n">i</span><span class="o">];</span>
        <span class="kt">int</span> <span class="n">k</span> <span class="o">=</span> <span class="n">i</span> <span class="o">-</span> <span class="mi">1</span><span class="o">;</span>
        <span class="c1">//把比当前item小的items都后移一位</span>
        <span class="k">while</span> <span class="o">(</span><span class="n">k</span> <span class="o">&gt;=</span> <span class="mi">0</span> <span class="o">&amp;&amp;</span> <span class="n">item</span> <span class="o">&lt;</span> <span class="n">arr</span><span class="o">[</span><span class="n">k</span><span class="o">])</span> <span class="o">{</span>
            <span class="n">arr</span><span class="o">[</span><span class="n">k</span> <span class="o">+</span> <span class="mi">1</span><span class="o">]</span> <span class="o">=</span> <span class="n">arr</span><span class="o">[</span><span class="n">k</span><span class="o">];</span>
            <span class="n">k</span><span class="o">--;</span>
        <span class="o">}</span>
        <span class="c1">//插入(Insert)当前item</span>
        <span class="n">arr</span><span class="o">[</span><span class="n">k</span> <span class="o">+</span> <span class="mi">1</span><span class="o">]</span> <span class="o">=</span> <span class="n">item</span><span class="o">;</span>
    <span class="o">}</span>
<span class="o">}</span>
</code></pre></div></div>

<h2 id="shell-sort希尔排序">Shell Sort(希尔排序)</h2>

<p>Insertion Sort的改进版本，设置一连串的Gap序列值(最后的Gap为1)，对数组的第 index + k * Gap  (0 &lt;= index &lt; Gap, k*Gap &lt; array.length, k ∈ {0,1,2…}) 项组成的多个相对应的数组进行Insertion Sort，逐渐使Gap至1，对最后Gap为1的数组进行一次Insertion Sort，完成排序。</p>

<p>例子：假设有数组为 [ 13 14 94 33 82 25 59 94 65 23 45 27 73 25 39 10 ]  (引用自<a href="https://www.wikiwand.com/zh-cn/%E5%B8%8C%E5%B0%94%E6%8E%92%E5%BA%8F">Wikipedia</a>)</p>

<p>①Gap = 5 (每组都做一次Insertion Sort)</p>

<p>第[0,5,10,15] 为一组-&gt;即[13,25,45,10]为一组-&gt;排序后[10,13,25,45]</p>

<p>第[1,6,11]为一组       -&gt;即[14,59,27]为一组     -&gt;排序后[14,27,59]</p>

<p>第[2,7,12]为一组       -&gt;即[94,94,73]为一组     -&gt;排序后[73,94,94]</p>

<p>第[3,8,13]为一组       -&gt;即[33,65,25]为一组     -&gt;排序后[25,33,65]</p>

<p>第[4,9,14]为一组       -&gt;即[82,23,39]为一组     -&gt;排序后[23,39,82]</p>

<p>-&gt;第一轮Gap=5结果为[10,14,73,25,23,13,27,94,33,39,25,59,94,65,82,45]</p>

<p>②Gap = 3</p>

<p>第[0,3,6,9,12,15] 为一组-&gt;即[10,25,27,39,94,45]为一组-&gt;排序后[10,25,27,39,45,94]</p>

<p>第[1,4,7,10,13]为一组    -&gt;即[14,23,94,25,65]为一组     -&gt;排序后[14,23,25,65,94]</p>

<p>第[2,5,8,11,14]为一组    -&gt;即[73,13,33,59,82]为一组     -&gt;排序后[13,33,59,73,92]</p>

<p>-&gt;第二轮Gap=3结果为[10,14,13,25,23,33,27,25,59,39,65,73,45,94,92,94]</p>

<p>③Gap = 1 (等同于Insertion Sort)</p>

<p>-&gt;最终结果为[10,13,14,23,25,25,27,33,39,45,59,65,73,92,94,94]</p>

<table>
  <thead>
    <tr>
      <th>In-place</th>
      <th>Stable</th>
      <th>Worst-case</th>
      <th>Average-case</th>
      <th>Best-case</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>√</td>
      <td>×</td>
      <td>О(<em>n</em><sup>2</sup>)</td>
      <td>Depends</td>
      <td>O(<em>n</em> log <em>n</em>)</td>
    </tr>
  </tbody>
</table>

<p><em>注：Gap序列的选取决定了Shell Sort的排序速度和时间复杂度，一个好的Gap序列有助于提高效率(但选取好的Gap序列很难)</em></p>

<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cm">/**
    * 希尔排序利用 gap sequence 为 length/2, length/4 ... 1
    */</span>
<span class="kd">public</span> <span class="kd">static</span> <span class="kt">void</span> <span class="nf">shellSort</span><span class="o">(</span><span class="kt">int</span><span class="o">[]</span> <span class="n">arr</span><span class="o">)</span> <span class="o">{</span>
    <span class="kt">int</span> <span class="n">length</span> <span class="o">=</span> <span class="n">arr</span><span class="o">.</span><span class="na">length</span><span class="o">;</span>
    <span class="c1">//从数组长度/2的Gap开始, 减小到Gap = 1</span>
    <span class="k">for</span> <span class="o">(</span><span class="kt">int</span> <span class="n">gap</span> <span class="o">=</span> <span class="n">length</span> <span class="o">/</span> <span class="mi">2</span><span class="o">;</span> <span class="n">gap</span> <span class="o">&gt;</span> <span class="mi">0</span><span class="o">;</span> <span class="n">gap</span> <span class="o">/=</span> <span class="mi">2</span><span class="o">)</span> <span class="o">{</span>
        <span class="c1">//相当于Insertion Sort从第2个元素开始insert,</span>
        <span class="c1">//Shell Sort从第gap个元素开始insert</span>
        <span class="k">for</span> <span class="o">(</span><span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="n">gap</span><span class="o">;</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="n">length</span><span class="o">;</span> <span class="n">i</span><span class="o">++)</span> <span class="o">{</span>

            <span class="kt">int</span> <span class="n">temp</span> <span class="o">=</span> <span class="n">arr</span><span class="o">[</span><span class="n">i</span><span class="o">];</span>

            <span class="c1">//相当于Insertion Sort比较当前的item和之前排序过的items</span>
            <span class="c1">//小于,则把之前的元素后移gap位(Insertion Sort是1位)</span>
            <span class="kt">int</span> <span class="n">j</span><span class="o">;</span>
            <span class="k">for</span> <span class="o">(</span><span class="n">j</span> <span class="o">=</span> <span class="n">i</span><span class="o">;</span> <span class="n">j</span> <span class="o">&gt;=</span> <span class="n">gap</span> <span class="o">&amp;&amp;</span> <span class="n">arr</span><span class="o">[</span><span class="n">j</span> <span class="o">-</span> <span class="n">gap</span><span class="o">]</span> <span class="o">&gt;</span> <span class="n">temp</span><span class="o">;</span> <span class="n">j</span> <span class="o">-=</span> <span class="n">gap</span><span class="o">)</span> <span class="o">{</span>
                <span class="n">arr</span><span class="o">[</span><span class="n">j</span><span class="o">]</span> <span class="o">=</span> <span class="n">arr</span><span class="o">[</span><span class="n">j</span> <span class="o">-</span> <span class="n">gap</span><span class="o">];</span>
            <span class="o">}</span>
            <span class="c1">//把当前item 插入正确的位置</span>
            <span class="n">arr</span><span class="o">[</span><span class="n">j</span><span class="o">]</span> <span class="o">=</span> <span class="n">temp</span><span class="o">;</span>
        <span class="o">}</span>
    <span class="o">}</span>
<span class="o">}</span>
</code></pre></div></div>

<h2 id="heap-sort堆排序">Heap Sort(堆排序)</h2>

<p>堆排序（原地）是运用了堆的性质，基本思想是，给定一个未排序的数组 <strong>H</strong> [1…n], ①把 <strong>H</strong> 转化为一个最大或最小堆(利用sift down操作的时间复杂度是О(<em>n</em>))，②执行弹出操作n-1次(每次弹出操作的时间复杂度是O( log <em>n</em>) ，具体操作是将堆顶元素和堆尾元素交换位置，堆大小-1，对新的堆顶元素进行sift down操作致相对应的位置，在n-1次后原数组即排序完成)</p>

<p>小顶堆生成降序排列，大顶堆生成升序排序。</p>

<ul>
  <li>对①操作时间复杂度О(<em>n</em>)的证明:</li>
</ul>

<p>为简便化，假设当前堆为一颗完全二叉树，则节点总数 <em>n=2<sup>(h+1)</sup> -1</em></p>

<p>其中h为height高度, root 为 height h, leaves为 height 0.</p>

<p>下列式子是 sift down 操作所需要的上限(worst-case):</p>

\[\sum^{h}_{i=1}\ \sum^{}_{nodes\:at\:hight\:i}{i} = \sum^{h}_{i=1}{i*2^{h-i}} = 2^{h+1}-h-2\]

<p>对height i 的每一个node它最糟糕的sift down就是被移动到height 0，即对height i 的 nodes来说，worst-case就是移动 i 次，height为h，即产生等式左侧的上限公式,可有数学归纳法简单得出右侧等式。</p>

<p>注意到，<em>2<sup>h+1</sup> - h - 2 &lt; 2<sup>(h+1)</sup> -1 = n</em> ,所以，最多是linear的 sift down操作，每一个sift down 操作又是比较了2个key，所以比较操作也是linear的。因此①的建堆操作是О(<em>n</em>)的时间复杂度。</p>

<table>
  <thead>
    <tr>
      <th>In-place</th>
      <th>Stable</th>
      <th>Worst-case</th>
      <th>Average-case</th>
      <th>Best-case</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>√</td>
      <td>×</td>
      <td>O(<em>n</em> log <em>n</em>)</td>
      <td>O(<em>n</em> log <em>n</em>)</td>
      <td>O(<em>n</em> log <em>n</em>)(distinct keys)</td>
    </tr>
  </tbody>
</table>

<p><em>注：Java中的PriorityQueue不指定Comparator时默认为最小堆，可学习源码。</em></p>

<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cm">/**
 * 基于最大堆的堆排序
 */</span>
<span class="kd">public</span> <span class="kd">static</span> <span class="kt">void</span> <span class="nf">heapSort</span><span class="o">(</span><span class="kt">int</span><span class="o">[]</span> <span class="n">arr</span><span class="o">)</span> <span class="o">{</span>
    <span class="kt">int</span> <span class="n">size</span> <span class="o">=</span> <span class="n">arr</span><span class="o">.</span><span class="na">length</span><span class="o">;</span>
    <span class="c1">//建立一个最大堆</span>
    <span class="k">for</span> <span class="o">(</span><span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="n">arr</span><span class="o">.</span><span class="na">length</span> <span class="o">/</span> <span class="mi">2</span> <span class="o">-</span> <span class="mi">1</span><span class="o">;</span> <span class="n">i</span> <span class="o">&gt;=</span> <span class="mi">0</span><span class="o">;</span> <span class="n">i</span><span class="o">--)</span> <span class="o">{</span>
        <span class="n">siftDown</span><span class="o">(</span><span class="n">arr</span><span class="o">,</span> <span class="n">i</span><span class="o">,</span> <span class="n">size</span><span class="o">);</span>
    <span class="o">}</span>
    <span class="c1">//不断交换heap头和尾的数值，因为是最大堆，最终排序为从小到大</span>
    <span class="k">while</span> <span class="o">(</span><span class="n">size</span> <span class="o">&gt;</span> <span class="mi">0</span><span class="o">)</span> <span class="o">{</span>
        <span class="kt">int</span> <span class="n">temp</span> <span class="o">=</span> <span class="n">arr</span><span class="o">[</span><span class="mi">0</span><span class="o">];</span>
        <span class="n">arr</span><span class="o">[</span><span class="mi">0</span><span class="o">]</span> <span class="o">=</span> <span class="n">arr</span><span class="o">[</span><span class="n">size</span> <span class="o">-</span> <span class="mi">1</span><span class="o">];</span>
        <span class="n">arr</span><span class="o">[</span><span class="n">size</span> <span class="o">-</span> <span class="mi">1</span><span class="o">]</span> <span class="o">=</span> <span class="n">temp</span><span class="o">;</span>
        <span class="n">size</span><span class="o">--;</span>
        <span class="c1">//重新让arr符合heap的性质，让交换上来的第一位元素下沉</span>
        <span class="n">siftDown</span><span class="o">(</span><span class="n">arr</span><span class="o">,</span> <span class="mi">0</span><span class="o">,</span> <span class="n">size</span><span class="o">);</span>
    <span class="o">}</span>
<span class="o">}</span>
    
<span class="cm">/**
 * 存在一个Parent节点的值小于任一Child节点，就让它Sift Down，直到符合堆的性质（最大堆）
 *
 * @param heap     存放堆的array
 * @param keyIndex 当前要处理的Parent节点的Index
 * @param heapSize Heap的大小
 */</span>
<span class="kd">private</span> <span class="kd">static</span> <span class="kt">void</span> <span class="nf">siftDown</span><span class="o">(</span><span class="kt">int</span><span class="o">[]</span> <span class="n">heap</span><span class="o">,</span> <span class="kt">int</span> <span class="n">keyIndex</span><span class="o">,</span> <span class="kt">int</span> <span class="n">heapSize</span><span class="o">)</span> <span class="o">{</span>
    <span class="kt">int</span> <span class="n">keyValue</span> <span class="o">=</span> <span class="n">heap</span><span class="o">[</span><span class="n">keyIndex</span><span class="o">];</span>
    <span class="kt">boolean</span> <span class="n">isHeap</span> <span class="o">=</span> <span class="kc">false</span><span class="o">;</span>
    <span class="k">while</span> <span class="o">(!</span><span class="n">isHeap</span> <span class="o">&amp;&amp;</span> <span class="n">keyIndex</span> <span class="o">&lt;</span> <span class="n">heapSize</span> <span class="o">/</span> <span class="mi">2</span><span class="o">)</span> <span class="o">{</span>
        <span class="c1">//左孩子的index</span>
        <span class="kt">int</span> <span class="n">childIndex</span> <span class="o">=</span> <span class="mi">2</span> <span class="o">*</span> <span class="n">keyIndex</span> <span class="o">+</span> <span class="mi">1</span><span class="o">;</span>
        <span class="c1">//如果有右孩子的情况</span>
        <span class="k">if</span> <span class="o">(</span><span class="n">childIndex</span> <span class="o">&lt;</span> <span class="n">heapSize</span> <span class="o">-</span> <span class="mi">1</span><span class="o">)</span> <span class="o">{</span>
            <span class="c1">//比较两个child值的大小，把index值设为大的那个（最大堆中）</span>
            <span class="k">if</span> <span class="o">(</span><span class="n">heap</span><span class="o">[</span><span class="n">childIndex</span><span class="o">]</span> <span class="o">&lt;</span> <span class="n">heap</span><span class="o">[</span><span class="n">childIndex</span> <span class="o">+</span> <span class="mi">1</span><span class="o">])</span> <span class="o">{</span>
                <span class="n">childIndex</span><span class="o">++;</span>
            <span class="o">}</span>
        <span class="o">}</span>
        <span class="c1">//递归比较子节点的大小和keyValue的大小来决定是否满足heap的属性</span>
        <span class="k">if</span> <span class="o">(</span><span class="n">heap</span><span class="o">[</span><span class="n">childIndex</span><span class="o">]</span> <span class="o">&lt;=</span> <span class="n">keyValue</span><span class="o">)</span> <span class="o">{</span>
            <span class="n">isHeap</span> <span class="o">=</span> <span class="kc">true</span><span class="o">;</span>
        <span class="o">}</span> <span class="k">else</span> <span class="o">{</span>
            <span class="c1">//child节点的值上移</span>
            <span class="n">heap</span><span class="o">[</span><span class="n">keyIndex</span><span class="o">]</span> <span class="o">=</span> <span class="n">heap</span><span class="o">[</span><span class="n">childIndex</span><span class="o">];</span>
            <span class="n">keyIndex</span> <span class="o">=</span> <span class="n">childIndex</span><span class="o">;</span>
        <span class="o">}</span>
    <span class="o">}</span>
    <span class="c1">//把原本的KeyValue放到最终的位置，形成一个heap</span>
    <span class="n">heap</span><span class="o">[</span><span class="n">keyIndex</span><span class="o">]</span> <span class="o">=</span> <span class="n">keyValue</span><span class="o">;</span>
<span class="o">}</span>
</code></pre></div></div>
<h2 id="quick-sort快速排序">Quick Sort(快速排序)</h2>

<p>快速排序也利用了分治(Divide and Conquer)的思想，然而和归并排序的方式不同，①它选择一个元素作为基准(pivot)，②并围绕拾取的基准分割给定的数组，将比基准小的元素放在基准前，将比基准大的元素放在基准后。③递归的不断排序子序列。</p>

<p><strong>快速排序改进方法</strong></p>

<ul>
  <li>
    <p>选取基准值有数种具体方法，此选取方法对排序的时间性能有决定性影响：如①永远选取第一个元素（在下方代码中的实现），②Median-of-Three方法选取基准（有很大程度提高了速度） ③还有很多别的方法……</p>
  </li>
  <li>
    <p>Early Cut-off：在数组快要达到排序状态时，从快速排序切换到插入排序，可以一定程序提高速度。</p>
  </li>
</ul>

<table>
  <thead>
    <tr>
      <th style="text-align: left">In-place</th>
      <th>Stable</th>
      <th>Worst-case</th>
      <th>Average-case</th>
      <th>Best-case</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td style="text-align: left">√</td>
      <td>×</td>
      <td>О(<em>n</em><sup>2</sup>)</td>
      <td>O(<em>n</em> log <em>n</em>)</td>
      <td>O(<em>n</em> log <em>n</em>)</td>
    </tr>
  </tbody>
</table>

<p><em>注1：快速排序被认为是最好排序方法来处理未排序的数据，即使归并排序有更好的表现保证，但快速排序在平均上来说更快！</em></p>

<p><em>注2：Java源码中的排序算法采用的DualPivotQuicksort，一种快速排序的方法之一（选取的Pivot方法不同）,且根据数组大小，结合了别的排序方法，可学习源码。</em></p>

<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">public</span> <span class="kd">static</span> <span class="kt">void</span> <span class="nf">quickSort</span><span class="o">(</span><span class="kt">int</span><span class="o">[]</span> <span class="n">arr</span><span class="o">)</span> <span class="o">{</span>
    <span class="n">quickSortHelper</span><span class="o">(</span><span class="n">arr</span><span class="o">,</span> <span class="mi">0</span><span class="o">,</span> <span class="n">arr</span><span class="o">.</span><span class="na">length</span> <span class="o">-</span> <span class="mi">1</span><span class="o">);</span>
<span class="o">}</span>

<span class="kd">private</span> <span class="kd">static</span> <span class="kt">void</span> <span class="nf">quickSortHelper</span><span class="o">(</span><span class="kt">int</span><span class="o">[]</span> <span class="n">arr</span><span class="o">,</span> <span class="kt">int</span> <span class="n">lo</span><span class="o">,</span> <span class="kt">int</span> <span class="n">hi</span><span class="o">)</span> <span class="o">{</span>
    <span class="k">if</span> <span class="o">(</span><span class="n">lo</span> <span class="o">&lt;</span> <span class="n">hi</span><span class="o">)</span> <span class="o">{</span>
        <span class="kt">int</span> <span class="n">partitionIndex</span> <span class="o">=</span> <span class="n">partition</span><span class="o">(</span><span class="n">arr</span><span class="o">,</span> <span class="n">lo</span><span class="o">,</span> <span class="n">hi</span><span class="o">);</span>
        <span class="n">quickSortHelper</span><span class="o">(</span><span class="n">arr</span><span class="o">,</span> <span class="n">lo</span><span class="o">,</span> <span class="n">partitionIndex</span> <span class="o">-</span> <span class="mi">1</span><span class="o">);</span>
        <span class="n">quickSortHelper</span><span class="o">(</span><span class="n">arr</span><span class="o">,</span> <span class="n">partitionIndex</span> <span class="o">+</span> <span class="mi">1</span><span class="o">,</span> <span class="n">hi</span><span class="o">);</span>
    <span class="o">}</span>
<span class="o">}</span>

<span class="cm">/**
 * Hoare Partition（https://www.wikiwand.com/en/Quicksort#/Hoare_partition_scheme）
 * 一种简单的Partition方法，选取一个pivot（我在代码中选取了index=lo的元素），
 * 然后用2个指针，从头尾向对方移动，直到检测到一个大于pivot，一个小于或等于pivot，
 * 彼此是相对不正确的顺序，然后交换两者。当2个指针相遇，调整pivot到正确位置，并返回最终index。
 *
 * @param arr 等待被排序的数组
 * @param lo  开始index,
 * @param hi  结束index
 * @return 选取的pivot最终正确的位置的index
 */</span>
<span class="kd">private</span> <span class="kd">static</span> <span class="kt">int</span> <span class="nf">partition</span><span class="o">(</span><span class="kt">int</span><span class="o">[]</span> <span class="n">arr</span><span class="o">,</span> <span class="kt">int</span> <span class="n">lo</span><span class="o">,</span> <span class="kt">int</span> <span class="n">hi</span><span class="o">)</span> <span class="o">{</span>
    <span class="kt">int</span> <span class="n">pivot</span> <span class="o">=</span> <span class="n">arr</span><span class="o">[</span><span class="n">lo</span><span class="o">],</span> <span class="n">loIndex</span> <span class="o">=</span> <span class="n">lo</span><span class="o">,</span> <span class="n">hiIndex</span> <span class="o">=</span> <span class="n">hi</span><span class="o">;</span>
    <span class="k">while</span> <span class="o">(</span><span class="n">loIndex</span> <span class="o">&lt;</span> <span class="n">hiIndex</span><span class="o">)</span> <span class="o">{</span>
        <span class="k">while</span> <span class="o">(</span><span class="n">loIndex</span> <span class="o">&lt;</span> <span class="n">hi</span> <span class="o">&amp;&amp;</span> <span class="n">arr</span><span class="o">[</span><span class="n">loIndex</span><span class="o">]</span> <span class="o">&lt;=</span> <span class="n">pivot</span><span class="o">)</span> <span class="n">loIndex</span><span class="o">++;</span>
        <span class="k">while</span> <span class="o">(</span><span class="n">hiIndex</span> <span class="o">&gt;</span> <span class="n">lo</span> <span class="o">&amp;&amp;</span> <span class="n">arr</span><span class="o">[</span><span class="n">hiIndex</span><span class="o">]</span> <span class="o">&gt;</span> <span class="n">pivot</span><span class="o">)</span> <span class="n">hiIndex</span><span class="o">--;</span>
        <span class="c1">//交换逆序元素,如果不设这个判断，最后一次loIndex&gt;hiIndex也会进行交换</span>
        <span class="k">if</span> <span class="o">(</span><span class="n">loIndex</span> <span class="o">&lt;=</span> <span class="n">hiIndex</span><span class="o">)</span> <span class="o">{</span>
            <span class="kt">int</span> <span class="n">temp</span> <span class="o">=</span> <span class="n">arr</span><span class="o">[</span><span class="n">loIndex</span><span class="o">];</span>
            <span class="n">arr</span><span class="o">[</span><span class="n">loIndex</span><span class="o">]</span> <span class="o">=</span> <span class="n">arr</span><span class="o">[</span><span class="n">hiIndex</span><span class="o">];</span>
            <span class="n">arr</span><span class="o">[</span><span class="n">hiIndex</span><span class="o">]</span> <span class="o">=</span> <span class="n">temp</span><span class="o">;</span>
        <span class="o">}</span>
    <span class="o">}</span>
    <span class="c1">//将pivot放到正确的位置</span>
    <span class="kt">int</span> <span class="n">temp</span> <span class="o">=</span> <span class="n">arr</span><span class="o">[</span><span class="n">lo</span><span class="o">];</span>
    <span class="n">arr</span><span class="o">[</span><span class="n">lo</span><span class="o">]</span> <span class="o">=</span> <span class="n">arr</span><span class="o">[</span><span class="n">hiIndex</span><span class="o">];</span>
    <span class="n">arr</span><span class="o">[</span><span class="n">hiIndex</span><span class="o">]</span> <span class="o">=</span> <span class="n">temp</span><span class="o">;</span>
    <span class="c1">//返回pivot最终正确的位置的index</span>
    <span class="k">return</span> <span class="n">hiIndex</span><span class="o">;</span>
<span class="o">}</span>
</code></pre></div></div>

<h2 id="merge-sort归并排序">Merge Sort(归并排序)</h2>

<p>归并排序是分治(Divide and Conquer)的一个典型应用。总的来说，排序分成两部分 ①将未排序的列表分成n个子列表（有递归和迭代两种方式，具体见下方代码），每个子列表包含一个元素（一个元素的列表被视为已排序）。②重复合并子列表以生成新的已排序子列表，直到只剩下一个子列表， 最后剩下的就是排序好的列表。</p>

<table>
  <thead>
    <tr>
      <th style="text-align: left">In-place</th>
      <th>Stable</th>
      <th>Worst-case</th>
      <th>Average-case</th>
      <th>Best-case</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td style="text-align: left">×</td>
      <td>√</td>
      <td>O(<em>n</em> log <em>n</em>)</td>
      <td>O(<em>n</em> log <em>n</em>)</td>
      <td>O(<em>n</em> log <em>n</em>)</td>
    </tr>
  </tbody>
</table>

<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cm">/**
 * 递归版(Top-down)的 归并排序
 * 处理一个未排序数组，不断递归的分成2半，分别排序，最后合并
 */</span>
<span class="kd">public</span> <span class="kd">static</span> <span class="kt">void</span> <span class="nf">mergeSortTopDown</span><span class="o">(</span><span class="kt">int</span><span class="o">[]</span> <span class="n">arr</span><span class="o">)</span> <span class="o">{</span>
    <span class="k">if</span> <span class="o">(</span><span class="n">arr</span><span class="o">.</span><span class="na">length</span> <span class="o">&gt;</span> <span class="mi">1</span><span class="o">)</span> <span class="o">{</span>
        <span class="kt">int</span> <span class="n">mid</span> <span class="o">=</span> <span class="n">arr</span><span class="o">.</span><span class="na">length</span> <span class="o">/</span> <span class="mi">2</span><span class="o">;</span>
        <span class="c1">//将原数组分成左右两半，分别拷贝到临时数组中</span>
        <span class="c1">//left=[leftIndex, midIndex), right = [midIndex, rightIndex)</span>
        <span class="kt">int</span><span class="o">[]</span> <span class="n">left</span> <span class="o">=</span> <span class="nc">Arrays</span><span class="o">.</span><span class="na">copyOfRange</span><span class="o">(</span><span class="n">arr</span><span class="o">,</span> <span class="mi">0</span><span class="o">,</span> <span class="n">mid</span><span class="o">);</span>
        <span class="kt">int</span><span class="o">[]</span> <span class="n">right</span> <span class="o">=</span> <span class="nc">Arrays</span><span class="o">.</span><span class="na">copyOfRange</span><span class="o">(</span><span class="n">arr</span><span class="o">,</span> <span class="n">mid</span><span class="o">,</span> <span class="n">arr</span><span class="o">.</span><span class="na">length</span><span class="o">);</span>
        <span class="c1">//对左右两半临时数组进行排序</span>
        <span class="n">mergeSortTopDown</span><span class="o">(</span><span class="n">left</span><span class="o">);</span>
        <span class="n">mergeSortTopDown</span><span class="o">(</span><span class="n">right</span><span class="o">);</span>
        <span class="c1">//将左右两半临时数组归并到原数组</span>
        <span class="n">merge</span><span class="o">(</span><span class="n">left</span><span class="o">,</span> <span class="n">right</span><span class="o">,</span> <span class="n">arr</span><span class="o">);</span>
    <span class="o">}</span>
<span class="o">}</span>

<span class="kd">private</span> <span class="kd">static</span> <span class="kt">void</span> <span class="nf">merge</span><span class="o">(</span><span class="kt">int</span><span class="o">[]</span> <span class="n">left</span><span class="o">,</span> <span class="kt">int</span><span class="o">[]</span> <span class="n">right</span><span class="o">,</span> <span class="kt">int</span><span class="o">[]</span> <span class="n">arr</span><span class="o">)</span> <span class="o">{</span>
    <span class="c1">//3个数组的初始index都设置为0</span>
    <span class="kt">int</span> <span class="n">leftIndex</span> <span class="o">=</span> <span class="mi">0</span><span class="o">,</span> <span class="n">rightIndex</span> <span class="o">=</span> <span class="mi">0</span><span class="o">,</span> <span class="n">mergedIndex</span> <span class="o">=</span> <span class="mi">0</span><span class="o">;</span>
    <span class="c1">//不断比较左右两个数组中元素的大小，复制到原数组中，直到一个数组元素完全复制完</span>
    <span class="k">while</span> <span class="o">(</span><span class="n">leftIndex</span> <span class="o">&lt;</span> <span class="n">left</span><span class="o">.</span><span class="na">length</span> <span class="o">&amp;&amp;</span> <span class="n">rightIndex</span> <span class="o">&lt;</span> <span class="n">right</span><span class="o">.</span><span class="na">length</span><span class="o">)</span> <span class="o">{</span>
        <span class="k">if</span> <span class="o">(</span><span class="n">left</span><span class="o">[</span><span class="n">leftIndex</span><span class="o">]</span> <span class="o">&lt;</span> <span class="n">right</span><span class="o">[</span><span class="n">rightIndex</span><span class="o">])</span> <span class="o">{</span>
            <span class="n">arr</span><span class="o">[</span><span class="n">mergedIndex</span><span class="o">++]</span> <span class="o">=</span> <span class="n">left</span><span class="o">[</span><span class="n">leftIndex</span><span class="o">++];</span>
        <span class="o">}</span> <span class="k">else</span> <span class="o">{</span>
            <span class="n">arr</span><span class="o">[</span><span class="n">mergedIndex</span><span class="o">++]</span> <span class="o">=</span> <span class="n">right</span><span class="o">[</span><span class="n">rightIndex</span><span class="o">++];</span>
        <span class="o">}</span>
    <span class="o">}</span>
    <span class="c1">//将剩余一个数组中的剩余元素复制到原数组的末尾</span>
    <span class="k">if</span> <span class="o">(</span><span class="n">leftIndex</span> <span class="o">==</span> <span class="n">left</span><span class="o">.</span><span class="na">length</span><span class="o">)</span> <span class="o">{</span>
        <span class="nc">System</span><span class="o">.</span><span class="na">arraycopy</span><span class="o">(</span><span class="n">right</span><span class="o">,</span> <span class="n">rightIndex</span><span class="o">,</span> <span class="n">arr</span><span class="o">,</span> <span class="n">mergedIndex</span><span class="o">,</span> 
                            <span class="n">right</span><span class="o">.</span><span class="na">length</span> <span class="o">-</span> <span class="n">rightIndex</span><span class="o">);</span>
    <span class="o">}</span> <span class="k">else</span> <span class="o">{</span>
        <span class="nc">System</span><span class="o">.</span><span class="na">arraycopy</span><span class="o">(</span><span class="n">left</span><span class="o">,</span> <span class="n">leftIndex</span><span class="o">,</span> <span class="n">arr</span><span class="o">,</span> <span class="n">mergedIndex</span><span class="o">,</span> 
                            <span class="n">left</span><span class="o">.</span><span class="na">length</span> <span class="o">-</span> <span class="n">leftIndex</span><span class="o">);</span>
    <span class="o">}</span>
<span class="o">}</span>
</code></pre></div></div>

<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cm">/**
 * 迭代版(Bottom-up)的 归并排序
 * 迭代的对原数组中不断增长的2的倍数(2,4,8...)长度的子数组进行排序
 */</span>
<span class="kd">public</span> <span class="kd">static</span> <span class="kt">void</span> <span class="nf">mergeSortBottomUp</span><span class="o">(</span><span class="kt">int</span><span class="o">[]</span> <span class="n">arr</span><span class="o">)</span> <span class="o">{</span>
    <span class="kt">int</span><span class="o">[]</span> <span class="n">temp</span> <span class="o">=</span> <span class="k">new</span> <span class="kt">int</span><span class="o">[</span><span class="n">arr</span><span class="o">.</span><span class="na">length</span><span class="o">];</span>
    <span class="c1">//对从长度为2开始的数组进行排序</span>
    <span class="k">for</span> <span class="o">(</span><span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">2</span><span class="o">;</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="o">(</span><span class="mi">2</span> <span class="o">*</span> <span class="n">arr</span><span class="o">.</span><span class="na">length</span><span class="o">);</span> <span class="n">i</span> <span class="o">*=</span> <span class="mi">2</span><span class="o">)</span> <span class="o">{</span>
        <span class="c1">//对每一次排序而言，对当前数组对半分，进行排序</span>
        <span class="k">for</span> <span class="o">(</span><span class="kt">int</span> <span class="n">j</span> <span class="o">=</span> <span class="mi">0</span><span class="o">;</span> <span class="n">j</span> <span class="o">&lt;</span> <span class="o">(</span><span class="n">arr</span><span class="o">.</span><span class="na">length</span> <span class="o">+</span> <span class="n">i</span><span class="o">)</span> <span class="o">/</span> <span class="n">i</span><span class="o">;</span> <span class="n">j</span><span class="o">++)</span> <span class="o">{</span>
            <span class="c1">//数组左中右index，等同于将数组分成了左右两半，对最后一个数组，需要判断是否超过原数组下标</span>
            <span class="kt">int</span> <span class="n">left</span> <span class="o">=</span> <span class="n">i</span> <span class="o">*</span> <span class="n">j</span><span class="o">;</span>
            <span class="kt">int</span> <span class="n">mid</span> <span class="o">=</span> <span class="nc">Math</span><span class="o">.</span><span class="na">min</span><span class="o">(</span><span class="n">left</span> <span class="o">+</span> <span class="n">i</span> <span class="o">/</span> <span class="mi">2</span><span class="o">,</span> <span class="n">arr</span><span class="o">.</span><span class="na">length</span><span class="o">);</span>
            <span class="kt">int</span> <span class="n">right</span> <span class="o">=</span> <span class="nc">Math</span><span class="o">.</span><span class="na">min</span><span class="o">(</span><span class="n">i</span> <span class="o">*</span> <span class="o">(</span><span class="n">j</span> <span class="o">+</span> <span class="mi">1</span><span class="o">),</span> <span class="n">arr</span><span class="o">.</span><span class="na">length</span><span class="o">);</span>
            <span class="c1">//对左右数组进行排序操作，等同于Top-down里的merge操作</span>
            <span class="kt">int</span> <span class="n">leftIndex</span> <span class="o">=</span> <span class="n">left</span><span class="o">,</span> <span class="n">rightIndex</span> <span class="o">=</span> <span class="n">mid</span><span class="o">,</span> <span class="n">mergedIndex</span> <span class="o">=</span> <span class="n">left</span><span class="o">;</span>
            <span class="k">while</span> <span class="o">(</span><span class="n">leftIndex</span> <span class="o">&lt;</span> <span class="n">mid</span> <span class="o">&amp;&amp;</span> <span class="n">rightIndex</span> <span class="o">&lt;</span> <span class="n">right</span><span class="o">)</span> <span class="o">{</span>
                <span class="k">if</span> <span class="o">(</span><span class="n">arr</span><span class="o">[</span><span class="n">leftIndex</span><span class="o">]</span> <span class="o">&lt;</span> <span class="n">arr</span><span class="o">[</span><span class="n">rightIndex</span><span class="o">])</span> <span class="o">{</span>
                    <span class="n">temp</span><span class="o">[</span><span class="n">mergedIndex</span><span class="o">++]</span> <span class="o">=</span> <span class="n">arr</span><span class="o">[</span><span class="n">leftIndex</span><span class="o">++];</span>
                <span class="o">}</span> <span class="k">else</span> <span class="o">{</span>
                    <span class="n">temp</span><span class="o">[</span><span class="n">mergedIndex</span><span class="o">++]</span> <span class="o">=</span> <span class="n">arr</span><span class="o">[</span><span class="n">rightIndex</span><span class="o">++];</span>
                <span class="o">}</span>
            <span class="o">}</span>
            <span class="k">if</span> <span class="o">(</span><span class="n">leftIndex</span> <span class="o">==</span> <span class="n">mid</span><span class="o">)</span> <span class="o">{</span>
                <span class="nc">System</span><span class="o">.</span><span class="na">arraycopy</span><span class="o">(</span><span class="n">arr</span><span class="o">,</span> <span class="n">rightIndex</span><span class="o">,</span> <span class="n">temp</span><span class="o">,</span> <span class="n">mergedIndex</span><span class="o">,</span> <span class="n">right</span> <span class="o">-</span> <span class="n">rightIndex</span><span class="o">);</span>
            <span class="o">}</span> <span class="k">else</span> <span class="o">{</span>
                <span class="nc">System</span><span class="o">.</span><span class="na">arraycopy</span><span class="o">(</span><span class="n">arr</span><span class="o">,</span> <span class="n">leftIndex</span><span class="o">,</span> <span class="n">temp</span><span class="o">,</span> <span class="n">mergedIndex</span><span class="o">,</span> <span class="n">mid</span> <span class="o">-</span> <span class="n">leftIndex</span><span class="o">);</span>
            <span class="o">}</span>
            <span class="c1">//注释掉这句话可以看具体排序过程</span>
            <span class="c1">//System.out.println(Arrays.toString(temp));</span>
            <span class="c1">//将排序好的数组拷贝回原数组相对应位置</span>
            <span class="nc">System</span><span class="o">.</span><span class="na">arraycopy</span><span class="o">(</span><span class="n">temp</span><span class="o">,</span> <span class="n">left</span><span class="o">,</span> <span class="n">arr</span><span class="o">,</span> <span class="n">left</span><span class="o">,</span> <span class="n">right</span> <span class="o">-</span> <span class="n">left</span><span class="o">);</span>
        <span class="o">}</span>
    <span class="o">}</span>
<span class="o">}</span>
</code></pre></div></div>]]></content><author><name>Jian Shi</name></author><category term="Algorithm" /><category term="Algorithm" /><category term="Java" /><category term="Sort" /><summary type="html"><![CDATA[Sorting Algorithm - Comparison Sorts]]></summary></entry></feed>