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 main

import (
    "fmt"
    "sort"
)

// 用于存放Hero数据
type Hero struct {
    Name  string  `json:"name"`
    Score float64 `json:"score"`
}

// 用于存放Hero切片
type heroData struct {
    data []Hero
    by   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 main

import (
	"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 []int
	by   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 = 12

    var (
        wasBalanced    = true // whether the last partitioning was reasonably balanced
        wasPartitioned = true // whether the slice was already partitioned
    )

    for {
        length := b - a

        if 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 = mid
            continue
        }

        mid, alreadyPartitioned := partition(data, a, b, pivot)
        wasPartitioned = alreadyPartitioned

        leftLen, rightLen := mid-a, b-mid
        balanceThreshold := length / 8
        if leftLen < rightLen {
            wasBalanced = leftLen >= balanceThreshold
            pdqsort(data, a, mid, limit)
            a = mid + 1
        } else {
            wasBalanced = rightLen >= balanceThreshold
            pdqsort(data, mid+1, b, limit)
            b = mid
        }
    }
}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

ctype--数据类型转换函数——vb.net

CType 函数 语法 CType(expression, typename) 组成部分 expression 任何有效表达式。 如果 expression 的值超出 typename 所允许的范围&#xff0c;Visual Basic 将引发异常。 typenameDim 语句的 As 子句中的任何合法表达式&#xff0c;即任何数据类型、对象、结构、类或接…

【系统架构师】-选择题(十三)数据库基础

1、在某企业的营销管理系统设计阶段&#xff0c;属性"员工"在考勤管理子系统中被称为"员工"&#xff0c;而在档案管理子系统中被称为"职工"&#xff0c;这类冲突称为&#xff08; 命名冲突&#xff09;。 同一个实体在同系统中存在不同的命名&am…

2024年财富自由秘籍,创业项目大揭秘!

2024年&#xff0c;一个崭新的创业项目如日中天般迅速崛起&#xff0c;吸引了无数创业者的目光——那就是APP广告变现。这不仅是一条轻松实现财富自由的道路&#xff0c;更是一个充满无限可能的黄金领域。 在移动互联网高速发展的今天&#xff0c;智能手机已成为我们生活中不可…

UE4\UE5 调试源代码流程(重点讲不去Github装源代码情况)

UE4\UE5 调试源代码流程 前言&#xff1a; 很多写UE C代码的小伙伴&#xff0c;肯定发现了&#xff0c;在虚幻源代码里面是没办法打断点进行调试的&#xff0c;就算走Debug调试流程&#xff0c;也依旧不能正常打断点调试&#xff0c;今天我们来分享一下不装Github源代码情况下…

各种数据获取stream流的方式

1.单列集合&#xff08;直接调用&#xff09; ArrayList<Integer> list new ArrayList<>();list.stream(); 2.双列集合 HashMap<String, Integer> map new HashMap<>();map.put("aaa",111);map.put("bbb",222);map.put("c…

Vue中引入Element组件、路由router、Nginx打包部署

目录 1、Element-ui(饿了么ui) 演示&#xff1a; 怎么打开NPM脚本&#xff1f; Vue路由router Nginx打包部署Vue-Cli项目 1、Element-ui(饿了么ui) element-ui(饿了么ui)是一个非常好用且美观的组件库(插件库)&#xff0c;主要用于网站快速成型&#xff0c;由国产团队饿了么…

RH850F1KM Part1 创建一个新工程

1、选择File->New ECU Project.# 2、填写工程名和工程文件路径&#xff0c;点击Next 3、点击Next 4、点击Finish 5、报错&#xff1a;# 6、步骤5报错原因&#xff1a; RH850F1KM 搭建MCAL配置环境中复制到BSWMD文件夹下的文件过多&#xff0c;除包含当前芯片型号外&#…

618值得入手的平价好物清单,看完再买不吃亏!

即将到来的618年中购物狂欢节&#xff0c;无疑是一年一度的购物盛宴。为了让大家的购物体验更加愉悦和充实&#xff0c;我特地为大家精选了一系列好物。如果你也打算在618尽情购物&#xff0c;那就赶紧收藏这份清单吧&#xff01; 一、舒适佩戴不伤耳——南卡骨传导耳机Runner…

EDA(四)Verilog

EDA&#xff08;四&#xff09;Verilog Verilog是一种用于电子系统设计自动化&#xff08;EDA&#xff09;的硬件描述语言&#xff08;HDL&#xff09;&#xff0c;主要用于设计和模拟电子系统&#xff0c;特别是在集成电路&#xff08;IC&#xff09;和印刷电路板&#xff08;…

关于服务端接口知识的汇总

大家好&#xff0c;今天给大家分享一下之前整理的关于接口知识的汇总&#xff0c;对于测试人员来说&#xff0c;深入了解接口知识能带来诸多显著的好处。 一、为什么要了解接口知识&#xff1f; 接口是系统不同模块之间交互的关键通道。只有充分掌握接口知识&#xff0c;才能…

面试算法之哈希专题

赎金信 class Solution { public:bool canConstruct(string ransomNote, string magazine) {// 小写字母int r_cnt[26];int m_cnt[26];for(int i 0; i< magazine.size(); i) {m_cnt[magazine[i]-a]; // 统计}// 对比for(int i 0; i< ransomNote.size(); i) {if(m_cnt[r…

用幽兰本体验大语言模型

大语言模型&#xff08;LLM&#xff09;是目前炙手可热的话题&#xff0c;每个人都想体验一下大语言模型的魅力。然而如果使用云端的大语言模型服务&#xff0c;则不仅速度慢&#xff0c;而且可能泄露自己的隐私。幽兰代码本使用瑞芯微公司推出的 RK3588 SoC 芯片作为核心硬件&…

财务管理|基于SprinBoot+vue的财务管理系统(源码+数据库+文档)

财务管理系统 目录 基于SprinBootvue的财务管理系统 一、前言 二、系统设计 三、系统功能设计 系统功能实现 1管理员功能模块 2员工功能模块 四、数据库设计 五、核心代码 六、论文参考 七、最新计算机毕设选题推荐 八、源码获取&#xff1a; 博主介绍&#xff1…

2024年必看:13大顶尖Scrum工具助力敏捷项目管理

Scrum 管理工具有&#xff1a;PingCode、Jira、Trello、Zoho Sprints、Active Collab、ProProfs Project、Scrumwise、ClickUp、Monday.com、QuickScrum、Yodiz、ScrumDo、nTask 在过去几年中&#xff0c;Scrum方法论已成为敏捷项目管理的主要框架之一。使用Scrum&#xff0c;项…

存储和NFS共享

存储类型 存储类型分为三种 直连式存储&#xff1a;Direct-Attached Storage&#xff0c;简称DAS网络附加存储&#xff1a;Network-Attached Storage&#xff0c;简称NAS存储区域网络&#xff1a;Storage Area Network&#xff0c;简称SAN DAS:存储和主机是直连的&#xff0…

为什么 Cloudflare 是 2024 年 Vercel 的最佳替代品?生态系统和价格比较

本文探讨了 Vercel 的功能&#xff0c;并与 Cloudflare 生态系统中的类似产品进行了比较。从托管到存储&#xff0c;我们将看到为什么 Cloudflare 可以在 2024 年成为 Vercel 的最佳替代品。 文章目录 介绍什么是 Cloudflare&#xff1f;Cloudflare vs Vercel&#xff1a;托管和…

防雷防浪涌电路设计

通信线路或者电源线路通常会铺设到户外&#xff0c;一旦线路铺到户外后&#xff0c;就需要考虑防雷的问题了&#xff0c;那么怎么设计保护电路&#xff0c;能够防止雷电等浪涌对电路的破坏呢&#xff1f; 通信线路或者电源线路通常会铺设到户外&#xff0c;一旦线路铺到户外后&…

每日Attention学习3——Cross-level Feature Fusion

模块出处 [link] [code] [PR 23] Cross-level Feature Aggregation Network for Polyp Segmentation 模块名称 Cross-level Feature Fusion (CFF) 模块作用 双级特征融合 模块结构 模块代码 import torch import torch.nn as nnclass BasicConv2d(nn.Module):def __init__(…

Google搜索广告怎么开户?谷歌广告开户投放引流技巧、账户搭建、谷歌ads广告推广投放策略 #搜索引擎 #谷歌广告#互联网营销

Google搜索广告开户步骤&#xff1a; 选择代理商&#xff1a;首先&#xff0c;您需要选择一个经验丰富、信誉良好的Google广告代理商。可以选择上海上弦来广告开户和代运营。 初步咨询&#xff1a;与代理商进行初步沟通&#xff0c;了解他们的服务内容、成功案例、收费标准等。…

Topaz Photo AI for Mac:专业级照片处理软件

Topaz Photo AI for Mac是一款专为Mac用户设计的专业级照片处理软件。它集成了先进的人工智能技术&#xff0c;为用户提供了强大的照片处理功能。无论是照片修复、增强还是转换&#xff0c;Topaz Photo AI都能轻松应对。 这款软件具备强大的AI技术&#xff0c;能够自动识别和修…
最新文章