3.1.3 用例举例

在学习它的实现之前我们还是应该先看看如何使用它。相应的我们这里考察两个用例:一个用来跟踪算法在小规模输入下的行为测试用例和一个来寻找更高效的实现的性能测试用例。

3.1.3.1 行为测试用例

为了在小规模的的输入下跟踪算法的行为,我们用一下测试用例测试我们对符号表的所有实现。这段代码会从标准输入接受多个字符串,构造一张符号表来将i 和第i 个字符串相关联,然后打印符号表。我们假设所有的字符串都只有一个字母。一般我们会使用”S E A R C H E X A M P L E”。按照我们的约定,用例会将键S和0,键R和3关联起来,等等。但E的值是12(而非1或者6),A的值为8(而非2),因为我们的关联性数组以为着每个键的顺序是不确定的(这和具体实现有关);对于有序符号表,用例应该将键按顺序打印出来。这是一种引索用例,,它是我们将在后面讨论的一种重要的符号表应用的一个特殊情况。

测试用例的实现代码如下所示。测试用例的键、值及输出如下图所示。

3.1.3.2 性能测试用例

FrequencyCounter用例会从标准输入中得到的一列字符串并记录每个(长度至少达到指定的数值)字符串的出现次数,然后遍历所有键并找出出现频率最高的键。这是一种字典。这个用例回答了一个简单的问题:哪个(不小于指定长度的)单词在一段文字中出现的频率最高?在本章中,我们会用这个用例以及三段文字来进行行能呢个测试:狄更斯的《双城记》中的第五行(tinyTale.txt),《双城记》全书(tale.txt),以及一个知名的叫做Leipzig Corpora Collection 的数据库(Leipzig1M.txt)。

 public class FrequencyCounter {

     /**
* Reads in a command-line integer and sequence of words from
* standard input and prints out a word (whose length exceeds
* the threshold) that occurs most frequently to standard output.
* It also prints out the number of words whose length exceeds
* the threshold and the number of distinct such words.
*/
public static void main(String[] args) {
int distinct = 0, words = 0;
int minlen = Integer.parseInt(args[0]);
ST<String, Integer> st = new ST<String, Integer>(); // compute frequency counts
while (!StdIn.isEmpty()) {
String key = StdIn.readString();
if (key.length() < minlen) continue;
words++;
if (st.contains(key)) {
st.put(key, st.get(key) + 1);
}
else {
st.put(key, 1);
distinct++;
}
} // find a key with the highest frequency count
String max = "";
st.put(max, 0);
for (String word : st.keys()) {
if (st.get(word) > st.get(max))
max = word;
} StdOut.println(max + " " + st.get(max));
StdOut.println("distinct = " + distinct);
StdOut.println("words = " + words);
}
}

以上代码为符号表的用例,该用例统计了标准输入中各个单词的出现频率,然后将频率最高的单词打印出来。命令行参数指定了表中的键的最短长度。

研究符号表处理大型文本的性能要考虑来两个方面的因素:首先,每个单吃都会被作为键进行搜索,因此处理性能和输入文本的单词总量必然有关;其次,输入的每个电磁都会被存入符号表(输入中不重复单词的总数也就是所有键都被插入以后符号表的大小),因此输入流中的不同的单词的总数也是相关的。我们需要这两个量来估计FrequencyCounter的运行时间。我们会在学习了一些算法之后再回头说明一些细节,但你应该对类似这样的符号表应用的需求有一个大致的印象。

很多例子都提出了一个简单的问题:我们的实现能够在一张用多次get()和put()方法构造出的巨型符号表中进行大量的get()操作吗?如果我们的查找操作不多,那么任意实现都能够满足需要。但没有一个高效的符号表作为基础是无法使用FrequencyCounter这样的程序来处理大型问题的。FrequencyCounter是一种极为常见的应用的代表,它的这些特性也是许多其他符号表应用的共性:

混合使用查找和插入的操作

大量的不同键

查找操作比插入操作多得多

虽然不可预测,但查找和插入操作的使用模式并非随机

我们的目标就是实现一种符号表来满足这些能够解决典型的实际问题的用例需要。

《Algorithms 4th Edition》读书笔记——3.1 符号表(Elementary Symbol Tables)-Ⅲ的更多相关文章

  1. 《Algorithms 4th Edition》读书笔记——3.1 符号表(Elementary Symbol Tables)-Ⅳ

    3.1.4 无序链表中的顺序查找 符号表中使用的数据结构的一个简单选择是链表,每个结点存储一个键值对,如以下代码所示.get()的实现即为遍历链表,用equals()方法比较需被查找的键和每个节点中的 ...

  2. 《Algorithms 4th Edition》读书笔记——3.1 符号表(Elementary Symbol Tables)-Ⅱ

    3.1.2 有序的符号表 典型的应用程序中,键都是Comparable的对象,因此可以使用a.compare(b)来比较a和b两个键.许多符号表的实现都利用Comparable接口带来的键的有序性来更 ...

  3. 《Algorithms 4th Edition》读书笔记——3.1 符号表(Elementary Symbol Tables)-Ⅰ

    3.1符号表 符号表最主要的目的就是将一个键和一个值联系起来.用例能够将一个键值对插入符号表并希望在之后能够从符号表的所有键值对中按照键值姐找到对应的值.要实现符号表,我们首先要定义其背后的数据结构, ...

  4. 符号表(Symbol Tables)

    小时候我们都翻过词典,现在接触过电脑的人大多数都会用文字处理软件(例如微软的word,附带拼写检查).拼写检查本身也是一个词典,只不过容量比较小.现实生活中有许多词典的应用: 拼写检查 数据库管理应用 ...

  5. C++Primer 4th edition读书笔记-第二章

    1 变量的定义用于为变量分配存储空间,还可以为变量指定初始值.在一个程序中,变量有且只有一个定义.声明用于向程序表明变量的名字和类型.定义也是声明:当定义变量时,我们声明了它的类型和名字.可以通过使用 ...

  6. 《Algorithms 4th Edition》读书笔记——2.4 优先队列(priority queue)-Ⅶ(延伸:堆排序的实现)

    2.4.5 堆排序 我们可以把任意优先队列变成一种排序方法.将所有元素插入一个查找最小元素的有限队列,然后再重复调用删除最小元素的操作来将他们按顺序删去.用无序数组实现的优先队列这么做相当于进行一次插 ...

  7. 《Algorithms 4th Edition》读书笔记——2.4 优先队列(priority queue)-Ⅵ

    · 学后心得体会与部分习题实现 心得体会: 曾经只是了解了优先队列的基本性质,并会调用C++ STL库中的priority_queue以及 java.util.PriorityQueue<E&g ...

  8. 《Algorithms 4th Edition》读书笔记——2.4 优先队列(priority queue)-Ⅴ

    命题Q.对于一个含有N个元素的基于堆叠优先队列,插入元素操作只需要不超过(lgN + 1)次比较,删除最大元素的操作需要不超过2lgN次比较. 证明.由命题P可知,两种操作都需要在根节点和堆底之间移动 ...

  9. 《C++ Primer 4th》读书笔记 序

    注:本系列读书笔记是博主写作于两三年前的,所以是基于<C++ Primer>第四版的,目前该书已更新至第五版,第五版是基于C++11标准的,貌似更新挺多的.博主今年应届硕士毕业,如若过阵子 ...

随机推荐

  1. Android——LayoutInflater详解

    在实际工作中,事先写好的布局文件往往不能满足我们的需求,有时会根据情况在代码中自定义控件,这就需要用到LayoutInflater. LayoutInflater在Android中是"扩展& ...

  2. linux shell在while中用read从键盘输入

    系统是ubuntu 14.04 64bit,之前曾想安装Stream来玩dota2,但最终没成功.由于Stream只有32bit,安装Stream时也安装了大量32bit的库.删除Stream后,这些 ...

  3. Laravel-高级篇-Artisan

    (慕课网_轻松学会Laravel-高级篇_天秤vs永恒老师_http://www.imooc.com/learn/702) 一.概述 Artisan是Laravel中自带的命令行工具的名称 由强大的S ...

  4. 线程 (detach的作用)

      线程状态在一个线程的生存期内,可以在多种状态之间转换.不同操作系统可以实现不同的线程模型,定义许多不同的线程状态,每个状 态还可以包含多个子状态.但大体说来,如下几种状态是通用的:       就 ...

  5. LDAP禁止匿名访问

    LDAP默认是允许用户匿名访问的,如下图:在使用工具连接时,勾选匿名绑定后,不需要输入UserDN和密码就可能连接到LDAP服务器,但是只能进行read及search操作.不能做任何的修改及删除操作. ...

  6. Layer中自定义属性的动画

    转载自:http://blog.jobbole.com/69211/ 默认情况下,CALayer 及其子类的绝大部分标准属性都可以执行动画,无论是添加一个 CAAnimation 到 Layer(显式 ...

  7. asp.net的3个经典范例(ASP.NET Starter Kit ,Duwamish,NET Pet Shop)学习资料

    asp.net的3个经典范例(ASP.NET Starter Kit ,Duwamish,NET Pet Shop)学习资料 NET Pet Shop .NET Pet Shop是一个电子商务的实例, ...

  8. (转)@@trancount解析

    在处理事务的时候,一般都用RollBack Transaction来回滚,但是如果在嵌套事务中这样使用的话,就会出现错误. 在SqlServer里,嵌套事务的层次是由@@TranCount全局变量反映 ...

  9. Java的优先级

    序列号 符号 名称 结合性(与操作数) 目数 说明 1 . 点 从左到右 双目 ( ) 圆括号 从左到右 [ ] 方括号 从左到右 2 + 正号 从右到左 单目 - 负号 从右到左 单目 ++ 自增 ...

  10. Lucene文件扩展名

    名称 文件后缀 描述 段文件(Segments File) segments.gen segments_N 存储提交点信息 锁文件(Lock File) write.lock 用来阻止多个indexW ...