这里有点奇怪。我的问题是,人们从运行我的代码中得到的结果是否与我一样?如果这样做,是我的代码错误(通常我是python程序员)还是golang中的错误?
系统信息: Go版本(1.1.2)linux x64(fedora 19)
代码上的背景信息:我正在做的是找到从三角形顶部到底部的最高成本路线,这是来自project_euler 18和67
错误:我设置了一个名为pathA的变量,这是一个整数列表,并为从三角形中找到的新值添加了一个新的int值,例如3、7、2追加8应该等于3、2、7、8,而且确实如此!...直到设置pathB。pathB设置正确,但是突然pathA与pathB的值相同。
tl; dr当我设置另一个变量时,一个变量被覆盖
我的代码如下:
package main import ( "fmt" ) func extendPaths(triangle, prePaths [][]int) [][]int { nextLine := triangle[len(prePaths)] fmt.Println("#####PrePaths: ", prePaths) fmt.Println("#####nextLine: ", nextLine) postPaths := [][]int{{}} for i := 0; i < len(prePaths); i++ { route := prePaths[i] nextA := nextLine[i] nextB := nextLine[i+1] fmt.Println("Next A:", nextA, "Next B:", nextB, "\n") pathA := append(route, nextA) fmt.Println("pathA check#1:", pathA) pathB := append(route, nextB) fmt.Println("pathA check#2:", pathA, "\n") postPaths = append(postPaths, pathA) postPaths = append(postPaths, pathB) } postPaths = postPaths[1:] prePaths = [][]int{postPaths[0]} for i := 1; i < len(postPaths)-1; i += 2 { if getSum(postPaths[i]) > getSum(postPaths[i+1]) { prePaths = append(prePaths, postPaths[i]) } else { prePaths = append(prePaths, postPaths[i+1]) } } prePaths = append(prePaths, postPaths[len(postPaths)-1]) return prePaths } func getSum(sumList []int) int { total := 0 for i := 0; i < len(sumList); i++ { total += sumList[i] } return total } func getPaths(triangle [][]int) { prePaths := [][]int{{triangle[0][0]}} for i := 0; i < len(triangle)-1; i++ { prePaths = extendPaths(triangle, prePaths) } } func main() { triangle := [][]int{{3}, {7, 4}, {2, 4, 6}, {8, 5, 9, 3}} getPaths(triangle) }
这给出了我的终端中的输出,如下所示:
#####PrePaths: [[3]] #####nextLine: [7 4] Next A: 7 Next B: 4 pathA check#1: [3 7] pathA check#2: [3 7] #####PrePaths: [[3 7] [3 4]] #####nextLine: [2 4 6] Next A: 2 Next B: 4 pathA check#1: [3 7 2] pathA check#2: [3 7 2] Next A: 4 Next B: 6 pathA check#1: [3 4 4] pathA check#2: [3 4 4] #####PrePaths: [[3 7 2] [3 7 4] [3 4 6]] #####nextLine: [8 5 9 3] Next A: 8 Next B: 5 pathA check#1: [3 7 2 8] pathA check#2: [3 7 2 5] Next A: 5 Next B: 9 pathA check#1: [3 7 4 5] pathA check#2: [3 7 4 9] Next A: 9 Next B: 3 pathA check#1: [3 4 6 9] pathA check#2: [3 4 6 3]
在这里,您可以看到在我设置pathA的最后4次中,它最初设置正确,但随后被pathB覆盖。
有人对此有任何想法吗?
编辑:
正如下面的评论所指出的,需要做的是制作新的切片并从原始文件中复制数据。这是使用http://blog.golang.org/go-slices-usage-and-internals中的代码进行了稍微修改的:
func AppendInt(slice []int, data ...int) []int { m := len(slice) n := m + len(data) if n > cap(slice) { newSlice := make([]int, (n+1)*2) copy(newSlice, slice) slice = newSlice } slice = slice[0:n] copy(slice[m:n], data) return slice }
我还更改了另一侧的代码,在其中创建了切片pathA和pathB。更改为:
for i := 0; i < len(prePaths); i++ { nextA := nextLine[i] nextB := nextLine[i+1] pathA := AppendInt(prePaths[i], nextA) pathB := AppendInt(prePaths[i], nextB) postPaths = append(postPaths, pathA) postPaths = append(postPaths, pathB) }
编辑2:
这是一大早,在进行第一次编辑时,我全力以赴,但我不完全理解您的解决方案,经过一番黑客之后,我终于到达了那里:
此代码不起作用(pathA被覆盖):
for i := 0; i < len(prePaths); i++ { nextA := nextLine[i] nextB := nextLine[i+1] pathA := append(prePaths[i], nextA) pathB := append(prePaths[i], nextB) postPaths = append(postPaths, pathA) postPaths = append(postPaths, pathB) }
此代码也不起作用(pathA被覆盖):
for i := 0; i < len(prePaths); i++ { newRoute := make([]int, len(prePaths[i]), (cap(prePaths[i])+1)*2) copy(newRoute, prePaths[i]) nextA := nextLine[i] nextB := nextLine[i+1] pathA := append(newRoute, nextA) pathB := append(newRoute, nextB) postPaths = append(postPaths, pathA) postPaths = append(postPaths, pathB) }
但是,如果我将上述两种情况混合到下面的代码中,则可以正常工作(pathA不会被覆盖):
for i := 0; i < len(prePaths); i++ { newRoute := make([]int, len(prePaths[i]), (cap(prePaths[i])+1)*2) copy(newRoute, prePaths[i]) nextA := nextLine[i] nextB := nextLine[i+1] pathA := append(newRoute, nextA) pathB := append(prePaths[i], nextB) postPaths = append(postPaths, pathA) postPaths = append(postPaths, pathB) }
因此,我的解决方案是复制数组,并让它们都使用不同的数组。
切片基本上是由三部分组成的结构:
指向切片中元素数组的指针
该数组的长度(“容量”)
实际存储在数组中的元素数(“长度”)
当您运行以下代码时:
append(x, element)
它执行以下操作:
检查扩展切片是否会超出基础数组的容量。如果是这样,请分配更大的一个并将现有元素复制到新阵列,然后更新容量。
将一个或多个新元素写入数组的末尾并更新长度。
返回新的切片。
在代码中,您具有以下内容:
pathA := append(route, nextA) pathB := append(route, nextB)
现在这里有两种可能性:
len(route) == cap(route)
,然后将分配一个新的支持数组,pathA
并pathB
具有独立的值。
len(route) < cap(route)
,所以pathA
和pathB
最终共享相同的背衬阵列。数组中的最后一个元素将是nextB
,因为该操作第二次运行。
在循环的前几次迭代中,第一种情况似乎是正确的,然后您遇到了第二种情况。您可以通过为其中一个路径手动创建副本来避免这种情况(使用分配切片make()
,然后用于copy()
复制旧数据)。