惊叹数据结构之美,品味排序算法之妙:对计排、桶排的详细介绍

惊叹数据结构之美,品味排序算法之妙:对计排、桶排的详细介绍
大家好,这里是小编的博客频道
小编的博客:就爱学编程
很高兴在ZEEKLOG这个大家庭与大家相识,希望能在这里与大家共同进步,共同收获更好的自己!!!

本文目录


引言

排序算法中的基数排序和计数排序都是非基于传统比较的排序方法,它们各自有着独特的实现原理和应用场景。下面小编将从代码实现的角度对这两种排序算法进行详细介绍。

在这里插入图片描述

那接下来就让我们开始遨游在知识的海洋!

正文


一、计数排序(Counting Sort)

原理概述

计数排序是一种适用于元素范围较小的排序算法。它利用一个额外的计数数组来记录待排序数组中每个元素出现的次数,然后根据这些次数来确定每个元素在最终排序数组中的位置。

代码实现步骤

1. 确定元素范围:找出待排序数组中的最小值和最大值,记为min和max。2. 创建计数数组:创建一个大小为max-min+1的计数数组count,用于记录每个元素出现的次数。数组的下标代表元素的值,数组的值代表该元素出现的次数。3. 统计频次:遍历待排序数组,统计每个元素出现的频率,并将该频率存储到计数数组中。4. 累计计数:将计数数组中的值进行累加,得到每个元素在最终排序数组中的位置。这个步骤确保了排序的稳定性(即相同元素的相对位置不变)。5. 构造排序结果:根据累加后的计数数组,将元素按顺序放入目标排序数组中。

示例代码

#include<iostream>usingnamespace std;int*count_sort(int* input,int len,int min,int max){int* arr =newint[max - min +1];// 创建计数数组for(int i =0; i < max - min +1; i++) arr[i]=0;// 初始化计数数组为0// 统计每个元素的出现次数for(int i =0; i < len; i++){ arr[input[i]- min]++;}int* ans =newint[len];// 创建目标排序数组int index =0;// 用于填充目标排序数组的索引// 根据计数数组构建目标排序数组for(int i = min; i <= max; i++){for(int j =0; j < arr[i - min]; j++){ ans[index++]= i;}}return ans;// 返回排序后的数组}intmain(){int arr[]={3,6,4,5,6,3,6,4,5,5,6,4,3};int len =sizeof(arr)/sizeof(int);int* sorted_arr =count_sort(arr, len,3,6);// 输出排序结果for(int i =0; i < len; i++){ cout << sorted_arr[i]<<" ";} cout << endl;delete[] sorted_arr;// 释放动态分配的内存return0;}

二、基数排序(Radix Sort)

原理概述

基数排序又称桶排序,它通过将所有数字分配到应在的位置最后再覆盖到原数组完成排序的过程。基数排序分为最高位优先法(MSD)和最低位优先法(LSD)。这里以最低位优先法为例进行说明。
基数排序的基本思想是从数字的最低有效位开始,依次对每个数位进行一次排序。每次排序都使用稳定的排序算法(如计数排序),以保证排序后元素的相对位置不变。经过多次排序后,整个数列就变得有序了。

代码实现步骤

1. 获取最大位数:找出待排序数组中所有数字的最大位数。2. 逐位排序:从最低有效位开始,依次对每个数位进行排序。每次排序都使用计数排序算法。3. 合并结果:由于每次排序都是稳定的,所以可以直接在原数组上进行操作,无需额外的合并步骤。

示例代码(以最低位优先法为例):

#include<iostream>#include<vector>#include<algorithm>#include<cmath>usingnamespace std;// 获取数字d在第pos位的值(0~9)intgetDigit(int d,int pos){return(d /static_cast<int>(pow(10, pos)))%10;}// 对数组arr按照第pos位进行计数排序voidcountingSortByDigit(vector<int>& arr,int pos){constint radix =10;// 基数为10(因为是十进制数) vector<int>output(arr.size());// 存储排序结果的数组 vector<int>count(radix,0);// 计数数组// 统计每个数字在第pos位上出现的次数for(int num : arr){int digit =getDigit(num, pos); count[digit]++;}// 修改count数组,使其包含实际位置信息for(int i =1; i < radix; i++){ count[i]+= count[i -1];}// 构建输出数组for(int i = arr.size()-1; i >=0; i--){int digit =getDigit(arr[i], pos); output[count[digit]-1]= arr[i]; count[digit]--;}// 将排序结果复制回原数组copy(output.begin(), output.end(), arr.begin());}// 基数排序主函数voidradixSort(vector<int>& arr){if(arr.empty())return;// 找到最大数的位数int maxNum =*max_element(arr.begin(), arr.end());int maxDigits =log10(maxNum)+1;// 从个位开始,逐位进行计数排序for(int pos =0; pos < maxDigits; pos++){countingSortByDigit(arr, pos);}}intmain(){ vector<int> arr ={170,45,75,90,802,24,2,66};radixSort(arr);// 输出排序结果for(int num : arr){ cout << num <<" ";} cout << endl;return0;}

三、总结

  • 计数排序:适用于元素范围较小的情况,时间复杂度为O(n+k),其中n是待排序元素的个数,k是元素的范围。空间复杂度高,需要额外的计数数组。
  • 基数排序:通过逐位排序来实现整体排序,通常使用计数排序作为子过程。时间复杂度为O(d*(n+r)),其中d是数字的最大位数,n是待排序元素的个数,r是基数(对于十进制数,r=10)。基数排序是稳定的排序算法。

快乐的时光总是短暂,咱们下篇博文再见啦!!!不要忘了,给小编点点赞和收藏支持一下,在此非常感谢!!!

Read more

【缓存算法】一篇文章带你彻底搞懂面试高频题LRU/LFU

【缓存算法】一篇文章带你彻底搞懂面试高频题LRU/LFU

系列文章目录 文章目录 * 系列文章目录 * 一、LRU缓存算法 * 1.哈希表 + 双向链表 * 二、LFU缓存算法 * 1、哈希表 + 平衡二叉树 * 2、双哈希表 * 三、总结 一、LRU缓存算法 1.哈希表 + 双向链表 1.题目链接:LRU缓存 2.题目描述: 3.算法思路: 1.双向链表 + 哈希表 组合: 双向链表(带哑头 / 哑尾节点):维护缓存节点的访问顺序,最近使用的节点放在链表头部,最少使用的节点放在链表尾部(淘汰时直接删尾部); 哈希表(cache):实现 key 到节点的 O (1) 快速查找,解决链表遍历查找慢的问题; 2.

By Ne0inhk
Flutter 组件 vnlunar 适配鸿蒙 HarmonyOS 实战:高精度农历算法,构建民俗文化日期与节气治理架构

Flutter 组件 vnlunar 适配鸿蒙 HarmonyOS 实战:高精度农历算法,构建民俗文化日期与节气治理架构

欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.ZEEKLOG.net Flutter 组件 vnlunar 适配鸿蒙 HarmonyOS 实战:高精度农历算法,构建民俗文化日期与节气治理架构 前言 在鸿蒙(OpenHarmony)生态迈向全球化部署、涉及多语言本地化(L10n)及深层文化特性适配的背景下,如何实现准确的阴阳历(农历)转换、二十四节气计算及民俗节日提醒,已成为提升应用“人文温度”与本地化竞争力的核心要素。在鸿蒙设备这类强调分布式时间同步与低功耗常驻显示(AOD)的环境下,如果应用依然依赖简单的查表法或通过网络接口获取农历信息,由于由于闰月计算的复杂性或离线环境限制,极易由于由于计算偏移导致传统节日提醒的误报。 我们需要一种能够实现天文级算法推演、支持高精度节气定位且具备纯 Dart 离线运作能力的历法治理方案。 vnlunar 为 Flutter 开发者引入了标准化的阴阳历转换协议。它不仅支持对天干地支、生肖及闰月的精确解构,更针对东南亚等地区的历法细微差异提供了专项适配。在适配到鸿蒙 HarmonyOS 流程

By Ne0inhk
【强化学习】演员评论家Actor-Critic算法(万字长文、附代码)

【强化学习】演员评论家Actor-Critic算法(万字长文、附代码)

📢本篇文章是博主强化学习(RL)领域学习时,用于个人学习、研究或者欣赏使用,并基于博主对相关等领域的一些理解而记录的学习摘录和笔记,若有不当和侵权之处,指出后将会立即改正,还望谅解。文章分类在👉强化学习专栏:        【强化学习】- 【单智能体强化学习】(7)---《演员评论家Actor-Critic算法》 演员评论家Actor-Critic算法 目录 Actor-Critic算法理解 1. 角色设定 2. 两者如何协作 3. 学习的核心 4. 为什么叫Actor-Critic? 生活中例子: Actor-Critic算法的背景与来源 1. 强化学习的起源 2. 策略梯度方法的局限性 3. Actor-Critic的提出 4. 历史发展与应用 Actor-Critic算法流程的推导 1. 强化学习的优化目标 2. 策略梯度定理 3. Critic:值函数估计 4. Actor:策略优化 5.

By Ne0inhk
哈希表的两种灵魂:深入探索开放定址与链地址法的核心机密

哈希表的两种灵魂:深入探索开放定址与链地址法的核心机密

🔥草莓熊Lotso:个人主页 ❄️个人专栏: 《C++知识分享》《Linux 入门到实践:零基础也能懂》 ✨生活是默默的坚持,毅力是永久的享受! 🎬 博主简介: 文章目录 * 前言: * 一. 哈希表核心概念 * 1.1 哈希表的本质 * 1.2 哈希冲突 * 1.3 负载因子 * 1.4 将关键字转为整数 * 二. 哈希函数设计 * 2.1 直接定址法 * 2.2 除法散列法(除留余数法) * 2.3 其他方法(了解) * 2.4 字符串哈希实现(特化仿函数) * 三. 哈希冲突解决策略 * 3.1 实现一:开放定址法(

By Ne0inhk