归并排序
上面的 gif 来自维基百科
Data Structure Visualization 这个万丈是一个很好的学习数据结构的网站,将数据结构可视化,可以直观的看到插入、删除、旋转、搜索、排序等效果。
归并排序(英语:Merge sort,或mergesort),是创建在归并操作上的一种有效的排序算法,效率为 (大O符号)。1945年由约翰·冯·诺伊曼首次提出。该算法是采用分治法(Divide and Conquer)的一个非常典型的应用,且各层分治递归可以同时进行。
归并
归并操作(merge),也叫归并算法,指的是将两个已经排序的序列合并成一个序列的操作。归并排序算法依赖归并操作。
递归法(Top-down)
- 申请空间,使其大小为两个已经排序序列之和,该空间用来存放合并后的序列
- 设定两个指针,最初位置分别为两个已经排序序列的起始位置
- 比较两个指针所指向的元素,选择相对小的元素放入到合并空间,并移动指针到下一位置
- 重复步骤3直到某一指针到达序列尾
-
迭代法(Bottom-up)
原理如下(假设序列共有 个元素):
将序列每相邻两个数字进行归并操作,形成 个序列,排序后每个序列包含两/一个元素
- 若此时序列数不是1个则将上述序列再次归并,形成 个序列,每个序列包含四/三个元素
- 重复步骤2,直到所有元素排序完毕,即序列数为1
递归法通过两个指针的移动来完成归并排序。迭代法则利用了分治思想。
Go
迭代法
func MergeSort(array []int) []int{
n := len(array)
if n < 2 {
return array
}
key := n / 2
left := MergeSort(array[0:key])
right := MergeSort(array[key:])
return merge(left, right)
}
func merge(left []int, right []int) []int{
newArr := make([]int, len(left)+len(right))
i, j, index :=0,0,0
for {
if left[i] > right[j] {
newArr[index] = right[j]
index++
j++
if j == len(right) {
copy(newArr[index:], left[i:])
break
}
}else{
newArr[index] = left[i]
index++
i++
if i == len(left) {
copy(newArr[index:], right[j:])
break
}
}
}
return newArr
}
func merge(data []int) []int {
sum := len(data)
if sum <= 1 {
return data
}
left := data[0 : sum/2]
lSize := len(left)
if lSize >= 2 {
left = merge(left)
}
right := data[sum/2:]
rSize := len(right)
if rSize >= 2 {
right = merge(right)
}
j := 0
t := 0
arr := make([]int, sum)
fmt.Println(left, right, data)
for i := 0; i < sum; i++ {
if j < lSize && t < rSize {
if left[j] <= right[t] {
arr[i] = left[j]
j++
} else {
arr[i] = right[t]
t++
}
} else if j >= lSize{
arr[i] = right[t]
t++
} else if t >= rSize{
arr[i] = left[j]
j++
}
}
return arr
}
上述代码来自维基百科,我在想,这不是相同的算法么?这两段程序有什么区别?同样都是递归