跳至主要内容

[ALGO] Sorting

Sorting (Bubble, Selection, Insertion, Merge, Quick, Counting, Radix) - VisuAlgo

Bubble

  1. Compare a pair of adjacent items (a, b),
  2. Swap that pair if the items are out of order (in this case, when a > b),
  3. Repeat Step 1 and 2 until we reach the end of array (the last pair is the (N-2)-th and (N-1)-th items as we use 0-based indexing),
  4. By now, the largest item will be at the last position. We then reduce N by 1 and repeat Step 1 until we have N = 1.

__time complex: O(N^2) __

func Bubble(nums []int) []int {
len := len(nums)
for i := 0; i < len-1; i++ {
for j := 0; j < len-1-i; j++ {
if nums[j] > nums[j+1] {
nums[j], nums[j+1] = nums[j+1], nums[j]
}
}
}
return nums
}

Selection

Given an array of N items and L = 0, Selection Sort will:

  1. Find the position X of the smallest item in the range of [L...N−1],
  2. Swap X-th item with the L-th item,
  3. Increase the lower-bound L by 1 and repeat Step 1 until L = N-2.
func Selection(nums []int) []int {
len := len(nums)
for i := len-1; i > 0; i-- {
max := nums[0]
minIdx := 0
for j := 0; j < i; j++ {
if nums[j] > max {
max = nums[j]
minIdx = j
}
}
nums[i], nums[maxIdx] = nums[maxIdx], nums[i]
}
return nums
}

Insertion

  1. Start with one card in your hand,
  2. Pick the next card and insert it into its proper sorted order,
  3. Repeat previous step for all cards.
func Insertion(nums []int) []int {
len := len(nums)
for i := 1; i < len; i++ {
for j := i; j > 0; j-- {
if nums[j-1] > nums[j] {
nums[j-1], nums[j] = nums[j], nums[j-1]
} else {
continue
}
}
}
return nums
}

Merge

  1. Merge each pair of individual element (which is by default, sorted) into sorted arrays of 2 elements,
  2. Merge each pair of sorted arrays of 2 elements into sorted arrays of 4 elements, Repeat the process...,
  3. Final step: Merge 2 sorted arrays of N/2 elements (for simplicity of this discussion, we assume that N is even) to obtain a fully sorted array of N elements.
func Merge(nums []int) []int {
length := len(nums)
if length <= 1 {
return nums
}
middle := int(length / 2)
return merge(Merge(nums[:middle]), Merge(nums[middle:]))
}

func merge(left, right []int) []int {
result := make([]int, len(left)+len(right))

i := 0
for len(left) > 0 && len(right) > 0 {
if left[0] < right[0] {
result[i] = left[0]
left = left[1:]
} else {
result[i] = right[0]
right = right[1:]
}
i++
}

for j := 0; j < len(left); j++ {
result[i] = left[j]
i++
}
for j := 0; j < len(right); j++ {
result[i] = right[j]
i++
}

return result
}

Quick (Random Quick Sort)

  • Divide step
    Choose an item p (known as the pivot) Then partition the items of a[i..j] into three parts: a[i..m-1], a[m], and a[m+1..j]. a[i..m-1] (possibly empty) contains items that are smaller than (or equal to) p. a[m] = p, i.e., index m is the correct position for p in the sorted order of array a. a[m+1..j] (possibly empty) contains items that are greater than (or equal to) p. Then, recursively sort the two parts.
  • Conquer step
    Don't be surprised... We do nothing :O!
  • Random Quick Sort
    Same as Quick Sort except just before executing the partition algorithm, it randomly select the pivot between a[i..j] instead of always choosing a[i] (or any other fixed index between [i..j]) deterministically.
func Quick(nums []int) []int {
quick(&nums, 0, len(nums)-1)
return nums
}

func quick(nums *[]int, pivotIdx, endIdx int) {
storeIdx := pivotIdx + 1
for i := pivotIdx + 1; i <= endIdx; i++ {
if (*nums)[i] < (*nums)[pivotIdx] {
(*nums)[i], (*nums)[storeIdx] = (*nums)[storeIdx], (*nums)[i]
storeIdx++
}
}
(*nums)[pivotIdx], (*nums)[storeIdx-1] = (*nums)[storeIdx-1], (*nums)[pivotIdx]

if pivotIdx < storeIdx-2 {
quick(nums, pivotIdx, storeIdx-2)
}
if storeIdx < endIdx {
quick(nums, storeIdx, endIdx)
}
}

Counting

Assumption: If the items to be sorted are Integers with small range, we can count the frequency of occurrence of each Integer (in that small range) and then loop through that small range to output the items in sorted order.

func Counting(nums []int) []int {
length := len(nums)
max := 0
for i := 0; i < length; i++ {
if nums[i] > max {
max = nums[i]
}
}

count := make([]int, max+1)
for i := 0; i < length; i++ {
count[nums[i]]++
}

idx := 0
for i := 0; i < max+1; i++ {
for j := 0; j < count[i]; j++ {
nums[idx] = i
idx++
}
}
return nums
}