要看懂STL相关,必须了解c++模板
目录
STL是什么
STL(标准模板库)是一套功能强大的 C++ 模板类,提供了通用的模板类和函数,这些模板类和函数可以实现多种流行和常用的算法和数据结构,如向量、链表、队列、栈。
STL内嵌在c++中,不需要外部安装链接。
c++标准模板库包含三个组件
组件 | 描述 |
---|---|
容器(Containers) | 管理某一类对象的集合。c++提供了诸如数组(array) , 链表(list), tree(树),栈(stack), 队列(queue), 集合(set),映射表(map)等各种不同类型的容器 |
算法(Algorithms) | 作用与容器。提供了对容器初始化、排序、搜索、转换等操作方式 |
迭代器(iterators) | 用于遍历对象集合。这里的集合指容器和容器的子集 |
算法
STL中收录了一系列的高效率的数学算法用于排序、查找等。STL所有算法都是基于模板实现。
算法分为质变算法和非质变算法:
- 质变算法:运算过程中会改变区间内元素的内容。如拷贝、替换、删除。
- 非质变算法:运算过程中不会改变区间内元素的内容。如查找、计数、遍历、寻找极值。
迭代器
对一个容器进行遍历,是算法和容器的连接器。
每种容器有各自的迭代器,迭代器的接口和一般指针类似。不同的算法需要不同类型的迭代器来实现相应的功能。
迭代器的种类
迭代器 | 功能 | 描述 |
---|---|---|
输入迭代器 | 提供对数据的只读访问 | 只读,支持++、==、!= |
输出迭代器 | 提供对数据的只写访问 | 只写,支持++ |
前项迭代器 | 提供读写操作,并能向前推进迭代器 | 读写,支持++、==、!= |
双向迭代器 | 提供读写操作,能向前和向后操作 | 读写,支持++、- |
随机访问迭代器 | 提供读写操作,并能以跳跃的方式访问容器的任意数据,是功能最强的迭代器 | 读写,支持++、-、[n]、-n、<、<=、>、>= |
示例程序
容器
容器就是由**数组(array) , 链表(list), tree(树),栈(stack), 队列(queue), 集合(set),映射表(map)**等数据结构组成的。
根据容器中的排列顺序,分为序列式容器和关联式容器:
- 序列式容器强调值的排序,每个元素由固定的位置(除非用删除、插入的方式改变其位置);vector、deque、list等。
- 关联式容器是非线性的树结构(二叉树)。元素间没有严格的物理上的顺序关系。关联式容器的一个显著特点:有一个值作为关键字key,起到索引作用;set、map等。
常用的容器(编程练习)
每种容器有很多种操作函数,每个练习只能尽可能多的展示出来。
string :字符串容器
/*
* string类的原型:
* class string
* {
* public:
* string(const char *str=NULL);//构造函数
* string(const string &other); //拷贝构造函数
* ~string();//析构函数
* private:
* char *m_data;//存放字符串
* }
* */
#include<iostream>
#include<string>
using namespace std;
int main(int argc,char *grgv[])
{
string str1 = "test string";
cout << "str1:" << str1 << endl;
string str2(str1);
//string str2 = str1;//与上面相同,拷贝构造
cout << "str2:" << str2 << endl;
str1.append(" other");//尾部追加字符串,若要追加字符,用push_back()
cout << "append \" other\":" << str1 << endl;
str1.insert(0," insert ");//在0位置插入字符串
cout << "insert \"insert \":" << str1 << endl;
str1.replace(str1.find("test"),4,"replace");
//找到str1中"test"字符串,从"t"开始替换4个为“replace”
cout << "repalce \"test\":" << str1 << endl;
string::iterator it;//string的迭代器
cout << "iterator output:";
for(it = str1.begin();it < str1.end();it++)//迭代器遍历str1
{
cout << *it;
}
cout << endl;
}
vector :向量
对于vector、list、deque三种容器:(摘自CSDN论坛)
(1)如果你需要高效的随即存取,而不在乎插入和删除的效率,使用vector
(2)如果你需要大量的插入和删除,而不关心随机存取,则应使用list
(3)如果你需要随机存取,而且关心两端数据的插入和删除,则应使用deque
vector是很常用的容器,类似C语言中的单向链表。
vector可以用来实现队列、栈等常用数据类型。
vector实现队列:
#include<iostream>
#include<vector>
using namespace std;
template <class T>
class Queue{//队列,先入先出的结构
private:
vector<T> elems;
public:
void push(T const& e)//入队,队尾插入
{
elems.push_back(e);
cout << "into queue:" << elems.back() << endl;
}
void pop()//出队,队头部删除
{
if(elems.empty())//队列已空
throw out_of_range("Queue::pop():empty queue!");
cout << "out queue:" << elems.front() << endl;
elems.erase(elems.begin());//擦除头部元素
}
bool empty()//队列判空
{
return elems.empty();
}
};
int main(int argc,char *argv[])
{
Queue<int> testQueue;
testQueue.push(1);
testQueue.push(2);
testQueue.push(3);
testQueue.pop();
testQueue.pop();
testQueue.pop();
testQueue.pop();
return 0;
}
vector实现栈:
#include<iostream>
#include<vector>
using namespace std;
template <class T>
class Stack{//栈,先进后出,只有栈顶元素可见
private:
vector<T> elems;
public:
void push(T const& e)//入栈
{
elems.push_back(e);//尾部插入
}
void pop() //出栈
{
if(elems.empty())
throw out_of_range("Stack::pop():stack empty!");
elems.pop_back();
}
T top() const//返回栈顶元素
{
if(elems.empty())
throw out_of_range("Stack::pop():stack empty!");
return elems.back();
}
bool empty()
{
return elems.empty();
}
};
int main(int argc,char *argv[])
{
Stack<int> stack;
stack.push(1);
stack.push(2);
stack.push(3);
cout << "stack top :" << stack.top() << endl;
stack.pop();
cout << "stack top :" << stack.top() << endl;
stack.pop();
cout << "stack top :" << stack.top() << endl;
return 0;
}
list :双向链表容器
list实现队列:
#include<iostream>
#include<list>
using namespace std;
template <class T>
class Queue//队列,先进先出
{
private:
list<T> elems;
public:
void push(T const& e)//入队
{
elems.push_back(e);
cout << "queue input:" << elems.back() << endl;
}
void pop()//出队
{
if(elems.empty())
throw out_of_range("Queue::pop():queue empty!");
cout << "queue output:" << elems.front() << endl;
elems.erase(elems.begin());
}
bool empty()//队列判空
{
return elems.empty();
}
};
int main(int argc,char *argv[])
{
Queue<int> q;
q.push(1);
q.push(2);
q.push(3);
q.pop();
q.pop();
q.pop();
q.pop();
return 0;
}
queue :队列容器
stack :栈容器
deque :双端队列容器
双端队列实现栈:
#include<iostream>
#include<deque>
using namespace std;
template <class T>
class Stack//栈,先进后出
{
private:
deque<T> elems;
public:
void push(T const& e)//入栈
{
elems.push_back(e);
cout << "stack in:" << elems.back() << endl;
}
void pop()//出栈
{
if(elems.empty())
throw out_of_range("Stack::pop():stack empty!");
cout << "stack out:" << elems.back() << endl;
elems.pop_back();
}
T top() const //返回栈顶元素
{
if(elems.empty())
throw out_of_range("Stack::pop():stack empty!");
return elems.back();
}
bool empty()//栈判空
{
return elems.empty();
}
};
int main(int argc,char *argv[])
{
Stack<int> s;
s.push(1);
s.push(2);
s.push(3);
s.push(4);
s.push(5);
s.pop();
s.pop();
cout << "empty stack:" << s.empty() << endl;
cout << "top elem of stack:" << s.top() << endl;
return 0;
}
priority_queue :按值排序的队列容器。
set :集合容器。
multiset :允许出现重复元素的集合容器。
map :关联数组容器。
map容器提供了一对一的关系(key->value),内部按照key值升序排列。
#include<iostream>
#include<map>
#include<string>
using namespace std;
int main(int argc,char *argv[])
{
map<int,string> m;
m.insert(pair<int,string>(11,"first"));//插入键值对
m.insert(pair<int,string>(12,"second"));
m.insert(pair<int,string>(13,"third"));
m.insert(pair<int,string>(14,"fourth"));
m.insert(pair<int,string>(15,"fifth"));
m[16]="sixth";//另一种键值对插入方式
map<int,string>::iterator it;
for(it = m.begin();it != m.end();it++)//迭代器遍历map容器
{
cout << it->first << "->" << it->second << endl;
}
map<int,string>::iterator find_it;
find_it = m.find(11);//按key=11查找元素
if(find_it == m.end())//没有搜索到
cout << "no this elem in map" << endl;
cout << "find elem:" << find_it->first << "->" << find_it->second << endl;
map<int,string>::iterator erase_it;
erase_it = m.find(14);
if(erase_it == m.end())
cout << "no this elem in map" << endl;
m.erase(erase_it);//删除key=14的元素
for(erase_it = m.begin();erase_it != m.end();erase_it++)//迭代器遍历map容器
{
cout << erase_it->first << "->" << erase_it->second << endl;
}
return 0;
}