Я бы хотел предложить несколько вещей:
Диапазон массива.Дейкстра однажды спорил о том, как должен выглядеть диапазон массива (или в Go, диапазон срезов): что для нотации l[i:j]
вы хотели бы, чтобы у нее были все эти свойства:
- Он должен начинатьсяв i.
- Это должно быть тривиально вычислить длину:
len(l[i:j]) == j-i
всегда верно - Это должно быть элегантно, чтобы выразить пустой диапазон, поэтому
i<=j
всегда верно
Следовательно, l [i: j] устанавливается как полуоткрытый диапазон: [i, j), нижняя граница включена и верхняя граница исключена.Это также способ среза Go (а также Python и многих других языков).
Дело в том, что лучше сохранить это соглашение в своем коде: при выполнении диапазона включайте нижнюю границуи исключить верхнюю границу.
Нарезка встроена в Go.Вы можете использовать это, и это дешево.Вам не нужно вычислять все эти
l
,
r
,
mid
таким многословным и подверженным ошибкам способом, вам просто нужно нарезать
slice
.
Дляпример:
func mergeSort(arr []int) {
size := len(arr)
if size <= 1 {
return
}
mid := size / 2
mergeSort(arr[:mid])
mergeSort(arr[mid:])
merge(arr, arr[:mid], arr[mid:])
}
Код намного понятнее и надежнее.
Срез не выполняет глубокое копирование, что означает, что
left := arr[l:mid]
создает только указатель на элементы
arr
.Вот почему я сказал, что нарезка дешево в го.
Однако без глубокого копирования при объединении фрагментов данные перезаписываются и, следовательно, повреждаются.Вам необходимо объединить новый фрагмент, а затем скопировать его обратно в оригинальный фрагмент.Вот почему считается, что наивный метод слияния имеет дополнительное использование памяти O(n)
.
func merge(arr, left, right []int) {
res := make([]int, len(arr))
leftSize, rightSize := len(left), len(right)
var i,j,k int
for i = range res {
if j >= leftSize || k >= rightSize {
break
}
if left[j] <= right[k] {
res[i] = left[j]
j++
} else {
res[i] = right[k]
k++
}
}
// Only one of these two copies run, so no need to increase i
copy(res[i:], left[j:])
copy(res[i:], right[k:])
copy(arr, res)
}
Детская площадка: https://play.golang.org/p/LlJj-JycfYE