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}}
}
相关文章:
go语言自定义排序接口Interface实现示例 sort.Sort(data Interface) 快速排序 pdqsort
go语言sort.Sort(data Interface) 排序接口自定义排序实现,golang里面的sort包中的Sort方法底层使用的是 pdqsort的一个快速排序算法, 我们可以将要排序的对象实现Interface接口后直接丢个这个函数即可自动按照我们指定的方式进行数据快速排序。 sort函…...

RIP动态路由协议详解
目录 一:RIP协议的基本信息 二:RIP协议中的更新方式 三:RIP协议中的计时器 定时更新器(UPDATE timer) 无效定时器(invalid Timer) 垃圾收集定时器(garbage collection timer&a…...

ROS2 安装与测试
文章目录 ROS2 安装与测试ROS2 安装1. 设置编码2. 添加源3. 安装 ROS24. 设置环境变量 ROS2 示例测试实例一:命令行实例实例二:小海龟仿真实例 参考链接 ROS2 安装与测试 ROS2 安装 基于 Ubuntu 22.04 LTS 操作系统。 1. 设置编码 sudo apt update &…...
MySQL数据分组技术深度解析及实践
在处理大量数据库记录时,数据分组是一种强大的工具,它允许我们按照特定列的值将数据划分为逻辑上的集合,进而对每个集合执行聚合操作,如计数、求和或平均值等。MySQL中的GROUP BY子句正是实现这一功能的关键所在。本文将详细介绍GROUP BY的使用方法,结合…...

【敦煌网注册/登录安全分析报告】
敦煌网注册/登录安全分析报告 前言 由于网站注册入口容易被黑客攻击,存在如下安全问题: 暴力破解密码,造成用户信息泄露短信盗刷的安全问题,影响业务及导致用户投诉带来经济损失,尤其是后付费客户,风险巨大…...

Python读取ASC文件并转换成Excel文件(坐标)
import pandas as pd# 读取asc文件,指定空格为分隔符 df pd.read_csv(out_view2.asc, sep , headerNone)# 去掉空列 df df.dropna(howall, axis1)# 将数据保存到Excel文件 df.to_excel(out_view2.xlsx, indexFalse, headerFalse)效果图...
Rust 的 Warp 库编写的 restful api 参数传递与解析方法
Warp是一个用 Rust 编写的流行的异步 web 框架。在使用 warp 构建 RESTful API 时,可以通过多种方式传递参数到你的处理函数中。 以下是一些常见的方法,说明如何在 warp 中传递参数: 路径参数: 你可以使用 warp::path 和 warp::…...
关不掉的弹窗
这里分两种方式 第一种 #include<Windows.h> int main(){system("mode 15,14");while(1){MessageBox(NULL,TEXT("关不掉吧!"),TEXT("中病毒啦~~你这个SB!"),MB_OK);}} 实际上不是关不掉,而是关不完 解决方法:找…...

【JVM】类加载机制及双亲委派模型
目录 一、类加载过程 1. 加载 2. 连接 a. 验证 b. 准备 c. 解析 3. 初始化 二、双亲委派模型 类加载器 双亲委派模型的工作过程 双亲委派模型的优点 一、类加载过程 JVM的类加载机制是JVM在运行时,将 .class 文件加载到内存中并转换为Java类的过程。它…...

WordPress插件:链接自动识别转为超链接
WordPress插件:链接自动识别转为超链接 <?phpfunction open_links_in_new_tab() {add_filter(the_content, make_clickable);function autoblank($text) {$return str_replace(<a, <a target"_blank", $text);return $return;}add_filter(th…...

Java----数组的定义和使用
1.数组的定义 在Java中,数组是一种相同数据类型的集合。数组在内存中是一段连续的空间。 2.数组的创建和初始化 2.1数组的创建 在Java中,数组创建的形式与C语言又所不同。 Java中数组创建的形式 T[] 数组名 new T[N]; 1.T表示数组存放的数据类型…...
【C++】-QT多线程-006
1【QT】多线程 #ifndef MYWIDGET_H #define MYWIDGET_H#include <QWidget>namespace Ui { class MyWidget; }class MyWidget : public QWidget {Q_OBJECTpublic:explicit MyWidget(QWidget *parent 0);~MyWidget();/* 5 自定义信号*/ /*所有的信号函数只声明不定义&…...

vscode go语言开发中在任意包运行和调试代码 Example使用方法
一般情况下我们在进行go语言开发的时候我们都需要创建一个main方法和main包才能运行go代码, 针对这个问题,go语言给我们内置了功能强大的testing测试框架, 其中一个很有意思的Example测试就非常的方便使用。 他不管你在什么包,也…...
数据库查询--条件查询
目录 1.关系运算条件的查询 2.逻辑运算符条件的查询 3.带关键字IN的查询 4.带BETWEEN AND关键字的查询 5.空值查询 6.带LIKE关键字的模糊查询 1.关系运算条件的查询 在SELECT语句中,最常见的是使用WHERE字句指定关系运算条件对数据进行过滤。 语法格式&#x…...
用 Python 和 AkShare 进行个股数据清洗:源码剖析和建议优化
这是《个股清洗源码》一个获取股票买卖盘信息并将其打印到控制台并保存到文件的脚本。 下面我们来对源码进行剖析 先复习一下源码 import os import akshare as ak from akshare import stock_bid_ask_em from datetime import datetime import pandas as pd from io import …...

颍川诞生了两个帝王的仲父
伯、仲、叔、季是古代兄弟的长幼排行顺序,《释名释亲属》载:“父之弟曰仲父……仲父之弟曰叔父”。也就是古代称父亲的兄弟为仲父,多用于帝王对宰相重臣的尊称。 历史上最有名的、有正史记载的帝王“仲父”有两位,而且都出自颍川…...

SpringAMQP发布、订阅——Fanout Exchange交换机代码模拟
发布订阅模型: MQ提供了很多交换机模型 其中常用的有下边三个: Fanout:广播 Direct:路由 Topic:话题 转换器只负责消息路由,不是存储,路由失败则消息丢失 Fanout Exchange:会将接收到的消息路由导每一个跟其绑定的queue. 利用SpringAMQP演示Fanout…...
js原生三种弹框
第一种: alert("提示内容"):提示弹框; alert("提示"); 第二种: prompt("内容","输入框默认值"):输入弹框,第一个值输入框提示内容,第二个值输入框默…...

LWIP+TCP客户端
一、TCP API函数 其中tcp_poll()函数的第三个参数表示隔几秒调用一次这个周期性函数 二、修改服务器的IP 三、TCP客户端编程思路 申请套接字绑定服务器IP和端口号等待客户端连接 进入连接回调函数在连接回调函数中 配置一些回调函数,如接收回调函数,周期…...

程序人生 | 人生如棋,落子无悔
人生的开始,始于哭声,浮浮沉沉几十年。终了,一声长叹,在一片哭声中撒手离去。 人生的道路虽然漫长,但是关键就是那么几次机会的选择,可以决定此后几十年的光阴。 有个故事讲:古代有个人去砍柴…...
python的deap库使用记录
主要是在遗传符号回归的代码中添加了注释和根据一部分源码做了一点改动 import operator import random import numpy as np import matplotlib.pyplot as plt from deap import algorithms, base, creator, tools, gp from operator import attrgetter##生成数据 def generat…...
一份简历的制作
个人简历是求职者面试前最需要准备的一项工具。一份好的简历可以帮助求职者获得更多的面试机会,并且为面试时的表现奠定基础。以下介绍制作简历的几个注意点,仅供参考。 一、个人信息 姓名*性别联系方式 (手机号)电子邮箱&#…...

网络匿名--不只是TOR
今天,我们将讨论互联网匿名和隐私: 如何隐藏你的真实身份。 什么是 TOR 。 如何以完全匿名的方式执行黑客任务。 如何使用proxy chain。 如何让我们的匿名性领先一步。 如何使用特定的操作系统保持匿名。 结论,如何实现互联网匿名和隐…...

【论文阅读笔记】Order Matters(AAAI 20)
个人博客地址 注:部分内容参考自GPT生成的内容 论文笔记:Order Matters(AAAI 20) 用于二进制代码相似性检测的语义感知神经网络 论文:《Order Matters: Semantic-Aware Neural Networks for Binary Code Similarity Detection》…...

中科院突破:TalkingGaussian技术实现3D人脸动态无失真,高效同步嘴唇运动!
DeepVisionary 每日深度学习前沿科技推送&顶会论文分享,与你一起了解前沿深度学习信息! 引言:探索高质量3D对话头像的新方法 在数字媒体和虚拟互动领域,高质量的3D对话头像技术正变得日益重要。这种技术能够在虚拟现实、电影…...
fastText-文本分类
fastText介绍 fastText是一个快速文本分类算法,与基于神经网络的分类算法相比有两大优点: 1、fastText在保持高精度的情况下加快了训练速度和测试速度 2、fastText不需要预训练好的词向量,fastText会自己训练词向量 3、fastText两个重要的优化:Hierarchical Softmax、N-gr…...

【nodejs 命令行交互神器 - inquirer.js】
需求 大家在开发时,有时需要从命令行读取用户的输入,或者让用户选择。在nodejs中,这个怎么实现? 原生实现 ❌ process.stdin.setEncoding(utf8);process.stdin.on(readable, () > {let chunk;// 使用循环确保我们读取所有的可用输入wh…...
Liunx软件包管理(上)
目录 一.前言 二.rpm RPM 包的结构 安装与升级 卸载 查询 验证 信息输出 三.yum Yum 的特点 安装和卸载 查询和信息 仓库管理 维护和调试 常用选项 四.更换镜像源 常用的镜像源 更换镜像源基础操作 一.前言 Linux 的软件包管理是指在 Linux 操作系统中安…...

华为eNSP中型企业局域网网络规划设计(下)
→b站传送门,感谢大佬← →华为eNSP中型企业局域网网络规划设计(上)← →拓扑图传送门,可以自己配置着玩← 配置ospf AR3 [AR3]ospf 1 router-id 3.3.3.3 //出口默认路由 [AR3-ospf-1]default-route-advertise always #area…...

C语言(指针)1
Hi~!这里是奋斗的小羊,很荣幸各位能阅读我的文章,诚请评论指点,关注收藏,欢迎欢迎~~ 💥个人主页:小羊在奋斗 💥所属专栏:C语言 本系列文章为个人学习笔记&#x…...