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

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 索引知识回顾五、总结 一、前言 在上一讲性能工具之 JProfiler 简单登录案例分析实战中已经发现SQL没有建立索引问题,本文将一起从代码层去分析为什么没有建立索引? 开源ERP项目地址:https://gitee.com/jishenghua/JSH_ERP 二、准备 打开IDEA找到登录请求资源路径位置

【数据结构】——原来排序算法搞懂这些就行,轻松拿捏

前言:快速排序的实现最重要的是找基准值,下面让我们来了解如何实现找基准值 基准值的注释:在快排的过程中,每一次我们要取一个元素作为枢纽值,以这个数字来将序列划分为两部分。 在此我们采用三数取中法,也就是取左端、中间、右端三个数,然后进行排序,将中间数作为枢纽值。 快速排序实现主框架: //快速排序 void QuickSort(int* arr, int left, int rig

usaco 1.3 Mixing Milk (结构体排序 qsort) and hdu 2020(sort)

到了这题学会了结构体排序 于是回去修改了 1.2 milking cows 的算法~ 结构体排序核心: 1.结构体定义 struct Milk{int price;int milks;}milk[5000]; 2.自定义的比较函数,若返回值为正,qsort 函数判定a>b ;为负,a<b;为0,a==b; int milkcmp(const void *va,c

hdu 1285(拓扑排序)

题意: 给各个队间的胜负关系,让排名次,名词相同按从小到大排。 解析: 拓扑排序是应用于有向无回路图(Direct Acyclic Graph,简称DAG)上的一种排序方式,对一个有向无回路图进行拓扑排序后,所有的顶点形成一个序列,对所有边(u,v),满足u 在v 的前面。该序列说明了顶点表示的事件或状态发生的整体顺序。比较经典的是在工程活动上,某些工程完成后,另一些工程才能继续,此时

《数据结构(C语言版)第二版》第八章-排序(8.3-交换排序、8.4-选择排序)

8.3 交换排序 8.3.1 冒泡排序 【算法特点】 (1) 稳定排序。 (2) 可用于链式存储结构。 (3) 移动记录次数较多,算法平均时间性能比直接插入排序差。当初始记录无序,n较大时, 此算法不宜采用。 #include <stdio.h>#include <stdlib.h>#define MAXSIZE 26typedef int KeyType;typedef char In

【软考】希尔排序算法分析

目录 1. c代码2. 运行截图3. 运行解析 1. c代码 #include <stdio.h>#include <stdlib.h> void shellSort(int data[], int n){// 划分的数组,例如8个数则为[4, 2, 1]int *delta;int k;// i控制delta的轮次int i;// 临时变量,换值int temp;in

每日一题|牛客竞赛|四舍五入|字符串+贪心+模拟

每日一题|四舍五入 四舍五入 心有猛虎,细嗅蔷薇。你好朋友,这里是锅巴的C\C++学习笔记,常言道,不积跬步无以至千里,希望有朝一日我们积累的滴水可以击穿顽石。 四舍五入 题目: 牛牛发明了一种新的四舍五入应用于整数,对个位四舍五入,规则如下 12345->12350 12399->12400 输入描述: 输入一个整数n(0<=n<=109 ) 输出描述: 输出一个整数

学习记录:js算法(二十八):删除排序链表中的重复元素、删除排序链表中的重复元素II

文章目录 删除排序链表中的重复元素我的思路解法一:循环解法二:递归 网上思路 删除排序链表中的重复元素 II我的思路网上思路 总结 删除排序链表中的重复元素 给定一个已排序的链表的头 head , 删除所有重复的元素,使每个元素只出现一次 。返回 已排序的链表 。 图一 图二 示例 1:(图一)输入:head = [1,1,2]输出:[1,2]示例 2:(图

鸡尾酒排序算法

目录 引言 一、概念 二、算法思想 三、图例解释 1.采用冒泡排序:   2.采用鸡尾酒排序:  3.对比总结 四、算法实现  1.代码实现  2.运行结果 3.代码解释   五、总结 引言 鸡尾酒排序(Cocktail Sort),也被称为双向冒泡排序,是一种改进的冒泡排序算法。它在冒泡排序的基础上进行了优化,通过双向遍历来减少排序时间。今天我们将学习如何在C

快速排序(java代码实现)

简介: 1.采用“分治”的思想,对于一组数据,选择一个基准元素,这里选择中间元素mid 2.通过第一轮扫描,比mid小的元素都在mid左边,比mid大的元素都在mid右边 3.然后使用递归排序这两部分,直到序列中所有数据均有序为止。 public class csdnTest {public static void main(String[] args){int[] arr = {3,