下面是一个函数的定义:

func CrossPointTwoRects(rec1, rec2 []int) [][]int {
    crossPoints := make([][]int, 0)
    existed := make(map[string]bool, 0)
    x1 := rec1[0]
    y1 := rec1[1]
    x2 := rec1[2]
    y2 := rec1[3]
    x3 := rec2[0]
    y3 := rec2[1]
    x4 := rec2[2]
    y4 := rec2[3]
    var xs = []int{x1, x2, x3, x4}
    var ys = []int{y1, y2, y3, y4}
    for _, x := range xs {
        for _, y := range ys {
            key := fmt.Sprintf("%d-%d", x, y)
            if x1 <= x && x <= x2 && x3 <= x && x <= x4 && y1 <= y && y <= y2 && y3 <= y && y <= y4 && !existed[key] {
                crossPoints = append(crossPoints, []int{x, y})
                existed[key] = true
            }
        }
    }
    return crossPoints
}

而rect1和rect2是四个长度的array.这个函数应该执行得很快,但是当你多次调用它的时候,它会花费更多的时间,甚至一次调用也要花费0.5ms,这太令人惊讶了.

有人能告诉我为什么吗?谢谢你的帮助

推荐答案

在Go中,可读性是最重要的.

classic 计算机科学课本的标题是算法+数据 struct =程序.


数据 struct 包括:

type Point struct {
    X, Y int
}

type Rectangle struct {
    P1 Point // Min
    P2 Point // Max
}

算法是:

func CrossPointTwoRects(r1, r2 Rectangle) []Point {
    var crossPoints []Point
    existed := make(map[Point]bool, 0)
    var xs = []int{r1.P1.X, r1.P2.X, r2.P1.X, r2.P2.X}
    var ys = []int{r1.P1.Y, r1.P2.Y, r2.P1.Y, r2.P2.Y}
    for _, x := range xs {
        if r1.P1.X <= x && x <= r1.P2.X && r2.P1.X <= x && x <= r2.P2.X {
            for _, y := range ys {
                if r1.P1.Y <= y && y <= r1.P2.Y && r2.P1.Y <= y && y <= r2.P2.Y {
                    p := Point{X: x, Y: y}
                    if !existed[p] {
                        if crossPoints == nil {
                            crossPoints = make([]Point, 0, 4)
                        }
                        crossPoints = append(crossPoints, p)
                        existed[p] = true
                    }
                }
            }
        }
    }
    return crossPoints
}

https://go.dev/play/p/7gGc5Xsm1xA


一些围棋基准:

func BenchmarkY(b *testing.B) {
    // Y - Intersection
    r1 := Rectangle{Point{1, 1}, Point{4, 4}}
    r2 := Rectangle{Point{2, 2}, Point{3, 3}}
    for i := 0; i < b.N; i++ {
        CrossPointTwoRects(r1, r2)
    }
}

func BenchmarkN(b *testing.B) {
    // N - No intersection
    r1 := Rectangle{Point{1, 1}, Point{4, 4}}
    r2 := Rectangle{Point{8, 8}, Point{9, 9}}
    for i := 0; i < b.N; i++ {
        CrossPointTwoRects(r1, r2)
    }
}

可比基准结果:

rocka2q:
BenchmarkY-12     8445902    142.8 ns/op    64 B/op   1 allocs/op
BenchmarkN-12   120209712     10.12 ns/op    0 B/op   0 allocs/op

zhuohuashiyi:
BenchmarkYZ-12     872277   1376 ns/op     283 B/op  23 allocs/op
BenchmarkNZ-12    1000000   1147 ns/op      51 B/op  16 allocs/op

coxley:
BenchmarkYC-12    5387480    212.2 ns/op    64 B/op   1 allocs/op
BenchmarkNC-12   13633231     82.94 ns/op   64 B/op   1 allocs/op

Go相关问答推荐

Makefile:现有文件上没有这样的文件或目录,不加载环境变量

调用API时使用nginx作为反向代理时从nginx获取502坏网关

按键值排序字符串- Golang

错误.如果它包含切片,则返回FALSE

如何用';贪婪原则';正确地

go mod tidy会自动升级go.mod中的go版本吗?

如何将 goose 迁移与 pgx 一起使用?

将字符串格式的x509证书生成主题名称

最长连续重复的字符golang

GoLang:net.LookupHost 返回重复的 ips

使用 unsafe.Pointer 将 struct point直接转换为另一个 struct 是否安全?

如何将元素从一个切片移动到另一个切片

接受通道和切片的通用函数

使用 oklog/run 来自 Go 编译器的错误(无值)用作值

每 N 秒运行一次函数,上下文超时

如何在gorm中处理多个查询

正确编码 JWT

gqlgen go,通过添加一个解析器来减少数据库调用

如何在 docker 文件中安装 golang 包?

Scanner.Buffer - 最大值对自定义拆分没有影响?