目录
1、字符串
String 是由一系列字符组成的。字符的类型是 char,可能有 2的16次方个值。数十年以来, 程序员的注意力都局限于 7 位 ASCII 码(请见表 5.5.4)或是 8 位扩展 ASCII 码表示的字符,但许 多现代的应用程序都已经需要使用 16 位 Unicode 编码了。
1.1、属性
字符串String拥有以下属性:
- 不可变性:String 对象是不可变的,因此可以将它们用于赋值语句、作为函数的参数或是返回值,而不用担心它们的值会发生变化。
- 索引:我们最常完成的操作就是从某个字符串中提取一个特定的字符,即 Java 的 String 类的 charAt() 方法。
- 子字符串:Java 的 substring() 方法实现了提取特定的子字符串的操作。
- 字符串的连接:在 Java 中通过将一个字符串追加到另一个字符串的末尾创建一个新字符串的操 作是一个内置的操作(使用“+”运算符),所需的时间与结果字符串的长度成正比。
1.2、字母表
当我们在做一些关于字符串相关的算法时,常常会对字符串中字符的数量和内容做一些限制,只使用特定的字符来降低算法的难度,就比如BASE64 算法中限定的字符数量就是64个,ASCII字母表是128个。下图就是常用字母表的搜集,其中 R是字符的数量,lgR则是表示一个索引所需要的比特数( 也就是需要用几位二进制数来表示字母的的排序索引)。
2、字符串排序方法
我们生活中,常常会需要给字符串排序的情况,就比如通讯录里边的名字排序等。接下来我们将要学习两类高效的排序方法。
第一类方法会从右到左检查键中的字符。这种方法一般被称为低位优先(Least-Signi cant-Digit First,LSD)的字符串排序。如果将一个字符串看作一个 256 进制的数字,那么从右向左检查字符串就等 价于先检查数字的最低位。这种方法最适合用于键的长度都相同的字符串排序应用。
第二类方法会从左到右检查键中的字符,首先查看的是最高位的字符。这些方法通常称为高位 优先(MSD)的字符串排序。高位优先的字符串排序的吸引人之处 在于,它们不一定需要检查所有的输入就能够完成排序。高位优先的字符串排序和快速排序类似, 因为它们都会将需要排序的数组切分为独立的部分并递归地用相同的方法处理子数组来完成排序。
3、键索引计数法
键索引计数法其实就是通过统计每个字符出现的频率,然后通过频率之和来转化成排序后的索引。
简单来说就是 比如a出现了3次,b出现了4次,c出现了5次,那么b字母开头的字符串排序后的索引,肯定是从第四个索引开始的,c开头的字符串排序后的索引肯定是从第八个索引(a+b=7)开始的。这样我们将字符串数组中的每个字符串中的字母都按照这样的方式排序的话,那么整个数组就都排序好了。
现在我们有20个学生,每个学生都有自己的分组编号(只有1、2、3、4 组),但是这些学生的名字的排序并不是按照组号的顺序排列的,所以我们需要将这20个学生的名字按照 组号的顺序排序好。
下面的代码是我们学生的信息类。
class Student{
String name;
int key; //组号
public int key() {
return key;
}
}
3.1、第一步:频率统计
这里我们创建一个大小为6的int数组 count,然后遍历每个学生,然后将组号出现的频率统计到count数组中。注意,我们这里没用组号作为索引,而是组号+1的形式作为索引。这里为什么要用组号+1的索引来统计,后面你就知道了。
3.2、第二步:将频率转换为索引
看上面的数据,我们发现1组的人有3个,2组的人有5个,3组的人有6个。那么,1组人的索引从0开始,2组人的索引从3开始,3组人的索引从8开始。我们发现每个组的开始索引都是前面组的人数的和。利用这点我们可以对count数组中的统计数据进行转换。
3.3、第三步:数据分类排序
看上面的数据我们可以发现,count数组中count[1]=0 对应着1组人员开始的索引,count[2]=3 对应着2组人员开始的索引,count[3]=8 对应着3组人员开始的索引。然后我们只需要一个辅助数组aux[],将原来数组的数据按照count中对应的索引,开始标记转移到aux[]数组中,