STL详解(五) 双端队列容器deque

一、deuqe简介

1、deuqe概念

        容器deque和vector非常相似,属于序列式容器。都是采用动态数组来管理元素,提供随机存取,并且有着和vector一样的接口。不同的是deque具有首尾两端进行快速插入、删除的能力。

2、Deque结构

        如图1是deque的逻辑结构,从表面上看,deque具有连续性的存储空间,并支持随机存取功能。实际上deque并不是我们所看到的样子,其内部结构,如图2所示。
deque在实现上主要有以下两点:
  1.由一段一段的定量连续空间构成,第一个区块朝某个方向扩展,最后一个区块朝相反方向扩展;
  2.管理这些分段的定量连续空间,维护其整体连续的假象,并提供随机存取的接口;

         
                                                         图 1 deque的逻辑结构

  
                                                                图 2  deque的内部结构


3、Deque的能力

   与vector相比,deque功能上的不同之处在于:

  •  首尾两端都能快速的安插、删除元素,因此需要在两端安插、删除元素时,最好采用deque。
  •  存在元素时,deque的内部结构会多一个间接过程,操作元素的效率会比vector低一些。
  • 迭代器需要在不同区块间跳转,所以必须是特殊的智能指针,非一般指针。
  • deque不支持对容量和内存重分配时机的控制,除了首尾两端安插、删除元素外,其他地方安插、删除元素都将导致元素的pointer、reference、iterator失效。不过,deque的内存重分配机制优于vector,因为deque不必在内存重分配时复制所有的元素。
  • deque的内存区块不再被使用时,会被释放。
  • 在建立vector容器时,一般来说伴随这建立空间->填充数据->重建更大空间->复制原空间数据->删除原空间->添加新数据,如此反复,保证vector始终是一块独立的连续内存空间;在建立deque容器时,一般便随着建立空间->建立数据->建立新空间->填充新数据,如此反复,没有原空间数据的复制和删除过程,是由多个连续的内存空间组成的。
     

  使用区别:
1 如果你需要高效的随即存取,而不在乎插入和删除的效率,使用vector 
2 如果你需要大量的插入和删除,而不关心随即存取,则应使用list 
3 如果你需要随即存取,而且关心两端数据的插入和删除,则应使用deque

4、deque的操作函数:

          Deque的操作函数和vector操作函数基本一模一样,duque的各项操作只有以下几点和vector不同:

 1、deque不提供容量操作( capacity()、reserve() )

 2、deque提供push_front()、pop_front()函数直接操作头部

5、Deque的特点:

 1、支持随机访问,即支持[ ]以及at(),但是性能没有vector好。
 2、可以在内部进行插入和删除操作,但性能不及list。
 3、deque两端都能够快速插入和删除元素,而vector只能在尾端进行。
 4、deque的元素存取和迭代器操作会稍微慢一些,因为deque的内部结构会多一个间接过程。
 5、deque迭代器是特殊的智能指针,而不是一般指针,它需要在不同的区块之间跳转。
 6、deque可以包含更多的元素,其max_size可能更大,因为不止使用一块内存。
 7、deque不支持对容量和内存分配时机的控制。
 8、在除了首尾两端的其他地方插入和删除元素,都将会导致指向deque元素的任何pointers、references、iterators失效。不过,deque的内存重分配优于vector,因为其内部结构显示不需要复制所有元素。
 9、deque的内存区块不再被使用时,会被释放,deque的内存大小是可缩减的。不过,是不是这么做以及怎么做由实际操作版本定义。
 10、deque不提供容量操作:capacity()和reverse(),但是vector可以。

二、成员函数列表

c.assign(beg,end) 将[beg; end)区间中的数据赋值给c。

c.assign(n,elem) 将n个elem的拷贝赋值给c。

c. at(idx) 传回索引idx所指的数据,如果idx越界,抛出out_of_range。

c.back() 返回容器c的最后一个元素的引用。如果c为空,则该操作未定义。

c.begin() 传回迭代器中的第一个数据地址。

c.clear() 移除容器中所有数据。

c.empty() 判断容器是否为空。

c.end() 返回一个迭代器,它指向容器c的最后一个元素的下一位置。

c.erase(pos) 删除pos位置的数据,传回下一个数据的位置。

c.erase(beg,end) 删除[beg,end)区间的数据,传回下一个数据的位置。

c.front() 返回容器c的第一个元素的引用。如果c为空,则该操作为空。

get_allocator 使用构造函数返回一个拷贝。

c.insert(pos,elem) 在pos位置插入一个elem拷贝,传回新数据位置

c.insert(pos,n,elem) 在pos位置插入>n个elem数据。无返回值

c.insert(pos,beg,end) 在pos位置插入在[beg,end)区间的数据。无返回值

c.max_size() 返回容器c可容纳的最多元素个数。

c.pop_back() 删除最后一个数据。

c.pop_front() 删除头部数据。

c.push_back(elem) 在尾部加入一个数据。

c.push_front(elem) 在头部插入一个数据。

c.rbegin() 返回一个逆序迭代器,它指向容器c的最后一个元素。

c.rend() 返回一个逆序迭代器,它指向容器c的第一个元素的前一个位置。

c.resize(num) 重新指定队列的长度。

c.size() 返回容器中实际数据的个数。

c.swap(c2) 交换容器c和c2中的所有元素。

swap(c1,c2) 交换容器c1和c2中的所有元素,和上一方法相似。

三、成员函数详解

1、构造函数

deque<Type> v1;             //创建一个空的deque,类型为Type
deque<Type> v2(v1);         //v2中包含v1中的所有元素
deque<Type> v2=v1;          //等价于v2(v1)
deque<Type> v3(n,value);    //v3中有n个元素,并且值都为value
deque<Type> v4(n);          //v4含有n个数据,数据均已缺省构造产生。
deque<Type> v5{a,b,c...};   //v5包含大括号中的所有元素
deque<Type> v6={a,b,c...};  //等价于v5{a,b,c....}
deque<Type> v7(beg,end)     //创建一个以[beg;end)区间的deque。
~deque<Type> ()             //销毁所有数据,释放内存。

2、遍历函数

c.begin()返回指向第一个元素的迭代器

c.end()返回指向最后一个元素下一个位置的迭代器

#include <bits/stdc++.h>
using namespace std;
int main()  
{ deque<int> d ;
  for (int i = 1; i <= 5; i++) d.push_back(i);
  deque<int>::iterator it;
  for(it=d.begin();it!=d.end();it++){
  cout << *it << " ";
  }
  cout << endl;
}  

运行结果: 1 2 3 4 5

c.rbegin()返回指向反向队列的第一个元素的迭代器(即原队列的最后一个元素)

c.rend()返回指向反向队列的最后一个元素的下一个位置(即原队列的第一个元素的前一个位置)

#include <bits/stdc++.h>
using namespace std;
int main()  
{  deque<int> d ;
   for (int i = 1; i <= 5; i++) d.push_back(i);
   deque<int>::reverse_iterator it;
   for(it=d.rbegin();it!=d.rend();it++)
      cout << *it << " ";
   cout << endl;
}  

运行结果: 5 4 3 2 1

c.at(pos)返回索引为pos的位置的元素,会执行边界检查,如果越界抛出out_of_range异常

#include <bits/stdc++.h>
using namespace std;
int main()  
{  deque<int> d ;
   for (int i = 1; i <= 5; i++) d.push_back(i);
   cout << "d.at(pos):" << d.at(4);
   return 0;
}  

运行结果: d.at(pos): 5

c.operator[ ]下标运算符重载

#include <bits/stdc++.h>
using namespace std;
int main()  
{  deque<int> d ;
   for (int i = 1; i <= 5; i++) d.push_back(i);
   cout << "d[2]:" << d[2];
   return 0;
} 

运行结果: d.[2]: 3

c.front()返回c容器的第一个元素

c.back()返回c容器的最后一个元素

#include <bits/stdc++.h>
using namespace std;
int main()  
{  deque<int> d ;
   for (int i = 1; i <= 5; i++) d.push_back(i);
   if(!d.empty())
   {  cout << "d.front():" << d.front() << endl;
      cout << "d.back(): " << d.back() << endl;
   }
}

运行结果:

d.front():1

d.back():5

3、修改函数(增加,删除,交换,赋值等)

c.assign(n,num)将n个num拷贝复制到容器c

c.assign(beg,end)将[beg,end)区间的数据拷贝复制到容器c

#include <bits/stdc++.h>
using namespace std;
int main()  
{  deque<int> d1 ,d2;
   for (int i = 1; i <= 5; i++) d1.push_back(i);
   d2.assign(2, 8);
   deque<int>::iterator it;
   cout << "d2.assign(n,num):";
   for(it=d2.begin();it!=d2.end();it++)
     cout << *it << " ";
   cout<<endl;
   d2.assign(d1.begin(), d1.begin()+3);
   cout << "d2.assign(beg,end):";
   for(it=d2.begin();it!=d2.end();it++)
     cout << *it << " ";
   cout << endl;
}  
   

运行结果: 

d2.assign(n,num): 8 8

d2.assign(beg,end): 1 2 3

operator=赋值运算符重载

#include <bits/stdc++.h>
using namespace std;
int main()  
{  deque<int> d1,d2;
   for (int i = 1; i <= 5; i++) d1.push_back(i);
   d2 = d1;
   deque<int>::iterator it;
   for(it=d2.begin();it!=d2.end();it++)
     cout << *it << " ";
   cout << endl;
}  

运行结果: 1 2 3 4 5

c.insert(pos,num)在pos位置插入元素num

c.insert(pos,n,num)在pos位置插入n个元素num

c.insert(pos,beg,end)在pos位置插入区间为[beg,end)的元素

#include <bits/stdc++.h>
using namespace std;
int main()  
{  deque<int> d ;
   for (int i = 1; i <= 5; i++) d.push_back(i);
   deque<int>::iterator it;
   cout << "insert before:" ;
   for(it=d.begin();it!=d.end();it++)
      cout << *it << " ";
   cout << endl;
   d.insert(d.end(),22);
   d.insert(d.end(), 3,88);
   int a[5] = {1,2,3,4,5};
   d.insert(d.begin(),a,a+3);
   cout << "insert after:" ;
   for(it=d.begin();it!=d.end();it++)
      cout << *it << " ";
} 

运行结果:

insert before:1 2 3 4 5

insert after:1 2 3 1 2 3 4 5 22 88 88 88

c.push_back(num)在末尾位置插入元素

c.pop_back()删除末尾位置的元素

c.push_front(num)在开头位置插入元素

c.pop_front()删除开头位置的元素

#include <bits/stdc++.h>
using namespace std;
int main()  
{  deque<int> d ;
   for (int i = 1; i <= 5; i++) d.push_back(i);
   d.push_back(10);
   deque<int>::iterator it;
   cout << "push_back(num):" ;
   for(it=d.begin();it!=d.end();it++)
      cout << *it << " ";
   cout << endl;
   d.pop_back();
   cout << "pop_back(num):" ;
   for(it=d.begin();it!=d.end();it++)
      cout << *it << " ";
   cout << endl;
   d.push_front(10);
   cout << "push_front(num):" ;
   for(it=d.begin();it!=d.end();it++)
      cout << *it << " ";
   cout << endl;
   d.pop_front();
   cout << "pop_front(num):" ;
   for(it=d.begin();it!=d.end();it++)
      cout << *it << " ";
   cout << endl;
   return 0;
} 

运行结果:

push_back(num):1 2 3 4 5 10

pop_back(num):1 2 3 4 5

push_front(num):10 1 2 3 4 5

pop_front(num):1 2 3 4 5

c.erase(pos)删除pos位置的元素

c.erase(beg,end)删除区间为[beg,end)之间的元素

#include <bits/stdc++.h>
using namespace std;
int main()  
{  deque<int> d ;
   for (int i = 1; i <= 5; i++) d.push_back(i);
   d.erase(d.begin());
   deque<int>::iterator it;
   cout << "erase(pos) after:" ;
   for(it=d.begin();it!=d.end();it++)
      cout << *it << " ";
   cout << endl;
   d.erase(d.begin(), d.begin()+3);
   cout << "erase(beg,end) after:" ;
   for(it=d.begin();it!=d.end();it++)
      cout << *it << " ";
} 

运行结果:

erase(pos) after:2 3 4 5

erase(beg,end) after:5

c.clear()清除c容器中拥有的所有元素

#include <bits/stdc++.h>
using namespace std;
int main()  
{  deque<int> d ;
   for (int i = 1; i <= 5; i++) d.push_back(i);
   deque<int>::iterator it;
   cout << "clear before:" ;
   for(it=d.begin();it!=d.end();it++)
     cout << *it << " ";
   cout << endl;
   d.clear();
   cout << "clear after:" ;
   for(it=d.begin();it!=d.end();it++)
     cout << *it << " ";
} 

运行结果:

clear before:1 2 3 4 5

clear after:


 

c1.swap(c2)交换容器c1,c2;

swap(c1,c2)同上。

#include <bits/stdc++.h>
using namespace std;
int main()  
{  deque<int> d1,d2,d3;
   for (int i = 1; i <= 5; i++) d1.push_back(i);
   d1.swap(d2);
   deque<int>::iterator it;
   cout << "d1 swap after:" ;
   for(it=d1.begin();it!=d1.end();it++)
      cout << *it << " ";
   cout << endl;
   cout << "d2 swap after:" ;
   for(it=d2.begin();it!=d2.end();it++)
      cout << *it << " ";
   cout << endl;
   swap(d3,d2);
   cout << "d3 swap after:" ;
   for(it=d3.begin();it!=d3.end();it++)
      cout << *it << " ";
   cout << endl;
}

运行结果:

d1 swap after:

d2 swap after:1 2 3 4 5

d3 swap after:1 2 3 4 5

4、判断函数及其它

c.empty()判断c容器是否为空

#include <bits/stdc++.h>
using namespace std;
int main()  
{  deque<int> d ;
   for (int i = 1; i <= 5; i++) d.push_back(i);
   if(!d.empty())
      cout << "d is not empty!" << endl;
   else
      cout << "d is empty!" << endl;
   return 0;
}

运行结果: d is not empty!

c.size()返回c容器中实际拥有的元素个数

#include <bits/stdc++.h>
using namespace std;
int main()  
{   deque<int> d ;
    for (int i = 1; i <= 5; i++) d.push_back(i);
    cout << "d.size():" << d.size() << endl;
    return 0;
} 

运行结果:d.size():5

c.resize(num)从新定义容器的大小

#include <bits/stdc++.h>
using namespace std;
int main()  
{  deque<int> d ;
   for (int i = 1; i <= 5; i++) d.push_back(i);
   cout << "d.size():" << d.size() << endl;
   d.resize(d.size()+5);
   cout << "d.resize() after:" << d.size() <<endl;
   deque<int>::iterator it;
   cout << "resize() after:" ;
   for(it=d.begin();it!=d.end();it++)
      cout << *it << " ";
} 

运行结果:

d.size():5

d.resize() after:10

resize() after:1 2 3 4 5 0 0 0 0 0

c.max_size()返回c容器可能存放元素的最大数量

#include <bits/stdc++.h>
using namespace std;
int main()  
{   deque<int> d ;
    for (int i = 1; i <= 5; i++) d.push_back(i);
    cout << "d.max_size():" << d.max_size() << endl;
    return 0;
}

运行结果:d.max_size():1073741823



重载运算符

operator==

operator!=

operator<

operator<=

operator>

operator>=

四、练习:

读程序写结果:

第一题:

#include <bits/stdc++.h>
using namespace std;
int main()  
{   deque<int> d;
	d.push_back( 10 );
	d.push_back(20);
	d.push_back(30);
	cout<<"原始双端队列:"<<endl;
	for(int i = 0; i < d.size(); i++)
		cout<<d.at(i)<<"\t";
	cout<<endl;
	d.push_front(5);
	d.push_front(3);
	d.push_front(1);
	cout<<"after push_front(5.3.1):"<<endl;
	for(int i = 0;i < d.size();i++)
		cout<<d.at(i)<<"\t";
	cout<<endl;
	d.pop_front();
	d.pop_front();
	cout<<"after pop_front() two times:"<<endl;
	for(int i = 0;i < d.size();i++)
		cout<<d.at(i)<<"\t";
	cout<<endl;
	return 0;
}

第二题:

#include <bits/stdc++.h>
using namespace std;
int main()  
{	deque<int> ideq(20); 
	deque<int>::iterator pos;
	int i; 
	//使用assign()赋值  assign在计算机中就是赋值的意思
	for (i = 0; i < 20; ++i)
		ideq[i] = i;
	printf("输出deque中数据:\n");
	for (i = 0; i < 20; ++i)
		printf("%d ", ideq[i]);
	putchar('\n');
	printf("\n在头尾加入新数据...\n");
	ideq.push_back(100);
	ideq.push_front(i);
	printf("\n输出deque中数据:\n");
	for (pos = ideq.begin(); pos != ideq.end(); pos++)
		printf("%d ", *pos);
	putchar('\n');

	const int FINDNUMBER = 19;
	printf("\n查找%d\n", FINDNUMBER);
	pos = find(ideq.begin(), ideq.end(), FINDNUMBER);
	if (pos != ideq.end())
		printf("find %d success\n", *pos);
	else
		printf("find failed\n");
	printf("\n在头尾删除数据...\n");
	ideq.pop_back();
	ideq.pop_front();
	printf("\n输出deque中数据:\n");
	for (pos = ideq.begin(); pos != ideq.end(); pos++)
		printf("%d ", *pos);
	putchar('\n');
	return 0;
}

1、B3656 【模板】双端队列 1

2、P2952 [USACO09OPEN] Cow Line S

3、CF1579E1 Permutation Minimization by Deque

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值