go语言自定义排序接口Interface实现示例 sort.Sort(data Interface) 快速排序 pdqsort

go语言sort.Sort(data Interface) 排序接口自定义排序实现,golang里面的sort包中的Sort方法底层使用的是 pdqsort的一个快速排序算法, 我们可以将要排序的对象实现Interface接口后直接丢个这个函数即可自动按照我们指定的方式进行数据快速排序。

sort函数原型和排序接口Interface说明

sort.Sort() 这里的参数是一个接口, 即我们只需要在我们自定义的类型里面实现这个Interface这个接口里面定义的Len Less Swap方法 然后将类型变量传进sor就会自动版我们进行排序.
函数原型:func Sort(data Interface)
Sort排序data。它调用1次data.Len确定长度,调用O(n*log(n))次data.Less和data.Swap。本函数不能保证排序的稳定性(即不保证相等元素的相对次序不变)。

排序接口
type Interface interface {
    // Len方法返回集合中的元素个数
    Len() int
    // Less方法报告索引i的元素是否比索引j的元素小
    Less(i, j int) bool
    // Swap方法交换索引i和j的两个元素
    Swap(i, j int)
}
一个满足sort.Interface接口的(集合)类型可以被本包的函数进行排序。方法要求集合中的元素可以被整数索引。

废话不多少,直接上代码:

go对象自定义排序实现源码

可自定义要排序的字段和排序方式

package mainimport ("fmt""sort"
)// 用于存放Hero数据
type Hero struct {Name  string  `json:"name"`Score float64 `json:"score"`
}// 用于存放Hero切片
type heroData struct {data []Heroby   func(h1 *Hero, h2 *Hero) bool
}// 自定义一个排序函数类型 By
type By func(h1 *Hero, h2 *Hero) bool// 自定义排序方法,
func (b By) MySort(hs []Hero) {hdata := &heroData{data: hs, by: b} // 排序对象初始化放这里sort.Sort(hdata)                    // 调用Sort进行排序
}func (h heroData) Len() int {return len(h.data)
}
func (h heroData) Less(i, j int) bool {// return h.data[i].Score < h.data[j].Score // 这里是固定使用Score排序,return h.by(&h.data[i], &h.data[j]) // 将排序字段放入到函数里面 外面需要怎么排序,这几传递一个函数来就可以
}
func (h heroData) Swap(i, j int) {h.data[i], h.data[j] = h.data[j], h.data[i]
}func main() {// 普通方式,固定排序字段// var h1 = heroData{data: []Hero{{Name: "John", Score: 99.8}, {Name: "Alice", Score: 80}, {Name: "Bob", Score: 45}}}// sort.Sort(h1)// fmt.Printf("%v \n", h1.data)// 准备数据data := []Hero{{Name: "John", Score: 99.8}, {Name: "Alice", Score: 80}, {Name: "Bob", Score: 45}, {Name: "Jack", Score: 100}}// 可自定义排序方法var nameSort = func(h1 *Hero, h2 *Hero) bool { return h1.Name < h2.Name }var scoreSort = func(h1 *Hero, h2 *Hero) bool { return h1.Score < h2.Score }//排序By(nameSort).MySort(data)fmt.Printf("按照Name排序:%v\n", data)By(scoreSort).MySort(data)fmt.Printf("按照Score排序: %v\n", data)
}

基本数据类型的排序代码

可自定义排序的方式 从大到小或者从小到大

package mainimport ("fmt""sort"
)/*
sort.Sort() 这里的参数是一个接口, 即我们只需要在我们自定义的类型里面实现这个Interface这个接口里面定义的Len Less Swap方法 然后将类型变量传进sor就会自动版我们进行排序.
函数原型:func Sort(data Interface)
Sort排序data。它调用1次data.Len确定长度,调用O(n*log(n))次data.Less和data.Swap。本函数不能保证排序的稳定性(即不保证相等元素的相对次序不变)。排序接口
type Interface interface {// Len方法返回集合中的元素个数Len() int// Less方法报告索引i的元素是否比索引j的元素小Less(i, j int) bool// Swap方法交换索引i和j的两个元素Swap(i, j int)
}
一个满足sort.Interface接口的(集合)类型可以被本包的函数进行排序。方法要求集合中的元素可以被整数索引。*/type MyDemo struct {data []intby   func(l int, r int) bool
}// 自定义一个函数数据类型 By
type By func(v1 int, v2 int) bool// 将这个MySort函数绑定到自定义类型By上面
func (b By) MySort(arr []int) {dd := MyDemo{data: arr, by: b}// 调用sort包里面的Sort方法sort.Sort(dd)
}// Len方法返回集合中的元素个数
func (m MyDemo) Len() int {return len(m.data)
}// Less方法报告索引i的元素是否比索引j的元素小
func (m MyDemo) Less(i, j int) bool {//return m.data[i] < m.data[j]return m.by(m.data[i], m.data[j]) // 将数据交给一个函数去比较
}// Swap方法交换索引i和j的两个元素
func (m MyDemo) Swap(i, j int) {//使用中间变量交换 传统方法// tmp := m.data[i]// m.data[i] = m.data[j]// m.data[j] = tmp// 利用go的批量赋值特性 直接交换m.data[i], m.data[j] = m.data[j], m.data[i]
}func main() {var mm = MyDemo{data: []int{1, 8, 99, 3, 6, 7, 8, 13, 199, 200, 20, 2}}fmt.Println("排序前:", mm)// 将这个匿名函数传递进去,每次数据比较的时候都会被调用mm.by = func(l, r int) bool {return l > r // 这里可以控制从大到小 > 还是从小到大 < 排序}// 排序sort.Sort(mm)fmt.Println("排序后:", mm)//排序后: {[1 2 3 6 7 8 8 13 20 99 199 200]}fmt.Println("------------------------------------------------")// 要排序的int切片arr := []int{90, 567, 1, 9, 8, 99, 3, 6, 7, 8, 13, 199, 200, 20, 2}// 定义用于排序的函数 注意,如果 这里的函数入参改为结构体, 就可以对结构体内的字段进行排序small2bigSort := func(v1, v2 int) bool { return v1 < v2 } // 从小到大排序函数big2smallSort := func(v1, v2 int) bool { return v1 > v2 } // 从大到小 排序函数By(small2bigSort).MySort(arr)fmt.Println("small2bigSort=", arr) // small2bigSort= [1 2 3 6 7 8 8 9 13 20 90 99 199 200 567]By(big2smallSort).MySort(arr)fmt.Println("big2smallSort=", arr) // big2smallSort= [567 200 199 99 90 20 13 9 8 8 7 6 3 2 1]
}

总结: 在上面的示例中我们使用了2种方式来传递排序函数, 1是直接以匿名函数的方式将函数先赋值给结构体字段,然后再通过方法调用, 另外一种方式是定义了一个函数变量, 然后将MySort这个方法绑定到了自定义函数上来实现调用系统的pdqsort实现快速排序。

pdqsort快速排序函数源码 参考


// pdqsort sorts data[a:b].
// The algorithm based on pattern-defeating quicksort(pdqsort), but without the optimizations from BlockQuicksort.
// pdqsort paper: https://arxiv.org/pdf/2106.05123.pdf
// C++ implementation: https://github.com/orlp/pdqsort
// Rust implementation: https://docs.rs/pdqsort/latest/pdqsort/
// limit is the number of allowed bad (very unbalanced) pivots before falling back to heapsort.
func pdqsort(data Interface, a, b, limit int) {const maxInsertion = 12var (wasBalanced    = true // whether the last partitioning was reasonably balancedwasPartitioned = true // whether the slice was already partitioned)for {length := b - aif length <= maxInsertion {insertionSort(data, a, b)return}// Fall back to heapsort if too many bad choices were made.if limit == 0 {heapSort(data, a, b)return}// If the last partitioning was imbalanced, we need to breaking patterns.if !wasBalanced {breakPatterns(data, a, b)limit--}pivot, hint := choosePivot(data, a, b)if hint == decreasingHint {reverseRange(data, a, b)// The chosen pivot was pivot-a elements after the start of the array.// After reversing it is pivot-a elements before the end of the array.// The idea came from Rust's implementation.pivot = (b - 1) - (pivot - a)hint = increasingHint}// The slice is likely already sorted.if wasBalanced && wasPartitioned && hint == increasingHint {if partialInsertionSort(data, a, b) {return}}// Probably the slice contains many duplicate elements, partition the slice into// elements equal to and elements greater than the pivot.if a > 0 && !data.Less(a-1, pivot) {mid := partitionEqual(data, a, b, pivot)a = midcontinue}mid, alreadyPartitioned := partition(data, a, b, pivot)wasPartitioned = alreadyPartitionedleftLen, rightLen := mid-a, b-midbalanceThreshold := length / 8if leftLen < rightLen {wasBalanced = leftLen >= balanceThresholdpdqsort(data, a, mid, limit)a = mid + 1} else {wasBalanced = rightLen >= balanceThresholdpdqsort(data, mid+1, b, limit)b = mid}}
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/833415.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

C++从入门到精通——类的6个默认成员函数之拷贝构造函数

拷贝构造函数 前言一、拷贝构造函数概念理解定义 二、拷贝构造函数的特征三、注意要点写法实践传址返回与引用返回的区别传址返回引用返回 传值返回和传址返回的对比总结测试 前言 类的6个默认成员函数&#xff1a;如果一个类中什么成员都没有&#xff0c;简称为空类。 空类中…

抢占用户|AI助力企业高效挖掘潜在客户,推动高质量转化

随着人工智能&#xff08;AI&#xff09;技术的崛起&#xff0c;企业终于可以在这个数字化时代获得一种强大的工具&#xff0c;帮助企业迅速而准确地找到潜在客户。AI不仅能够处理海量的数据&#xff0c;还能自动分析和识别潜在客户的特征和行为模式&#xff0c;为企业营销提供…

母婴用品网站设计与实现 java母婴用品网站源代码+论文+ppt

母婴用品网站设计与实现:基于JSP与MySQL的实践探索 引言 随着信息化时代的到来,母婴用品网站作为信息获取和商品交易的平台,其开发与设计成为了一个迫切的课题。本文将探讨如何利用JSP技术和MySQL数据库构建一个功能完备、用户友好的母婴用品网站。 系统概述 背景与必要…

【WEEK11】 【DAY1】Employee Management System Part 2【English Version】

2024.5.6 Monday Continuing from 【WEEK10】 【DAY2】Employee Management System Part 1【English Version】 Contents 10.3. Page Internationalization10.3.1. Preparation10.3.2. Configuration File Writing10.3.2.1. Create an i18n (abbreviation for internationaliza…

YOLOv8深度剖析专栏导航

本专栏计划更新关于YOLOv8目标检测、实例分割、关键点检测、旋转目标检测任务的实践和理论知识。实践篇会包括训练自己的数据集、并对模型进行验证、预测和导出&#xff1b;理论篇会介绍各任务的预测流程和训练流程。下面是已更新的文章目录&#xff1a; 1.软件安装及YOLOv8环境…

系统守护者:揭秘限流的四大算法与实战攻略

在网络世界的广阔天地中&#xff0c;服务如同繁忙的港口&#xff0c;每天迎来送往数不尽的请求。然而&#xff0c;潮水般的流量背后隐藏着风险&#xff0c;稍有不慎&#xff0c;系统便会因不堪重负而倾覆。这时&#xff0c;"限流"便如同智慧的灯塔&#xff0c;指引着…

专业的保密网文件导入导出系统,让文件流转行为更可控安全

军工单位因其涉及国防安全和军事机密&#xff0c;对保密工作有极高的要求&#xff0c;通常会采取严格的网络隔离措施来保护敏感信息和提高网络安全性。常见的方式是通过物理隔离将网络彻底分隔开来&#xff0c;比如保密网和非保密网。网络隔离后&#xff0c;仍有数据交换的需求…

Linux命令--tcpdump命令--使用与详解

原文网址&#xff1a;Linux命令--tcpdump命令--使用与详解_IT利刃出鞘的博客-CSDN博客 简介 本文介绍Linux的tcpdump命令的用法。 tcpdump可以输出网络的通信记录&#xff0c;可以用来排查问题、查看被攻击网站的详细情况等。 示例 捕获eth0的数据包 tcpdump -i ens33 捕…

GORM的常见命令

文章目录 一、什么是GORM&#xff1f;二、GORM连接mysql以及AutoMigrate创建表三、查询1、检索此对象是否存在于数据库&#xff08;First,Take,Last方法&#xff09;2、Find()方法检索3、根据指定字段查询 四、更新1、Save() 保存多个字段2、更新单个字段 五、删除 一、什么是G…

Python中设计注册登录代码

import hashlib import json import os import sys # user interface 用户是界面 UI """ 用户登录系统 1.注册 2.登陆 0.退出 """ # 读取users.bin def load(path): return json.load(open(path, "rt")) # 保存user.bin def save(dic…

Figma 高效技巧:设计系统中的图标嵌套

Figma 高效技巧&#xff1a;设计系统中的图标嵌套 在设计中&#xff0c;图标起着不可或缺的作用。一套便捷易用的图标嵌套方法可以有效提高设计效率。 分享一下我在图标嵌套上走过的弯路和经验教训。我的图标嵌套可以分三个阶段&#xff1a; 第一阶段&#xff1a;建立图标库 一…

目标检测实战(八): 使用YOLOv7完成对图像的目标检测任务(从数据准备到训练测试部署的完整流程)

文章目录 一、目标检测介绍二、YOLOv7介绍三、源码/论文获取四、环境搭建4.1 环境检测 五、数据集准备六、 模型训练七、模型验证八、模型测试九、错误总结9.1 错误1-numpy jas mp attribute int9.2 错误2-测试代码未能跑出检测框9.3 错误3- Command git tag returned non-zero…

【unity】(2)GameObject

GameObject类是基本的游戏对象类型&#xff0c;它可以用来代表场景中的任何实体。 基本属性 name 类型&#xff1a;string说明&#xff1a;GameObject的名称。用法&#xff1a; GameObject go new GameObject(); go.name "My GameObject";activeSelf 类型&#xf…

Apple OpenELM设备端语言模型

Apple 发布的 OpenELM&#xff08;一系列专为高效设备上处理而设计的开源语言模型&#xff09;引发了相当大的争论。一方面&#xff0c;苹果在开源协作和设备端AI处理方面迈出了一步&#xff0c;强调隐私和效率。另一方面&#xff0c;与微软 Phi-3 Mini 等竞争对手相比&#xf…

森林消防新利器:高扬程水泵的革新与应用/恒峰智慧科技

随着全球气候变化的加剧&#xff0c;森林火灾的频发已成为威胁生态安全的重要问题。在森林消防工作中&#xff0c;高效、快速的水源供给设备显得尤为重要。近年来&#xff0c;高扬程水泵的广泛应用&#xff0c;为森林消防工作带来了新的希望与突破。 一、高扬程水泵的技术优势 …

【Node.js】使用 PostgreSQL、Sequelize 和 Express.js 进行 Node.js 认证

使用 PostgreSQL、Sequelize 和 Express.js 进行 Node.js 认证 作者&#xff1a;Racheal Kuranchie 来源&#xff1a;https://medium.com/rachealkuranchie/node-js-authentication-with-postgresql-sequelize-and-express-js-20ae773da4c9 使用 PostgreSQL、Sequelize 和 Expr…

Linux上安装及卸载OpenJDK

Linux上安装Java Development Kit (JDK) 8的步骤如下&#xff1a; 1. 添加Java JDK 8的Yum源 首先&#xff0c;你需要添加Java JDK 8的Yum源到系统。这可以通过下载并安装Oracle JDK的方式完成&#xff0c;但由于Oracle JDK在某些情况下可能需要遵守特定的许可协议&#xff0c…

探索Baidu Comate:编程世界中的新利器

文章目录 Baidu Comate 介绍Baidu Comate的优势Baidu Comate安装过程Baidu Comate实战演练代码调优代码解释代码生成注释生成 总结 Baidu Comate 介绍 随着GPT的大火&#xff0c;衍生了各种AI工具&#xff0c;这些AI工具遍布在各行业各领域中&#xff0c;有AI写作、AI办公、AI…

[力扣题解] 216. 组合总和 III

题目&#xff1a;216. 组合总和 III 思路 回溯法 代码 class Solution { private:vector<vector<int>> result;vector<int> path;public:void function(int k, int n, int startindex, int sum){int i;// 剪枝// 超过了, 不用找了;if(sum > n){return…

向各位请教一个问题

这是菜鸟上的一道题目&#xff0c;单单拿出来问问大家&#xff0c;看看能不能解惑 &#xff0c;谢谢各位&#xff01; 题目25&#xff1a;求12!3!...20!的和 解题思路&#xff1a;这个题不知道为什么我用DEV C 5.11显示出来为0.000000&#xff0c;可能版本有问题&#xff1f;&a…