常见排序算法总结 (二) - 不基于比较的排序

devtools/2024/11/27 0:40:29/

计数排序

算法思想

用哈希表记录每个不同元素出现的次数,然后再根据这个记录还原。

稳定性分析

计数排序是稳定的,如果待排序元素不是纯数值,那么用链地址法来解决冲突,遍历的过程中按链表元素的先后顺序还原元素就可以保证元素的相对位置不发生改变。

具体实现

public void countingSort(int[] arr) {// 查找数组中的最小最大值,确定映射范围int min = Integer.MAX_VALUE, max = Integer.MIN_VALUE;for(int item : arr) {min = Math.min(min, item);max = Math.max(max, item);}int range = max - min + 1;int[] count = new int[range];// 统计每个元素出现的次数for (int item : arr) {count[item - min]++; // 注意每个元素都要先映射后记录}// 改造成前缀分区的形式,方便快速地确定还原后的元素位置for (int i = 1; i < count.length; i++) {count[i] += count[i - 1];}// 还原数组元素int[] res = new int[arr.length];for (int i = arr.length - 1; i >= 0; i--) {int cur = arr[i];res[--count[cur - min]] = cur;}// 把结果回写到原数组中System.arraycopy(res, 0, arr, 0, arr.length);
}

基数排序

算法思想

将元素根据基数从低位到高位分别散列到不同的分区中,再依次收集,就可以得到有序序列。

稳定性分析

基数排序是稳定的,收集的过程中依次收集值相等的元素,就不会改变它们的相对位置。

具体实现

public void radixSort(int[] arr) {int base = 10; // 定义基数,基数可以在一定范围内修改,也许会影响性能int n = arr.length;int[] res = new int[n];// 根据最小值映射原数组,防止数组下标出现负数int min = Integer.MAX_VALUE, max = Integer.MIN_VALUE;for(int item : arr) {min = Math.min(min, item);}for(int i = 0; i < n; i++) {arr[i] -= min;max = Math.max(max, arr[i]);}// 根据最大值计算当前基数下最长数字的长度int bits = 0;while (max != 0) {bits++;max /= base;}int[] count = new int[base];// 最长的数字有多少位,就要重复收集多少次for (int offset = 1; bits > 0; offset *= base, bits--) {Arrays.fill(count, 0); // 避免脏数据导致 res 数组下标越界// 统计每个元素出现的次数for (int item : arr) {// 注意这个偏移的写法,在元素本身不可更改的情况下很好用count[(item / offset) % base]++;}// 改造成前缀分区的形式,方便快速地确定还原后的元素位置for (int i = 1; i < base; i++) {count[i] += count[i - 1];}// 还原数组元素for (int i = n - 1; i >= 0; i--) {res[--count[(arr[i] / offset) % base]] = arr[i];}// 把结果回写到原数组中System.arraycopy(res, 0, arr, 0, n);}// 把数组元素映射回来for (int i = 0; i < n; i++) {arr[i] += min;}
}

梳理总结

不基于比较的排序使用起来有限制,要求数组元素的数值范围有限。
上述两种算法>排序算法的效率很高,时间复杂度达到了 O ( N ) O(N) O(N) N N N 表示数组中元素的数量;同时也需要 O ( M ) O(M) O(M) 的额外空间, M M M 表示用到的哈希表长度。
计数排序和基数排序是有应用场景的,在某些算法题中,明确数组元素范围有限的情况下,手写的计数排序可以在排序这个步骤上提升效率。

后记

使用 Leetcode 912. 排序数组 进行测试,两种算法都能通过,并且效果很好。


http://www.ppmy.cn/devtools/137260.html

相关文章

【高阶数据结构】图论

> 作者&#xff1a;დ旧言~ > 座右铭&#xff1a;松树千年终是朽&#xff0c;槿花一日自为荣。 > 目标&#xff1a;了解什么是图&#xff0c;并能掌握深度优先遍历和广度优先遍历。 > 毒鸡汤&#xff1a;有些事情&#xff0c;总是不明白&#xff0c;所以我不会坚持…

Maven 依赖管理

Maven 依赖管理 Maven 是一个强大的工具&#xff0c;它简化了项目依赖的管理。 Maven 自动化了下载和包含必要库的过程&#xff0c;这对于构建 Java 应用程序至关重要。 本文将涵盖 Maven 依赖管理的核心方面&#xff0c;包括如何声明依赖、依赖范围、传递依赖、依赖管理、排…

Python Scikit-learn简介(二)

数据处理 数据划分 机器学习的数据&#xff0c;可以划分为训练集、验证集和测试集&#xff0c;也可以划分为训练集和测试集。 from sklearn.model_selection import train_test_split# 示例数据 X [[1, 2], [3, 4], [5, 6], [7, 8]] y [0, 1, 0, 1]# 划分数据集 X_train,…

全面解析多种mfc140u.dll丢失的解决方法,五种方法详细解决

当你满心期待地打开某个常用软件&#xff0c;却突然弹出一个错误框&#xff0c;提示“mfc140u.dll丢失”&#xff0c;那一刻&#xff0c;你的好心情可能瞬间消失。这种情况在很多电脑用户的使用过程中都可能出现。无论是游戏玩家还是办公族&#xff0c;面对这个问题都可能不知所…

Android opencv使用Core.hconcat 进行图像拼接

Android 集成OpenCV-CSDN博客 import org.opencv.android.Utils; import org.opencv.core.Core; import org.opencv.core.CvType; import org.opencv.core.Mat; import org.opencv.imgcodecs.Imgcodecs; import android.graphics.Bitmap; import android.graphics.BitmapFactor…

【论文解析】HAQ: Hardware-Aware Automated Quantization With Mixed Precision

作者及发刊详情 inproceedings{haq, author {Wang, Kuan and Liu, Zhijian and Lin, Yujun and Lin, Ji and Han, Song}, title {HAQ: Hardware-Aware Automated Quantization With Mixed Precision}, booktitle {IEEE Conference on Computer Vision and Pattern Recognit…

基于FPGA的2FSK调制-串口收发-带tb仿真文件-实际上板验证成功

基于FPGA的2FSK调制 前言一、2FSK储备知识二、代码分析1.模块分析2.波形分析 总结 前言 设计实现连续相位 2FSK 调制器&#xff0c;2FSK 的两个频率为:fI15KHz&#xff0c;f23KHz&#xff0c;波特率为 1500 bps,比特0映射为f 载波&#xff0c;比特1映射为 载波。 1&#xff09…

大学课程项目中的记忆深刻 Bug —— 一次意外的数组越界

开头 在编程的世界里&#xff0c;每一行代码都像是一个小小的宇宙&#xff0c;承载着开发者的心血与智慧。然而&#xff0c;即便是最精心编写的代码&#xff0c;也难免会遇到那些突如其来的 bug&#xff0c;它们就像是潜伏在暗处的小怪兽&#xff0c;时不时跳出来捣乱。 在我…