Skip to content

Merge Sort

Introduction

  • Divide and Conquer Algorithm
    • Divide
    • Conquer
    • Merge
  • Stable Algorithm
  • θ(n log n) time and O(n) aux space
  • Well suited for linked list. Works in O(1) aux space
  • Used in external sorting
  • In generate for array. Quick sort outperforms it.

Merge Two Sorted Array

Input: a[] = {12, 17, 22}
b[] = {7, 8, 8, 17}
Ouput: c[] = {7, 8, 8, 12, 17, 22}

Input: a[] = {11, 11, 22}
b[] = {33}
Ouput: c[] = {11, 11, 22, 33}

Naive Solution

package main

import (
    "fmt"
    "sort"
)

type Person struct {
    id   int
    name string
}

func main() {
    a := []int{10, 15, 20, 20}
    b := []int{1, 2, 13}
    c := merge(a, b)
    fmt.Println(c)
}

func merge(a []int, b []int) []int {
    c := make([]int, len(a)+len(b))
    for i, ele := range a {
        c[i] = ele
    }
    for i, ele := range b {
        c[len(a)+i] = ele
    }
    sort.Ints(c)
    return c
}

Time Complexity: O((m+n) log(m+n))
Space Complexity: θ(m+n)

Dry Run:
a[] = {10, 15, 20, 20}
b[] = {1, 2, 13}

After 1st Loop: c[] = {10, 15, 20, 20, , , _}
After 2st Loop: c[] = {10, 15, 20, 20, 1, 2, 13}
After Sorting: c[] = {1, 2, 10, 13, 15, 20, 20}

Efficient Solution

Initially i=0, j =0

if a[i] <= b[j] { append a[i]; i++}
else append b[j]; j++

package main

import "fmt"

func main() {
    a := []int{5, 10, 15, 20}
    b := []int{10, 20, 30}
    res := merge(a, b)
    fmt.Println(res)
}

func merge(a []int, b []int) (result []int) {
    i := 0
    j := 0
    for i < len(a) && j < len(b) {
        if a[i] <= b[j] {
            result = append(result, a[i])
            i++
        } else {
            result = append(result, b[j])
            j++
        }
    }

    for i < len(a) {
        result = append(result, a[i])
        i++
    }
    for j < len(b) {
        result = append(result, b[j])
        j++
    }
    return
}

Time Complexity: θ(m+n)

Dry Run:
a := {5, 10, 15, 20}
b := {10, 20, 30}

First Loop
i=0, j=0
c[]={5} i=1
c[]={5, 10} i=2
c[]={5, 10, 10} j=1
c[]={5, 10, 10, 15} i=3
c[]={5, 10, 10, 15, 20} i=4

Second Loop
Nothing

Third Loop
c[]={5, 10, 10, 15, 20, 20} j=2
c[]={5, 10, 10, 15, 20, 20, 30} j=3

Merge Function of Merge Sort

Input: a[] = {12, 15, 22, 13, 32}
                     |---------|     |-----|
low = 0
mid = 2
high = 4

Output: a[] = {12, 13, 17 , 22, 32}

Input: a[] = {7, 10, 12, 14, 9}
                     |-------------|  |--|
low = 0
mid = 3
high = 4

Output: a[] = {7, 10, 12, 14, 9}

Implementation Idea

a[] = {13, 18, 21, 45, 10, 15, 80}
low = 0
mid = 3
high = 6
left[] = {13, 18, 21, 45}
right[] = { 10, 15, 80}

merge left and right array
a[] = {10, 13, 15, 18, 21, 45, 80}

Implementation

func merge(a []int, low int, mid int, high int) {

    // Setting up auxilary array
    n1 := mid - low + 1
    n2 := high - mid
    left := make([]int, n1)
    right := make([]int, n2)
    for i := 0; i < n1; i++ {
        left[i] = a[low+i]
    }
    for i := 0; i < n2; i++ {
        right[i] = a[mid+i+1]
    }

    // standard merge logic

    i := 0
    j := 0
    k := low
    for i < n1 && j < n2 {
        if left[i] < right[j] {
            a[k] = left[i]
            i++
            k++
        } else {
            a[k] = right[j]
            k++
            j++
        }
    }
    for i < n1 {
        a[k] = left[i]
        k++
        i++
    }
    for j < n2 {
        a[k] = right[j]
        k++
        j++
    }
}

Time complexity: θ(n)
Aux Space: θ(n)

Merge Sort Algorithm

func mergeSort(arr []int, l, r int) {
    if r > l { // atleast 2 elements
        m := (l + r) / 2
        mergeSort(arr, l, m)
        mergeSort(arr, m+1, r)
        merge(arr, l, m, r)
    }
}

Explaination

Merge Sort Analysis