当前位置: 首页 > news >正文

模仿 Go Sort 排序接口实现的自定义排序

查看完整代码,点击这里

最近在使用 Go 语言实现一些简单的排序算法时,发现无法实现一个支持多种类型的排序方法,当然实现一个 int 类型的排序算法是简单的。例如下面的选择排序:

func SelectionSort(arr []int, length int)  {
    for i := 0; i < length; i++ {
        minIndex := i
        for j := i + 1; j < length; j++ {
            if arr[j] < arr[j - 1] {
                minIndex = j
            }
        }
        arr[i], arr[minIndex] = arr[minIndex], arr[i]
    }
}

但是如何实现一个方法,可以对字母排序、按照结构体内数据排序... 呢?

我首先想到的当然是 interface 类型,将 int 替换成 interface 就可以了吗?实际是不行的,Go 语言对于类型的要求非常严格,因为程序无法判断 interface 具体是什么数据类型,所以它也不知道该怎么比较一个未知的数据类型,这会导致一个运行时错误。

interface 的断言也是行不通的,因为我们也不知道会传入什么数据类型,又怎么判断要断言为什么数据类型呢。

然后我就想到了 Go 自带的 sort 排序包,发现自定义数据类型的排序需要实现对应的接口。以下内容与此文章类似,有部分参考的内容。

Interface 接口

既然 Go 不知道怎么排序未知的数据类型,我们自己来定义比较的规则不就可以了吗?Go 的 sort 包正是这样实现的。

// A type, typically a collection, that satisfies sort.Interface can be
// sorted by the routines in this package. The methods require that the
// elements of the collection be enumerated by an integer index.
type Interface interface {
    // Len is the number of elements in the collection.
    Len() int
    // Less reports whether the element with
    // index i should sort before the element with index j.
    Less(i, j int) bool
    // Swap swaps the elements with indexes i and j.
    Swap(i, j int)
}

Less() 解决的就是问题的症结,我们可以自己定义比较的逻辑。

示例

以下内容是展示如何使用这个接口。

自定义排序的结构体

这里定义了一个学生的数据结构,我们将对所有的学生进行排序,学生包含他的姓名以及成绩,排序的规则是按照学习的成绩排序

type Student struct {
    Name  string
    Score int
}
type Students []Student

实现排序的接口

func (s Students) Len() int {
    return len(s)
}

// 在比较的方法中,定义排序的规则
func (s Students) Less(i, j int) bool {
    if s[i].Score < s[j].Score {
        return true
    } else if s[i].Score > s[j].Score {
        return false
    } else {
        return s[i].Name < s[i].Name
    }
}

func (s Students) Swap(i, j int) {
    temp := s[i]
    s[i] = s[j]
    s[j] = temp
}

实现排序逻辑

Go 提供了基于快排实现的排序方法,这里为了体验为什么 Go 这么定义 Interface 接口,我使用了选择排序的方法代替 Go 的快排。

func Sort(s sort.Interface) {
    length := s.Len()
    for i := 0; i < length; i++ {
        minIndex := i
        for j := i + 1; j < length; j++ {
            if s.Less(j, i) {
                minIndex = j
            }
        }
        s.Swap(minIndex, i)
    }
}

在这个排序中,我使用了接口中定义的三个方法: Len(),Less(),Swap()。最重要的还是 Less(),没有它程序就不知道如何去比较两个未知元素的大小。

重写输出

为了更好的输出学生的信息,重写学生的字符串输出格式

func (s Student) String() string {
    return fmt.Sprintf("Student: %s %v", s.Name, s.Score)
}

测试输出

通过以下程序测试我们的排序算法

func main() {
    arr := []int{10, 9, 8, 7, 6, 5, 4, 3, 2, 1}
    SelectionSort(arr, len(arr))

    fmt.Println(arr)

    students := student.Students{}

    students = append(students, student.Student{"D", 90})
    students = append(students, student.Student{"C", 100})
    students = append(students, student.Student{"B", 95})
    students = append(students, student.Student{"A", 95})
    Sort(students)

    for _, student := range students {
        fmt.Println(student)
    }
}

以下是输出结果:

[1 2 3 4 5 6 7 8 9 10]
Student: D 90
Student: A 95
Student: B 95
Student: C 100

总结

查看 sort 包的官方文档,可以看到对 Float64intString 的结构体和接口实现,他们的原理跟上文描述其实都是一样的,只不过是扩展包替我们预先封装了这些常用的数据类型而已。

实际排序时,优先使用官方提供的 Sort 方法,这里只是为了练习才自己实现了一个选择排序。

相关文章:

  • 串口发送数据速度
  • Lsb图片隐写
  • react-native-echarts 在手机上 图表出现滚动条解决方法
  • Python利用Selenium自动登录掘金
  • ASP.NET CORE Combines Angular to Create SPA
  • 海量数据处理 - 十道面试题与十个海量数据处理方法总结
  • 如何搭建一个完整的交易框架
  • 2018以太坊智能合约编程语言solidity的最佳IDEs
  • easyui datagrid 相关取数据总结
  • 平台化技术:从C/S到B/S
  • ckeditor 3.6在IE11不能粘贴
  • SQLServer之修改DEFAULT约束
  • LinkedList源码
  • 爬虫基础 - 抓包
  • Object.assign方法不能实现深复制
  • JS 中的深拷贝与浅拷贝
  • [微信小程序] 使用ES6特性Class后出现编译异常
  • 【140天】尚学堂高淇Java300集视频精华笔记(86-87)
  • 0基础学习移动端适配
  • Angularjs之国际化
  • Bootstrap JS插件Alert源码分析
  • input的行数自动增减
  • java8 Stream Pipelines 浅析
  • java多线程
  • Redis在Web项目中的应用与实践
  • Spark in action on Kubernetes - Playground搭建与架构浅析
  • Work@Alibaba 阿里巴巴的企业应用构建之路
  • 聊聊hikari连接池的leakDetectionThreshold
  • 数组的操作
  • 我的业余项目总结
  • 用简单代码看卷积组块发展
  • 曾刷新两项世界纪录,腾讯优图人脸检测算法 DSFD 正式开源 ...
  • ###C语言程序设计-----C语言学习(3)#
  • (1)常见O(n^2)排序算法解析
  • (C)一些题4
  • (cos^2 X)的定积分,求积分 ∫sin^2(x) dx
  • (带教程)商业版SEO关键词按天计费系统:关键词排名优化、代理服务、手机自适应及搭建教程
  • (二)Linux——Linux常用指令
  • (附源码)计算机毕业设计ssm高校《大学语文》课程作业在线管理系统
  • (接口自动化)Python3操作MySQL数据库
  • (亲测)设​置​m​y​e​c​l​i​p​s​e​打​开​默​认​工​作​空​间...
  • (十二)devops持续集成开发——jenkins的全局工具配置之sonar qube环境安装及配置
  • (四)Linux Shell编程——输入输出重定向
  • (未解决)macOS matplotlib 中文是方框
  • (最简单,详细,直接上手)uniapp/vue中英文多语言切换
  • ***通过什么方式***网吧
  • .bat批处理出现中文乱码的情况
  • .net mvc 获取url中controller和action
  • .net项目IIS、VS 附加进程调试
  • .NET应用架构设计:原则、模式与实践 目录预览
  • [AndroidStudio]_[初级]_[修改虚拟设备镜像文件的存放位置]
  • [BROADCASTING]tensor的扩散机制
  • [BT]BUUCTF刷题第4天(3.22)
  • [BUUCTF 2018]Online Tool(特详解)
  • [C++] sqlite3_get_table 的使用