【C++序列式容器】deque

目录

deque

1. Member functions

1.1 constructor、destructor、operator=

1.1.1 constructor

1.1.2 destructor

1.1.3 operator=

1.2 Iterators

1.3 Capacity

1.3.1 size

1.3.2 max_size

1.3.3 resize

1.3.4 empty

1.3.5 shrink_to_fit

1.4 Element access

1.4.1 operator[]

1.4.2 at

1.4.3 front

1.4.4 back

1.5 Modifiers

1.5.1 assign

1.5.2 push_back

1.5.3 push_front

1.5.4 pop_back

1.5.5 pop_front

1.5.6 insert

1.5.7 erase

1.5.8 swap

1.5.9 clear

1.5.10 emplace

1.5.11 emplace_front

1.5.12 emplace_back

1.6 Allocator

1.6.1 get_allocator

2. Non-member function overloads

2.1 relational operators

2.2 swap

3. deque对象的遍历方法

3.1 operator[]

3.2 迭代器

3.3 范围for


deque

template < class T, class Alloc = allocator<T> > class deque;

deque(通常发音为 "deck")是双端队列的不规则缩写。双端队列是具有动态大小的序列容器,可以在两端(前端或后端)扩展或收缩。

特定的库可能以不同的方式实现deque,通常是某种形式的动态数组。但无论如何,它们都允许通过随机访问迭代器直接访问单个元素,并根据需要通过扩展和收缩容器自动处理存储。

因此,它们提供了与vector类似的功能,但可以在序列的开头(而不仅仅是结尾)有效地插入和删除元素。但是,与vector不同,deque不能保证将所有元素存储在连续的存储位置:通过偏移指向另一个元素的指针来访问deque中的元素会导致未定义的行为。

vector和deque都提供了非常相似的接口,可以用于类似的目的,但两者的内部工作方式截然不同: vector使用的是单个数组,偶尔需要重新分配以满足增长的需要,而deque的元素可以分散在不同的存储块中,容器内部保留了必要的信息,可以在恒定时间内通过统一的顺序接口(通过迭代器)直接访问其中的任何元素。因此,deque的内部结构要比vector复杂一些,但这使得它们在某些情况下能够更有效地增长,特别是在序列很长的情况下,重新分配的代价会更高。

对于在开头或结尾以外的位置频繁插入或移除元素的操作,deque的性能比list和forward_list差,迭代器和引用也不一致。

deque定义在头文件deque和命名空间std中。

1. Member functions

1.1 constructor、destructor、operator=

1.1.1 constructor

// default (1)
explicit deque(const allocator_type & alloc = allocator_type());
// fill(2)
explicit deque(size_type n);
deque(size_type n, const value_type & val, const allocator_type & alloc = allocator_type());
// range (3)
template <class InputIterator> deque(InputIterator first, InputIterator last, const allocator_type & alloc = allocator_type());
// copy (4)
deque(const deque & x);
deque(const deque & x, const allocator_type & alloc);
// move (5)
deque(deque && x);
deque(deque && x, const allocator_type & alloc);
// initializer list (6)
deque(initializer_list<value_type> il, const allocator_type & alloc = allocator_type());
#include <deque>
#include <string>
#include <iostream>
using namespace std;

template<typename T>
void printDq(deque<T>& dq)
{
	for (auto& e : dq)
	{
		cout << e << " ";
	}
	cout << endl;
}

int main()
{
	deque<int> dq1; // default
	printDq(dq1);   // 空

	deque<int> dq2(5); // fill
	printDq(dq2);      // 0 0 0 0 0

	deque<int> dq3(10, 1); // fill
	printDq(dq3);          // 1 1 1 1 1 1 1 1 1 1

	string s("hello world");
	deque<char> dq4(s.begin() + 3, --s.end()); // range
	printDq(dq4);                              // l o   w o r l

	deque<char> dq5(dq4); // copy
	// 等价于deque<char> dq5 = dq4;
	printDq(dq5);        // l o   w o r l

	deque<char> dq6(std::move(dq5));  // move
	cout << "dq5: ";    printDq(dq5); // dq5: 
	cout << "dq6: ";    printDq(dq6); // dq6: l o   w o r l

	deque<string> dq7{ "happy","new","year" }; // initializer list
	// 等价于deque<string> dq7 = { "happy","new","year" };
	printDq(dq7);                              // happy new year

	return 0;
}

1.1.2 destructor

~deque();

1.1.3 operator=

// copy (1)
deque& operator=(const deque& x);
// move (2)
deque& operator=(deque&& x);
// initializer list (3)
deque& operator=(initializer_list<value_type> il);
#include <deque>
#include <iostream>
using namespace std;

template<typename T>
void printDq(deque<T>& dq)
{
	for (auto& e : dq)
	{
		cout << e << " ";
	}
	cout << endl;
}

int main()
{
	deque<int> dq(5, 2);
	printDq(dq); // 2 2 2 2 2

	deque<int> dq1;
	dq1 = dq;     // copy
	printDq(dq1); // 2 2 2 2 2

	deque<int> dq2;
	dq2 = std::move(dq1);             // move
	cout << "dq1: ";    printDq(dq1); // dq1: 
	cout << "dq2: ";    printDq(dq2); // dq2: 2 2 2 2 2

	deque<int> dq3;
	dq3 = { 1,2,3,4,5,6 }; // initializer list
	printDq(dq3);          // 1 2 3 4 5 6

	return 0;
}

1.2 Iterators

// begin
iterator begin() noexcept;
const_iterator begin() const noexcept;
// end
iterator end() noexcept;
const_iterator end() const noexcept;
// rbegin
reverse_iterator rbegin() noexcept;
const_reverse_iterator rbegin() const noexcept;
// rend
reverse_iterator rend() noexcept;
const_reverse_iterator rend() const noexcept;
// cbegin
const_iterator cbegin() const noexcept;
// cend
const_iterator cend() const noexcept;
// crbegin
const_reverse_iterator crbegin() const noexcept;
// crend
const_reverse_iterator crend() const noexcept;
函数功能

begin

&

end

begin返回一个迭代器,指向deque对象的第一个元素

end返回一个迭代器,指向deque对象的最后一个元素的下一个位置

rbegin

&

rend

rbegin返回一个反向迭代器,指向deque对象的最后一个元素

rend返回一个反向迭代器,指向deque对象的第一个元素的上一个位置

cbegin

&

cend

cbegin返回一个const迭代器,指向deque对象的第一个元素

cend返回一个const迭代器,指向deque对象的最后一个元素的下一个位置

crbegin

&

crend

crbegin返回一个const反向迭代器,指向deque对象的最后一个元素

crend返回一个const反向迭代器,指向deque对象的第一个元素的上一个位置

begin&end和rbegin&rend返回的迭代器指向:

​​

const_iterator是一个指向const内容的迭代器。迭代器本身可以修改,但是它不能被用来修改它所指向的内容。

begin&end/rbegin&rend和cbegin&cend/crbegin&crend的不同:

  • begin&end/rbegin&rend的返回类型由对象是否是常量来决定。如果不是常量,返回iterator;如果是常量,返回const_iterator。
  • cbegin&cend/crbegin&crend的返回类型是const_iterator,不管对象本身是否是常量。
#include <deque>
#include <iostream>
using namespace std;

int main()
{
	deque<int> dq{ 1,2,3,4 };

	deque<int>::iterator it = dq.begin();
	while (it != dq.end())
	{
		cout << *it << " ";
		++it;
	}
	cout << endl;
	// 1 2 3 4

	auto rit = dq.rbegin();
	// deque<int>::reverse_iterator rit = dq.rbegin();
	while (rit != dq.rend())
	{
		cout << *rit << " ";
		++rit;
	}
	cout << endl;
	// 4 3 2 1

	return 0;
}

1.3 Capacity

1.3.1 size

size_type size() const noexcept;
// 返回deque中元素的个数

1.3.2 max_size

size_type max_size() const noexcept;
// 返回deque能够容纳的最大元素个数

1.3.3 resize

void resize(size_type n);
void resize(size_type n, const value_type& val);
// 调整deque的大小为n
// 如果n<当前的大小,多余的元素会被截掉
// 如果n>当前的大小,则:
// 1)如果没有指定填充元素,则使用默认构造函数
// 2)如果指定了填充元素val,则多出的空间用val填充

1.3.4 empty

bool empty() const noexcept;
// 检测deque是否为空,是返回true,否则返回false

1.3.5 shrink_to_fit

void shrink_to_fit();
// 收缩容量以适应vector的大小
// 这个请求没有约束力,容器实现可以自由地进行优化,使容量大于其大小

Capacity系列函数使用示例:

#include <deque>
#include <iostream>
using namespace std;

template<typename T>
void printDq(deque<T>& dq)
{
	for (auto& e : dq)
	{
		cout << e << " ";
	}
	cout << endl;
}

int main()
{
	deque<int> dq(3, 6);
	cout << dq.size() << endl;     // 3
	cout << dq.max_size() << endl; // 1073741823

	dq.resize(8, 7);
	printDq(dq); // 6 6 6 7 7 7 7 7

	dq.resize(5);
	printDq(dq); // 6 6 6 7 7
	
	if (dq.empty())
		cout << "deque为空" << endl;
	else
		cout << "deque不为空" << endl;
	// deque不为空

	return 0;
}

1.4 Element access

1.4.1 operator[]

reference operator[](size_type n);
const_reference operator[](size_type n) const;
// 返回deque中n位置的元素的引用
// 没有越界检查

1.4.2 at

reference at(size_type n);
const_reference at(size_type n) const;
// 返回deque中n位置的元素的引用
// 有越界检查,如果越界会抛异常

1.4.3 front

reference front();
const_reference front() const;
// 返回deque中第一个元素的引用

1.4.4 back

reference back();
const_reference back() const;
// 返回deque中最后一个元素的引用

Element access系列函数使用示例:

#include <deque>
#include <iostream>
using namespace std;

int main()
{
	deque<int> dq{ 1,2,3,4 };

	cout << dq[0] << endl;      // 1
	cout << dq.at(1) << endl;   // 2
	cout << dq.front() << endl; // 1
	cout << dq.back() << endl;  // 4

	return 0;
}

1.5 Modifiers

1.5.1 assign

// range (1)
template <class InputIterator> void assign(InputIterator first, InputIterator last);
// fill (2)
void assign(size_type n, const value_type& val);
// initializer list (3)
void assign(initializer_list<value_type> il);
#include <deque>
#include <iostream>
using namespace std;

template<typename T>
void printDq(deque<T>& dq)
{
	for (auto& e : dq)
	{
		cout << e << " ";
	}
	cout << endl;
}

int main()
{
	deque<int> dq1{ 1,2,3,4 };
	deque<int> dq2{ 5,6,7,8,9 };

	dq1.assign(dq2.begin() + 2, --dq2.end()); // range
	printDq(dq1);                             // 7 8

	dq1.assign(10, 1); // fill
	printDq(dq1);      // 1 1 1 1 1 1 1 1 1 1
	
	dq1.assign({ 77,88 }); // initializer list
	printDq(dq1);          // 77 88

	return 0;
}

1.5.2 push_back

void push_back(const value_type& val);
void push_back(value_type&& val);
// 尾插
#include <deque>
#include <iostream>
using namespace std;

template<typename T>
void printDq(deque<T>& dq)
{
	for (auto& e : dq)
	{
		cout << e << " ";
	}
	cout << endl;
}

int main()
{
	deque<int> dq{ 1,2,3,4 };
	int val = 5;

	dq.push_back(val);
	printDq(dq); // 1 2 3 4 5

	dq.push_back(6);
	printDq(dq); // 1 2 3 4 5 6

	return 0;
}

1.5.3 push_front

void push_front(const value_type& val);
void push_front(value_type&& val);
// 头插
#include <deque>
#include <iostream>
using namespace std;

template<typename T>
void printDq(deque<T>& dq)
{
	for (auto& e : dq)
	{
		cout << e << " ";
	}
	cout << endl;
}

int main()
{
	deque<int> dq{ 2,3,4 };
	int val = 1;

	dq.push_front(val);
	printDq(dq); // 1 2 3 4

	dq.push_front(0);
	printDq(dq); // 0 1 2 3 4

	return 0;
}

1.5.4 pop_back

void pop_back();
// 尾删
#include <deque>
#include <iostream>
using namespace std;

template<typename T>
void printDq(deque<T>& dq)
{
	for (auto& e : dq)
	{
		cout << e << " ";
	}
	cout << endl;
}

int main()
{
	deque<int> dq{ 1,2,3,4 };

	dq.pop_back();
	printDq(dq); // 1 2 3

	dq.pop_back();
	printDq(dq); // 1 2

	return 0;
}

1.5.5 pop_front

void pop_front();
// 头删
#include <deque>
#include <iostream>
using namespace std;

template<typename T>
void printDq(deque<T>& dq)
{
	for (auto& e : dq)
	{
		cout << e << " ";
	}
	cout << endl;
}

int main()
{
	deque<int> dq{ 1,2,3,4 };

	dq.pop_front();
	printDq(dq); // 2 3 4

	dq.pop_front();
	printDq(dq); // 3 4

	return 0;
}

1.5.6 insert

// single element(1)
iterator insert(const_iterator position, const value_type& val);
// fill(2)
iterator insert(const_iterator position, size_type n, const value_type& val);
// range(3)
template <class InputIterator> iterator insert(const_iterator position, InputIterator first, InputIterator last);
// move(4)
iterator insert(const_iterator position, value_type&& val);
// initializer list(5)
iterator insert(const_iterator position, initializer_list<value_type> il);


// 在position位置插入
#include <deque>
#include <iostream>
using namespace std;

template<typename T>
void printDq(deque<T>& dq)
{
	for (auto& e : dq)
	{
		cout << e << " ";
	}
	cout << endl;
}

int main()
{
	deque<int> dq1{ 1,2,3,4 };
	deque<int> dq2{ 11,22,33,44,55 };
	int val = 5;

	dq1.insert(dq1.end(), val); // single element
	printDq(dq1);               // 1 2 3 4 5

	dq1.insert(dq1.begin(), 1, 0); // fill
	printDq(dq1);                  // 0 1 2 3 4 5

	dq1.insert(dq1.begin() + 3, ++dq2.begin(), --dq2.end()); // range
	printDq(dq1);                                            // 0 1 2 22 33 44 3 4 5

	dq1.insert(dq1.begin(), 100); // move
	printDq(dq1);                 // 100 0 1 2 22 33 44 3 4 5

	dq1.insert(dq1.end(), { 20,21 }); // initializer list
	printDq(dq1);                     // 100 0 1 2 22 33 44 3 4 5 20 21

	return 0;
}

1.5.7 erase

iterator erase(const_iterator position);
iterator erase(const_iterator first, const_iterator last);
// 删除
#include <deque>
#include <iostream>
using namespace std;

template<typename T>
void printDq(deque<T>& dq)
{
	for (auto& e : dq)
	{
		cout << e << " ";
	}
	cout << endl;
}

int main()
{
	deque<int> dq{ 0,1,2,3,4 };

	dq.erase(dq.begin() + 3);
	printDq(dq); // 0 1 2 4

	dq.erase(++dq.begin(), --dq.end());
	printDq(dq); // 0 4

	return 0;
}

1.5.8 swap

void swap(deque& x);
// 交换
#include <deque>
#include <iostream>
using namespace std;

template<typename T>
void printDq(deque<T>& dq)
{
	for (auto& e : dq)
	{
		cout << e << " ";
	}
	cout << endl;
}

int main()
{
	deque<int> dq1{ 0,1,2,3,4 };
	deque<int> dq2{ 88,99 };

	dq1.swap(dq2);
	printDq(dq1); // 88 99
	printDq(dq2); // 0 1 2 3 4

	return 0;
}

1.5.9 clear

void clear() noexcept;
// 清空
#include <deque>
#include <iostream>
using namespace std;

int main()
{
	deque<int> dq{ 0,1,2,3,4 };

	dq.clear();
	if (dq.empty())
		cout << "dq被清空" << endl;
	else
		cout << "dq没被清空" << endl;
	// dq被清空

	return 0;
}

1.5.10 emplace

template <class... Args> iterator emplace(const_iterator position, Args&&... args);
// 对应insert,区别是:
// 当调用insert时,我们将元素类型的对象传递给它们,这些对象被拷贝到容器中
// 当调用emplace时,则是将参数传递给元素类型的构造函数,然后使用这些参数在容器管理的内存空间中直接构造元素

1.5.11 emplace_front

template <class... Args> void emplace_front(Args&&... args);
// 对应push_front,区别是:
// 当调用push_front时,我们将元素类型的对象传递给它们,这些对象被拷贝到容器中
// 当调用emplace_front时,则是将参数传递给元素类型的构造函数,然后使用这些参数在容器管理的内存空间中直接构造元素

1.5.12 emplace_back

template <class... Args> void emplace_back(Args&&... args);
// 对应push_back,区别是:
// 当调用push_back时,我们将元素类型的对象传递给它们,这些对象被拷贝到容器中
// 当调用emplace_back时,则是将参数传递给元素类型的构造函数,然后使用这些参数在容器管理的内存空间中直接构造元素

1.6 Allocator

1.6.1 get_allocator

allocator_type get_allocator() const noexcept;
// 返回空间配置器

2. Non-member function overloads

2.1 relational operators

// (1)
template <class T, class Alloc> bool operator==(const deque<T, Alloc>& lhs, const deque<T, Alloc>& rhs);
// (2)
template <class T, class Alloc> bool operator!=(const deque<T, Alloc>& lhs, const deque<T, Alloc>& rhs);
// (3)
template <class T, class Alloc> bool operator<(const deque<T, Alloc>& lhs, const deque<T, Alloc>& rhs);
// (4)
template <class T, class Alloc> bool operator<=(const deque<T, Alloc>& lhs, const deque<T, Alloc>& rhs);
// (5)
template <class T, class Alloc> bool operator>(const deque<T, Alloc>& lhs, const deque<T, Alloc>& rhs);
// (6)
template <class T, class Alloc> bool operator>=(const deque<T, Alloc>& lhs, const deque<T, Alloc>& rhs);

2.2 swap

template <class T, class Alloc> void swap (deque<T, Alloc>& x, deque<T, Alloc>& y);

3. deque对象的遍历方法

3.1 operator[]

#include <deque>
#include <iostream>
using namespace std;

int main()
{
	deque<int> dq{ 1,2,3,4 };

	for (size_t i = 0; i < dq.size(); ++i)
	{
		cout << dq[i] << " ";
	}
	cout << endl;
	// 1 2 3 4

	return 0;
}

3.2 迭代器

#include <deque>
#include <iostream>
using namespace std;

int main()
{
	deque<int> dq{ 1,2,3,4 };

	deque<int>::iterator it = dq.begin();
	while (it != dq.end())
	{
		cout << *it << " ";
		++it;
	}
	cout << endl;
	// 1 2 3 4

	auto rit = dq.rbegin();
	// deque<int>::reverse_iterator rit = dq.rbegin();
	while (rit != dq.rend())
	{
		cout << *rit << " ";
		++rit;
	}
	cout << endl;
	// 4 3 2 1

	return 0;
}

3.3 范围for

#include <deque>
#include <iostream>
using namespace std;

int main()
{
	deque<int> dq{ 1,2,3,4 };

	for (auto& e : dq)
	{
		cout << e << " ";

	}
	cout << endl;
	// 1 2 3 4

	return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Java中的Deque是一种双端队列,它可以在两端进行插入和删除操作。Deque是"Double Ended Queue"的缩写。在Java中,Deque接口是Queue接口的子接口,它扩展了Queue接口,提供了更多的方法来支持双端操作。 可以使用Java的LinkedList类来实现Deque接口。下面是一个使用Deque的简单示例: ```java import java.util.Deque; import java.util.LinkedList; public class DequeExample { public static void main(String[] args) { Deque<String> deque = new LinkedList<>(); // 在队尾添加元素 deque.addLast("element1"); deque.offerLast("element2"); deque.offer("element3"); // offer方法等同于offerLast // 在队头添加元素 deque.addFirst("element4"); deque.offerFirst("element5"); System.out.println("Deque: " + deque); // 获取并移除队尾元素 String lastElement = deque.removeLast(); System.out.println("Removed last element: " + lastElement); // 获取并移除队头元素 String firstElement = deque.removeFirst(); System.out.println("Removed first element: " + firstElement); System.out.println("Updated Deque: " + deque); } } ``` 输出结果: ``` Deque: [element5, element4, element1, element2, element3] Removed last element: element3 Removed first element: element5 Updated Deque: [element4, element1, element2] ``` 在上面的示例中,我们使用了Deque的常用方法,如addFirst、addLast、offerFirst、offerLast、removeFirst和removeLast等。 希望这个示例对你有帮助!如果还有其他问题,请随时提问。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值