因为C++语言几乎是C的一个超集,只要注意某些写法和规则,C++一样可以以C的形式去使用,实际上在上一篇中,我得所有输入输出就是用的C++中的基本输入输出流。对于C++来讲,更合适的用法应该是定义一些类,建立起程序中需要的各种对象,这样可以隐藏起很多实现细节。在这里,我们更进一步,使用C++的STL(标准模板库),它不仅给我们提供了很多内部机制,更重要的是,它已经被ISO列入到C++的语言定义中了,我们可以放心的使用。
在这里,说到为什么有C++还要学习C,甚至我第一个写的实现就是C。个人来讲,可能是觉得C比较好玩吧,所有的操作都是你可以看到的。我喜欢将C比作一把双刃剑,喜欢那种锋利的感觉(是不是玄幻看多了)。还有可能是学校第一门计算机语言类的课就讲的C,到现在还能记住拿C+OpenCV1.0写的曼德勃罗集合...
STL提供了许多的容器类,例如向量、链表、集合,还包括了许多检索、排序、插入和删除等等的基本算法。利用C++的模板特性,每个STL算法都能用到很多不同的容器类上。容器类的元素可以是用户定义类型或者是内部类型的。这里的容器都被描述为C++模板,可以对特定类型进行实例化。例如,STL里有一个vector容器类,由它可以导出各种具体类型,比如vector
在STL里,除了有vector容器(它与Java的vector类差不多),还提供了一个deque容器类。deque(念为deck)是一种双端队列,它正好能符合我们对前缀操作的需要:可以用它存放NPREF个元素,丢掉最前面的元素并在后面添一个新的,这都是O(1)操作。实际上,STL的deque比我们需要的东西更一般,它允许在两端进行压入和弹出,而执行性能方面的保证是我们选择它的原因。
STL还额外提供了一个map容器,其内部用来实现基于平衡的树。在map中可以储存(关键码——值)的数对。map的内部代码实现保证从任何关键码出发提取相关值的操作都是O(logn)的。虽然这种的效率没有散列表高,但是胜在不需要额外写很多代码(虽然我个人还是很喜欢散列表)
当我们拥有了这些强力工具后,就可以进行代码的编写了。首先我们先进行一下声明:
typedef deque Prefix;
map> statetab;
另外别忘了:
using namespace std;
STL提供了deque的模板,记法deque
对于整个程序来说,add函数应该是其中比较不好理解的一部分。
void add(Prefix &prefix, const string &s)
{
/*判断读入的字符串是否符合要求*/
if (prefix.size() == NPREF)
{
statetab[prefix].push_back(s);
prefix.pop_front();
}
prefix.push_back(s);
}
这几个非常简单的语句确实做了不少事情。map容器类重载了下标运算符 ([ ]运算符),使它在这里成为一种查询运算。表达式 statetab[prefix]在statetab里完成一次查询,以prefix作为查询的关键码,返回对于所找到的项的一个引用。如果对应的向量不存在,这个操作将建立一个新向量。vector和deque类的push_back函数分别把一个新字符串加到向量或deque的最后;pop_front从deque里弹出头一个元素。
对于使用这种方法来说,实现简单(当然我还是喜欢C),但是速度相比C来说就会差得很远,虽然还不是最慢的。
喜欢C可能还是因为对于基础的东西,喜欢自己一步步去写吧。
Coding time
#include "stdafx.h"
#include
#include
#include
#include
#include
#include
对于Awk和Perl语言,我完全没有接触过,因此在这里就不做说明。
对于这么多的语言来讲,程序设计实践这本书中给出了代码运行的各种时间,在下图中我们可以看出:C代码的执行时间要远远快于其他类型的代码。当然,随着时间的发展,cpu的运行速度也越来越快,但这个时间仍然具有参考意义。