重庆分公司,新征程启航

为企业提供网站建设、域名注册、服务器等服务

【算法设计与分析】2.常见STL总结-创新互联

写在前面

创新互联是专业的通化网站建设公司,通化接单;提供成都网站建设、网站设计,网页设计,网站设计,建网站,PHP网站建设等专业做网站服务;采用PHP框架,可快速的进行通化网站开发网页制作和功能扩展;专业做搜索引擎喜爱的网站,专业的做网站团队,希望更多企业前来合作!

【算法设计与分析】这一系列是作者在本学期学习算法的时候做的笔记,由于本人水平有限,对很多概念的理解比较浅显😭,欢迎各位大佬多多评价,多多批评指正,希望与大家互相交流学习👻。

参考资料

[1] Mark Allen Weiss 《数据结构与算法分析C语言描述》
[2] Stephen Prata《C Primer Plus》
[3] 余文溪 黄襄念《C++ STL——数据结构与算法实现》
[4] HUST算法设计与分析组 PPT
[5]高畅 《LeetCode 101:和你一起轻松刷题》

最后更新时间

2022-11-25 22:40


文章目录
  • 2.常见STL总结
    • 2.1 vector
    • 2.2 set
    • 2.3 string
    • 2.4 map
    • 2.5 queue
    • 2.6 priority_queue
    • 2.7 stack
    • 2.8 pair

2.常见STL总结 2.1 vector

定义

#includevectorname;

  上面这个定义其实就是相当于定义了一个一维数组name[SIZE],只不过其长度可以根据需要进行变化。
  如果typename也是一个STL容器,定义的时候需要在>>符号之间加上一个空格,防止编译器误以为是移位符。

vector>name;

  定义二维数组有以下两种方式:

vectorname[SIZE];
vector>name;

  动态开辟二维vector:

int m = 3;//行数
int n = 4;//列数
vector>Name(m, vector(n));//默认初始化为0
for (int i = 0; i< m; i++)
{for (int j = 0; j< n; j++)
	{cout<< Name[i][j];
	}
	cout<< endl;
}

内部元素的访问

  1. 下标
    直接使用name[index]即可。
  2. 迭代器
    一个类似于指针的东西,定义为
vector::iterator it;

  然后就可以用这个迭代器来访问容器内的元素:

#include#includeusing namespace std;
int main()
{vectorvi;
	for (int i = 1; i<= 5; i++)
	{vi.push_back(i);
	}
	vector::iterator it = vi.begin();
	for (int i = 0; i< 5; i++)
	{cout<< *(it + i);
	}
	return 0;
}

  其中,vi.begin()为取vi的首元素地址,it指向这个地址。再引入vi.end(),它是去取尾元素地址的下一个地址,不是尾元素地址。
  还有另一种使用迭代器遍历的方法:

#include#includeusing namespace std;
int main()
{vectorvi;
	for (int i = 1; i<= 5; i++)
	{vi.push_back(i);
	}
	for (vector::iterator it = vi.begin(); it != vi.end(); it++)
	{cout<< *it;
	}
	return 0;
}

  注意vector迭代器并不支持it的写法,所以只能用it!=vi.end()

push_back()
  push_back(x)就是在vector最后添加一个元素x,时间复杂度为 O ( 1 ) O(1) O(1)。

#include#includeusing namespace std;
int main()
{vectorvi;
	for (int i = 1; i<= 3; i++)//将1、2、3依次插入vi末尾
	{vi.push_back(i);
	}
	for (int i = 0; i< vi.size(); i++)
	{cout<< vi[i];
	}
	return 0;
}

pop_back()
  pop_back用以删除vector的尾元素,时间复杂度 O ( 1 ) O(1) O(1)。

#include#includeusing namespace std;
int main()
{vectorvi;
	for (int i = 1; i<= 3; i++)//将1、2、3依次插入vi末尾
	{vi.push_back(i);
	}
	vi.pop_back();
	for (int i = 0; i< vi.size(); i++)
	{cout<< vi[i];//输出1 2
	}
	return 0;
}

size()
  size()用来获得vector中元素的个数,返回unsigned类型,时间复杂度为 O ( 1 ) O(1) O(1)。

clear()
  clear()直接清空vector中所有的元素,时间复杂度为 O ( N ) O(N) O(N),N为元素的个数。

insert()
  insert(it,x)用来向vector的迭代器it处插入一个元素x,时间复杂度为 O ( N ) O(N) O(N)。

#include#includeusing namespace std;
int main()
{vectorvi;
	for (int i = 1; i<= 5; i++)
	{vi.push_back(i);//1 2 3 4 5
	}
	vi.insert(vi.begin() + 2, -1);
	for (int i = 0; i< vi.size(); i++)
	{cout<< vi[i];//1 2 -1 3 4 5
	}
	return 0;
}

erase()
  1. 删除单个元素erase(it)

#include#includeusing namespace std;
int main()
{vectorvi;
	for (int i = 1; i<= 5; i++)
	{vi.push_back(i);//1 2 3 4 5
	}
	vi.erase(vi.begin() + 3);
	for (int i = 0; i< vi.size(); i++)
	{cout<< vi[i];//1 2 3 5
	}
	return 0;
}

  2.删除一个区间内的所有元素earse(first,last),区间左闭右开。

#include#includeusing namespace std;
int main()
{vectorvi;
	for (int i = 1; i<= 5; i++)
	{vi.push_back(i);//1 2 3 4 5
	}
	vi.erase(vi.begin() + 1, vi.begin() + 3);
	for (int i = 0; i< vi.size(); i++)
	{cout<< vi[i];//1 4 5
	}
	return 0;
}

主要用途

  1. 作为数组存储数据,尤其适用于元素不确定的场合。
  2. 为了能够满足数据中间用空格隔开并且最后一个数据后面不能有额外的空格,可以先用vector记录所有需要输出的数据,然后一次性输出。
  3. 用邻接表存储图。
2.2 set

定义

setname;

  set翻译为集合,是一个内部自动有序且不含重复元素的容器。

元素访问
  注意,由于除了vector和string之外的STL容器都不支持*(it+i)的访问方式,所以只能按以下方式枚举:

#include#includeusing namespace std;
int main()
{setst;
	st.insert(3);
	st.insert(5);
	st.insert(2);
	st.insert(3);
	for (set::iterator it = st.begin(); it != st.end(); it++)
	{cout<< *it<< endl; //2 3 5
	}
	return 0;
}

  可以发现,set内的元素自动递增排序,且自动去除了重复的元素。

insert()
  insert(x)可以将x插入到set容器中,并且自动排序和去重,时间复杂度为 O ( log ⁡ N ) O(\log N) O(logN),N为元素个数。

find()
  find(value)返回set中对应值为value的迭代器,时间复杂度为 O ( log ⁡ N ) O(\log N) O(logN)。若不存在,则返回st.end()

#include#includeusing namespace std;
int main()
{setst;
	for (int i = 1; i<= 3; i++)
	{st.insert(i);
	}
	set::iterator it = st.find(2);
	cout<< *it<< endl;
	it = st.find(4);
	if (it == st.end())
	{cout<< "Not found"<< endl;
	}
	return 0;
}

erase()
  1.删除单个元素:st.erase(it),it为所需要删除元素的迭代器,可结合find()函数实现,时间复杂度 O ( 1 ) O(1) O(1)。或者st.erase(value),value为所需要元素的值,时间复杂度 O ( log ⁡ N ) O(\log N) O(logN)。

st.erase(st.find(100));
st.erase(100);

  2.删除一个区间内的所有元素:st.erase(first,last),first为所需要删除区间的起始迭代器,last为所需要删除区间的末尾迭代器的下一个地址。

st.erase(st.find(100),st.end());//删除元素30到末尾之间的元素

size()
  获取set内元素的个数,时间复杂度 O ( 1 ) O(1) O(1)。

clear()
  清空set中所有的元素,时间复杂度 O ( N ) O(N) O(N)。

主要用途

  1. 自动去重并按升序排序。
  2. set中元素唯一,如果遇到不唯一的情况,需要使用multiset。
  3. C++11添加了unordered_set,使其去重但不排序,速度比set快很多。
2.3 string

定义

#include//注意string和string.h是不一样的头文件
string str;
string str="abcd";

元素访问

  1. 元素下标
string str="abcd";
cout<
  1. 迭代器
string::iterator it;
string str="abcd";
for(it=str.begin();it!=str.end();it++)
{cout<<*it;
}

operatpr+=
  string的加法,可以将string直接拼接起来。

string str1="abc";
string str2="def";
string str3=str1+str2;//将str1和str2拼接,赋给str3
str1+=str2;//将str2直接拼接到str1上

compare operator
  两个string类型可以直接使用==,!=,<,<=,>,>=比较大小,比较顺序是字典序。

#include#includeusing namespace std;
int main()
{string str1 = "aa";
	string str2 = "aaa";
	string str3 = "abc";
	string str4 = "xyz";
	if (str1< str2) cout<< "ok1"<< endl;//ok1
	if (str1 != str3) cout<< "ok2"<< endl;//ok2
	if (str4 >= str3) cout<< "ok3"<< endl;//ok3
	return 0;
}

length()/size()
  length()返回字符串存放的字符数,时间复杂度为 O ( 1 ) O(1) O(1),size()与其用法基本相同。

insert()

  1. insert(pos,string),在pos号位置插入字符串string,时间复杂度 O ( N ) O(N) O(N)。
string str="abcxyz",str2="opq";
str.insert(3,str2);
cout<
  1. insert(it,it1,it2),it为原字符串欲插入的位置,it2和it3为待插字符串的首尾迭代器,用来表示串[it2,it3)将被插在it的位置上,时间复杂度 O ( N ) O(N) O(N)。
string str1="abcxyz",str2="opq";
str1.insert(str1.begin()+3,str2.begin(),str2.end());//abcopqxyz

erase()

  1. erase(it),删除单个元素,it为元素的迭代器,时间复杂度 O ( N ) O(N) O(N)。
  2. erase(first,last),删除区间内的元素,时间复杂度 O ( N ) O(N) O(N)。
  3. erase(pos,length),pos为需要删除的起始位置,length为要删除的长度,时间复杂度 O ( N ) O(N) O(N)。

clear()
  清空string中的所有元素,时间复杂度 O ( 1 ) O(1) O(1)。

substr()
  substr(pos,len)返回从pos开始,长度为len的子串,时间复杂度为 O ( l e n ) O(len) O(len)

string::npos
  它是一个常数,值为-1,用作find函数失配时的返回值。

find()
  str1.find(str2),当str2时str1的子串时,返回其在str中第一次出现的位置,否则返回string::npos。
str1.find(str2,pos)从str1的pos号开始匹配,返回值同上。时间复杂度 O ( m n ) O(mn) O(mn),m和n分别是str1和str2的长度。

replace()
  str1.replace(pos,len,str2)把str1从pos号位置开始,长度为len的子串替换为str2。
str1.replace(it1,it2,str2)把str1的迭代器[it1,it2)范围的子串替换为str2。

#include#includeusing namespace std;
int main()
{string str1 = "abcxyz";
	string str2 = "opq";
	str1.replace(3, 4, str2);
	cout<< str1<< endl;//abcopq
	str1.replace(str1.begin() + 1, str1.end(), str2);
	cout<< str1<< endl;//aopq
}
2.4 map

  map翻译为映射,类似于hash表,能将某个类型的元素映射到另一个类型的元素。

定义

mapmp;

  其中前一个为键(key),后一个为值(value)。map中的键是唯一的。如下面的代码:

mapmp;
mp['c']=20;
mp['c']=30;

最后c的映射应该为30,20被覆盖掉。

元素访问
  1.通过下标访问。
  2.通过迭代器访问。
因为map的每一对映射都有两个typename,所以map可以使用it->firstit->second来分别访问map中的key和value。
  另外,map中的元素会以键的次序从小到大自动排序,其内部使用红黑树实现。

find()
  find(key)返回键为key的映射的迭代器,时间复杂度为 O ( N ) O(N) O(N)。

#include#includeusing namespace std;
int main()
{mapmp;
	mp['c'] = 100;
	map::iterator it = mp.find('c');
	cout<< it->first<< ":"<< it->second<< endl;//c:100
	it = mp.find('b');
	if (it == mp.end())
		cout<< "Not Found"<< endl;
	return 0;
}

erase()/size()/clear()
  与前面大致相同,不再介绍。

map的常见用途

  1. 建立字符(字符串)与整数之间的映射关系,减少代码量。
  2. 判断大整数或其他类型的数据是否存在。
  3. 字符串到字符串的映射也有可能遇到。
  4. 如果一个键需要对应多个值,则需要使用multimap。另外C++11中添加了unordered_map,使其只处理映射而不按key排序,速度比map快很多。
2.5 queue

  queue翻译为队列,在STL中是一个先进先出的容器。

定义

queuename;

元素访问
  由于queue本身是一种先进先出的限制性数据结构,因此只能通过front()来访问队首元素,或back()访问队尾元素。

#include#includeusing namespace std;
int main()
{queueq;
	for (int i = 1; i<= 5; i++)
	{q.push(i);//将i入队
	}
	cout<< q.front()<< endl;//1
	cout<< q.back()<< endl;//5
	return 0;
}

push()
  push(x)将x入队,时间复杂度 O ( 1 ) O(1) O(1)。

pop()
  pop()将队首元素出列,时间复杂度 O ( 1 ) O(1) O(1)。

front()/back()
  分别获得队首元素和队尾元素,时间复杂度 O ( 1 ) O(1) O(1)。

empty()
  empty()检测queue是否为空,返回true则为空,返回false则非空,时间复杂度 O ( 1 ) O(1) O(1)。

size()
  返回queue中元素的个数,时间复杂度 O ( 1 ) O(1) O(1)。

queue常见用途

  1. 广度优先搜索时,可以不用自己手动实现队列。
  2. 双端队列deque、优先队列priority_queue,前者是首位皆可插入和删除的队列,后者则是使用堆实现的默认将当前队列大元素置于队首的容器。
2.6 priority_queue

  称为优先队列,其底层是用堆来实现的。在优先队列中,队首元素一定是当前队列中优先级最高的那一个。

定义

priority_queuename;

元素访问
  优先队列没有front()和back(),只能通过top()函数访问队首元素,也称堆顶元素。

#include#includeusing namespace std;
int main()
{priority_queueq;
	q.push(3);
	q.push(4);
	q.push(1);
	cout<< q.top()<< endl;//4
	return 0;	
}

push()/pop()/empty()/size()
  与queue相同,不再介绍。

优先级的设置

  1. 基本数据类型的优先级设置(以int为例)。
priority_queueq;
priority_queue,less>;
priority_queue,greater>;

其中,第二个参数vector是用来承载底层数据结构堆的容器,第三个参数则是对第一个参数的比较类,less表示数字越大的优先级越大,greater表示数字越小优先级越大。

  1. 结构体的优先级设置
    给定一个水果-价格结构体:
struct fruit
{string name;
	int price;
}

如果想要按照水果价格越高优先级越高排序,则需要重载运算符"<":

struct fruit
{string name;
	int price;
	friend bool operator< (fruit f1,fruit f2)
	{return f1.price< f2.price;//价格高优先级高
	}
}

注意,如果重载大于号会显示编译错误,因为从数学上来说只需重载小于号即可(aa,a==b等价于!(a同理,若想要以价格低的水果为优先级高的次序输出,只需要把return中的小于号改为大于号即可。

struct fruit
{string name;
	int price;
	friend bool operator< (fruit f1,fruit f2)
	{return f1.price >f2.price;//价格低优先级高
	}
}

另外,还可以将函数写在结构体外,即:

struct cmp
{bool operator () (fruit f1,fruit f2)
	{return f1.price< f2.price;
    {}

在这种情况下,需要使用第一种方法定义优先队列:

priority_queue,cmp>p;

常见用途
  priority_queue可以解决一些贪心问题,也可以对迪杰斯特拉算法进行优化。

2.7 stack

  stack翻译为栈,在STL种是一个后进后出的容器。

定义

stackname;

元素访问
  由于stack是一个后进后出的数据结构,所以只能通过top()来访问栈顶的元素。

push()/top()/pop()/empty()/size()
  与前面大致相同,不再介绍。

常见用途
  stack常用来模拟实现一些递归,防止程序对栈内存的限制而导致程序运行出错。

2.8 pair

  pair将两个元素绑在一起作为一个合成元素。

定义

#includepairname;

元素访问
  pair中只有两个元素,分别是first和second,只需按照正常结构体的方式去访问即可。

比较操作数
  两个pair类型数据可以直接使用“==”,“<=”等比较大小,比较规则是现以first的大小作为标准,只有当first相等时才会去判别second的大小。

常见用途
  用来代替二元结构体及其构造函数,节省编码时间。还可以作为map的键值对进行插入,如:

mapmp;
mp.insert(make_pair("heihei",5));
mp.insert(pair("haha",10));

你是否还在寻找稳定的海外服务器提供商?创新互联www.cdcxhl.cn海外机房具备T级流量清洗系统配攻击溯源,准确流量调度确保服务器高可用性,企业级服务器适合批量采购,新人活动首月15元起,快前往官网查看详情吧


文章名称:【算法设计与分析】2.常见STL总结-创新互联
浏览路径:http://cqcxhl.com/article/ccohjp.html