TDD
实践:Go
语言快排算法实现
包结构介绍
在学习Learn Go WIth Tests的过程中,我在$GOPATH
的src
下创建了项目learn-go-with-tests
,本小节实现快排算法,所以关注点在下图的红框中。
需要注意的是,即便我们按照TDD
流程开发算法,我们也要注意qsort.go
文件内至少声明包package quicksort
。随后我们开始进行下面的TDD
流程。
先写测试
编写如下测试:
// qsort_test.go
package quicksort
import "testing"
func TestQsort(t *testing.T) {
var got = [8]int{1, 8, 2, 4, 3, 7, 5, 6};
Qsort(got[:]);
exp := [8]int{1, 2, 3, 4, 5, 6, 7, 8};
if cmp(got[:], exp[:]) != true {
t.Errorf("expected %v but got %v", exp, got);
}
}
func cmp(a []int, b []int) bool {
if len(a) != len(b) {
return false;
}
for i := 0; i < len(a); i++ {
if a[i] != b[i] {
return false;
}
}
return true;
}
尝试运行测试
执行go test
得到意料之中的报错信息:
先使用最少的代码来让失败的测试先跑起来
现在只需让代码可编译,这样就可以检查测试用例能否通过。我们在qsort.go
文件中定义Qsort
函数:
// qsort.go
package quicksort
func Qsort(arr []int) {
}
再次执行go test
命令,我们发现编译已经成功,但如意料之中测试失败:
把代码补充完整,使得它能够通过测试
将目光投向Qsort
函数,我们将其补充完整。
package quicksort
func Qsort(arr []int) {
qsortHelper(arr, 0, len(arr) - 1);
}
// sort elements in arr[low, high]
func qsortHelper(arr []int, low int, high int) {
if low > high {
return
}
tmp := arr[low];
i := low;
j := high;
for i != j {
for arr[j] >= tmp && j > i {
j--;
}
for arr[i] <= tmp && j > i {
i++;
}
if j > i {
t := arr[i];
arr[i] = arr[j];
arr[j] = t;
}
}
arr[low] = arr[i];
arr[i] = tmp;
qsortHelper(arr[:], low, i - 1);
qsortHelper(arr[:], i + 1, high);
}
我们再次测试,这一次执行go test -v
,参数-v
用于输出测试的详细信息:
可以看到,我们通过了测试。
重构
我们对helper
进行重构,主要体现在变量交换上,我们可以避免临时变量的使用。比如上面交换arr[i]
与arr[j]
时,我们可以利用Go
语言多变量赋值的操作arr[i], arr[j] = arr[j], arr[i];
。其他小改动在如下代码中给出。
// qsort.go
package quicksort
func Qsort(arr []int) {
qsortHelper(arr, 0, len(arr) - 1);
}
// sort elements in arr[low, high]
func qsortHelper(arr []int, low, high int) { // 参数易读
if low > high {
return
}
tmp := arr[low];
var i, j = low, high; // 赋值易读
for i != j {
for arr[j] >= tmp && j > i {
j--;
}
for arr[i] <= tmp && j > i {
i++;
}
if j > i {
arr[i], arr[j] = arr[j], arr[i]; // 交换不需要临时变量
}
}
arr[low] = arr[i];
arr[i] = tmp;
qsortHelper(arr[:], low, i - 1);
qsortHelper(arr[:], i + 1, high);
}
基准测试
编写基准测试:
// qsort_test.go
func BenchmarkRepeat(b *testing.B) {
for i := 0; i < b.N; i++ {
arr := [8]int{8, 6, 7, 1, 3, 4, 2, 5};
Qsort(arr[:]);
}
}
执行go test -bench=.
命令执行基准测试,可以得到:
结果说明执行一次快排函数执行了134 ns
,函数一共执行了20487184
次。