{"id":19285974,"url":"https://github.com/chenjiandongx/collections","last_synced_at":"2025-04-22T03:33:14.055Z","repository":{"id":57508093,"uuid":"164803527","full_name":"chenjiandongx/collections","owner":"chenjiandongx","description":"📂 Golang 实现的 collections 模块，灵感来自 Python queue 和 Python collections","archived":false,"fork":false,"pushed_at":"2019-10-23T08:22:45.000Z","size":41,"stargazers_count":28,"open_issues_count":0,"forks_count":14,"subscribers_count":4,"default_branch":"master","last_synced_at":"2025-04-01T18:55:42.233Z","etag":null,"topics":["go-queue","golang","queue"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/chenjiandongx.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2019-01-09T06:35:10.000Z","updated_at":"2024-05-06T02:55:15.000Z","dependencies_parsed_at":"2022-09-26T17:51:39.136Z","dependency_job_id":null,"html_url":"https://github.com/chenjiandongx/collections","commit_stats":null,"previous_names":["chenjiandongx/go-queue"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/chenjiandongx%2Fcollections","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/chenjiandongx%2Fcollections/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/chenjiandongx%2Fcollections/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/chenjiandongx%2Fcollections/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/chenjiandongx","download_url":"https://codeload.github.com/chenjiandongx/collections/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":250167614,"owners_count":21386004,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["go-queue","golang","queue"],"created_at":"2024-11-09T21:47:34.010Z","updated_at":"2025-04-22T03:33:13.787Z","avatar_url":"https://github.com/chenjiandongx.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# 📂 collctions\r\n\r\n\u003e Golang 实现的 collections 模块，灵感来自 [Python queue](https://docs.python.org/3/library/queue.html) 和 [Python collections](https://docs.python.org/3/library/collections.html)\r\n\r\n[![Build Status](https://travis-ci.org/chenjiandongx/collections.svg?branch=master)](https://travis-ci.org/chenjiandongx/collections) [![Build status](https://ci.appveyor.com/api/projects/status/b0qa418u4j502086?svg=true)](https://ci.appveyor.com/project/chenjiandongx/collections) [![Go Report Card](https://goreportcard.com/badge/github.com/chenjiandongx/collections)](https://goreportcard.com/report/github.com/chenjiandongx/collections) [![License: MIT](https://img.shields.io/badge/License-MIT-brightgreen.svg)](https://opensource.org/licenses/MIT) [![GoDoc](https://godoc.org/github.com/chenjiandongx/collections?status.svg)](https://godoc.org/github.com/chenjiandongx/collections)\r\n\r\n## 📚 目录\r\n\r\n* [Queue - 先进先出队列](#Queue)\r\n* [LifoQueue - 后进先出队列](#LifoQueue)\r\n* [PriorityQueue - 优先队列](#PriorityQueue)\r\n* [Deque - 双端队列](#Deque)\r\n* [OrderedMap - 有序 Map](#OrderedMap)\r\n* [Counter - 计数器](#Counter)\r\n* [AVLTree - AVL 树](#AVLTree)\r\n* [Sort - 排序](#Sort)\r\n\r\n### 🔰 安装\u0026引用\r\n\r\n```bash\r\n$ go get github.com/chenjiandongx/collections\r\n\r\nimport \"github.com/chenjiandongx/collections\"\r\n```\r\n\r\n### 📦 Collections\r\n\r\n### Queue\r\n\u003e 先进先出队列（线程安全）\r\n\r\n📝 方法集\r\n```shell\r\nGet()(interface{}, bool)    // 出队\r\nPut(v interface{})          // 入队\r\nQsize() int                 // 返回队列长度\r\nIsEmpty() bool              // 判断队列是否为空\r\n```\r\n\r\n✏️ 示例\r\n```go\r\nvar nums = 1000\r\n\r\nq := collections.NewQueue()\r\nvar item interface{}\r\nvar ok bool\r\nfor i := 0; i \u003c nums; i++ {\r\n    q.Put(i)\r\n}\r\nfor i := 0; i \u003c nums; i++ {\r\n    if item, ok = q.Get(); ok {\r\n        fmt.Println(item.(int))\r\n    }\r\n}\r\n\r\nfmt.Println(q.IsEmpty())\r\nfmt.Println(q.Qsize())\r\n```\r\n\r\n### LifoQueue\r\n\u003e 后进先出队列（线程安全）\r\n\r\n📝 方法集\r\n```shell\r\nGet()(interface{}, bool)    // 出队\r\nPut(v interface{})          // 入队\r\nQsize() int                 // 返回队列长度\r\nIsEmpty() bool              // 判断队列是否为空\r\n```\r\n\r\n✏️ 示例\r\n```go\r\nvar nums = 1000\r\n\r\nq := collections.NewLifoQueue()\r\nvar item interface{}\r\nvar ok bool\r\nfor i := 0; i \u003c nums; i++ {\r\n    q.Put(i)\r\n}\r\nfor i := nums-1; i \u003e=0; i-- {\r\n    if item, ok = q.Get(); ok {\r\n        fmt.Println(item.(int))\r\n    }\r\n}\r\n\r\nfmt.Println(q.IsEmpty())\r\nfmt.Println(q.Qsize())\r\n```\r\n\r\n### PriorityQueue\r\n\u003e 优先队列（线程安全）\r\n\r\n📝 方法集\r\n```shell\r\nGet()(interface{}, bool)    // 出队\r\nPut(v *PqNode)              // 入队\r\nQsize() int                 // 返回队列长度\r\nIsEmpty() bool              // 判断队列是否为空\r\n\r\n// 优先队列节点\r\ntype PqNode struct {\r\n    Value           string\r\n    Priority, index int\r\n}\r\n```\r\n\r\n✏️ 示例\r\n```go\r\nvar nums = 1000\r\n\r\nq := collections.NewPriorityQueue()\r\n\r\nfor i := 0; i \u003c nums; i++ {\r\n    r := rand.Int()\r\n    q.Put(\u0026collections.PqNode{Value: string(r), Priority: rand.Int()})\r\n}\r\n\r\nfor i := 0; i \u003c nums/2; i++ {\r\n    item1, _ := q.Get()\r\n    item2, _ := q.Get()\r\n    fmt.Println(item1.(*collections.PqNode).Priority \u003e item2.(*collections.PqNode).Priority)\r\n}\r\n\r\nfmt.Println(q.IsEmpty())\r\nfmt.Println(q.Qsize())\r\n```\r\n\r\n### Deque\r\n\u003e 双端队列（线程安全）\r\n\r\n📝 方法集\r\n```shell\r\nGetLeft()(interface{}, bool)        // 左边出队\r\nGetRight()(interface{}, bool)       // 右边出队\r\nPutLeft(v interface{})              // 左边入队\r\nPutRight(v interface{})             // 右边入队\r\nQsize() int                         // 返回队列长度\r\nIsEmpty() bool                      // 判断队列是否为空\r\n```\r\n\r\n✏️ 示例\r\n```go\r\nvar nums = 1000\r\nq := collections.NewDeque()\r\n\r\nvar item interface{}\r\nvar ok bool\r\n\r\nfor i := 0; i \u003c nums; i++ {\r\n    q.PutLeft(i)\r\n}\r\nfmt.Println(q.Qsize())\r\n\r\nfor i := nums - 1; i \u003e= 0; i-- {\r\n    q.PutRight(i)\r\n}\r\nfmt.Println(q.Qsize())\r\n\r\nfor i := 0; i \u003c nums; i++ {\r\n    item, ok = q.GetRight()\r\n    fmt.Println(item, ok)\r\n}\r\nfor i := nums - 1; i \u003e= 0; i-- {\r\n    item, ok = q.GetLeft()\r\n    fmt.Println(item, ok)\r\n}\r\n\r\nitem, ok = q.GetLeft()\r\nfmt.Println(item, ok)\r\n\r\nitem, ok = q.GetRight()\r\nfmt.Println(item, ok)\r\n```\r\n\r\n### OrderedMap\r\n\u003e 有序 Map，接口设计参考 [cevaris/ordered_map](https://github.com/cevaris/ordered_map)\r\n\r\n📝 方法集\r\n```shell\r\nSet(key, value interface{})                 // 新增键值对\r\nGet(key interface{}) (interface{}, bool)    // 取值\r\nDelete(key interface{}) bool                // 删除键\r\nIter() (interface{}, interface{}, bool)     // 遍历\r\nLen() int                                   // 键值对数量\r\n// 指针回退到 Head，遍历时 current 指针会向后移动 BackToHead 使其移动到头指针，以便下一次从头遍历\r\nBackToHead()                               \r\n```\r\n\r\n✏️ 示例\r\n```go\r\nmaxNum := 100\r\nom := collections.NewOrderedMap()\r\nfor i := 0; i \u003c maxNum; i++ {\r\n    om.Set(i, i+1)\r\n}\r\n\r\nfmt.Println(om.Len())\r\nom.Delete(0)\r\nfmt.Println(om.Len())\r\n\r\nfor k, v, ok := om.Iter(); ok; k, v, ok = om.Iter() {\r\n    fmt.Println(k, v)\r\n}\r\n\r\nom.BackToHead()\r\nfor k, v, ok := om.Iter(); ok; k, v, ok = om.Iter() {\r\n    fmt.Println(k, v)\r\n}\r\n```\r\n\r\n📣 讨论\r\n\r\n有序 Map 在 Golang 中应该是十分常见的需求，Map 最大的优势就是其查找性能，**理论上** Map 查找的时间复杂度为常数级。但实际情况我们可以通过 benchmark 来验证。在 [Go Maps Don’t Appear to be O(1)](https://medium.com/@ConnorPeet/go-maps-are-not-o-1-91c1e61110bf) 这篇文章中，作者测试了 Golang Map 查找的实际性能，不过作者是基于 Go1.4 的，版本有点旧了。下面是我修改了作者的测试案例后在 Go1.10 下跑出来的结果。\r\n\r\n![](https://user-images.githubusercontent.com/19553554/51075377-83f8cd80-16c5-11e9-9973-4904a4661aeb.png)\r\n\r\n上图是使用 [go-echarts](https://github.com/go-echarts/go-echarts) 绘制的。测试通过与二分查找对比，二分查找的时间复杂度为 **O(log2n)**。很明显，在 10e5 数量级下两者的性能差别还不是特别大，主要差距是在 10e6 后体现的。结论：Map 的性能优于 **O(log2n)**，但不是常数级。\r\n\r\n**collections.OrderdMap 🆚 cevaris/ordered_map**\r\n\r\n本来我一直使用的是 [cevaris/ordered_map](https://github.com/cevaris/ordered_map)，后来自己重新实现了一个。实现完就与其进行了性能测试对比，它是基于两个 Map 实现的，而我是使用的 Map+LinkedList，LinkedList 在删除和插入操作上的时间复杂度都是 **O(1)**，用其来存储 Map key 的顺序是一个很好的选择。\r\n\r\n同样的测试代码，BenchMark 结果如下\r\n```shell\r\ngoos: windows\r\ngoarch: amd64\r\npkg: github.com/chenjiandongx/collections\r\nBenchmarkCollectionsSet-8        2000000               689 ns/op             187 B/op          3 allocs/op\r\nBenchmarkCevarisSet-8            1000000              1212 ns/op             334 B/op          3 allocs/op\r\nBenchmarkCollectionsGet-8        2000000               823 ns/op             187 B/op          3 allocs/op\r\nBenchmarkCevarisGet-8            1000000              1281 ns/op             334 B/op          3 allocs/op\r\nBenchmarkCollectionsIter-8       2000000               670 ns/op             187 B/op          3 allocs/op\r\nBenchmarkCevarisIter-8           1000000              1341 ns/op             366 B/op          4 allocs/op\r\n```\r\n**collections.OrderedMap Win 🖖 性能+内存占用全部占优 🚀**\r\n\r\n### Counter\r\n\u003e 计数器\r\n\r\n📝 方法集\r\n```shell\r\n// key-value item\r\ntype Item struct {\r\n    k interface{}\r\n    v int\r\n}\r\n\r\nAdd(keys ...interface{})            // 新增 item\r\nGet(key interface{}) int            // 获取 key 计数\r\nGetAll() []Item                     // 获取全部 key 计数\r\nTop(n int) []Item                   // 获取前 key 计数\r\nDelete(key interface{}) bool        // 删除 key，成功返回 true，key 不存在返回 false\r\nLen() int                           // key 数量\r\n```\r\n\r\n✏️ 示例\r\n```go\r\nc := collections.NewCounter()\r\nc.Add(\"a\", \"b\", \"c\", \"d\", \"a\", \"c\")\r\nfmt.Println(c.Get(\"A\"))\r\nfmt.Println(c.Get(\"a\"))\r\nfmt.Println(c.Get(\"b\"))\r\nfmt.Println(c.Top(2))\r\nfmt.Println(c.Len())\r\nfmt.Println(c.All())\r\nc.Delete(\"a\")\r\n```\r\n\r\n### AVLTree\r\n\u003e AVL 二叉自平衡查找树\r\n\r\n📝 方法集\r\n```shell\r\nNewAVLTree() *AVLTree       // 生成 AVL 树\r\nInsert(v int)               // 插入节点\r\nSearch(v int) bool          // 搜索节点\r\nDelete(v int) bool          // 删除节点\r\nGetMaxValue() int           // 获取所有节点中的最大值\r\nGetMinValue() int           // 获取所有节点中的最小值\r\nAllValues() []int           // 返回排序后所有值\r\n```\r\n\r\n✏️ 示例\r\n```go\r\nvar maxNum = 100\r\n\r\ntree := NewAVLTree()\r\nfor i := 0; i \u003c maxNum; i++ {\r\n    tree.Insert(i)\r\n    tree.Insert(maxNum + i)\r\n}\r\nfmt.Println(len(tree.AllValues()))\r\nfmt.Println(tree.GetMaxValue())\r\nfmt.Println(tree.GetMinValue())\r\nfmt.Println(tree.Search(50))\r\nfmt.Println(tree.Search(100))\r\nfmt.Println(tree.Search(-10))\r\nfmt.Println(tree.Delete(-10))\r\nfmt.Println(tree.Delete(10))\r\n```\r\n\r\n📣 讨论\r\n\r\nAVL 树是自平衡树的一种，其通过左旋和右旋来调整自身的平衡性，使其左右子树的高度差最大不超过 1。AVL 在插入、查找、删除的平时时间复杂度都是 O(logn)，在基本的 BST（二叉查找树）中，理想情况的效率也是为 O(logn)，但由于操作的性能其实是依赖于树的高度，BST 最坏的情况会导致树退化成链表，此时时间复杂度就变为 O(n)，为了解决这个问题，自平衡二叉树应运而生。\r\n\r\nAVL 的主要精髓在于`旋转`，旋转分为 4 种情况，左旋，左旋+右旋，右旋，右旋+左旋。调整树结构后需要重新计算树高。\r\n\r\n**左子树左节点失衡**\r\n\u003e 左左情况 直接右旋\r\n```shell\r\n    x                \r\n  x        =\u003e 右旋         x\r\nx                       x    x\r\n```\r\n\r\n**左子树右节点失衡**\r\n\u003e 左右情况 先左旋后右旋\r\n```shell\r\n  x                        x     \r\nx         =\u003e 左旋         x       =\u003e 右旋        x\r\n  x                     x                     x    x\r\n```\r\n\r\n**右子树右节点失衡**\r\n\u003e 右右情况 直接左旋\r\n```shell\r\nx                \r\n  x       =\u003e 左旋          x\r\n    x                   x    x\r\n```\r\n\r\n**右子树左节点失衡**\r\n\u003e 右左情况 先右旋后左旋\r\n```shell\r\nx                      x     \r\n  x       =\u003e 右旋        x       =\u003e 左旋        x\r\nx                          x                 x    x\r\n```\r\n\r\nAVL 主要的性能消耗主要在插入，因为其需要通过旋转来维护树的平衡，但如果使用场景是经常需要排序和查找数据的话，AVL 还是可以展现其良好的性能的。\r\n\r\n**benchmark**\r\n```\r\nBenchmarkAVLInsert10e1-6        2000000000               0.00 ns/op\r\nBenchmarkAVLInsert10e2-6        2000000000               0.00 ns/op\r\nBenchmarkAVLInsert10e3-6        2000000000               0.00 ns/op\r\nBenchmarkAVLInsert10e4-6        2000000000               0.02 ns/op\r\nBenchmarkAVLInsert10e5-6        1000000000               0.82 ns/op\r\nBenchmarkAVLSearch-6            2000000000               0.00 ns/op\r\nBenchmarkAVLDelete-6            2000000000               0.00 ns/op\r\n```\r\n\r\n### Sort\r\n\r\n📝 方法集\r\n```shell\r\nBubbleSort()        // 冒泡排序\r\nInsertionSort()     // 插入排序\r\nQuickSort()         // 快速排序\r\nShellSort()         // 希尔排序\r\nHeapSort()          // 堆排序\r\nMergeSort()         // 归并排序\r\n```\r\n\r\n✏️ 示例\r\n```go\r\nvar maxCnt = 10e4\r\n\r\nfunc yieldRandomArray() []int {\r\n    res := make([]int, maxCnt)\r\n    for i := 0; i \u003c maxCnt; i++ {\r\n        res[i] = rand.Int()\r\n    }\r\n    return res\r\n}\r\n\r\nBubbleSort(yieldRandomArray())\r\nInsertionSort(yieldRandomArray())\r\nQuickSort(yieldRandomArray())\r\nShellSort(yieldRandomArray())\r\nHeapSort(yieldRandomArray())\r\nMergeSort(yieldRandomArray())\r\n```\r\n\r\n📣 讨论\r\n\r\n**排序算法时间复杂度比较**\r\n\r\n| 排序算法 |  是否稳定  |  平均    |   最好  |    最差   |   动画演示  |\r\n| -------- | --------- |----------| --------| -------- | ----------- |\r\n| BubbleSort | 是 | O(n^2) |  O(n) |  O(n^2) | ![](https://upload.wikimedia.org/wikipedia/commons/3/37/Bubble_sort_animation.gif) |\r\n| InsertionSort | 是 | O(n^2) |  O(n) |  O(n^2) | ![](https://upload.wikimedia.org/wikipedia/commons/2/25/Insertion_sort_animation.gif) |\r\n| QuickSort | 否 | O(nlogn) | O(nlogn) |  O(n^2) | ![](https://upload.wikimedia.org/wikipedia/commons/6/6a/Sorting_quicksort_anim.gif) |\r\n| ShellSort | 否 |O(nlogn) |  O(n) | O(n^2)  | ![](https://upload.wikimedia.org/wikipedia/commons/2/25/Insertion_sort_animation.gif) |\r\n| HeapSort | 否 | O(nlogn) |  O(nlogn) | O(nlogn) | ![](https://upload.wikimedia.org/wikipedia/commons/1/1b/Sorting_heapsort_anim.gif) |\r\n| MergeSort | 是 | O(nlogn) |  O(nlogn) | O(nlogn) | ![](https://upload.wikimedia.org/wikipedia/commons/c/c5/Merge_sort_animation2.gif) |\r\n\r\n通过 benchmark 来测试平均排序性能\r\n\r\n**数据随机分布**\r\n```go\r\nvar maxCnt int = 10e4\r\n\r\nfunc yieldRandomArray(cnt int) []int {\r\n    res := make([]int, cnt)\r\n    for i := 0; i \u003c cnt; i++ {\r\n        res[i] = rand.Int()\r\n    }\r\n    return res\r\n}\r\n```\r\n\r\n运行结果\r\n```shell\r\nBenchmarkBubbleSort-8                  1        17361549400 ns/op\r\nBenchmarkInsertionSort-8               1        1934826900 ns/op\r\nBenchmarkQuickSort-8                 100          10651807 ns/op\r\nBenchmarkShellSort-8                 100          16476199 ns/op\r\nBenchmarkHeapSort-8                  100          14231607 ns/op\r\nBenchmarkMergeSort-8                 100          14840583 ns/op\r\n```\r\n\r\n冒泡和直接插入排序在随机数据集的排序性能最差，为 O(n^2)，剩余 4 种排序快排效率最佳，其他 3 者性能很接近。\r\n\r\n**换两种极端的数据分布方式**\r\n\r\n**数据升序分布**\r\n```go\r\nfunc yieldArrayAsce(cnt int) []int {\r\n    res := make([]int, cnt)\r\n    for i := 0; i \u003c cnt; i++ {\r\n        res[i] = i\r\n    }\r\n    return res\r\n}\r\n```\r\n\r\n运行结果\r\n```shell\r\nBenchmarkBubbleSort-8               5000            266690 ns/op\r\nBenchmarkInsertionSort-8           10000            213429 ns/op\r\nBenchmarkQuickSort-8                   1        3291222900 ns/op\r\nBenchmarkShellSort-8                1000           1716406 ns/op\r\nBenchmarkHeapSort-8                  200           6806788 ns/op\r\nBenchmarkMergeSort-8                 300           4677485 ns/op\r\n```\r\n\r\n在数据基本升序的情况下，冒泡和直接插入排序能够取得良好的性能。而快排就给跪了，就是最差的 O(n^2) 了。\r\n\r\n**数据降序分布**\r\n```go\r\nfunc yieldArrayDesc(cnt int) []int {\r\n    res := make([]int, cnt)\r\n    for i := 0; i \u003c cnt; i++ {\r\n        res[i] = cnt-i\r\n    }\r\n    return res\r\n}\r\n```\r\n\r\n运行结果\r\n```shell\r\nBenchmarkBubbleSort-8                  1        6710048800 ns/op\r\nBenchmarkInsertionSort-8               1        3881599100 ns/op\r\nBenchmarkQuickSort-8                   1        3373971200 ns/op\r\nBenchmarkShellSort-8                 500           2876371 ns/op\r\nBenchmarkHeapSort-8                  200           7081150 ns/op\r\nBenchmarkMergeSort-8                 300           4448222 ns/op\r\n```\r\n\r\n在数据基本降序的情况下，冒泡和直接插入排序一如既往的差，快排又给跪了，又是 O(n^2)...\r\n\r\n那自己实现的排序和 Golang 官方提供的 sort.Sort 排序方法对比，效率如何呢\r\n\r\n\r\n定义一个 struct，实现 sort.Interface\r\n```go\r\nimport \"sort\"\r\n\r\ntype StdItems struct {\r\n    data []int\r\n}\r\n\r\nfunc (o StdItems) Less(i, j int) bool {\r\n    return o.data[i] \u003c o.data[j]\r\n}\r\n\r\nfunc (o StdItems) Swap(i, j int) {\r\n    o.data[i], o.data[j] = o.data[j], o.data[i]\r\n}\r\n\r\nfunc (o StdItems) Len() int {\r\n    return len(o.data)\r\n}\r\n```\r\n\r\n只取 n(logn) 复杂度的排序算法与标准 sort 进行对比\r\n\r\n**数据随机分布**\r\n```shell\r\nBenchmarkStdSort-8                            50          22978524 ns/op\r\nBenchmarkQuickSort-8                         100          11648689 ns/op\r\nBenchmarkShellSort-8                         100          17353544 ns/op\r\nBenchmarkHeapSort-8                          100          14501199 ns/op\r\nBenchmarkMergeSort-8                         100          13793086 ns/op\r\n```\r\n\r\n是不是眼前一亮 😂，自己写的快排居然这么厉害，比标准的 sort 快了不止两倍？？？ 这里出现这种情况的主要原因是 sort 实现了 sort.Interface，该接口需要有三个方法 Less()/Len()/Swap()，而接口的类型转换是有成本的。**通用意味着兼容，兼容意味着妥协，这是专和精权衡后的结果**。当然，标准的 sort 大部分情况的性能都是可接受的。但当你需要追求极致性能的话，自己针对特定需求实现排序算法肯定会是更好的选择。\r\n\r\n**数据升序分布**\r\n```shell\r\nBenchmarkStdSort-8                           200           7285511 ns/op\r\nBenchmarkQuickSort-8                           1        3351046900 ns/op\r\nBenchmarkShellSort-8                        1000           1679506 ns/op\r\nBenchmarkHeapSort-8                          200           6632256 ns/op\r\nBenchmarkMergeSort-8                         300           4308582 ns/op\r\n```\r\n\r\n是不是又是眼前一亮 🤣，我去 为什么这次标准的排序比快排快了这么多，官方的排序不也是快排吗？（这个测试结果看起来好像也没人会比快排慢是吧 😅）\r\n\r\n**数据降序分布**\r\n```shell\r\nBenchmarkStdSort-8                           200           7405331 ns/op\r\nBenchmarkQuickSort-8                           1        3390954400 ns/op\r\nBenchmarkShellSort-8                         500           2900240 ns/op\r\nBenchmarkHeapSort-8                          200           7091124 ns/op\r\nBenchmarkMergeSort-8                         300           4295169 ns/op\r\n```\r\n\r\nemmmmmmm，同上 😓\r\n\r\n关于官方排序的具体实现，可以参考 [src/sort/sort.go](https://golang.org/src/sort/sort.go)，实际上是直接插入排序，快速排序，堆排序和归并排序的组合排序。[这篇文章](https://github.com/polaris1119/The-Golang-Standard-Library-by-Example/blob/master/chapter03/03.1.md) 对这部分有介绍\r\n\r\n最后，按官方的排序针对自己想要的数据类型排序，但不使用接口那套，对比上面排序中最快的算法以及接口实现的 sort\r\n\r\n**数据随机分布**\r\n```shell\r\nBenchmarkStdSort-8                           100          22649399 ns/op\r\nBenchmarkQuickSort-8                         100          10870924 ns/op\r\nBenchmarkStdSortWithoutInterface-8           100          10511605 ns/op\r\n```\r\n\r\n**数据升序分布**\r\n```shell\r\nBenchmarkStdSort-8                           200           7006117 ns/op\r\nBenchmarkShellSort-8                        1000           1667537 ns/op\r\nBenchmarkStdSortWithoutInterface-8          1000           1619643 ns/op\r\n```\r\n\r\n**数据降序分布**\r\n```shell\r\nBenchmarkStdSort-8                           200           7614625 ns/op\r\nBenchmarkShellSort-8                         500           3051834 ns/op\r\nBenchmarkStdSortWithoutInterface-8          1000           1689479 ns/op\r\n```\r\n\r\n🖖 [StdSortWithoutInterface](https://github.com/chenjiandongx/collections/blob/master/std_sort.go) 完胜！！！\r\n\r\n我们还可以进一步思考如何获得更高的排序性能，使用 goroutine 将一个数据切分成两半，分别使用 `StdSortWithoutInterface` 排序，将排序后的结果进行一次归并排序，就可以得到最终的有序数组，这次我们测试的数组长度为 **10e5**\r\n\r\n为了验证真正的`并行计算` 我们将分别测试 cpu 数量为 1, 2, 8 的情况\r\n```shell\r\nBenchmarkStdSort                               5         260696480 ns/op\r\nBenchmarkStdSort-2                             5         246746560 ns/op\r\nBenchmarkStdSort-8                             5         248532560 ns/op\r\nBenchmarkStdSortWithoutInterface              10         124666470 ns/op\r\nBenchmarkStdSortWithoutInterface-2            10         120676740 ns/op\r\nBenchmarkStdSortWithoutInterface-8            10         126062650 ns/op\r\nBenchmarkStdSortWithGoroutine                 20         125163280 ns/op\r\nBenchmarkStdSortWithGoroutine-2               20          80835825 ns/op\r\nBenchmarkStdSortWithGoroutine-8               20          81232625 ns/op\r\n```\r\n\r\n😎 WOW!!! cpu 数量为 1 时大家相差无几，cpu \u003e 1 以后，goroutine 做到了真正的并行，利用多核进行计算，速度提升了 **1.5** 倍，比默认的 Sort 方法提升了 **4** 倍。喏，这就是算法的魅力。\r\n\r\n### 📃 License\r\nMIT [©chenjiandongx](http://github.com/chenjiandongx)\r\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fchenjiandongx%2Fcollections","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fchenjiandongx%2Fcollections","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fchenjiandongx%2Fcollections/lists"}