让编程改变世界
Change the world by program
容器和算法
渐渐地我们发觉编写的每一个程序都或多或少地需要存储一些数据,而C++在这方面只提供了几种最基本的方法。 你可以创建局部或全局变量来保存单个值,可以使用数组来保存多个值。 今天的概念:能容纳两个或更多个值的数据结构通常我们称为容器(container)。 这么说来,数组是C++唯一直接支持的容器,但数组并不适合用来解决所有的问题。
你打算编写一个简单的拼写检查程序,你会肿么做呢?
某鱼油提议使用一个相当长的单词表,而检查某给定单词的拼写是否正确就可以通过检查它是否列在那个单词表里来实现:如果单词在表里,就说明它拼写正确。 好滴,环顾左右,我们可以直接利用的也只有数组这个容器可以存放一个好长的单词表。 但是我们好像为“只有耕不完的地,没有累不死的牛”提供了又一个佐证。 因为如果利用数组来实现这个单词表的话,我们将不得不遍历每一个数组元素并把它与给定单词进行比较。 我们不能说这种办法不能解决问题,只是这个解决方案的效率实在是太低下了。 计算机领域的科学家们在过去的几十年里投入了大量的精力来为不同类别的问题寻找最合适的数据结构。 就拿刚才提到的拼写检查程序来说吧,最适合用来解决这类问题的数据结构是散列表和二叉树。 这个话题我们会在今后的《数据结构和算法》这系列教程中详细讲解。 这两种数据结构以某种特殊的方式来存储数据,在那些数据里检查某个特定的元素是否存在的效率是最高的。
何谓容器我们已经知晓,那么我们如何来制作一个容器呢?恩?啊?
其实前两节课小甲鱼已经带大家实现一种新容器。猜的没错,基于模板的Stack类就是一种新容器。 既然知道如何创建和使用模板,鱼油们其实大可以抄起一本讨论数据结构的书去尝试实现一些自己的容器。 许多伟大的程序员就是花了一辈子的时间这么做!
在此,小甲鱼带领众鱼油向前辈们敬礼!
现在的C++程序员用不着那么辛苦了,我们可以坐享其成。 在C++标准库里有许多现成的容器,它们都经过了老一辈精心的设计和测试,可以直接拿来就用,这节课,我们也是来教大家如何使用。 解决一个问题,找到最合适的容器只是编程工作的一部分。还需要一些适当的函数(算法)来处理这个容器里的数据才能实现最优效率。 哈哈,这方面同样有许多“标准的”功能是你经常会用到的,在《数据结构和算法》我们将详细讲解。
向量容器
数组这种数据结构最大的先天不足就是它受限于一个固定的长度。 在程序里用int myArray[40]这样的语句定义一个数组时,程序将遇到两个问题: 首先,你最多只能在那个变量里存储40个整型数据,万一你需要存储第41个数据,那么你就相当不走运了。 其次,不管程序是不是真的需要存储40个整型数据,编译器都会为它分配40个整型数据的空间。 像这样的问题用C语言解决起来往往很复杂,而C++提供的解决方案就高明得多了。 C++标准库提供的向量(vector)类型从根本上解决了数组先天不足的问题。 就像可以创建各种不同类型的数组一样,我们也可以创建各种不同类型的向量。
std::vector<type> vectorName;
这种语法相信鱼油们应该不会再感到陌生了。 我们用不着对一个向量能容纳多少个元素做出限定,因为向量可以动态地随着你往它里面添加元素而无线增大(前提是有足够可用的内存) 然后你还可以用它的size()方法查知某给定响亮的当前长度(它当前包含的元素个数) 定义一个向量后,我们可以用push_back()方法往它里边添加东西。 我们还可以用访问数组元素的语法来访问某给定向量里的各个元素。 综合上述几点我们一起来完成一个简单栗子!提示
C++标准库是用C++编写程序的乐趣之一,它可以让你轻而易举地解决许多非常复杂的问题,我们甚至不必完全了解它的内部工作情况。 C++的类型检查功能非常强大,如果你试图把一个其他类型的值放到一个字符串向量里,编译器会立刻报错。 把一些元素放到一个向量里以后,就可以用赋值操作符来改变它们的值了,就像对待数组元素那样:names[0] = “Jonny”;