1 回答

TA貢獻(xiàn)1780條經(jīng)驗(yàn) 獲得超4個(gè)贊
我想建議幾件事:
數(shù)組范圍。Dijkstra 曾經(jīng)爭論過數(shù)組范圍(或在 Go 中,切片范圍)應(yīng)該如何:對于 的符號
l[i:j]
,您希望它具有所有這些屬性:它應(yīng)該從 i 開始。
計(jì)算長度應(yīng)該是微不足道的:
len(l[i:j]) == j-i
總是正確的表達(dá)一個(gè)空范圍應(yīng)該是優(yōu)雅的,所以
i<=j
總是如此
因此,l[i:j]被設(shè)置為一個(gè)半開范圍:[i,j],包含下界,排除上界。這也是 Go 切片的工作方式(以及 Python 和許多其他語言)。
關(guān)鍵是,最好在您的代碼中保留此約定:在執(zhí)行范圍時(shí),包括下限并排除上限。
切片是內(nèi)置于 Go 中的。你可以使用它而且很便宜。您不需要以如此冗長且容易出錯(cuò)的方式計(jì)算所有這些
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]
只創(chuàng)建一個(gè)指向 的元素的指針arr
。這就是為什么我說切片在 Go 中很便宜。
但是,如果沒有深拷貝,當(dāng)您合并切片時(shí),數(shù)據(jù)會(huì)被覆蓋并因此損壞。您需要合并到一個(gè)新的切片中,然后將其復(fù)制回原始切片。這就是為什么 naive mergesort 被認(rèn)為有O(n)
額外的內(nèi)存使用。
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)
}
Playground: https://play.golang.org/p/LlJj-JycfYE
- 1 回答
- 0 關(guān)注
- 174 瀏覽
添加回答
舉報(bào)