前言
本系列博客为学习数据结构与算法过程中的原创笔记,其中代码实现基于C++语言。
STL中的向量和表
在C++语言的库中包含有公共数据结构的实现,这就是众所周知的标准模版库(Standard Template Library, STL)。表就是STL实现的数据结构之一。
表有两个流行的实现。
vector给出了表的可增长的数组实现。使用vector的优点是长度可自由控制,且在常量的时间里是可索引的。缺点是插入和删除操作的代价是昂贵的,除非操作发生在vector的末尾。
list提供了表的双向链表实现。
使用list的优点是, 如果变化发生的位置已知的话, 插入新项和删除已有项的代价是很小的。
缺点是list不容易索引。
vector和list两者在查找时效率都很低。此类型的数据结构,都有公共的方法,下述的前三个方法事实上对所有的STL容器都适用。
- int size() const:返回容器内的元素个数。
- void clear():删除容器内所有元素。
- bool empty():如果容器为空返回true,否则返回false。
vector和list都支持在表的末尾进行访问和操作。
- void push_back( const Object & x ):在表的末尾添加x。
- void pop_back():删除表的末尾对象。
- const Object & back() const:返回表的末尾的对象。
- const Object & front() const:返回表的末尾的对象。
双向链表允许在表的前端进行高效的改变,下面方法只对list有效。
- void push_front( const Object & x): 在list的前端添加x。
- void pop_front( ): 在list的前端删除对象。
vector也有list所不具有的特有的方法。 有两个方法可以进行高效的索引。 另外两个方法允许程序员观察和改变vector的内部容量。
- Object & operator[] (int idx): 返 回vector中idx索引位置的对象, 不包含边界检
测( 也提供返回常量引用的访问函数)。 - Object & at ( int idx ): 返 回vector中idx索引位置的对象, 包含边界检测( 也提供返回常量引用的访问函数)。
- int capacity( ) const: 返回vector的内部容量。
- void reserve( int new Capacity ): 设 定vector的新容量。 如果己有良好的估计的话, 这可以避免对vector进行扩展。
迭代器
迭代器是一种检查容器内元素并遍历元素的数据类型。可以替代下标访问vector对象的元素。
迭代器通过iterator给出。例如,对于list<string>,定义为list<string>::iterator,对与vector<int>,定义为vector<int>::iterator。
以下列举迭代器一些相关的方法和操作。
- iterator begin():返回指向容器的第一项的迭代器。
- iterator end():返回指向容器的终止标志的迭代器(容器最后一项后面的位置)。
- iter++和++iter:推进迭代器至下一个位置。
- *iter:返回存储在迭代器iter指定位置的对象的引用。
下述代码列举了一个简单的对vector进行迭代器操作的使用。
#include <iostream>
#include <vector>
using namespace std;
int main()
{
vector<int> data1 = {1, 2, 4, 6, 8}, data2; //定义data1, data2并初始化data1
vector<int>::iterator iter; //定义迭代器
cout << "data1 =";
for(iter = data1.begin(); iter != data1.end(); iter++) //迭代器的循环条件
{
cout << " " << *iter; //输出data1
data2.push_back(*iter); //向data2写数据
data2.push_back((*iter) * 2);
}
cout << endl << "data2 =";
for(iter = data2.begin(); iter != data2.end(); iter++)
{
cout << " " << *iter;
}
cout << endl;
return 0;
}
栈
栈(stack)是限制插入和删除操作只能在一个位置上的表,这个位置是表的末端,称作栈的顶(top),栈顶元素是唯一可见(可访问)的元素。栈的基本操作有push(进栈)和pop(出栈)两种。栈有时又被称作LIFO(后进先出)表。
栈的实现比较简单,此处不再详细介绍。
在C++的STL中,对栈进行了封装,加入头文件#include <stack>即可调用,其共有五个常用操作函数top()、push()、pop()、size()和empty(),STL中栈的操作如下:
- stack<Elemtype > StackElem 创建一个空的stack对象
- StackElem.top() 返回栈顶数据。
- StackElem.push(elem) elem入栈
- StackElem.pop() 弹出栈顶元素(出栈)
- StackElem.size() 返回栈中数据的个数
- StackElem.empty() 判断栈是否为空
下面代码是一个简单的栈的使用范例,包含上述所有函数。
#include <iostream>
#include <list>
#include <stack>
using namespace std;
int main()
{
/* * stack不是一种数据结构,是一种容器适配器(container adapter), * 因此它需要一个基础的容器来存储,这个容器可以是vector, deque,list * 等标准容器,未指定时默认是deque。 */
stack<string> stackTest; //定义栈stackTest存储数据类型为string
string words;
for(int i = 0; i < 5; i++)
{
cin >> words;
stackTest.push(words); //words入栈
}
cout << stackTest.size() << endl; //输出栈元素个数
while(!stackTest.empty()) //栈是否为空
{
cout << stackTest.top() << " "; //输出栈顶元素
stackTest.pop(); //出栈
}
cout << endl;
return 0;
}
队列
队列(queue)也是以表存储数据,但只允许从表的两端访问元素,而且限定从表的一端读入数据,从另一端读出数据。队列跟栈类似,没有迭代器,不能遍历,跟栈不同的地方是它属于FIFO(先进先出)表。
queue的实现也是基于list,本文主要讲用法,因此不再介绍具体实现,可参考《STL源码剖析》一书。
在C++的STL中,同时也对queue进行了封装,加入头文件#include <queue>即可调用,其共有五个常用操作函数front()、back()、push()、pop()、size()和empty(),与栈的常用函数类似。STL中queue的操作如下:
- queue<Elemtype > queueElem 创建一个空的queue对象
- queueElem.front() 返回队列头部数据
- queueElem.back() 返回队列尾部数据
- queueElem.push(elem) 向队列尾部添加数据elem
- queueElem.pop() 队列头部数据出队
- queueElem.size() 返回队列中数据的个数
- queueElem.empty() 判断队列是否为空
下面代码是一个简单的队列的使用范例,包含上述所有函数。
#include <iostream>
#include <queue>
#include <list>
using namespace std;
int main()
{
queue<string, list<string> > queueTest; //跟栈一样,此处用list存储
string words;
for(int i = 0; i < 5; i++)
{
cin >> words;
queueTest.push(words); //队首入队
}
cout << queueTest.size() << " " << queueTest.back() <<endl; //输出队列长度和队尾元素
while(!queueTest.empty())
{
cout << queueTest.front() << " " << endl; //输出队首元素
queueTest.pop(); //出队
}
return 0;
}
如你所见,本文只是简单的介绍了表,vector,栈和队列,而且并没有详细介绍各自的实现,只是借助STL介绍了他们的一些基础用法,希望对你有所帮助。