golang实现一个通用类型数组排序函数

先考虑某一个具体类型的数组(比如[]int)的排序方式,实现如伪代码所示:

func sort(arr []int) {

	for i := 0; i < len(arr)-1; i++ {
		for j := i + 1; j < len(arr); j++ {
			if arr[i] > arr[j] {
				arr[i], arr[j] = arr[j], arr[i]
			}
		}
	}
}

现仔细考察之,通过伪代码所示,我们如果对一个数组排序,需要知道:

  • 数组的长度
  • 数据里面任意两个元素的大小
  • 交换数组里面的任意两个元素的位置

推广到一般情况,通用类型也应该具有这三种能力。另外,对于sort函数的签名,参数类型为[]int,为了能够传递通用类型的数组,也需要进化下。

以上两点,结合golang语言的特点,可以把通用类型数组type成一个interface,然后三个能力用方法来规定。接口定义可以设计成如下的样子:

type SortInterface interface {
	Len() int
	Cmp(i, j int) bool
	Swap(i, j int)
}
  • Len方法返回数组的元素个数
  • Cmp方法返回两个下标对应的元素的大小
  • Swap方法交换两个下标对应的元素位置

sort函数定义:

func sort(arr SortInterface) {
	for i := 0; i < arr.Len()-1; i++ {
		for j := i + 1; j < arr.Len(); j++ {
			if arr.Cmp(i, j) {
				arr.Swap(i, j)
			}
		}
	}
}

由于我们定义了一个接口,并且接口定义了三个方法,只要是实现了了该接口的数组都可以对之排序。

举个例子:

如代码块所示,我们要对该数组排序:

arr := []int{1, 5, 2, 4, 7, 0, 9, 3, 5}

第一步,先type一个类型,比如:

type Array []int

第二步,实现接口三个方法

func (a Array) Cmp(i, j int) bool {
	return a[i] - a[j] > 0
}

func (a Array) Swap(i, j int) {
	a[i], a[j] = a[j], a[i]
}

func (a Array) Len() int {
	return len(a)
}

加上测试代码,完整代码如下:

package main

import (
	"fmt"
)

type Array []int

func (a Array) Cmp(i, j int) bool {
	return a[i]-a[j] > 0
}

func (a Array) Swap(i, j int) {
	a[i], a[j] = a[j], a[i]
}

func (a Array) Len() int {
	return len(a)
}

type SortInterface interface {
	Len() int
	Cmp(i, j int) bool
	Swap(i, j int)
}

func Sort(arr SortInterface) {
	for i := 0; i < arr.Len()-1; i++ {
		for j := i + 1; j < arr.Len(); j++ {
			if arr.Cmp(i, j) {
				arr.Swap(i, j)
			}
		}
	}
}

func main() {
	arr := []int{1, 5, 2, 4, 7, 0, 9, 3, 5}
	fmt.Println(arr)
	Sort(Array(arr))
	fmt.Println(arr)
}

运行结果

╰─➤  go run main.go
[1 5 2 4 7 0 9 3 5]
[0 1 2 3 4 5 5 7 9]