Warring: 本篇文章纯粹是为了勾引你去使用 stl 或 java 集合类,未必面面俱到,在文末我会推荐一些其他链接。
大三以前我一直没写过什么大程序,一个程序顶多两三百行了事,总是不停地重造车轮:每个程序都重写一遍链表、栈、队列,认为这是依赖最少的“纯C程序”。
后来《数据挖掘》第一次上机作业——挖频繁项集,我又开始写“纯C程序”了:一开始就轻松地实现了一个链表,然后我发现还得实现多个链表组成的集合,于是又得去实现一个“链表的链表”,这时我就觉得有点烦了:编程应该是一件快乐的事情,老是去折腾链表就无聊了,要是有直接能用的链表就好了。
恰好C++的 stl 库和java的 util 包就提供了这样的链表: C++中的 list、java中 LinkedList。
使用它们至少有如下优点:
list 使用了模版,LinkedList 使用了泛型,使得它们支持各种数据类型:
// C++ 例子 #include <iostream> #include <list> using namespace std; typedef struct _MyStruct{ int a; double b; }MyStruct; int main() { list<int> lint; list<MyStruct> lstruct; list<string> lclass; list<int*> lpoint; // 链表的链表 list<list<int> > llist; /*上面有个空格是给VC6吃的, VS2010等都表示没胃口*/ return 0; } |
// java 例子 import java.util.LinkedList; interface MyInterface{ public void nothing(); } public class Temp { @SuppressWarnings("unused") public static void main(String[] args) { LinkedList<Integer> lint; // 基本类型使用包装类 LinkedList<String> lclass; LinkedList<MyInterface> linter;// 接口也可以 // 链表的链表 LinkedList<LinkedList<Integer>> llist; } } |
list 和 LinkedList 都是基于对象的,面向对象的一个特性就是数据和操作的整合,对象不仅有成员数据,还有成员函数,所以我们在定义了链表后就可以使用各种操作啦!VC、VS中C++对象引用成员函数可自动补齐,既省脑力又省指力,eclipse中java对象引用成员方法的自动补齐则更为犀利。
// C++ 例子 #include <iostream> #include <list> using namespace std; int main() { list<int> L; L.push_back(2);// 尾部追加 L.push_back(3); L.push_front(1);// 头部添加 L.pop_back();// 尾部删除 L.pop_front();// 头部删除 cout<<L.front()<<endl; // 输出结果是 2 return 0; } |
// java 例子 import java.util.LinkedList; public class Temp { public static void main(String[] args) { // java 的对象都是 new 出来的 LinkedList<Integer> L = new LinkedList<Integer>(); // 以下流程同 C++ 版 L.addLast(2); L.add(3);// 同addLast L.addFirst(1); L.removeLast(); L.removeFirst(); System.out.println(L.getFirst()); } } |
list 和 LinkedList 等集合类是完全开源的,阅读源代码能解开一切疑惑。
在 VC、VS 中选中记号,右键弹出菜单,选择“转到定义”:
然后就跳到了它定义的地方:
printf 等函数如果选择“转到定义”,我们还是只能看到它们在头文件中的声明,其具体实现是看不到的。但是 stl 的集合类的源代码全部写在头文件中,所以我们能看到完整的源代码。
不过由于 stl 的实现使用了大量的宏,很难看明白,而我也不是靠 C++ 吃饭的,所以也就不自找麻烦,懒得去看了。所以如果你看到我说“list 是双向链表”,那是我从书上看到的,或者我猜的^_^。
选中记号,一个框框自己就冒出来了:
下面有两个按钮:
首次使用“转到定义”时可能会提示“Source not found”:
点击 Attach Source 按钮,选择 jdk 安装目录下的 src.zip就可以了:
我的路径是D:/Program Files/Java/jdk1.7.0/src.zip
一开始刚使用 VC、eclipse 开发环境的时候我也什么都不懂,然后会写、编译、运行 Hello World 级的程序了,然后就试验性地使用一些平时不用的菜单/按钮,也许有些菜单/按钮可有可无,但是它们能提高效率,这也是很值得去掌握的。
windows 和 linux 下 C++ 中都可以使用 stl,否则也不会被称为“标准模板库”了;而 java 的 util 包中的各种集合类也是跨平台使用的。
我们自己写的链表有可能存在 Bug,但是使用 stl 和 util 的集合类就不用担心了:那是一群专业人士开发出来的,都用了N年了,要是程序中出现了 Bug,一定不是 list 或 LinkedList 的责任。
查看源代码可以知道 list 和 LinkedList 都是双向链表, 两端都可以添加、删除元素,于是它们又是天生的栈和队列:
栈操作 | list | LinkedList | ||
---|---|---|---|---|
方案一 | 方案二 | 方案一 | 方案二 | |
Push | push_back | push_front | addLast | addFirst |
Pop | 先back后pop_back | 先front后pop_front | removeLast | removeFirst |
队列操作 | list | LinkedList | ||
---|---|---|---|---|
方案一 | 方案二 | 方案一 | 方案二 | |
Enqueue | push_back | push_front | addLast | addFirst |
Dequeue | 先front后pop_front | 先back后pop_back | removeFirst | removeLast |
这些操作的时间复杂度都是 O(1),最优的O(∩_∩)O~。
这篇介绍了链表,顺带着把栈和队列也搞定了,我想你已经感觉到 stl 或 util 的强大了。C++ 设计得很复杂,还有操作符重载,所以我一直对 C++ 怀有成见,也正是发现了 stl 的强大,我才逐渐喜欢上 C++,现在如果做可执行程序的话我肯定选 C++,复杂的语言也可以简单地用不是!
三十分钟掌握STL(前半部分很不错,后半部分真心没看懂o(╯□╰)o)