几个效率高的排序算法

2023-11-03

实用排序算法(复杂度小于等于O(n^2))中效率最低但实现并不是最简单的的两个,C、C++教材却总喜欢拿来大讲特讲,非常不利于初学者养成“程序效率”的思维。

实际上,各种排序算法里,除了堆排序实现较为复杂外,从代码量的角度,大多数算法都不比冒泡、选择算法复杂多少。

举几个高速的排序算法的例子,这些才适合进入教材

鸽巢排序,排序字节串、宽字节串最快的排序算法,计数排序的变种(将计数缓冲区大小固定,少一次遍历开销),速度是STL中std::sort的20多倍,更重要的是实现极其简单!缺点是需要一个size至少等于待排序数组取值范围的缓冲区,不适合int等大范围数据

C/C++ code
   
   
void PigeonholeSort(BYTE * array, int length) { int b[ 256 ] = { 0 }; int i,k,j = 0 ; for (i = 0 ; i < length; i ++ ) b[array[i]] ++ ; for (i = 0 ; i < 256 ; i ++ ) for (k = 0 ; k < b[i]; k ++ ) array[j ++ ] = i; }




多一次遍历的计数排序,排序字节串的话速度约是鸽巢排序的一半

C/C++ code
   
   
void CountingSort(BYTE * array, int length) { int t; int i, z = 0 ; BYTE min,max; int * count; min = max = array[ 0 ]; for (i = 0 ; i < length; i ++ ) { if (array[i] < min) min = array[i]; else if (array[i] > max) max = array[i]; } count = ( int * )malloc((max - min + 1 ) * sizeof ( int )); for (i = 0 ; i < max - min + 1 ; i ++ ) count[i] = 0 ; for (i = 0 ; i < length; i ++ ) count[array[i] - min] ++ ; for (t = min ; t <= max ; t ++ ) for (i = 0 ; i < count[t - min]; i ++ ) array[z ++ ] = (BYTE)t; free(count); }



快速排序,快排最标准的递归实现,速度约是std::sort的一半

C/C++ code
   
   
void swap(BYTE * a,BYTE * b) { BYTE tmp; if ( a != b ) { tmp = * a; * a = * b; * b = tmp; } } int partition(BYTE * arr, int left, int right) { int i = left - 1 , j = right; BYTE v = arr[right]; while ( 1 ) { while (arr[ ++ i] < v); while (arr[ -- j] > v) if (j == 1 ) break ; if (i >= j) break ; swap( & arr[i], & arr[j]); } swap( & arr[i], & arr[right]); return i; } void quicksort(BYTE * arr, int left, int right) { if (left < right) { int i = partition(arr,left,right); quicksort(arr,left,i - 1 ); quicksort(arr,i + 1 ,right); } } void QuickSort(BYTE * array, int length) { quicksort(array, 0 ,length - 1 ); }



这是速度与std::sort相当的三路划分快排

C/C++ code
   
   
void swap(BYTE * a,BYTE * b) { BYTE tmp; if ( a != b ) { tmp = * a; * a = * b; * b = tmp; } } void quicksort(BYTE * arr, int left, int right) { if (left < right) { BYTE v = arr[right]; int i = left - 1 ,j = right,p = left - 1 ,q = right,k = 0 ; while ( 1 ) { while (arr[ ++ i] < v); while (arr[ -- j] > v) if (j == left) break ; if (i >= j) break ; swap( & arr[i], & arr[j]); if (arr[i] == v) { p ++ ; swap( & arr[p], & arr[i]); } if (arr[j] == v) { q -- ; swap( & arr[q], & arr[j]); } } swap( & arr[i], & arr[right]); j = i - 1 ; i ++ ; for (k = left; k <= p; k ++ ,j -- ) swap( & arr[k], & arr[j]); for (k = right - 1 ; k >= q; k -- ,i ++ ) swap( & arr[k], & arr[i]); quicksort(arr,left,j); quicksort(arr,i,right); } } void QuickSort(BYTE * array, int length) { quicksort(array, 0 ,length - 1 ); }




相当简单的梳排序,效率是std::sort的三分之一

C/C++ code
   
   
void CombSort(BYTE * arr, int size) { UINT gap = size, swapped = 1 , i = 0 ; BYTE swap = 0 ; while ((gap > 1 ) || swapped) { if (gap > 1 ) gap = gap / 1.3 ; swapped = 0 ; i = 0 ; while ((gap + i) < size) { if (arr[i] - arr[i + gap] > 0 ) { swap = arr[i]; arr[i] = arr[i + gap]; arr[i + gap] = swap; swapped = 1 ; } ++ i; } } }



LSD基数排序,与std::sort速度相当,但是需要一个与输入缓冲一样大的缓冲区

C/C++ code
   
   
#define R 256 #define digit(a, d) ( a >> 8*d ) static BYTE * aux; void radix_sort(BYTE * arr, int left, int right) { if (left < right) { int d = 0 ; for (d = 3 ; d >= 0 ; d -- ) { int i = 0 , j = 0 , count[R + 1 ]; for (j = 0 ; j < R; j ++ ) count[j] = 0 ; for (i = left; i <= right; i ++ ) count[digit(arr[i],d) + 1 ] ++ ; for (j = 1 ; j < R; j ++ ) count[j] += count[j - 1 ]; for (i = left; i <= right; i ++ ) aux[count[digit(arr[i],d)] ++ ] = arr[i]; for (i = left; i <= right; i ++ ) arr[i] = aux[i - 1 ]; } } } void RadixSort(BYTE * array, int length) { aux = (BYTE * )malloc(length); radix_sort(array, 0 ,length - 1 ); free(aux); }



归并排序,效率越是std::sort的六分之一,通常的实现是递归,但和快排不同,归并改循环极其容易

C/C++ code
   
   
void merge(BYTE * array, int low, int mid, int high) { int i, k; BYTE * temp = (BYTE * ) malloc(high - low + 1 ); int begin1 = low; int end1 = mid; int begin2 = mid + 1 ; int end2 = high; for (k = 0 ; begin1 <= end1 && begin2 <= end2; ++ k) if (array[begin1] < array[begin2]) temp[k] = array[begin1 ++ ]; else temp[k] = array[begin2 ++ ]; while (begin1 <= end1) temp[k ++ ] = array[begin1 ++ ]; while (begin2 <= end2) temp[k ++ ] = array[begin2 ++ ]; for (i = 0 ; i < (high - low + 1 ); i ++ ) array[low + i] = temp[i]; free(temp); } void merge_sort(BYTE * array, UINT first, UINT last) { UINT mid,i; for (mid = 1 ; mid <= last - first; mid += mid) for (i = first; i <= last - mid; i += mid + mid) merge(array,i,i + mid - 1 ,min(i + mid + mid - 1 ,last)); } void MergeSort(BYTE * array, UINT length) { merge_sort(array, 0 ,length - 1 ); }
这是堆排序,相对复杂些,效率是std::sort的四分之一
C/C++ code
      
      
UINT parent(UINT i) { return (UINT)floor(i / 2 ); } UINT left(UINT i) { return 2 * i; } UINT right(UINT i) { return ( 2 * i + 1 ); } void Max_Heapify(BYTE * A, UINT i, UINT length) { UINT l = left(i); UINT r = right(i); UINT largest; BYTE temp; if (l < length && A[l] > A[i]) largest = l; else largest = i; if (r < length && A[r] > A[largest]) largest = r; if (largest != i) { temp = A[i]; A[i] = A[largest]; A[largest] = temp; Max_Heapify(A, largest, length); } } void Build_Max_Heap(BYTE * A, UINT length) { int i = 0 ; for (i = length; i >= 0 ; i -- ) Max_Heapify(A, i, length); } void HeapSort(BYTE * A, UINT length) { BYTE temp; int i = 0 ; Build_Max_Heap(A,length); for (i = length - 1 ; i >= 1 ; i -- ) { temp = A[ 0 ]; A[ 0 ] = A[i]; A[i] = temp; length = length - 1 ; Max_Heapify(A, 0 , length); } }



本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

几个效率高的排序算法 的相关文章

  • 静态只读字符串数组

    我在我的 Web 应用程序中使用静态只读字符串数组 基本上数组有错误代码 我将所有类似的错误代码保存在一个数组中并检查该数组 而不是检查不同常量字符串中的每个错误代码 like public static readonly string m
  • 构建 Vue 微前端应用程序(带有路由和 vuex 存储)

    我需要帮助配置使用 Vuex Vue Router 和 Vue i18n 的微前端应用程序的构建 分发 TL DR 我在构建将导入到现有系统中的微前端应用程序时遇到问题 我们的团队尝试通过 vue cli service 和 vue web
  • 如何在C(Linux)中的while循环中准确地睡眠?

    在 C 代码 Linux 操作系统 中 我需要在 while 循环内准确地休眠 比如说 10000 微秒 1000 次 我尝试过usleep nanosleep select pselect和其他一些方法 但没有成功 一旦大约 50 次 它
  • 如何判断计算机是否已重新启动?

    我曾经使用过一个命令行 SMTP 邮件程序 作为试用版的限制 它允许您在每个 Windows 会话中最多接收 10 封电子邮件 如果您重新启动计算机 您可能还会收到 10 个以上 我认为这种共享软件破坏非常巧妙 我想在我的应用程序中复制它
  • 当一组凭据下的计划任务启动的进程在另一组凭据下运行另一个程序时,Windows 是否有限制

    所以我有一个简单的例子 其中我有应用程序 A 它对用户 X 本地管理员 有一些硬编码的凭据 然后它使用硬编码的绝对路径启动带有这些凭据的应用程序 B A 和 B 以及 dotnet 控制台应用程序 但是它们不与控制台交互 只是将信息写入文件
  • 查看 NuGet 包依赖关系层次结构

    有没有一种方法 文本或图形 来查看 NuGet 包之间的依赖关系层次结构 如果您使用的是新的 csproj 您可以在此处获取所有依赖项 在项目构建后 项目目录 obj project assets json
  • C# 数据表更新多行

    我如何使用数据表进行多次更新 我找到了这个更新 1 行 http support microsoft com kb 307587 my code public void ExportCSV string SQLSyntax string L
  • unordered_map 中字符串的 C++ 哈希函数

    看起来 C 标准库中没有字符串的哈希函数 这是真的 在任何 c 编译器上使用字符串作为 unordered map 中的键的工作示例是什么 C STL提供模板专业化 http en cppreference com w cpp string
  • 将 Long 转换为 DateTime 从 C# 日期到 Java 日期

    我一直尝试用Java读取二进制文件 而二进制文件是用C 编写的 其中一些数据包含日期时间数据 当 DateTime 数据写入文件 以二进制形式 时 它使用DateTime ToBinary on C 为了读取 DateTime 数据 它将首
  • C# 存档中的文件列表

    我正在创建一个 FileFinder 类 您可以在其中进行如下搜索 var fileFinder new FileFinder new string C MyFolder1 C MyFolder2 new string
  • 启动时的 Excel 加载项

    我正在使用 Visual C 创建 Microsoft Excel 的加载项 当我第一次创建解决方案时 它包含一个名为 ThisAddIn Startup 的函数 我在这个函数中添加了以下代码 private void ThisAddIn
  • 使用valgrind进行GDB远程调试

    如果我使用远程调试gdb我连接到gdbserver using target remote host 2345 如果我使用 valgrind 和 gdb 调试内存错误 以中断无效内存访问 我会使用 target remote vgdb 启动
  • 为什么从字典中获取时会得到 Action<> 的克隆?

    我有以下字典 private Dictionary
  • 在视口中查找 WPF 控件

    Updated 这可能是一个简单或复杂的问题 但在 wpf 中 我有一个列表框 我用一个填充数据模板从列表中 有没有办法找出特定的数据模板项位于视口中 即我已滚动到其位置并且可以查看 目前我连接到了 listbox ScrollChange
  • C++ int 前面加 0 会改变整个值

    我有一个非常奇怪的问题 如果我像这样声明一个 int int time 0110 然后将其显示到控制台返回的值为72 但是当我删除前面的 0 时int time 110 然后控制台显示110正如预期的那样 我想知道两件事 首先 为什么它在
  • 使 Guid 属性成为线程安全的

    我的一个类有一个 Guid 类型的属性 该属性可以由多个线程同时读写 我的印象是对 Guid 的读取和写入不是原子的 因此我应该锁定它们 我选择这样做 public Guid TestKey get lock testKeyLock ret
  • 实体框架中的“it”是什么

    如果以前有人问过这个问题 请原谅我 但我的任何搜索中都没有出现 它 我有两个数据库表 Person 和 Employee 对每个类型的表进行建模 例如 Employee is a Person 在我的 edmx 设计器中 我定义了一个实体
  • 为boost python编译的.so找不到模块

    我正在尝试将 C 代码包装到 python 中 只需一个类即可导出两个函数 我编译为map so 当我尝试时import map得到像噪音一样的错误 Traceback most recent call last File
  • 灵气序列解析问题

    我在使用 Spirit Qi 2 4 编写解析器时遇到一些问题 我有一系列键值对以以下格式解析
  • 如何将十六进制字符串转换为无符号长整型?

    我有以下十六进制值 CString str str T FFF000 如何将其转换为unsigned long 您可以使用strtol作用于常规 C 字符串的函数 它使用指定的基数将字符串转换为 long long l strtol str

随机推荐

  • python更换版本。

    问题背景 由于ddddocr库需要python3 9及以下的版本 本人安装的为python3 11版本 所以需要更换版本 解决办法 1 安装所需要版本的pyhton我安装的是python3 9 之前安装的python3 11是不需要卸载的
  • 机器学习笔记(一):监督学习与无监督学习概述

    机器学习的两种模型 监督学习和无监督学习 一 监督学习 supervised learning 监督学习是实际应用中使用更多的机器学习类型 1 监督学习就是学习从x到y 即学习从输入到输出的映射的算法 关键特征就是提供学习算法的实例供机器学
  • Microsoft Dynamics CRM 2015 之安装SQL Server 2012过程中出现“启用windows功能NetFx3时出错...

    错误详细信息 安装 Microsoft NET Framework 3 5 时出错 启用 Windows 功能 NetFx3 时出错 错误代码 2146498298 请尝试从 Windows 管理工具启用 Windows 功能 NetFx3
  • LeetCode日记

    题目 实现 strStr 函数 给定一个 haystack 字符串和一个 needle 字符串 在 haystack 字符串中找出 needle 字符串出现的第一个位置 从0开始 如果不存在 则返回 1 说明 当 needle 是空字符串时
  • html input date不起效,JavaScript – HTML 5 input type =“date”在Firefox中不起作用

    Firefox doesn t support HTML5 s 你有两个选择 gt 总是使用Javascript日期时间选择器 或 gt 检查浏览器是否支持该标签 如果是使用它 如果没有 然后回退在javascript datepicker
  • frida启动报错:./frida-server-15.1.27-android-x86_64: can‘t execute: Is a directory

    报错场景 在MuMu模拟器上安装frida server 启动的时候报错 报错信息如下 frida server 15 1 27 android x86 64 can t execute Is a directory 原因剖析 报错信息上显
  • 10g r2 RAC Dataguard 3 nodes

    最近在深圳实施windows 2003 上的oracle RAC项目 原来计划是两个节点 结果客户要求三个节点 因为是他们认为购买的服务器只有二个cpu 原来计划是四个cpu 然后还要在做dataguard 一开始安装很顺利 两个节点测试也
  • HTTP状态 405 - 方法不允许

    错误描述 HTTP状态 405 方法不允许 类型 状态报告 消息 Request method GET not supported 描述 请求行中接收的方法由源服务器知道 但目标资源不支持 此时的原因是请求类型错误 网页是get请求 但是实
  • springMVC项目如何配置tomcat

    先打开项目然后按图片所示操作 最后点击ok就可以启动项目啦
  • 【机器学习教程】四、随机森林:从论文到实践

    引言 随机森林 Random Forest 是机器学习领域中一种强大的集成学习算法 它的优秀性能和广泛应用使得它成为了机器学习领域的一个重要里程碑 本文将从算法的发展历程 重要论文 原理以及实际应用等方面详细介绍随机森林 并提供一个复杂的实
  • 时间段随机 java_java生成指定范围的随机日期

    有这样一个需求 构造一个方法 随机生成1990 12 31 00 00 00到 2013 12 31 00 00 00之间任意一个时间点 思路是这样 在javaAPI中 Date类型和long类型很好转化 所以我们可以把问题转化为 求两个l
  • Selinux

    1 Selinux的影响 对于文件的影响 当selinux开启时 内核会对每个文件及每个开启的程序进行标签加载 标签内记录程序和文件的安全上下文 context 对于程序功能的影响 当selinux开启会对程序的功能加载开关 并设定此开关的
  • HBuilder 打包 H5 APP 进行认证登录

    H5 Mui App 统一身份认证登录过程的记录 在 h5 app 开发的过程中 用到到统一认证登录的功能 统一身份认证登接口 来进行登录验证 在开发 h5 app 的时候 一般会提供 app 网页版的 这时候会发现 网页版和打包的APP几
  • Perl知识点滴

    函数多返回值 v1 abc v2 bcd v3 v4 upcase v1 v2 sub upcase my parms for parms tr a z A Z return wantarray parms parms 0 print v3
  • 【数据结构】6.4 AVL树(C++)

    数据结构 6 4 AVL树 没有学过二叉搜索树 也叫二叉排序树或二叉查找树 的小伙伴们建议先学习一下 这样阅读会更轻松哦 点我学习二叉搜索树 目录 一 AVL树的概念 1 二叉搜索树的问题 2 AVL树的性质 二 AVL树实现平衡的方法 1
  • 为啥要用三层结构

    开发人员可以只关注整个结构中的其中某一层 可以很容易的用新的实现来替换原有层次的实现 可以降低层与层之间的依赖 有利于标准化 利于各层逻辑的复用 结构更加的明确 在后期维护的时候 极大地降低了维护成本和维护时间 体现了高内聚 低耦合的思想
  • DocuCentre SC2020 打印机连接

    驱动下载地址 https support fb fujifilm com setupDriverForm do ctry code CN lang code zh CN d lang zh CN pid DCSC2020 anchor0 安
  • 《再也不怕elasticsearch》es环境搭建、集群搭建

    Elasticsearch环境搭建 大家好我是迷途 一个在互联网行业 摸爬滚打的学子 热爱学习 热爱代码 热爱技术 热爱互联网的一切 再也不怕elasticsearch系列 帅途会慢慢由浅入深 为大家剖析一遍 各位大佬请放心 虽然这个系列帅
  • 90、基于STM32单片机数字频率计频率检测配NE555脉冲发生器设计(程序+原理图+PCB源文件+参考论文+硬件设计资料+元器件清单等)

    单片机主芯片选择方案 方案一 AT89C51是美国ATMEL公司生产的低电压 高性能CMOS型8位单片机 器件采用ATMEL公司的高密度 非易失性存储技术生产 兼容标准MCS 51指令系统 片内置通用8位中央处理器 CPU 和Flash存储
  • 几个效率高的排序算法

    实用排序算法 复杂度小于等于O n 2 中效率最低但实现并不是最简单的的两个 C C 教材却总喜欢拿来大讲特讲 非常不利于初学者养成 程序效率 的思维 实际上 各种排序算法里 除了堆排序实现较为复杂外 从代码量的角度 大多数算法都不比冒泡