随机快速排序比尾递归快速排序运行得更快吗?
来源:stackoverflow
2024-04-14 12:27:37
0浏览
收藏
积累知识,胜过积蓄金银!毕竟在Golang开发的过程中,会遇到各种各样的问题,往往都是一些细节知识点还没有掌握好而导致的,因此基础知识点的积累是很重要的。下面本文《随机快速排序比尾递归快速排序运行得更快吗?》,就带大家讲解一下知识点,若是你对本文感兴趣,或者是想搞懂其中某个知识点,就请你继续往下看吧~
问题内容
我在golang中实现了随机快速排序和尾递归快速排序并记录了运行时间。我发现尾递归快速排序需要更多时间来对数组进行排序。我输入的数组长度是 250, 500, 750, 1000, 1250, 1500, 1750, 2000, 2250, 2500。
下面是我的 golang 代码实现。
随机快速排序:
// this method will sort the array and place pivot at than correct position.
// we will then run another randomizedquicksort on the partitioned array.
// it take both float and int arrays as input
func randomizedquicksort(arr []interface{}, left int, right int) {
if left < right {
pivot := randomizedpartition(arr, left, right)
randomizedquicksort(arr, left, pivot-1)
randomizedquicksort(arr, pivot+1, right)
}
}
func partition(a []interface{}, left int, right int) int {
pivot := a[right]
i := left - 1
for j := left; j <= right-1; j++ {
switch piv := pivot.(type) {
case float64:
if a[j].(float64) < piv {
i++
//swap
a[i], a[j] = a[j], a[i]
}
case int:
if a[j].(int) < piv {
i++
//swap
a[i], a[j] = a[j], a[i]
}
}
}
//swap pivot with pth index
a[right], a[i+1] = a[i+1], a[right]
return i + 1
}
尾递归快速排序:
// this method will sort the array and place pivot at than correct position.
// we will then run another quicksort on the partitioned array.
// last thing we do is recursion in tail recursion
func tailrecursivequicksort(a []interface{}, left int, right int) {
for left < right {
pi := tailpartition(a, left, right)
tailrecursivequicksort(a, left, right-1)
left = pi + 1
}
}
// this method will partition the array around pivot and return pivot's index
func tailpartition(a []interface{}, left int, right int) int {
pivot := a[right]
p := left - 1
for i := left; i < right; i++ {
switch piv := pivot.(type) {
case float64:
// if element is found lower than pivot swap it with pth element
if a[i].(float64) <= piv {
//swap
p++
a[p], a[i] = a[i], a[p]
}
case int:
// if element is found lower than pivot swap it with pth element
if a[i].(int) <= piv {
//swap
p++
a[p], a[i] = a[i], a[p]
}
}
}
//swap pivot with pth index
a[right], a[p+1] = a[p+1], a[right]
return p + 1
}
尾递归快速排序的一个示例单元测试用例:
package main
import (
"fmt"
"testing"
"time"
)
// 250 numbers
func testtailrecursionquicksort1(t *testing.t) {
starttime := time.now()
actualarray := []interface{}{123, 39, 2, 198, 236, 5, 214, 195, 100, 86, 162, 16, 233, 34, 197, 209, 173, 174, 238, 75, 6, 12, 191, 4, 44, 108, 85, 72, 216, 210, 248, 152, 226, 155, 38, 103, 45, 136, 206, 19, 181, 107, 81, 133, 118, 35, 190, 154, 212, 193, 232, 106, 196, 43, 243, 63, 245, 165, 60, 124, 36, 235, 137, 176, 228, 234, 183, 22, 187, 128, 142, 42, 29, 224, 131, 112, 110, 117, 217, 98, 178, 13, 74, 146, 122, 109, 1, 121, 78, 229, 46, 127, 150, 114, 28, 95, 8, 237, 32, 207, 166, 227, 144, 120, 15, 17, 94, 151, 47, 88, 247, 192, 82, 230, 31, 41, 138, 56, 21, 97, 53, 164, 126, 30, 67, 91, 66, 105, 71, 148, 125, 10, 218, 99, 203, 25, 119, 40, 250, 246, 153, 51, 84, 102, 186, 33, 37, 93, 104, 68, 18, 50, 139, 80, 205, 199, 20, 57, 27, 249, 145, 223, 168, 83, 140, 90, 201, 23, 184, 221, 156, 163, 202, 204, 157, 175, 241, 219, 116, 54, 149, 129, 194, 49, 64, 167, 211, 62, 87, 89, 59, 169, 14, 244, 200, 79, 24, 141, 171, 77, 189, 147, 134, 180, 225, 185, 73, 111, 213, 215, 158, 52, 69, 70, 11, 135, 7, 115, 101, 177, 76, 61, 208, 242, 48, 132, 26, 188, 182, 92, 239, 3, 58, 9, 172, 113, 160, 220, 222, 143, 130, 65, 170, 240, 231, 55, 159, 96, 179, 161}
expectedarray := []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250}
tailrecursivequicksort(actualarray, 0, 249)
timediff := time.now().sub(starttime)
fmt.printf("time take to sort %v numbers is %v", len(actualarray), timediff)
for i := 0; i < len(actualarray); i++ {
if actualarray[i] != expectedarray[i] {
t.fail()
break
}
}
}
运行时间日志:
=== RUN TestRandomizedQuickSort1 Time take to sort 250 numbers is 93.1µs--- PASS: TestRandomizedQuickSort1 (0.00s) === RUN TestRandomizedQuickSort2 Time take to sort 500 numbers is 153.913µs--- PASS: TestRandomizedQuickSort2 (0.00s) === RUN TestRandomizedQuickSort3 Time take to sort 750 numbers is 249.653µs--- PASS: TestRandomizedQuickSort3 (0.00s) === RUN TestRandomizedQuickSort4 Time take to sort 1000 numbers is 299.693µs--- PASS: TestRandomizedQuickSort4 (0.00s) === RUN TestRandomizedQuickSort5 Time take to sort 1250 numbers is 452.812µs--- PASS: TestRandomizedQuickSort5 (0.00s) === RUN TestRandomizedQuickSort6 Time take to sort 1500 numbers is 577.646µs--- PASS: TestRandomizedQuickSort6 (0.00s) === RUN TestRandomizedQuickSort7 Time take to sort 1750 numbers is 793.466µs--- PASS: TestRandomizedQuickSort7 (0.00s) === RUN TestRandomizedQuickSort8 Time take to sort 2000 numbers is 2.100078ms--- PASS: TestRandomizedQuickSort8 (0.00s) === RUN TestRandomizedQuickSort9 Time take to sort 2250 numbers is 1.534166ms--- PASS: TestRandomizedQuickSort9 (0.00s) === RUN TestRandomizedQuickSort10 Time take to sort 2500 numbers is 1.488542ms--- PASS: TestRandomizedQuickSort10 (0.00s) PASS Debugger finished with the exit code 0 === RUN TestTailRecursionQuickSort1 Time take to sort 250 numbers is 2.166925ms--- PASS: TestTailRecursionQuickSort1 (0.00s) === RUN TestTailRecursionQuickSort2 Time take to sort 500 numbers is 11.049337ms--- PASS: TestTailRecursionQuickSort2 (0.01s) === RUN TestTailRecursionQuickSort3 Time take to sort 750 numbers is 36.98923ms--- PASS: TestTailRecursionQuickSort3 (0.04s) === RUN TestTailRecursionQuickSort4 Time take to sort 1000 numbers is 213.94526ms--- PASS: TestTailRecursionQuickSort4 (0.21s) === RUN TestTailRecursionQuickSort5 Time take to sort 1250 numbers is 87.065747ms--- PASS: TestTailRecursionQuickSort5 (0.09s) === RUN TestTailRecursionQuickSort6 Time take to sort 1500 numbers is 105.232837ms--- PASS: TestTailRecursionQuickSort6 (0.11s) PASS Debugger finished with the exit code 0 === RUN TestTailRecursionQuickSort7 Time take to sort 1750 numbers is 2.632979054s--- PASS: TestTailRecursionQuickSort7 (2.63s) === RUN TestTailRecursionQuickSort8 Time take to sort 2000 numbers is 1.082278134s--- PASS: TestTailRecursionQuickSort8 (1.08s) === RUN TestTailRecursionQuickSort9 Time take to sort 2250 numbers is 3.14799009s--- PASS: TestTailRecursionQuickSort9 (3.15s) === RUN TestTailRecursionQuickSort10 Time take to sort 2500 numbers is 4.877045862s--- PASS: TestTailRecursionQuickSort10 (4.88s)
运行这两种算法的测试用例后,我发现随机快速排序比尾递归更快。尾递归不就是随机快速排序的优化吗?让我知道你的想法。
谢谢
正确答案
问题的代码不包含随机配分函数。尾递归仅在每个循环上将大小减少一(从右到右-1),这是最坏的情况。如果存在大量重复元素,代码中使用的 lomuto 分区方案会降低到最坏情况时间复杂度:
https://en.wikipedia.org/wiki/Quicksort#Repeated_elements
示例 c++ hoare 分区代码,在较小的分区上递归,然后循环返回较大的分区。
void quicksort(int a[], int lo, int hi)
{
while (lo < hi){
int p = a[lo + (hi - lo) / 2];
int i = lo - 1;
int j = hi + 1;
while (1){
while (a[++i] < p);
while (a[--j] > p);
if (i >= j)
break;
std::swap(a[i], a[j]);
}
if(j - lo < hi - j){
quicksort(a, lo, j);
lo = j+1;
} else {
quicksort(a, j+1, hi);
hi = j;
}
}
}
一个真正的 c++ 尾递归示例。 visual studio 发布版本会将尾递归调用转换为循环。
void QuickSort(int a[], int lo, int hi)
{
if(lo < hi){
int p = a[lo + (hi - lo) / 2];
int i = lo - 1;
int j = hi + 1;
while (1){
while (a[++i] < p);
while (a[--j] > p);
if (i >= j)
break;
std::swap(a[i], a[j]);
}
if(j - lo < hi - j){
QuickSort(a, lo, j);
QuickSort(a, j+1, hi); // converted to loop
} else {
QuickSort(a, j+1, hi);
QuickSort(a, lo, j); // converted to loop
}
}
}今天关于《随机快速排序比尾递归快速排序运行得更快吗?》的内容介绍就到此结束,如果有什么疑问或者建议,可以在golang学习网公众号下多多回复交流;文中若有不正之处,也希望回复留言以告知!
版本声明
本文转载于:stackoverflow 如有侵犯,请联系study_golang@163.com删除
时尚搭档,更是影音伴侣!女神节用华为 FreeClip 耳夹耳机 & 华为 Pocket 2 俘获她的芳心
- 上一篇
- 时尚搭档,更是影音伴侣!女神节用华为 FreeClip 耳夹耳机 & 华为 Pocket 2 俘获她的芳心
- 下一篇
- 如何格式化包含动态数量元素的字符串?
查看更多
最新文章
-
- Golang · Go问答 | 1年前 |
- 在读取缓冲通道中的内容之前退出
- 139浏览 收藏
-
- Golang · Go问答 | 1年前 |
- 戈兰岛的全球 GOPRIVATE 设置
- 204浏览 收藏
-
- Golang · Go问答 | 1年前 |
- 如何将结构作为参数传递给 xml-rpc
- 325浏览 收藏
-
- Golang · Go问答 | 1年前 |
- 如何用golang获得小数点以下两位长度?
- 478浏览 收藏
-
- Golang · Go问答 | 1年前 |
- 如何通过 client-go 和 golang 检索 Kubernetes 指标
- 486浏览 收藏
-
- Golang · Go问答 | 1年前 |
- 将多个“参数”映射到单个可变参数的习惯用法
- 439浏览 收藏
-
- Golang · Go问答 | 1年前 |
- 将 HTTP 响应正文写入文件后出现 EOF 错误
- 357浏览 收藏
-
- Golang · Go问答 | 1年前 |
- 结构中映射的匿名列表的“复合文字中缺少类型”
- 352浏览 收藏
-
- Golang · Go问答 | 1年前 |
- NATS Jetstream 的性能
- 101浏览 收藏
-
- Golang · Go问答 | 1年前 |
- 如何将复杂的字符串输入转换为mapstring?
- 440浏览 收藏
-
- Golang · Go问答 | 1年前 |
- 相当于GoLang中Java将Object作为方法参数传递
- 212浏览 收藏
-
- Golang · Go问答 | 1年前 |
- 如何确保所有 goroutine 在没有 time.Sleep 的情况下终止?
- 143浏览 收藏
查看更多
课程推荐
-
- 前端进阶之JavaScript设计模式
- 设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
- 543次学习
-
- GO语言核心编程课程
- 本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
- 516次学习
-
- 简单聊聊mysql8与网络通信
- 如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
- 500次学习
-
- JavaScript正则表达式基础与实战
- 在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
- 487次学习
-
- 从零制作响应式网站—Grid布局
- 本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
- 485次学习
查看更多
AI推荐
-
- ChatExcel酷表
- ChatExcel酷表是由北京大学团队打造的Excel聊天机器人,用自然语言操控表格,简化数据处理,告别繁琐操作,提升工作效率!适用于学生、上班族及政府人员。
- 3179次使用
-
- Any绘本
- 探索Any绘本(anypicturebook.com/zh),一款开源免费的AI绘本创作工具,基于Google Gemini与Flux AI模型,让您轻松创作个性化绘本。适用于家庭、教育、创作等多种场景,零门槛,高自由度,技术透明,本地可控。
- 3390次使用
-
- 可赞AI
- 可赞AI,AI驱动的办公可视化智能工具,助您轻松实现文本与可视化元素高效转化。无论是智能文档生成、多格式文本解析,还是一键生成专业图表、脑图、知识卡片,可赞AI都能让信息处理更清晰高效。覆盖数据汇报、会议纪要、内容营销等全场景,大幅提升办公效率,降低专业门槛,是您提升工作效率的得力助手。
- 3419次使用
-
- 星月写作
- 星月写作是国内首款聚焦中文网络小说创作的AI辅助工具,解决网文作者从构思到变现的全流程痛点。AI扫榜、专属模板、全链路适配,助力新人快速上手,资深作者效率倍增。
- 4525次使用
-
- MagicLight
- MagicLight.ai是全球首款叙事驱动型AI动画视频创作平台,专注于解决从故事想法到完整动画的全流程痛点。它通过自研AI模型,保障角色、风格、场景高度一致性,让零动画经验者也能高效产出专业级叙事内容。广泛适用于独立创作者、动画工作室、教育机构及企业营销,助您轻松实现创意落地与商业化。
- 3798次使用
查看更多
相关文章
-
- GoLand调式动态执行代码
- 2023-01-13 502浏览
-
- 用Nginx反向代理部署go写的网站。
- 2023-01-17 502浏览
-
- Golang取得代码运行时间的问题
- 2023-02-24 501浏览
-
- 请问 go 代码如何实现在代码改动后不需要Ctrl+c,然后重新 go run *.go 文件?
- 2023-01-08 501浏览
-
- 如何从同一个 io.Reader 读取多次
- 2023-04-11 501浏览

