---
# System prepended metadata

title: Lecture 05 - Merge Sort
tags: [課堂筆記, 演算法]

---

# Lecture 05 - Merge sorting
> 課程內容 : 中興大學資工系 范耀中教授 (112 學年度第 2 學期)
>
> 其他科目內容請參見 [[Here]](https://hackmd.io/@ChenZE/By4SOO6Jyl)

## 1. Top-down merge sort
> Basic plan
> * DIvide array into two halves
> * Recursively sort each half
> * Merge two halves

:::info
Merge sort 的核心思想是使用 divide and conquer 的方式將==問題簡化，逐一解決==後再將結果合併
:::

![S__2179076](https://hackmd.io/_uploads/S1lZRB4VR.jpg)


### 1.1 Merge sort demo
![S__2179077](https://hackmd.io/_uploads/BkAJyLEEA.jpg)

* 將原始 Array 切成兩個 sub-Array (`[0:lo, mid:hi]`)
* 排序左邊的 sub-Array(`aux[0:lo]`) 以及 右邊的 sub-Array(`aux[mid:hi]`)
* 依序比較 Left array 的元素(index : i)以及 Right array 的元素(index : j)
* **哪個元素小就回填**原始 Array(index : k)

### 1.2 Java implementation
```java
// copy original array
for (int k=lo; k<=hi; k++)
    aux[k] = a[k];(#)

// merge
int i = lo;      // index of left sub-array
int j = mid + 1; // index of right sub-array

for (int k=lo; k<=hi; k++)
{
    // left array finished, only merge right array
    if (i > mid)
        a[k] = aux[j++];(#)
    
    // right array finished, only merge left array
    else if (j > hi)
        a[k] = aux[i++];
    
    // right element > left element
    else if (less(aux[j], aux[i]))(#)
        a[k] = aux[j++];
    
    // right element < left element
    else
        a[k] = aux[i++];
}    
```
### 1.3 Animation
* [20 random items](https://www.toptal.com/developers/sorting-algorithms/merge-sort)
* [20 reverse-sorted items](https://www.toptal.com/developers/sorting-algorithms/merge-sort)

### 1.4 Complexity analysis
複雜度分析分為 **拆分(split)** 與 **合併(merge)** 兩步驟來看

#### 拆分

以 size $= N$ 的 Array 為例，需要將原始的大 Array 做拆分，分成 $[\frac{N}{2},\frac{N}{2}]$ 的兩個小的陣列，再將兩個小的陣列切分成 $[\frac{N}{4}, \frac{N}{4}, \frac{N}{4}, \frac{N}{4}]$ 的四個小陣列。直到拆分成 $[1, 1, ...,1]$ 的陣列為止，需要進行 $N-1$ 次的拆分，時間複雜度為 $O(n-1)=n$

#### 合併

**合併的同時也需要完成排序(sorted)**，每次排序的過程中，需要將==所有== sub-Array 的元素從左到右看過一次，並把小的元素放到大 Array 中，**每個回合都需要進行 N 次** ( $\because$ N 個元素)

合併的過程需要進行 $\log N$ 個回合，所以合併的複雜度為 $O(N \cdot \log N)$

整體時間複雜度為 $O((N-1) + N \cdot \log N) = N \cdot \log N$

:::info
合併的過程中，每回合的 sub-Array 元素個數依序為 : $1 \rightarrow 2 \rightarrow 4 \rightarrow ... \rightarrow 2^k$ 且 $N=2^k$，因此總共需要 $k = \log 2^k = \log N$ 的回合數
:::

![S__2179078](https://hackmd.io/_uploads/ryfE1wENA.jpg)

### 1.5 Improvement
#### 缺點
Merge sort 在排序的過程中，需要將
* 原始的大 Array **複製** (2N for array copy)
* **提出**兩個小 Array 的元素作比較 (2N for comparison)
* 從小的 Array **複製**到大 Array 之中 (2N for move back)

上述過程需要多付出 **6 倍**的 Array access 的成本，以長度為 N 的 Array 來說，就==需要付出 6N 的搬移成本==
([Java demo](#12-Java-implementation) 中有 # 符號的地方)

![S__2179079](https://hackmd.io/_uploads/BktMGw4EA.jpg)

#### 改善 (1) : Cutoff
當切分成小 Array 的時候，**直接使用 insertion 做排序**。習慣上當只剩下 10 個元素時就直接使用 Insertion sort 做排序

#### 改善 (2) : Stop if already sorted
若兩個小 Array 本身**已經排序好(?)**，則合併過程就不用再排序

如何判斷**已經排序好** :question: 
1. 每回合 **merge 前兩邊的小 Array 本身都是已經排好的**
2. 每次 merge 的過程都是比兩邊 array 的最左側元素，所以只需 ==確定左邊陣列的最大值(最右元素) < 右邊陣列的最小值(最左元素)== 就可保證兩個陣列已經排好，合併過程不用再比較

![S__2179081](https://hackmd.io/_uploads/SJGNrDEEC.jpg)

## 2. Bottom-top merge sort
> Basic plan
> * Pass through array, merging sub-arrays if size 1
> * Repeat for sub-arrays of size 2, 4, 8, ...

:::info
針對 size = 1 的 sub-arrays 排序，排完後再對 size = 2 的 sub-array 排序
:::

![S__2179082](https://hackmd.io/_uploads/HyUKiwEEC.jpg)

### 2.1 Natural merge sort
:::info
:bulb: **Idea**
Exploit pre-existing order by identifying naturally-occurring runs
:::

> **Tim sort**
> * Natural merge sort
> * Use **insertion sort** to make initial runs(if needed)
> * A few more clever optimizations

Tim sort(by Tim Peter)所看到的一些事情 : 
1. 沒人規定 Array 在拆解的時候 sub-Array 必須要一樣大
2. 任意長度的 Array 可能本身**隱含了一些順序**

:::info
:point_right: 對 Array 做 Linear search 來找出**逐漸遞增**的 sub-Array
:::

![S__2179083](https://hackmd.io/_uploads/B11VkO440.jpg)

## 3. Comparators (比較級)
一個物件有多個 attribute 且欲對多個 attribute 做比較。

許多 programming language 都有提供 comparator 的實作，只要知道概念即可不用記實作細節，需要使用時再查就好

## 4. Stability
> Definition : 
> 當單一元素有多個 attributes 時，**對多個屬性排序**後，相對應的**順序會不會亂掉**

![S__2179085](https://hackmd.io/_uploads/rktVJcVNC.jpg)

### 4.1 Insertion sort : Stable
A 本身已經照順序，B 排序的過程不會影響到 A 的順序

| index $i$ | index $j$ | 0          | 1          | 2          | 3          | 4     |
| :-:       | :-:       | :-:        | :-:        | :-:        | :-:        | :-:   |
| 0         | 0         | $B_1$      | $\bf{A_1}$ | $\bf{A_2}$ | $\bf{A_3}$ | $B_2$ |
| 1         | 0         | $\bf{A_1}$ | $B_1$      | $\bf{A_2}$ | $\bf{A_3}$ | $B_2$ |
| 2         | 1         | $\bf{A_1}$ | $\bf{A_2}$ | $B_1$      | $\bf{A_3}$ | $B_2$ |
| 3         | 2         | $\bf{A_1}$ | $\bf{A_2}$ | $\bf{A_3}$ | $B_1$      | $B_2$ |
| 4         | 4         | $\bf{A_1}$ | $\bf{A_2}$ | $\bf{A_3}$ | $B_1$      | $B_2$ |


### 4.2 Selection sort : Not stable

| index $i$ | min | 0          | 1          | 2          |
| :-:       | :-: | :-:        | :-:        | :-:        |
| 0         | 2   | $\bf{B_1}$ | $\bf{B_2}$ | $A$        |
| 1         | 1   | $A$        | $\bf{B_2}$ | $\bf{B_1}$ |
| 2         | 2   | $A$        | $\bf{B_2}$ | $\bf{B_1}$ |
|           |     | $A$        | $\bf{B_2}$ | $\bf{B_1}$ |

### 4.3 Shell sort : Not stable
B 本身已經有順序，對 A 排列的過程中會影像 B 的順序

| h   | 0          | 1          | 2          | 3          | 4          |
| :-: | :-:        | :-:        | :-:        | :-:        | :-:        |
|     | $\bf{B_1}$ | $\bf{B_2}$ | $\bf{B_3}$ | $\bf{B_4}$ | $A_1$      |
| 4   | $A_1$      | $\bf{B_1}$ | $\bf{B_2}$ | $\bf{B_3}$ | $\bf{B_4}$ |
| 1   | $A_1$      | $\bf{B_1}$ | $\bf{B_2}$ | $\bf{B_3}$ | $\bf{B_4}$ |
|     | $A_1$      | $\bf{B_1}$ | $\bf{B_2}$ | $\bf{B_3}$ | $\bf{B_4}$ |


:::info
基本上只要牽涉到==長距離的移動==，就有可能是 Unstable
:::

### 4.4 Merge sort : Stable
Left sub-array : `[A1, A2, A3, B, D]`

Right sub-array : `[A4, A5, C, E, F, G]`

Merge : `[A1, A2, A3, A4, A5, B, C, D, E, F, G]`

## 5. Summary :star:
![S__2179090](https://hackmd.io/_uploads/S1p7zsENC.jpg)

:::danger
**inplace** 表示排序過程中==是否需要額外的記憶體空間==，打 :heavy_check_mark: 表示不需要
:::

## Reference
1. [Merge sort](https://medium.com/appworks-school/初學者學演算法-排序法進階-合併排序法-6252651c6f7e)
2. [Sorting animation](https://www.toptal.com/developers/sorting-algorithms)