草庐IT

go - Golang 新手 - 对指针感到困惑,请帮助将 c++ 片段转换为 go

coder 2023-06-29 原文

刚接触golang,正在慢慢学习。为了学习,我选择将这段算法转换为 golang“http://www.geeksforgeeks.org/backtracking-set-7-suduku/”。 我已经尽力了,但 golang 指针比 c++ 指针更容易混淆。
我尝试了很多不同的方法来让它工作,但指针的东西仍然让我心烦意乱。我只是无法让下面提到的两个功能正常工作。有时输出是 - 找不到解决方案。有时,它只是输出不变的网格。
有人可以修复 SolveSudoku() 和 FindUnassignedLocation() 函数(以及任何其他函数,如果有的话)并解释如何在 GO 中使用引用和指针。
我也尝试阅读 GO 网站上的一些文档,但这并不是那么好,而且我没有足够的经验来理解那里给出的极小的东西。
如果有人建议在此代码中可以改进的更多内容,我也将不胜感激,错误? , 错误?, 任何东西。

package main

import "fmt"

const (
    UNASSIGNED = 0
    N          = 9
)

func SolveSudoku(grid [N][N]int) bool {
    var row, col int
    if !FindUnassignedLocation(grid, row, col) {
        return true
    }
    for num := 1; num <= 9; num++ {
        if isSafe(grid, row, col, num) {
            grid[row][col] = num
            if SolveSudoku(grid) {
                return true
            }
            grid[row][col] = UNASSIGNED
        }
    }
    return false
}

func FindUnassignedLocation(grid [N][N]int, row int, col int) bool {
    for row = 0; row < N; row++ {
        for col = 0; col < N; col++ {
            if grid[row][col] == UNASSIGNED {
                return true
            }
        }
    }
    return false
}

func UsedInRow(grid [N][N]int, row int, num int) bool {
    for col := 0; col < N; col++ {
        if grid[row][col] == num {
            return true
        }
    }
    return false
}

func UsedInCol(grid [N][N]int, col int, num int) bool {
    for row := 0; row < N; row++ {
        if grid[row][col] == num {
            return true
        }
    }
    return false
}

func UsedInBox(grid [N][N]int, boxStartRow int, boxStartCol int, num int) bool {
    for row := 0; row < 3; row++ {
        for col := 0; col < 3; col++ {
            if grid[row+boxStartRow][col+boxStartCol] == num {
                return true
            }
        }
    }
    return false
}

func isSafe(grid [N][N]int, row int, col int, num int) bool {
    return !UsedInRow(grid, row, num) && !UsedInCol(grid, col, num) && !UsedInBox(grid, row-row%3, col-col%3, num)
}

func printGrid(grid [N][N]int) {
    for row := 0; row < N; row++ {
        for col := 0; col < N; col++ {
            fmt.Printf("%2d", grid[row][col])
        }
        fmt.Printf("\n")
    }
}

func main() {
    var grid = [N][N]int{
        [N]int{3, 0, 6, 5, 0, 8, 4, 0, 0},
        [N]int{5, 2, 0, 0, 0, 0, 0, 0, 0},
        [N]int{0, 8, 7, 0, 0, 0, 0, 3, 1},
        [N]int{0, 0, 3, 0, 1, 0, 0, 8, 0},
        [N]int{9, 0, 0, 8, 6, 3, 0, 0, 5},
        [N]int{0, 5, 0, 0, 9, 0, 6, 0, 0},
        [N]int{1, 3, 0, 0, 0, 0, 2, 5, 0},
        [N]int{0, 0, 0, 0, 0, 0, 0, 7, 4},
        [N]int{0, 0, 5, 2, 0, 6, 3, 0, 0},
    }

    if SolveSudoku(grid) == true {
        printGrid(grid)
    } else {
        fmt.Printf("No solution exists")
    }

    return
}

最佳答案

您的问题并不是您不了解指针。指针在 Go 中的工作方式与在 C++ 中的工作方式大体相同(除了因为 Go 具有逃逸分析和 GC 之类的东西,所以您不必担心悬空或无效指针,而代价是没有指针算法是可疑的)。

您的问题是对 C++ 和 Go 中数组之间差异的误解。在 C++ 中,数组实际上是一个指针,语法是一个别名。 int a[9]int *a 是同一类型,静态大小调整和自由初始化只是一个很酷的编译器技巧。访问数组是指针运算的奇特语法,后跟取消引用——如前所述,这是 Go 所没有的。

在 Go 中,数组是 而不是指针。当您有一个接受 a [9]int 的函数时,您实际上是在告诉编译器复制九个整数值,而不是指向内存中恰好有九个整数值的位置的指针。将 func(a [2]int) 视为编写 func(a1, a2 int) 的好方法。

这也导致了另一个细微的代码差异,在 C++ 中 int a[9][9] 是一个指向九个指针的指针,每个指针指向九个整数。在 Go 中,它是一个字面的、连续的 RMO 存储的 9x9 整数 block 。

Go 中有两种简单的解决方案:

  1. 使用指向数组的指针。如 grid *[N][N]int 中。这工作正常,但访问和存储数组中的东西有点不干净。您必须使用 (*grid)[i][j] 显式取消引用指针,该指针看起来很难看并且可能有点难以阅读。

  2. 使用 slice 。这是更好的选择,也是更惯用的 Go 风格。它还避免了到处都是令人讨厌的全局常量。代价是您确实牺牲了一些关于列大小的先验保证。

我将用带有一些注释的 slice 重写几个方法,剩下的交给你:

func main() {
    // We can omit the []int on every line, Go infers it
    var grid = [][]int{
        {3, 0, 6, 5, 0, 8, 4, 0, 0},
        {5, 2, 0, 0, 0, 0, 0, 0, 0},
        {0, 8, 7, 0, 0, 0, 0, 3, 1},
        {0, 0, 3, 0, 1, 0, 0, 8, 0},
        {9, 0, 0, 8, 6, 3, 0, 0, 5},
        {0, 5, 0, 0, 9, 0, 6, 0, 0},
        {1, 3, 0, 0, 0, 0, 2, 5, 0},
        {0, 0, 0, 0, 0, 0, 0, 7, 4},
        {0, 0, 5, 2, 0, 6, 3, 0, 0},
    }

    // == true is superfluous
    if SolveSudoku(grid) {
        printGrid(grid)
    } else {
        fmt.Println("No solution exists")
    }

    // Don't need to explicitly return, Go's mains are "void"
}


func UsedInCol(grid [][]int, col int, num int) bool {
    // We can use range to iterate over the whole slice.
    // The first value (which we ignore) is the slice index, the value you
    // used to call "row".
    // Now row is the slice containing the given row, this is similar to an iterator.
    for _,row := range grid {
        if row[col] == num {
            return true
        }
    }
    return false
}

杂项说明:

  1. 以前使用常量 N 的地方,现在可以使用 len(grid)。要获取列的长度,请使用 len(grid[0])(警告:确保 grid[0] 存在)。

  2. 由于它是一个值,因此将 [N][N]int 作为参数或返回值几乎总是效率低下,因为它在每次函数调用时都是相当大的副本。指针追逐通常更快,除非 N 值非常小(可能是 1-2)。

  3. Go 中不存在引用,除非是极端技术意义上的引用,例如封闭变量的行为。

  4. 一个更好的方法可能是声明类似 type SudokuGrid struct { grid []int; 的东西rows,cols int } 与某种 At/Set 方法集,这让你有一些大小保证回来。我会把这个(或者它是否是个好主意)留给你。

关于go - Golang 新手 - 对指针感到困惑,请帮助将 c++ 片段转换为 go,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26728331/

有关go - Golang 新手 - 对指针感到困惑,请帮助将 c++ 片段转换为 go的更多相关文章

  1. ruby-on-rails - 如何优雅地重启 thin + nginx? - 2

    我的瘦服务器配置了nginx,我的ROR应用程序正在它们上运行。在我发布代码更新时运行thinrestart会给我的应用程序带来一些停机时间。我试图弄清楚如何优雅地重启正在运行的Thin实例,但找不到好的解决方案。有没有人能做到这一点? 最佳答案 #Restartjustthethinserverdescribedbythatconfigsudothin-C/etc/thin/mysite.ymlrestartNginx将继续运行并代理请求。如果您将Nginx设置为使用多个上游服务器,例如server{listen80;server

  2. ruby-on-rails - Rails 应用程序中的 Rails : How are you using application_controller. rb 是新手吗? - 2

    刚入门rails,开始慢慢理解。有人可以解释或给我一些关于在application_controller中编码的好处或时间和原因的想法吗?有哪些用例。您如何为Rails应用程序使用应用程序Controller?我不想在那里放太多代码,因为据我了解,每个请求都会调用此Controller。这是真的? 最佳答案 ApplicationController实际上是您应用程序中的每个其他Controller都将从中继承的类(尽管这不是强制性的)。我同意不要用太多代码弄乱它并保持干净整洁的态度,尽管在某些情况下ApplicationContr

  3. ruby - 有人可以帮助解释类创建的 post_initialize 回调吗 (Sandi Metz) - 2

    我正在阅读SandiMetz的POODR,并且遇到了一个我不太了解的编码原则。这是代码:classBicycleattr_reader:size,:chain,:tire_sizedefinitialize(args={})@size=args[:size]||1@chain=args[:chain]||2@tire_size=args[:tire_size]||3post_initialize(args)endendclassMountainBike此代码将为其各自的属性输出1,2,3,4,5。我不明白的是查找方法。当一辆山地自行车被实例化时,因为它没有自己的initialize方法

  4. ruby-on-rails - Cucumber 是否只是 rspec 的包装器以帮助将测试组织成功能? - 2

    只是想确保我理解了事情。据我目前收集到的信息,Cucumber只是一个“包装器”,或者是一种通过将事物分类为功能和步骤来组织测试的好方法,其中实际的单元测试处于步骤阶段。它允许您根据事物的工作方式组织您的测试。对吗? 最佳答案 有点。它是一种组织测试的方式,但不仅如此。它的行为就像最初的Rails集成测试一样,但更易于使用。这里最大的好处是您的session在整个Scenario中保持透明。关于Cucumber的另一件事是您(应该)从使用您的代码的浏览器或客户端的角度进行测试。如果您愿意,您可以使用步骤来构建对象和设置状态,但通常您

  5. ruby - 使用 `+=` 和 `send` 方法 - 2

    如何将send与+=一起使用?a=20;a.send"+=",10undefinedmethod`+='for20:Fixnuma=20;a+=10=>30 最佳答案 恐怕你不能。+=不是方法,而是语法糖。参见http://www.ruby-doc.org/docs/ProgrammingRuby/html/tut_expressions.html它说Incommonwithmanyotherlanguages,Rubyhasasyntacticshortcut:a=a+2maybewrittenasa+=2.你能做的最好的事情是:

  6. ruby - 如何计算 Liquid 中的变量 +1 - 2

    我对如何计算通过{%assignvar=0%}赋值的变量加一完全感到困惑。这应该是最简单的任务。到目前为止,这是我尝试过的:{%assignamount=0%}{%forvariantinproduct.variants%}{%assignamount=amount+1%}{%endfor%}Amount:{{amount}}结果总是0。也许我忽略了一些明显的东西。也许有更好的方法。我想要存档的只是获取运行的迭代次数。 最佳答案 因为{{incrementamount}}将输出您的变量值并且不会影响{%assign%}定义的变量,我

  7. ruby-on-rails - 需要帮助最大化多个相似对象中的 3 个因素并适当排序 - 2

    我需要用任何语言编写一个算法,根据3个因素对数组进行排序。我以度假村为例(如Hipmunk)。假设我想去度假。我想要最便宜的地方、最好的评论和最多的景点。但是,显然我找不到在所有3个中都排名第一的方法。Example(assumingthereare20importantattractions):ResortA:$150/night...98/100infavorablereviews...18of20attractionsResortB:$99/night...85/100infavorablereviews...12of20attractionsResortC:$120/night

  8. arrays - Ruby 数组 += vs 推送 - 2

    我有一个数组数组,想将元素附加到子数组。+=做我想做的,但我想了解为什么push不做。我期望的行为(并与+=一起工作):b=Array.new(3,[])b[0]+=["apple"]b[1]+=["orange"]b[2]+=["frog"]b=>[["苹果"],["橙子"],["Frog"]]通过推送,我将推送的元素附加到每个子数组(为什么?):a=Array.new(3,[])a[0].push("apple")a[1].push("orange")a[2].push("frog")a=>[[“苹果”、“橙子”、“Frog”]、[“苹果”、“橙子”、“Frog”]、[“苹果”、“

  9. ruby - 帮助使用 Ruby 中的 "Whenever"gem 来执行 cron 任务 - 2

    我以前没有使用过cron,所以我不能确定我这样做是对的。我想要自动化的任务似乎没有运行。我在终端中执行了这些步骤:sudogeminstall每当切换到应用程序目录无论何时。(这创建了文件schedule.rb)我将此代码添加到schedule.rb:every10.minutesdorunner"User.vote",environment=>"development"endevery:hourdorunner"Digest.rss",:environment=>"development"end我将此代码添加到deploy.rb:after"deploy:symlink","depl

  10. += 的 Ruby 方法 - 2

    有没有办法让Ruby能够做这样的事情?classPlane@moved=0@x=0defx+=(v)#thisiserror@x+=v@moved+=1enddefto_s"moved#{@moved}times,currentxis#{@x}"endendplane=Plane.newplane.x+=5plane.x+=10putsplane.to_s#moved2times,currentxis15 最佳答案 您不能在Ruby中覆盖复合赋值运算符。任务在内部处理。您应该覆盖+,而不是+=。plane.a+=b与plane.a=

随机推荐