STL数据结构容器总结

本文详细介绍了STL中的序列式容器,包括Vector、List、Deque等,强调了它们的特点和使用场景。特别是Vector,其动态扩展可能导致迭代器失效。此外,还探讨了关联式容器如Set和Map,它们基于红黑树实现,自动排序元素。文章通过实例解释了各种容器的使用和操作,帮助理解STL容器的优势和适用范围。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1.序列式容器

Vector

vector的操作与array很像,唯一差别在于空间运用的灵活性。array是静态空间,vector是动态空间。

vector的实现技术,关键在于其对大小的控制以及重新配置时的数据移动效率。为了降低空间配置时的速度成本,实际配置的容量大小永远大于或者等于vector大小(vector.size())。当我们push_back()插入一个新元素时,先判断是否有备用空间,有就直接在备用空间上构造函数,并调整迭代器finish。如果没有就扩充空间(重新配置、移动数据、释放原空间)。

空间配置原则:如果原大小为0,则配置1.如果原大小不为0,则配置为原大小的两倍。前半段用来存放原数据,后半段用来存放新数据。

注意,所谓动态增加大小,不是在原空间之后接连续空间(无法保证原空间后还有可供配置的空间),而是以原大小的两倍另外配置一块较大空间,然后将原数据拷贝至新空间,然后才开始在原内容后构造新元素,并释放原空间。因此,对vector的任何操作,一旦引起空间重新配置,指向原空间的所有迭代器就失效了(vector的迭代器是普通指针)。

例子:
1、Ducci序列
对于一个n元组(a1,a2,…,an),可以对每个数求出它和下一个数的差的绝对值,得到一个新的n元组(|a1-a2|,|a2-a3|,…,|an-a1|),重复这个过程得到的序列称为Ducci序列。例如;(8,11,2,7)->(3,9,5,1)->(6,4,4,2)->(2,0,2,4)->(2,2,2,2)->(0,0,0,0).
也有的Ducci序列会一直循环下去。现在输入一个n元组(3<n<15),判断它最终会循环还是变成0.

<分析>
序列可以直接使用vector来表示,vector本身已经重载了等号运算符对两个容器的内容进行比较。直接使用“==”操作符即可。判断是否重复使用set<vector>

using namespace std
#define _for(i,a,b)  for( int i=(a); i<(b) ; ++i)
int readint() { int x;  scanf("%d",&x);  return x; }
int main(){
	int T = readint();
	vector<int>  seq ,zeroseq;
	set< vector<int> > seqs;
	while(T--){
		int n =readint();
		seq.clear();   zeroseq.resize(n);
		_for(i, 0, n)  seq.push_back( readint() ); 	
		bool zero = false;  bool loop = false;
		seqs.clear(), seqs.insert(seq);
		do{
				if(seq == zeroseq) { puts(" LOOP") ; break;}
				int a0 = seq[0];
				_for(i,0,n) {
						if (i == n-1)  seq[i] = abs(seq[i] - a0);
						else seq[i] = abs( seq[i]-seq[i+1] );		
				}
				if (seqs.count(seq)) { puts("LOOP"); break;} // seqs.count(seq)表示seq如果在seqs里已经存在则返回true;
				seqs.insert(seq);
		}while(true)
	} 
	return 0;
}

List

list不能再像vector一样用普通指针作为迭代器,因为其节点不能保证在存储空间中连续存在。

List有一个重要性质:插入(insert)操作和接合(splice)操作都不会造成原有的list迭代器失效。这在vector里面是不成立的,因为vector的插入操作可能造成记忆体重新配置,导致原有的迭代器全部失效。甚至list的元素删除(erase)操作,也只有“指向被删除元素”的迭代器失效,其他迭代器不受影响。

STL list 的节点node结构

template <class T>
struct  _list_node{
	typedef void* void_pointer;
	void_pointer prev;    //型别为void*,其实也可以设为 _list_node<T>*
	void_pointer next;
	T data;
}

插入操作完成后,新节点将位于哨兵迭代器(标示初插入点)所指节点的前方——这是STL对于插入操作的标准规范。

当我们push_back()将新元素插入到list尾端时,此函数内部调用了insert();
void push_back() (const T& x) { insert(end(),x);}
insert()是一个重载函数,有多种形式,其中一种简单的形式如下:首先配置并构造一个节点,然后在尾端进行适当的指针操作,将新节点插入进去。

//函数目的:在迭代器position所指位置插入一个节点,内容为x
iterator insert( iterator position, const  T& x){
	link_type tmp = creat_node(x);
	tmp ->next =position.node;
	tmp->prev = position.node->prev;
	(link_type(position.node->prev))->next = tmp;
	position.node ->prev = tmp;
	return tmp;
}

deque

vector 是单向开口的连续线性空间,deque则是一种双向开口的连续分段线性空间。vector从技术角度来说也可以在头尾两端进行操作,但是其头部操作效率

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值