{"id":23444097,"url":"https://github.com/sevagh/go-sort","last_synced_at":"2025-10-12T16:07:09.322Z","repository":{"id":57503761,"uuid":"229843187","full_name":"sevagh/go-sort","owner":"sevagh","description":"collection of tested Go integer sort algorithms","archived":false,"fork":false,"pushed_at":"2020-06-22T04:03:32.000Z","size":320,"stargazers_count":2,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-06-08T11:55:17.283Z","etag":null,"topics":["bitonic-sort","block-sort","heapsort","introsort","mergesort","pdqsort","quicksort","radix-sort","timsort"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"bsd-2-clause","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/sevagh.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-12-24T00:38:51.000Z","updated_at":"2024-03-09T09:23:48.000Z","dependencies_parsed_at":"2022-08-28T02:00:57.340Z","dependency_job_id":null,"html_url":"https://github.com/sevagh/go-sort","commit_stats":null,"previous_names":["sevagh/go-mergesort"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sevagh%2Fgo-sort","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sevagh%2Fgo-sort/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sevagh%2Fgo-sort/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sevagh%2Fgo-sort/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/sevagh","download_url":"https://codeload.github.com/sevagh/go-sort/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sevagh%2Fgo-sort/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":259064039,"owners_count":22799739,"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":["bitonic-sort","block-sort","heapsort","introsort","mergesort","pdqsort","quicksort","radix-sort","timsort"],"created_at":"2024-12-23T18:26:41.809Z","updated_at":"2025-10-12T16:07:04.272Z","avatar_url":"https://github.com/sevagh.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"Collection of Go sorting algorithms and experiments.\n\nPlots are log-log on both axes. My first crude **TimSort1** implementation does surprisingly well - the refined **TimSort2** is better still.\n\n![ns](.github/ns.png)\n\n## Notes\n\nThe original goal of this project was to implement minimal versions of **timsort** and **pdqsort** and validate their performance improvement over standard mergesort and quicksort. It includes many search algorithms copied or adapted from Go's [pkg/sort](https://golang.org/src/sort/sort.go).\n\nMany implementations are for `[]int`, but some are for `sort.Interface` to enable quicksort killer adversary testing.\n\nLessons learned:\n\n1. sort.Sort in pkg/sort (QuickSort2 in this package) is introsort\n2. sort.Stable in pkg/sort (MergeSort2 in this package) is block-insertion-sort-plus-merge - not very dissimilar to TimSort, but with fixed-size blocks instead of different-sized already-ordered runs\n3. Implementing a basic form of TimSort without galloping or magic constants was actually rather intuitive and led to good performance gains by leveraging the symMerge (in-place merge) routine already implemented for sort.Stable in pkg/sort\n4. The Block Quicksort modification of pdqsort gives worse performance in Go\n\nHere's a conclusion from a different go-pdqsort implementation that might explain it:\n\n\u003eFrom the result the pattern defeating sort is much slower than the sort from standrad library. It is expected since go's memory layout is mainly heap managed and it is very different from what's in C++ and Rust. Therefore the key invention from pdqsort to reduce the cpu branch prediction is not impactful on speed, and slowing down due to more memory access.\n\n\\- https://github.com/MnO2/go-pdqsort\n\nSo far the notable implementations of pdqsort have been the [original in C++](https://github.com/orlp/pdqsort) and the [Rust implementation](https://github.com/stjepang/pdqsort).\n\n5. The bad partition/pattern busting part of pdqsort has a good performance boost over a standard CLRS quicksort with bad partition selection\n\n```\nsevagh:go-sort $ go test -benchmem -run=^a -bench='.*(QuickSort1|PdqSort1).*Random(8192|65536)$' -v\ngoos: linux\ngoarch: amd64\npkg: github.com/sevagh/go-sort\nBenchmarkPdqSort1Random8192-8               3015            383876 ns/op               0 B/op          0 allocs/op\nBenchmarkPdqSort1Random65536-8               121           9831749 ns/op               0 B/op          0 allocs/op\nBenchmarkQuickSort1Random8192-8              100          25272420 ns/op               0 B/op          0 allocs/op\nBenchmarkQuickSort1Random65536-8             100        1673251259 ns/op               0 B/op          0 allocs/op\nPASS\nok      github.com/sevagh/go-sort       173.248s\n```\n\n6. Overall pdqsort is more difficult to implement than timsort\n7. The embedded [bigO](./bigO) library for least squares fitting BigO estimation is a good method of validating or verifying any of the implemented algorithms:\n\n```\nsevagh:go-sort $ go test -v -count=1 -run='BigO'\n=== RUN   TestBigOTimSort\n--- PASS: TestBigOTimSort (4.32s)\n    bigo_test.go:27: O(Nlg(N))\n=== RUN   TestBigOQuickSort1WorstCase\n--- PASS: TestBigOQuickSort1WorstCase (0.00s)\n    bigo_test.go:46: O(N^2)\n=== RUN   TestBigOInsertionSortAscending\n--- PASS: TestBigOInsertionSortAscending (0.00s)\n    bigo_test.go:65: O(N^2)\n=== RUN   TestBigOInsertionSortRandom\n--- PASS: TestBigOInsertionSortRandom (0.00s)\n    bigo_test.go:84: O(Nlg(N))\nPASS\nok      github.com/sevagh/go-sort       4.328s\n```\n\nE.g. showing that the pattern-busting of PdqSort1 (that's essentially only just bolted onto QuickSort1) reduces the worst case O(N^2):\n\n```\nsevagh:go-sort $ go test -v -count=1 -run='WorstCase'\n=== RUN   TestBigOQuickSort1WorstCase\n--- PASS: TestBigOQuickSort1WorstCase (0.00s)\n    bigo_test.go:46: O(N^2)\n=== RUN   TestBigOPdqSort1WorstCaseQuickSort\n--- PASS: TestBigOPdqSort1WorstCaseQuickSort (0.00s)\n    bigo_test.go:103: O(N)\nPASS\nok      github.com/sevagh/go-sort       0.002s\n```\n\n8. I learned of the [killer adversary for quicksort](https://www.cs.dartmouth.edu/~doug/mdmspe.pdf), which is implemented in [sort_test.go](https://github.com/golang/go/blob/master/src/sort/sort_test.go#L456) in the Golang stdlib pkg/sort (and copied here in adversary_test.go). Verification with a handful of `sort.Interface`-based versions of QuickSort and PdqSort:\n\n```\nsevagh:go-sort $ go test -v -run 'Adversary'\n=== RUN   TestQuickSortIface1Adversary\n--- FAIL: TestQuickSortIface1Adversary (0.00s)\n    adversary_test.go:24: used 560000 comparisons sorting adversary data with size 10000\n=== RUN   TestPdqSortIface1Adversary\n--- FAIL: TestPdqSortIface1Adversary (0.00s)\n    adversary_test.go:24: used 560000 comparisons sorting adversary data with size 10000\n=== RUN   TestAdversaryStdSort\n--- PASS: TestAdversaryStdSort (0.00s)\nFAIL\nexit status 1\nFAIL    github.com/sevagh/go-sort       0.011s\n```\n\nHere we see `sort.Sort`, which is introsort (QuickSort2 in this project), does well. QuickSort1 is obviously vulnerable. PdqSort1 with its bad partition busting is still not clever enough to escape the killer adversary.\n\nGiven the direct `[]int` implementation of all the algorithms here, the caller has no control on the implementation of the sort interface (namely the Less method), so the killer adversary is irrelevant.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsevagh%2Fgo-sort","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsevagh%2Fgo-sort","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsevagh%2Fgo-sort/lists"}