Go指南练习10-等价二叉查找树

这个是A Tour of Go这个教程里面的第十个练习,原题如下:

不同二叉树的叶节点上可以保存相同的值序列。例如,以下两个二叉树都保存了序列 `1,1,2,3,5,8,13`。

在大多数语言中,检查两个二叉树是否保存了相同序列的函数都相当复杂。 我们将使用 Go 的并发和信道来编写一个简单的解法。

本例使用了 tree 包,它定义了类型:

type Tree struct {
    Left  *Tree
    Value int
    Right *Tree
}

1. 实现 Walk 函数。

2. 测试 Walk 函数。

函数 tree.New(k) 用于构造一个随机结构的已排序二叉查找树,它保存了值 k2k3k, …, 10k

创建一个新的信道 ch 并且对其进行步进:

go Walk(tree.New(1),
Tags:

Go指南练习9-图像

这个是A Tour of Go这个教程里面的第九个练习,原题如下:

还记得之前编写的图片生成器 吗?我们再来编写另外一个,不过这次它将会返回一个 image.Image 的实现而非一个数据切片。

定义你自己的 Image 类型,实现必要的方法并调用 pic.ShowImage

Bounds 应当返回一个 image.Rectangle ,例如 image.Rect(0, 0, w, h)

ColorModel 应当返回 color.RGBAModel

At 应当返回一个颜色。上一个图片生成器的值 v 对应于此次的 color.RGBA{v, v, 255, 255}

原题模板代码如下:

package main

import "golang.org/x/tour/pic"
Tags:

Go指南练习8-rot13Reader

这个是A Tour of Go这个教程里面的第八个练习,原题如下:

有种常见的模式是一个 io.Reader 包装另一个 io.Reader,然后通过某种方式修改其数据流。

例如,gzip.NewReader 函数接受一个 io.Reader(已压缩的数据流)并返回一个同样实现了 io.Reader 的 *gzip.Reader(解压后的数据流)。

编写一个实现了 io.Reader 并从另一个 io.Reader 中读取数据的 rot13Reader,通过应用 rot13 代换密码对数据流进行修改。

rot13Reader 类型已经提供。实现 Read 方法以满足 io.Reader

原题模板代码如下:

package
Tags:

Go指南练习7-Reader

这个是A Tour of Go这个教程里面的第七个练习,原题如下:

实现一个 Reader 类型,它产生一个 ASCII 字符 'A' 的无限流。

原题代码模板如下:

package main

import (
	"golang.org/x/tour/reader"
)

type MyReader struct{}

// TODO: 给 MyReader 添加一个 Read([]byte) (int, error) 方法

func main() {
	reader.Validate(MyReader{})
}

这题其实就是要实现一个Read接口:

func (T) Read(b []byte) (n int, err error)

然后在这个接口里面一直返回b的长度,给b注入相应长度的A的ASCII码就好:

package main

import (
	"golang.org/x/tour/reader"
)

type MyReader
Tags:

 Go指南练习6-错误

这个是A Tour of Go这个教程里面的第六个练习,原题如下:

之前的练习中复制 Sqrt 函数,修改它使其返回 error 值。

Sqrt 接受到一个负数时,应当返回一个非 nil 的错误值。复数同样也不被支持。

创建一个新的类型

type ErrNegativeSqrt float64

并为其实现

func (e ErrNegativeSqrt) Error() string

方法使其拥有 error 值,通过 ErrNegativeSqrt(-2).Error() 调用该方法应返回 "cannot Sqrt negative number: -2"

注意: 在 Error 方法内调用 fmt.Sprint(e) 会让程序陷入死循环。可以通过先转换 e 来避免这个问题:

Tags:

Go指南练习5-Stringer

这个是A Tour of Go这个教程里面的第五个练习,原题如下:

通过让 IPAddr 类型实现 fmt.Stringer 来打印点号分隔的地址。

例如,IPAddr{1, 2, 3, 4} 应当打印为 "1.2.3.4"

原题模板如下:

package main

import "fmt"

type IPAddr [4]byte

// TODO: Add a "String() string" method to IPAddr.

func main() {
	hosts := map[string]IPAddr{
		"loopback":  {127, 0, 0, 1},
		"googleDNS": {8, 8, 8, 8},
	}
	for name, ip := range hosts {
		fmt.Printf("%v: %v\n", name, ip)
	}
}

这个程序可以直接运行,结果如下:

loopback: [127 
Tags:

Go指南练习4-斐波那契闭包

这个是A Tour of Go这个教程里面的第四个练习,原题如下:

实现一个 fibonacci 函数,它返回一个函数(闭包),该闭包返回一个斐波纳契数列 `(0, 1, 1, 2, 3, 5, …)`。

原题代码模板如下:

package main

import "fmt"

// fibonacci is a function that returns
// a function that returns an int.
func fibonacci() func() int {
}

func main() {
	f := fibonacci()
	for i := 0; i < 10; i++ {
		fmt.Println(f())
	}
}

这题需要fibonacci函数返回一个闭包函数,这个闭包函数需要引用函数体外的变量,并对其进行修改,以保存中间结果——该数列的最新的两个值。实现代码如下:

package main

import "fmt"

// 返回一个“返回int的函数”
func fibonacci()
Tags:

Go指南练习3-映射Map

这个是A Tour of Go这个教程里面的第三个练习,原题如下:

实现 WordCount。它应当返回一个映射,其中包含字符串 s 中每个“单词”的个数。函数 wc.Test 会对此函数执行一系列测试用例,并输出成功还是失败。

你会发现 strings.Fields 很有帮助。

打开上面对应的链接,可以看到strings.Fields的作用是将一段话中的单词提取出来,并返回一个切片[]string。我们只需要用循环统计一下这个切片里面单词出现的次数就好了。实现如下:

package main

import (
	"golang.org/x/tour/wc"
	"strings"
)

func WordCount(s string) map[string]int {
	m := make(map[string]int)
	
	for _, w := range strings.Fields(s)
Tags:

Go指南练习2-切片

这个是A Tour of Go这个教程里面的第二个练习,原题如下:

实现 Pic。它应当返回一个长度为 dy 的切片,其中每个元素是一个长度为 dx,元素类型为 uint8 的切片。当你运行此程序时,它会将每个整数解释为灰度值(好吧,其实是蓝度值)并显示它所对应的图像。

图像的选择由你来定。几个有趣的函数包括 (x+y)/2x*yx^yx*log(y) 和 x%(y+1)

(提示:需要使用循环来分配 [][]uint8 中的每个 []uint8;请使用 uint8(intValue) 在类型之间转换;你可能会用到 math 包中的函数。)

这个题比较简单,就是要利用循环,创建一个二维切片(数组),然后给每个元素赋一个值,这个值可以根据二维数组的坐标xy来计算,题目中提供了几个函数。我们用…

Tags:

Go指南练习1-循环与函数

A Tour of Go这个教程(中文版)真是做的太好了,学习和练习Go的基础还是很不错的。把上面的练习都做了,来做个记录。这个练习是控制与循环里面的,原题如下:

为了练习函数与循环,我们来实现一个平方根函数:用牛顿法实现平方根函数。

计算机通常使用循环来计算 x 的平方根。从某个猜测的值 z 开始,我们可以根据 z² 与 x 的近似度来调整 z,产生一个更好的猜测:

z -= (z*z - x) / (2*z)

重复调整的过程,猜测的结果会越来越精确,得到的答案也会尽可能接近实际的平方根。

在提供的 func Sqrt 中实现它。无论输入是什么,对 z 的一个恰当的猜测为 1。 要开始,请重复计算 10 次并随之打印每次的 z 值。观察对于不同的值 x(1、2、3 …), 你得到的答案是如何逼近结果的,猜测提升的速度有多快。

提示:用类型转换或浮点数语法来声明并初始化一个浮点数值:

z := 1.0
z := float64(1)

然后,修改循环条件,使得当值停止改变(或改变非常小)的时候退出循环。观察迭代次数大于还是小于

Tags: