c++容器

1、vector容器

1.1vector性质

        a)该容器的数据结构和数组相似,被称为单端数组

        b)在存储数据时不是在原有空间上往后拓展,而是找到一个新的空间,将原数据深拷贝到新空间,释放原空间。该过程被称为动态拓展

        

        vector迭代器支持随机访问。

1.2 vector构造函数

	std::vector<int> vec1{};//无参构造

	std::vector<int> vec2(3, 4);//初始化3个元素4到int型vector中

	std::vector<int> vec3(vec2.begin(), vec2.end());//迭代器初始化

	std::vector<int> vec4(vec3);//拷贝构造

 注意:拷贝构造函数中为深拷贝

1.3 vector赋值操作

	std::vector<float> vec1 = temp_vec;//operator=,深拷贝形式

	std::vector<float> vec2;

	vec2.assign(3, 8); // n个elem赋值

	vec2.assign(vec1.begin(), vec1.end());//区间赋值,这里是区间是迭代器

 1.4 vector容量和大小

void Print_vec(std::vector<float>& vec) {
	for (auto i : vec) {
		cout << i << " ";

	}
	cout << endl;
}
int main() {

	//初始化vector
	std::vector<float> vec(5, 8);
	
	std::cout << vec.empty() << std::endl; ;//判断是否为空
	std::cout << vec.size() << std::endl; //输出vector容器中元素数量
	std::cout << vec.capacity() << std::endl; //输出vector容器中容量

	vec.resize(10); //重新指定vec的元素数量,多余的默认0填充
	vec.resize(15, 3);//重新指定vec的元素数量的重载,可以指定填充值

	Print_vec(vec);
	system("pause");
	return 0;
}

1.5 vector插入删除

1.6vector数据存取

 1.7 vector互换容器swap

        目的:实现两个容器内容互换。

        实际用途:实现容器容量的收缩,减少内存浪费。

        (说明:当一个大容量的vector只有少量元素时,只使用resize重新指定其元素数量并不会改变其容量大小,而使用一个小容量的vector与其进行内容互换的实质是将两个容器的地址互换,此时使用的小容量vector是匿名类型,系统会自动把多余的容量内存释放。)

目的示例:

void Print_vec(std::vector<float>& vec) {
	for (auto i : vec) {
		cout << i << " ";

	}
	cout << endl;
}
int main() {

	//初始化vector
	std::vector<float> vec1(5, 8);
	std::vector<float> vec2(9, 4);

	Print_vec(vec1);
	Print_vec(vec2);

	vec1.swap(vec2);
	
	Print_vec(vec1);
	Print_vec(vec2);

	system("pause");
	return 0;
}

实际用途示例:

	std::vector<float> vec1(10000, 8);
	std::vector<float> vec2(9, 4);
	
	std::cout << vec1.capacity() << std::endl;
	std::cout << vec1.size() << std::endl;
	vec1.swap(vec2);

	std::cout << vec1.capacity() << std::endl;
	std::cout << vec1.size() << std::endl;

 1.8 vector预留空间

        目的:减少vector在动态拓展时的拓展次数,即减少从原空间拷贝到新空间的次数。

        接口:vec.reserve(r_size)

int main() {

	//初始化vector
	//统计开辟空间次数,利用指针指向vec的首地址,当指针地址改变则说明开辟了一次空间
	int* p = NULL;
	int num = 0;
	std::vector<int> vec;

	vec.reserve(10000);

	for (int i = 0; i < 10000; ++i) {
		vec.push_back(i);
		if (p != &vec[0]) {
			p = &vec[0];
			num++;
		}
	}

	std::cout << num << std::endl;
	system("pause");
	return 0;
}

预留空间与不预留空间的动态拓展次数对比:

 

2、deque容器(双向队列)

2.1 deque性质

        a)双端数组,可以直接在头端进行数据插入。

        b)与vector的区别:deque在头端插删数据的效率高于vector,vector访问数据的速度比deque快,即分别在靠头端的数据更改整体数据访问速度上有速度差异。

        c)deque使用多个缓冲区来保存数据,使用中控器来维护指向这些缓冲区的地址。

        d)deque迭代器支持随机访问

 2.2 deque构造函数

void Printdq(const std::deque<int>& d) {

	//常引用时使用的只读迭代器
	for (std::deque<int>::const_iterator c_iter = d.begin(); c_iter != d.end(); ++c_iter) {
		//*c_iter = 100;
		std::cout << *c_iter << " ";
	}
	std::cout << std::endl;
}
int main() {

	//初始化deque
	std::deque<int> deq1{};
	deq1.push_back(2);
	deq1.push_front(3);
	Printdq(deq1);
	//n个elem
	std::deque<int> deq2(4, 55);
	Printdq(deq2);

	//拷贝构造1
	std::deque<int> deq3(deq2);
	Printdq(deq3);
	//拷贝构造2
	std::deque<int> deq4(deq1.begin(), deq1.end());
	Printdq(deq4);
	system("pause");
	return 0;
}

 2.3 deque赋值操作

int main() {

	//初始化deque
	std::deque<int> deq1(10,7);
	Printdq(deq1);
	
	// operator=
	std::deque<int> deq2 = deq1;

	//assign
	std::deque<int> deq3;
	deq3.assign(deq2.begin(), deq2.end());

	std::deque<int> deq4;
	deq4.assign(8, 9);//n个elem assign

	system("pause");
	return 0;
}

2.4 deque大小操作

注:deque容器没有与vector类似的容量获取接口。 

int main() {

	//初始化deque
	std::deque<int> deq1(10,7);
	Printdq(deq1);
	
	std::cout << deq1.empty() << std::endl;
	std::cout << deq1.size() << std::endl;

	deq1.resize(15);
	deq1.resize(20,99);
	Printdq(deq1);
	deq1.resize(5);
	Printdq(deq1);

	system("pause");
	return 0;
}

 2.5 deque插入和删除        

int main() {

	//初始化deque
	std::deque<int> deq1(10,7);

	//前后插入
	deq1.push_front(3);
	deq1.push_back(9);
	Printdq(deq1);
	
	//前后删除
	deq1.pop_front();
	deq1.pop_back();
	Printdq(deq1);

	//insert指定位置插入
	std::deque<int> deq2(4, 5);
	deq1.insert(deq1.begin()+1, 2); //在deque第2个位置插入元素2
	Printdq(deq1);

	deq1.insert(deq1.begin(), 4, 5);//在deque头端插入4个5
	Printdq(deq1);

	deq1.insert(deq1.begin() + 2, deq2.begin(), deq2.end() - 2);//在deque第3个位置插入deq2的末尾前所有元素
	Printdq(deq1);

	//删除指定区间元素
	deq1.erase(deq1.begin() + 1, deq1.end());

	//全部删除
	deq1.clear();

	std::cout << deq1.empty() << std::endl;
	std::cout << deq1.size() << std::endl;

	system("pause");
	return 0;
}

 2.6 deque数据存取

2.7 deque排序操作

        目的:实现对deque容器中的元素排序。

void Printdq(const std::deque<int>& d) {

	//常引用时使用的只读迭代器
	for (std::deque<int>::const_iterator c_iter = d.begin(); c_iter != d.end(); ++c_iter) {
		//*c_iter = 100;
		std::cout << *c_iter << " ";
	}
	std::cout << std::endl;
}
int main() {

	//初始化deque
	std::deque<int> deq1{1,4,2,4,6,1,3};

	std::sort(deq1.begin(), deq1.end());

	Printdq(deq1);
	system("pause");
	return 0;
}

 3、stack容器(栈)

3.1 性质

        a)stack容器中的元素遵循先入后出原则(FILO),只有一个出口

        b)stack容器只有栈顶中的元素才可以被外界使用不允许有遍历行为。

        c)入栈push,出栈pop。

 3.2 stack常用接口

int main() {

	//构造stack
	std::stack<int> st1{};
	std::stack<int> st2{};

	//数据存取
	st1.push(3);
	st1.push(4);
	st1.push(5);
	st1.pop();
	std::cout << st1.top() << std::endl;

	//大小操作
	std::cout << st1.size() << std::endl;
	std::cout << st1.empty() << std::endl;

	//赋值操作
	st2 = st1;
	//验证深浅拷贝
	st2.pop();
	std::cout << st1.top() << std::endl;
	//结果为深拷贝

	system("pause");
	return 0;
}

4、queue容器(队列)

4.1 queue性质

        queue遵循先入先出原则(FIFO),具有两个出口,队头和队尾,只能从队尾和队头利用元素(队尾push,队头pop),因此queue不能遍历

 4.2 queue常用接口

5、list容器(双向循环链表)

5.1 list性质

        a)链表为非连续的存储结构,其元素之间的逻辑顺序通过指针实现。

        b)链表由一系列结点组成,每个节点具有数据域指针域,分别用于存储当前位置元素指向下一元素地址

        c)stl中的list容器是双向循环链表,即其指针域具有前后两元素的地址,且第一个元素的前指针指向该链表最后一个元素的地址,最后一个元素的后指针指向该链表第一个元素的地址。

        d)list的插入/删除不会造成原有迭代器的失效,迭代器只支持前移和后移(iter++/iter--)

        优点:

        1、链表可以对任意位置快速插入和删除(仅需修改对应位置的相关指针指向)。

        2、链表采用动态存储分配,不会造成内存浪费和溢出。

        缺点:遍历速度较数组慢(链表每次都要通过指针域获取下一元素)。

 

5.2 list构造函数

int main() {

	//构造list
	std::list<double> lis1;
	lis1.push_back(2);
	lis1.push_back(3);
	lis1.push_back(4);

	std::list<double> lis2(4, 6.);

	std::list<double> lis3(lis1.begin(), lis1.end());

	std::list<double> lis4(lis3);

	system("pause");
	return 0;
}

5.3 list赋值和交换

int main() {

	//构造list
	std::list<double> lis1;
	lis1.push_back(2);
	lis1.push_back(3);
	lis1.push_back(4);

	std::list<double> lis2;
	std::list<double> lis3;
	std::list<double> lis4;

	//赋值操作
	lis2 = lis1;
	lis3.assign(lis1.begin(), lis1.end());
	lis4.assign(4, 6.);

	//交换
	lis1.swap(lis4);

	system("pause");
	return 0;
}

5.4 list大小操作

int main() {

	//构造list
	std::list<double> lis1;
	lis1.push_back(2);
	lis1.push_back(3);
	lis1.push_back(4);

	std::cout << lis1.size() << std::endl;
	std::cout << lis1.empty() << std::endl;

	lis1.resize(5);
	PrintList(lis1);

	lis1.resize(8,10);
	PrintList(lis1);

	lis1.resize(3);
	PrintList(lis1);

	system("pause");
	return 0;
}

 

5.5 list插入和删除

int main() {

	//构造list
	std::list<double> lis1;
	std::list<double> lis2(5, 99);
	//插入元素
	lis1.push_back(2);
	lis1.push_back(3);
	lis1.push_back(4);
	lis1.push_front(6);
	lis1.push_front(9);

	lis1.pop_back();
	lis1.pop_front();

	//指定位置插入元素
	lis1.insert(lis1.begin(), 3);
	lis1.insert(lis1.begin(), 4, 3);
	lis1.insert(lis1.begin(), lis2.begin()++,lis2.end()); //只能对迭代器使用++/--

	//删除
	lis1.erase(lis1.begin());
	lis1.erase(lis1.begin(), lis1.begin()++);

	lis1.remove(99);
	lis1.clear();

	PrintList(lis1);

	system("pause");
	return 0;
}

5.6 list数据存取

int main() {

	//构造list
	std::list<double> lis1;
	std::list<double> lis2(5, 99);
	//插入元素
	lis1.push_back(2);
	lis1.push_back(3);
	lis1.push_back(4);
	lis1.push_front(6);
	lis1.push_front(9);

	std::cout << lis1.front() << std::endl;
	std::cout << lis1.back() << std::endl;
	lis1.back() = 10;
	std::cout << lis1.back() << std::endl;
	PrintList(lis1);

	system("pause");
	return 0;
}

5.6 list反转和排序

注:

        a)list的反转和排序是由stl提供的list成员函数,即使用sort(iter.begin(),iter.end())是错误的。

        b)list排序默认为从小到大,如需获取降序队列,须构造相应的bool模板函数或list元素类型作为输入类型的bool函数

        c)如果需要比较自定义类型,同样自行构造相应的bool函数,在其中对自定义成员变量进行比较输出bool即可。

template<class T>
bool Max_to_Min(T a, T b) {
	return a > b;
}

int main() {

	//构造list
	std::list<double> lis1;
	//插入元素
	lis1.push_back(2);
	lis1.push_back(3);
	lis1.push_back(4);
	lis1.push_front(6);
	lis1.push_front(9);

	//反转
	std::cout << "反转前: " << std::endl;
	PrintList(lis1);
	lis1.reverse();
	std::cout << "反转后: " << std::endl;
	PrintList(lis1);
	
	//排序
	std::cout << "升序排序: " << std::endl;
	std::cout << "排序前: " << std::endl;
	PrintList(lis1);
	lis1.sort();
	std::cout << "排序后: " << std::endl;
	PrintList(lis1);
	std::cout << std::endl;

	std::cout << "降序排序: " << std::endl;
	std::cout << "排序前: " << std::endl;
	PrintList(lis1);
	lis1.sort(Max_to_Min<double>);
	std::cout << "排序后: " << std::endl;
	PrintList(lis1);

	system("pause");
	return 0;
}

 6、set/multiset容器(集合)

6.1 性质

        a)所有元素在插入时会被自动排序,set/multiset属于关联式容器,基于二叉树实现。

        b)set和multiset区别,set不允许有重复元素,multiset允许重复元素。

        c)set不支持随机读取。

 6.2 构造和赋值

void pirntSet(const std::set<int>& s) {
	for (std::set<int>::const_iterator iter = s.begin(); iter != s.end(); ++iter) {
		std::cout << *iter << " ";
	}
	std::cout << std::endl;
}


int main() {

	//构造set/multiset
	std::set<int> s1;
	std::multiset<int> ms1;

	s1.insert(1);
	s1.insert(1);
	s1.insert(4);
	s1.insert(2);
	s1.insert(3);
	s1.insert(1);

	pirntSet(s1);

	//拷贝构造
	std::set<int> s2(s1);

	//operator=
	std::set<int> s3;
	s3 = s1;

	pirntSet(s2);
	pirntSet(s3);
	system("pause");
	return 0;
}

6.3 set大小和交换

 6.4 set插入和删除

 6.5 set查找和统计

 6.6 set与multiset区别

 set容器在使用insert接口时,具有pair类型返回值,用于接受迭代器和是否插入成功的bool值。

int main() {

	//构造set/multiset
	std::set<int> s1;
	std::multiset<int> ms1;

	s1.insert(1);
	ms1.insert(1);

	pair<std::set<int>::iterator, bool> ret = s1.insert(1);
	if (ret.second) {
		std::cout << "插入成功" << std::endl;
	}
	else {
		std::cout << "插入失败" << std::endl;
	}
	
	printSet(s1);
	printMultiSet(ms1);
	system("pause");
	return 0;
}

 6.7 对组创建

	pair<int, bool> p1(3, true);
	int a = 10;
	double b = 2.;
	pair<int, double> p2 = make_pair(a, b);

	//pair访问
	std::cout << p1.first << "," << p1.second << std::endl;

6.8 set容器排序规则修改

        set容器默认从小到大排序,利用仿函数可以修改排序规则。

        注:修改排序规则后再进行insert插值,set不会修改排序规则后之前插入的元素排序

6.8.1 对内置类型排序规则修改

        在初始化时进行如下修改即可:

        set<int , 包含排序规则仿函数的类名>  set1;

//使用类来重载()运算符是为了防止正常的函数使用()出错

class MySort {
public:
	bool operator()(const int &a, const int& b) const{
		return a > b;
	}
};
int main() {

	//构造set/multiset
	std::set<int, MySort> s1;
	s1.insert(1);
	s1.insert(4);
	s1.insert(3);
	s1.insert(5);
	s1.insert(2);
	s1.insert(7);

	std::cout << "set" << std::endl;
	for (std::set<int, MySort>::iterator iter = s1.begin(); iter != s1.end(); iter++) {
		std::cout << *iter << " ";
	}

	system("pause");
	return 0;
}

6.8.2 对自定义类型排序规则修改

class Person {
public:
	Person(string name,int power,double size) {
		this->m_Name = name;
		this->m_Power = power;
		this->m_Size = size;
	}
	string m_Name;
	int m_Power;
	double m_Size;
};

class SortPerson {
public:
	bool operator()(const Person& a, const Person& b) const{
		if (a.m_Power == b.m_Power) {
			return a.m_Size > b.m_Size;
		}
		else
			return a.m_Power > b.m_Power;
	}
};
int main() {

	//构造set/multiset
	std::set<Person, SortPerson> s1;

	Person p1("Tom", 100, 50);
	Person p2("Aris", 80, 50);
	Person p3("Tom", 80, 75);

	s1.insert(p1);
	s1.insert(p2);
	s1.insert(p3);

	for (std::set<Person, SortPerson>::iterator iter = s1.begin(); iter != s1.end(); iter++) {
		std::cout << "m_Name: " << (*iter).m_Name << " m_Power: " << (*iter).m_Power << " m_Size: " << (*iter).m_Size << std::endl;
	}

	system("pause");
	return 0;
}

 7、map容器

7.1 map性质

        a)map所有元素都是pair,pair的第一个元素为键值key,第二个元素为实值value。(pair参见6.7)

        b)map所有元素根据键值自动排序

        c)map/multimap与set类似,属于关联式容器,底层基于二叉树实现。

        优点:map可以根据key值快速找到value。

        map与maltimap区别:map不允许有重复的key值,multimap运行重复key值。

7.2 map构造、赋值

 

void printMap(const map<int, float>& m) {
	for (map<int, float>::const_iterator iter = m.begin(); iter != m.end(); ++iter) {
		cout << (*iter).first << " ," << (*iter).second << endl;;
	}
}
int main() {

	//构造map
	map<int, float> map1;
	map1.insert(pair<int, float>(2, 3.));
	map1.insert(pair<int, float>(1, 34.));
	map1.insert(pair<int, float>(4, 5.));

	map<int, float> map2(map1);

	map<int, float> map3 = map1;
	printMap(map1);

	system("pause");
	return 0;
}

 7.3 map大小和交换

	map<int, float> map1;
	map1.insert(pair<int, float>(2, 3.));
	map1.insert(pair<int, float>(1, 34.));
	map1.insert(pair<int, float>(4, 5.));

	map<int, float> map2(map1);

	map<int, float> map3;
	map3.insert(pair<int, float>(3, 15.));
	printMap(map1);
	cout << map1.size() << endl;
	cout << map1.empty() << endl;

	map1.swap(map3);
	printMap(map1);

7.4 map插入和删除

7.5 map查找、统计

7.6 map排序

        map排序与set排序类似,都需要定义相关仿函数才能更改排序顺序。

        a)内置类型的map排序顺序更改:

class Mapsort {
public:
	bool operator()(const int & p1, const int& p2)const {
		return p1 > p2;
	}
};
int main() {

	//构造map
	map<int, float,Mapsort> map1;
	map1.insert(pair<int, float>(2, 3.));
	map1.insert(pair<int, float>(1, 34.));
	map1.insert(pair<int, float>(4, 5.));
	map1.insert(pair<int, float>(7, 52.));
	map1.insert(pair<int, float>(8, 35.));

	for (map<int, float, Mapsort>::iterator iter = map1.begin(); iter != map1.end(); ++iter) {
		cout << (*iter).first << " ," << (*iter).second << endl;;
	}
	cout << endl;
	system("pause");
	return 0;
}

        b)自定义类型的map顺序修改:

class Person {
public:
	Person(string name,int power,double size) {
		this->m_Name = name;
		this->m_Power = power;
		this->m_Size = size;
	}
	string m_Name;
	int m_Power;
	double m_Size;
};

class SortPerson {
public:
	bool operator()(const Person& a, const Person& b) const{
		if (a.m_Power == b.m_Power) {
			return a.m_Size > b.m_Size;
		}
		else
			return a.m_Power > b.m_Power;
	}
};

int main() {

	//构造map
	map<Person, float, SortPerson> map1;

	Person p1("Tom", 324, 12);
	Person p2("Asdo", 56, 120);
	Person p3("Utuma", 324, 56);
	Person p4("Laxiy", 78, 70);
	Person p5("Caisax", 56, 86);

	map1.insert(pair<Person, float>(p1, 3.));
	map1.insert(pair<Person, float>(p2, 34.));
	map1.insert(pair<Person, float>(p3, 5.));
	map1.insert(pair<Person, float>(p4, 52.));
	map1.insert(pair<Person, float>(p5, 35.));

	for (map<Person, float, SortPerson>::iterator iter = map1.begin(); iter != map1.end(); ++iter) {
		cout << "m_Name:" << (*iter).first.m_Name;
		cout << "\tm_Power:" << (*iter).first.m_Power;
		cout << "\tm_Size:" << (*iter).first.m_Size;
		cout << "\tvalue:" << (*iter).second;

		cout << endl;
	}
	cout << endl;
	system("pause");
	return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值