Go语言快速排序&TDD
单元测试
新建一个名为Quicksort的包,在该包下进行TDD。首先编写一个单元测试文件。
testing 提供对 Go 包的自动化测试的支持。通过 go test 命令,能够自动执行如下形式的任何函数:
func TestXxx(*testing.T)
需要注意的是,测试文件名必须以xxx_test.go命名,并且测试文件中的方法必须是Test[^a-z]开头。执行单元测试的时候,只需执行go test命令即可。
该文件命名为quicksort_test.go,代码如下:
package Quicksort
import "testing"
func TestQuicksort(t *testing.T) {
sortArray := []int{3, 2, 7, 1, 4, 6, 9, 8, 5, 10}
Sort(sortArray,0,9)
expected := []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
for i := 0;i < 10;i++ {
if sortArray[i] != expected[i] {
t.Errorf("expected '%d' but got '%d'", expected[i], sortArray[i])
}
}
}
此时若尝试运行测试,会得到如下结果:
# github.com/github-user/Quicksort
./quicksort_test.go:7:5: undefined: Sort
FAIL github.com/github-user/Quicksort [build failed]
运行测试
显然,这是因为还没有实现Sort函数导致的。接下来,实现快速排序Sort函数。新建一个quicksort.go文件,在里面编写如下代码:
package Quicksort
func Sort(arr []int,low,high int){
}
此时,已经拥有Sort函数,只不过里面没有实现任何代码。再次执行go test得到如下输出:
补充完成快排代码,使得测试通过
快速排序的主要思想是先从数列中挑出一个元素,称为 “基准”(pivot),然后将待排序的元素分为两部分,比基准小的元素放在基准前面,反之放在基准后面。最后递归地把小于基准值元素的子数列和大于基准值元素的子数列排序;然后分别对这两部分元素继续进行排序,以达到整个序列有序。
动图演示:
实现代码如下:
package Quicksort
func Sort(arr []int,low,high int){
if (low < high){
i:=low
j:=high
x:=arr[low]
for ;i < j;{
for ;i<j&&arr[j]>=x; {
j--
}
if i < j{
arr[i] = arr[j]
i++
}
for ;i<j&&arr[i]<x; {
i++
}
if i < j{
arr[j] = arr[i]
j--
}
}
arr[i] = x
Sort(arr,low,i-1)
Sort(arr,i+1,high)
}
}
再次运行测试:
发现测试通过。
重构
将go语言对比c语言,发现for循环中可以省略掉两个分号,因此省略掉for循环中的分号。将代码修改如下:
func Sort(arr []int,low,high int){
if (low < high){
i:=low
j:=high
x:=arr[low]
for i < j{
for i<j&&arr[j]>=x {
j--
}
if i < j{
arr[i] = arr[j]
i++
}
for i<j&&arr[i]<x {
i++
}
if i < j{
arr[j] = arr[i]
j--
}
}
arr[i] = x
Sort(arr,low,i-1)
Sort(arr,i+1,high)
}
}
基准测试
基准测试可以测试一段程序的运行性能及耗费 CPU 的程度。Go 语言中提供了基准测试框架,使用方法类似于单元测试,使用者无须准备高精度的计时器和各种分析工具,基准测试本身即可以打印出非常标准的测试报告。
基准测试的使用规则:
1.基准测试的代码文件必须以_test.go结尾。
2.基准测试的函数必须以Benchmark开头。
3.基准测试函数必须接受一个指向testing.B类型的指针作为唯一参数。
4.在测试执行之前,需要调用b.ResetTimer(重置计时器)来重置时间,以便过滤掉测试之前代码所消耗的时间。
5.测试代码需要写在for循环中,并且循环中的最大之是b.N。
因此,新建一个benchmark_test.go文件
package Quicksort
import "testing"
func BenchmarkQuicksort(b *testing.B) {
for i := 0; i < b.N; i++ {
sortArray := []int{3, 2, 7, 1, 4, 6, 9, 8, 5, 10}
Sort(sortArray,0,9)
}
}
执行
go test -bench=.
运行基准测试
结果说明运行一次这个函数需要 59.4 纳秒,一共运行了200000000次。