字符串排序:键索引计数法

2024-08-30 10:18

本文主要是介绍字符串排序:键索引计数法,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

字符串排序:键索引计数法

  • 描述
  • 适用性
  • 步骤
    • 1、频率统计
    • 2、构建索引
    • 3、数据分类
    • 4、回写数组
  • 代码实现
  • 总结
  • 参考

描述

关于字符串的排序有很多种方式,像《算法》一书中列举的低位优先、高位优先等,其中最先提到的是键索引计数法,它也是其他排序方式的基础,我们先来了解下。

适用性

关于键索引计数法进行字符串排序,并不是全部都适用,因为它的排序算法核心就是通过统计元素出现频次、构建排序因子的索引边界来递进式完成所有元素排序,它主要适合于以下场景:

  • 用于小整数键的算法
    比如数组arr ={1,2,3,4,2,3,4,2,1,3,4,2,3,4},它里面重复的数字比较多,不重复的只有1,2,3,4,这时就可以用此方法。
  • 用于小整数键的分组排序
    还可以应用在基于小整数键的分组排序,比如有字母{a,b,c,d,e,f,g,h},各字母不重复、但是分组重复,其分组序号格式{字母,分组号}描述为{a,1}、{b,2}、{c,1}、{d,2}、{e,3}、{f,4}、{g,4}、{h,1},最终按照分组号进行排序实现的元素排列为a、c、h、b、d、e、f、g
    在这里插入图片描述
    综上,我们可以看到按照分组号可以将元素归纳如下:
分组号元素
1a、c、h
2b、d
3e
4f、g

步骤

1、频率统计

在这里插入图片描述
我们可以看到,每个分组出现频次如下:

分组号元素元素出现频次
1a、c、h3
2b、d2
3e1
4f、g2

统计频次的目的是为了给构建索引提供条件,我们知道所谓键索引计数就是通过索引 + 频次来完成的。索引可以理解为每个分组的排序边界,每个分组的起始索引即较小一侧边界,而每个分组的结束索引即较大一侧边界,如果索引边界为startIndexendIndex,分组内元素出现频次为t,那么每个分组中的索引边界和分组内元素出现频次的关系是endIndex = startIndex + t,每个分组都按照逻辑序号紧紧相邻,较大的分组起始索引与它相邻的第一个较小分组的结束索引一致。

如果将这个场景延展到一个直线上,也可以将索引边界理解为坐标点,将频次理解为步长,或者是坐标点之间的间距

2、构建索引

在这里插入图片描述
当已知了间距,下面根据间距从0开始计算和整理索引边界,可以参考上图,方法很简单,是从0开始递增每个分组的频次即可。

3、数据分类

在这里插入图片描述
当建立好索引后,下面开始进行数据分类,说白了这一步就是将元素排序填充的过程,因为已经知道了所有排序分组的起止边界了,也知道每个分组的容量了,接下来就是挨个映射填充就可以完成排序工作了。

分组元素填充后,起始索引递增
这里面的填充技巧的细节点在于,每填充一个分组内元素后,将对应的该分组的起始索引递增1,代表完成了一个分组内地排序,若后续还有同样分组内的元素填充则理所当然填充到该分组的下一个临近位即可。

4、回写数组

这一步是将已排序好的元素重新回写到原数组中即可。

代码实现

  • 纯小整数版
/*** @author: <a href=mailto:keycasiter@qq.com>guanjian</a>* @date: 2021/4/8 13:15* @description: */
public class IndexCountSortDemo {public static void main(String[] args) {int[] nums = {2, 3, 4, 1, 2, 4, 3, 1, 2, 2, 1};indexCountIndex(nums);//打印结果   1 1 1 2 2 2 2 3 3 4 4}public static void indexCountIndex(int[] nums) {int[] count = new int[6];//计算频率for (int i = 0; i < nums.length; i++) {count[nums[i] + 1]++;}//将频率转化为索引for (int i = 1; i < count.length; i++) {count[i] = count[i] + count[i - 1];}//数据分类int[] aux = new int[nums.length];for (int i = 0; i < nums.length; i++) {aux[count[nums[i]]++] = nums[i];//aux[count[nums[i]]] = nums[i];//count[nums[i]]++;}//回写数据(这里是打印)for (int i = 0; i < nums.length; i++) {System.out.print(aux[i] + " ");}}
}
  • 小整数分组排序元素
/*** @author: <a href=mailto:keycasiter@qq.com>guanjian</a>* @date: 2021/4/8 13:15* @description: */
public class IndexCountSortDemo {public static class Item<T> {private int group;private T data;public Item(int group, T data) {this.group = group;this.data = data;}public int getGroup() {return group;}public void setGroup(int group) {this.group = group;}public T getData() {return data;}public void setData(T data) {this.data = data;}}public static void main(String[] args) {Item<String>[] arr = new Item[]{new Item(1, "a"),new Item(2, "b"),new Item(1, "c"),new Item(2, "d"),new Item(3, "e"),new Item(4, "f"),new Item(4, "g"),new Item(1, "h")};indexCountIndexByItem(arr);//打印结果   a c h b d e f g}public static void indexCountIndexByItem(Item[] arr) {int[] count = new int[6];//计算频率for (int i = 0; i < arr.length; i++) {count[arr[i].group + 1]++;}//将频率转化为索引for (int i = 1; i < count.length; i++) {count[i] = count[i] + count[i - 1];}//数据分类Item[] aux = new Item[arr.length];for (int i = 0; i < arr.length; i++) {aux[count[arr[i].group]++] = arr[i];// aux[count[arr[i].group]] = arr[i];// count[arr[i].group]++;}//回写数据(这里是打印)for (int i = 0; i < arr.length; i++) {System.out.print(aux[i].data + " ");}}
}

总结

键索引计数法是一种对于小整数键排序非常有效却常常被忽略的排序方法。理解它的工作原理是理解字符串排序的第一步,它是一个线性时间级别的排序方法。

参考

字符串排序:键索引计数法
《算法》第4版

这篇关于字符串排序:键索引计数法的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1120534

相关文章

Mysql数据库聚簇索引与非聚簇索引举例详解

《Mysql数据库聚簇索引与非聚簇索引举例详解》在MySQL中聚簇索引和非聚簇索引是两种常见的索引结构,它们的主要区别在于数据的存储方式和索引的组织方式,:本文主要介绍Mysql数据库聚簇索引与非... 目录前言一、核心概念与本质区别二、聚簇索引(Clustered Index)1. 实现原理(以 Inno

Java Map排序如何按照值按照键排序

《JavaMap排序如何按照值按照键排序》该文章主要介绍Java中三种Map(HashMap、LinkedHashMap、TreeMap)的默认排序行为及实现按键排序和按值排序的方法,每种方法结合实... 目录一、先理清 3 种 Map 的默认排序行为二、按「键」排序的实现方式1. 方式 1:用 TreeM

Python实现字典转字符串的五种方法

《Python实现字典转字符串的五种方法》本文介绍了在Python中如何将字典数据结构转换为字符串格式的多种方法,首先可以通过内置的str()函数进行简单转换;其次利用ison.dumps()函数能够... 目录1、使用json模块的dumps方法:2、使用str方法:3、使用循环和字符串拼接:4、使用字符

Python 常用数据类型详解之字符串、列表、字典操作方法

《Python常用数据类型详解之字符串、列表、字典操作方法》在Python中,字符串、列表和字典是最常用的数据类型,它们在数据处理、程序设计和算法实现中扮演着重要角色,接下来通过本文给大家介绍这三种... 目录一、字符串(String)(一)创建字符串(二)字符串操作1. 字符串连接2. 字符串重复3. 字

一文详解MySQL索引(六张图彻底搞懂)

《一文详解MySQL索引(六张图彻底搞懂)》MySQL索引的建立对于MySQL的高效运行是很重要的,索引可以大大提高MySQL的检索速度,:本文主要介绍MySQL索引的相关资料,文中通过代码介绍的... 目录一、什么是索引?为什么需要索引?二、索引该用哪种数据结构?1. 哈希表2. 跳表3. 二叉排序树4.

Java 字符串操作之contains 和 substring 方法最佳实践与常见问题

《Java字符串操作之contains和substring方法最佳实践与常见问题》本文给大家详细介绍Java字符串操作之contains和substring方法最佳实践与常见问题,本文结合实例... 目录一、contains 方法详解1. 方法定义与语法2. 底层实现原理3. 使用示例4. 注意事项二、su

Java实现将HTML文件与字符串转换为图片

《Java实现将HTML文件与字符串转换为图片》在Java开发中,我们经常会遇到将HTML内容转换为图片的需求,本文小编就来和大家详细讲讲如何使用FreeSpire.DocforJava库来实现这一功... 目录前言核心实现:html 转图片完整代码场景 1:转换本地 HTML 文件为图片场景 2:转换 H

Java使用正则提取字符串中的内容的详细步骤

《Java使用正则提取字符串中的内容的详细步骤》:本文主要介绍Java中使用正则表达式提取字符串内容的方法,通过Pattern和Matcher类实现,涵盖编译正则、查找匹配、分组捕获、数字与邮箱提... 目录1. 基础流程2. 关键方法说明3. 常见场景示例场景1:提取所有数字场景2:提取邮箱地址4. 高级

Python 字符串裁切与提取全面且实用的解决方案

《Python字符串裁切与提取全面且实用的解决方案》本文梳理了Python字符串处理方法,涵盖基础切片、split/partition分割、正则匹配及结构化数据解析(如BeautifulSoup、j... 目录python 字符串裁切与提取的完整指南 基础切片方法1. 使用切片操作符[start:end]2

MyBatis的xml中字符串类型判空与非字符串类型判空处理方式(最新整理)

《MyBatis的xml中字符串类型判空与非字符串类型判空处理方式(最新整理)》本文给大家介绍MyBatis的xml中字符串类型判空与非字符串类型判空处理方式,本文给大家介绍的非常详细,对大家的学习或... 目录完整 Hutool 写法版本对比优化为什么status变成Long?为什么 price 没事?怎