【stl容器--实践操作】
创始人
2024-05-10 08:03:25
0

目录:

  • 前言
  • 一、string
    • (一)初始化 、 赋值 、 拼接
    • (二)单个字符的访问和修改
      • []、at()
    • (三)插入和删除
      • insert 、erase
    • (四)查找和替换
      • find、rfind、replace
    • (五)比较
      • compare
    • (六)获取子串
      • substr
  • 二、vector
    • (一)初始化和赋值 --(4+3)
      • =、assign
    • (二)访问数据 -- (4)
      • []、at()、front、back
    • (三)插入、删除和清空
      • insert、erase、clear
    • (四)大小和容量
      • size、capacity、resize
    • (五)交换
      • swap
    • (六)预开辟空间
      • reserve
  • 三、deque
  • 四、stack
  • 五、queue
  • 六、list
    • 构造、赋值、交换、大小和容量、插入、删除和清空、访问数据、
  • 七、set、multiset
    • (一)初始化、赋值
      • =
    • (二)插入、删除
      • insert、erase、clear
    • (三)查找、统计
      • find、count
    • (四)大小、交换
      • size、swap
    • (五)排序
  • 拓展:
    • pair
  • 八、map、multimap
    • (一)初始化、赋值
    • (二)插入、删除
      • insert、erase、clear
    • (三)查找、统计
      • find、count
    • (四)大小、交换
      • size、empty、swap
    • (五)排序
  • 总结

前言

打怪升级:第15天
在这里插入图片描述

一、string

string类对string变量、字符串(char*)以及单个字符(char)一般都有对应的函数。
string本质上就是字符串,内部原理是char*(了解过C语言的朋友应该可以更好地理解下面的内容)

(一)初始化 、 赋值 、 拼接

c++重载的函数是非常多的,我们需要做的是先来见识一番,之后根据自己的习惯和需求掌握其中几种即可。
在这里插入图片描述

//  string四种初始化方式
string s1;    //  无参构造
string s2("hello string");  //  使用字符串初始化
string s3(s2);       //  使用同为string的s2初始化(拷贝构造)
string s4(10, 'w');  //  使用字符初始化
// 补充: string s5(s2.substr(0,10));   拷贝构造:s2从下标为0的位置开始往后10个字符

示例:
在这里插入图片描述

// string赋值方式  --  对 operator= 的重载
char* str="hello string";
string s6;
s6=str;
s6=s2;
s6='w';// 使用函数赋值  assign()
s6.assign(str);   //  使用字符串赋值
s6.assign(str, n1);  //  从下标为n1处开始
s6.assign(str, n1, n2); //  从下标为n1处开始,前n2个字符
s6.assign(s2);
//s6.assign(s2, n1);  这个函数在vs中可以使用,但是在Dev上识别不出来,应该是vs对assign函数做了扩展。
//s6.assign(s2, n1, n2);
s6.assign(10, 'w');

在这里插入图片描述


(二)单个字符的访问和修改

[]、at()

string s1("hello");
for(int i = 0; i < s1.size(); i++)
{cout << s1.at(i) << ' ';  // 等同于 s1[i] 
}
cout << endl;

(三)插入和删除

insert 、erase

在这里插入图片描述

	string s1("hello");s1.insert(s1.size(), " 靓仔");cout << s1 << endl;s1.erase(5, s1.size() - 5);   //  如果第二个数据大于后面剩余的字符个数,那就只会把后面的字符全部删掉cout << s1 << endl;

运行实例:
在这里插入图片描述


(四)查找和替换

find、rfind、replace

find函数在找不到时会返回 string::npos
在这里插入图片描述

string s7;
int pos = s7.find("bit", n1, n2);  // 在s7中,从下标为n1的位置开始,前n2个字符中是否存在字符串"bit"//	找到了返回下标,找不到就返回EOF
s7.rfind();      //   从右往左查找,找最后一次出现的位置
s7="abcdefghigklmn";
s7.replace(2, 0, "0000");     //  替换下标为2的位置0个字符为字符串"0000",等价于:插入     

运行实例:
在这里插入图片描述


(五)比较

compare

等于:返回 0
大于: 返回 1
小于:返回 -1

void test05()
{string s1("hello");string s2("hello");cout << s1.compare(s2) << endl;
}

(六)获取子串

substr

在这里插入图片描述

	string s1 = "panda@csdn.com";int pos = s1.find('@');string s2 = s1.substr(0, pos);cout << "用户名:" << s2 << endl;

运行实例:在这里插入图片描述


二、vector

不定长的单头数组
在这里插入图片描述
在这里插入图片描述

(一)初始化和赋值 --(4+3)

=、assign

	//  初始化    --  4种vectorv1;  //  无参构造vectorv2(v1);   //  拷贝构造vectorv3(v1.begin(), v1.end());  // 通过区间初始化vectorv4(10, 8);   //  使用n个数字初始化//   赋值   --  3种cout << "赋值" << endl;vectorv5;v5 = v1;       //  operator=            vectorv6;v6.assign(v1.begin(), v1.end());  //  assign()函数,区间赋值vectorv8;v8.assign(10, 8);    //  使用n个数字赋值

运行实例:
在这里插入图片描述


(二)访问数据 – (4)

[]、at()、front、back

vectorv1;InitVector(v1);// operator[]for (int i = 0; i < v1.size(); i++){cout << v1[i] << ' ';}cout << endl;// at()for (int i = 0; i < v1.size(); i++){cout << v1.at(i) << ' ';}cout << endl;// front(), back()cout << v1.front() << ' ' << v1.back() << endl;//补充: begin(), end()               iterator:迭代器for(vector::iterator it = v1.begin(); it < v1.end(); it++){cout << *it << ' ';}cout << endl;

运行实例:在这里插入图片描述


(三)插入、删除和清空

insert、erase、clear

vectorv1;InitVector(v1);PrintVector(v1);v1.pop_back();     //  尾删PrintVector(v1);v1.insert(v1.begin() + 2, 10);  //  在下标为2的位置插入一个 10PrintVector(v1); v1.insert(v1.begin(), 2, 100);  //  在最前面插入两个 100PrintVector(v1);v1.erase(v1.end() - 1);  //  删除最后一个位置的数据PrintVector(v1);v1.erase(v1.begin(), v1.begin() + 2); // 删除 [0,2)之间的数据PrintVector(v1);v1.clear();				 // 清空PrintVector(v1);

运行实例:在这里插入图片描述


(四)大小和容量

size、capacity、resize

	vectorv1;InitVector(v1);v1.resize(12);    //  改变容器大小,空位默认用 0 填充bool temp = v1.empty(); //  判空cout << "size->" << v1.size() << endl;cout << "capacity->" << v1.capacity() << endl;v1.push_back(12);PrintVector(v1);

运行实例:
在这里插入图片描述


(五)交换

swap

	vectorv1;InitVector(v1);PrintVector(v1);vectorv2(6, 'w');PrintVector(v2);swap(v1, v2);PrintVector(v1);PrintVector(v2);// 收缩内存  --  借助匿名容器v1.assign(100000, 1);cout << "交换前:size->" << v1.size() << " capacity->" << v1.capacity() << endl;v1.resize(10);cout << "resize:size->" << v1.size() << " capacity->" << v1.capacity() << endl;vector(v1).swap(v1);    //   匿名容器执行完当前语句后被系统回收cout << "交换后:size->" << v1.size() << " capacity->" << v1.capacity() << endl;

运行实例:
在这里插入图片描述


(六)预开辟空间

reserve

	cout << "系统自动更新capacity" << endl;vectorv1;int* pi = NULL;int num = 0;for (int i = 0; i < 100000; i++){v1.push_back(i);if (pi != &v1[0]){pi = &v1[0];num++;}}cout << "重新开辟内存次数:" << num << endl;cout << "提前开辟好空间" << endl;vectorv2;v2.reserve(100000);  //  reserve是预开辟空间,但是实际大小还是0int* ppi = NULL;num = 0;for (int i = 0; i < 100000; i++){v2.push_back(i);if (ppi != &v2[0]){ppi = &v2[0];num++;}}cout << "重新开辟内存次数:" << num << endl;

运行实例:
在这里插入图片描述
注意:如果发生了重新开辟内存,那么之前声明的迭代器就需要进行更新才能使用。


三、deque

双端数组(双端队列) – 操作选项同上面的vector
在这里插入图片描述


四、stack

:stack是一种非常简单的数据结构,只能从栈顶进出数据
它和vector并不一样,
vector是一个数组,虽然是单端数组,但是数组有的操作vector也有,比如遍历、排序、POS位置的插入和删除等
而stack则有更多的限制,只能访问栈顶的数据,如果想要访问后面的数据就需要将栈顶数据出栈,那么栈顶数据就丢失了,
由于栈的限制很多,所以它操作起来非常简单。(因为它能做的操作少啊)
在这里插入图片描述
在这里插入图片描述

class Person
{
public:Person(string name, int age){this->_name = name;this->_age = age;}string _name;int _age;
};//  stack
void test03()
{stacks;Person p1("宁姚", 32);Person p2("陈平安", 33);Person p3("天真", 5000);s.push(p1);              // 入栈s.push(p2);s.push(p3);cout << "size->" << s.size() << endl;   //  获取大小while (!s.empty())  //  判空{cout << "name->" << s.top()._name << "\tage->" << s.top()._age << endl;   //  获取栈顶数据s.pop();       //  出栈}cout << "size->" << s.size() << endl;
}

举个栗子:
在这里插入图片描述


五、queue

队列:queue和stack一样也是很简单的容器,它的要求是只能在队头出数据,只能在队尾入数据
在这里插入图片描述在这里插入图片描述


六、list

链表:list (底层为双向循环链表)
在这里插入图片描述

构造、赋值、交换、大小和容量、插入、删除和清空、访问数据、

vector有的list基本上都有,并且用法完全相同(但是底层原理是不同的)。
list更多的操作:

  1. 删除:remove
  2. 翻转:reverse
  3. 排序:sort
    在这里插入图片描述

bool Mycompare(int a, int b)
{// 升序//return a < b;//  降序return a > b;
}void test04()
{listl1;for (int i = 10; i > 5; i--){l1.push_back(i);l1.push_front(1);}cout << "改变前:";for_each(l1.begin(), l1.end(), Print);  // Print()是自己写的函数模板cout << endl;cout << "翻转后:";l1.reverse();     //   翻转for_each(l1.begin(), l1.end(), Print);cout << endl;// 所有不支持随机访问的容器,不可以使用标准算法,既sort(),因此这里容器自己提供了 list.sort()算法// 对于自定义类型必须指定排序函数,不然编译器不知道如何排序cout << "升序列:";l1.sort();        //  排序  --  升序for_each(l1.begin(), l1.end(), Print);cout << endl;cout << "降序列:";l1.sort(MyCompare);  //  排序  --  降序:自己提供一个排序函数for_each(l1.begin(), l1.end(), Print);cout << endl;cout << "移除 1:";l1.remove(1);     //  移除for_each(l1.begin(), l1.end(), Print);cout << endl;
}

运行实例:
在这里插入图片描述

list没有的操作:

  1. 对数据的访问:at()、[ ]
    因为list底层是链表,无法像数组一样通过下标进行访问。
list::iterator it = li.begin(); // iterator 是迭代器,这里it可以当做一个指针使用,但是它并不是指针
it = it + 1; //  error ,链表不支持随机访问
it++;   //  right
it--;   //  right, 双向链表可以找到前后节点
//  这里说的是设立的思想,不过至于为什么支持 ++ 不支持 it + 1,那是因为大佬们在设计的时候只重载了 ++,而没有重载 + 号,
//  这是为了防止使用者 有了 +1, 就想用 +2 、 +300等的随机访问操作,这在链表中是无法使用的。

七、set、multiset

集合:set – (底层为红黑树
特点:在加入数据时会自动对数据进行排序,因此也叫关联式容器;
使用时只需包含头文件< set >;
set中不能出现重复的数据(重复数据不会被插入);
multiset可以出现重复数据。

(一)初始化、赋值

=

set的初始化和赋值比较简单,初始化只有默认构造和拷贝构造,赋值只有:=

sets1;    //  默认构造
sets2(s1); // 拷贝构造//   赋值
sets3;
s3=s2;

(二)插入、删除

insert、erase、clear

由于set在放入数据时会自动排序,无需设置将数据放到首部、尾部还是中间某个位置,
因此set容器放入数据只需要一个insert即可。

sets4;
s4.insert(10);
s4.insert(20);
s4.insert(50);
s4.insert(40);
s4.insert(30);
for(set::iterator it=s4.begin(); it!=s4.end(); ++it)cout<< *it<<' ';cout<

运行实例这里是引用

(三)查找、统计

find、count

在set中由于不能出现重复数据,因此count(key)只有0或1两个值。
在这里插入图片描述

void test06()
{sets;s.insert(1);s.insert(5);s.insert(4);s.insert(2);s.insert(3);set::iterator it = s.find(2);if (it == s.end())cout << "did not find" << endl;elsecout << *it << endl;it = s.find(20);if (it == s.end())cout << "did not find" << endl;elsecout << *it << endl;cout << "number of 2->" << s.count(2) << endl;
}

运行实例:
在这里插入图片描述


(四)大小、交换

size、swap

(五)排序

set在插入数据时直接对数据进行排序,默认是升序序列,如果我们要改变排序规则就需要在插入数据之前进行,
这里我们可以写一个仿函数(重载小括号),这里需要将仿函数写在类里面,因为set后面的括号里需要的是一个类型。
在这里插入图片描述

class MyCompare
{
public:templatebool operator()(t v1, t v2)const  //  vs中这个 const不能省略{return v1 > v2;}
};int main()
{sets1;s1.insert(50);s1.insert(20);s1.insert(40);s1.insert(30);s1.insert(10);for (set::iterator it = s1.begin(); it != s1.end(); it++)cout << *it << ' ';cout << endl;return 0;
}

结果:
在这里插入图片描述

对于自定义类型数据,我们必须设置比较函数

class Person
{
public:Person(string name, int age){this->_name = name;this->_age = age;}string _name;int _age;
};class MyCompare
{
public:bool operator()(const Person& s1, const Person& s2)const  //  const都不可省{return s1._name.compare(s2._name) >= 0;}
};int main()
{sets2;Person p1("陈平安", 32);Person p2("宁姚", 31);Person p3("裴钱", 24);s2.insert(p1);s2.insert(p2);s2.insert(p3);for (set::iterator it = s2.begin(); it != s2.end(); it++)cout << "name->" << (*it)._name << "age->" << it->_age << endl;return 0;
}

示例:
在这里插入图片描述


拓展:

pair

对组:pair,内置函数模板很少,这里我们了解一下它的初始化、赋值以及访问。
在这里插入图片描述

	vector >array;pairPerson("崔巉", 240);   //  初始化array.push_back(Person);Person = make_pair("左右", 230);   // 赋值array.push_back(Person);Person = make_pair("刘十六", 2000);array.push_back(Person);Person = make_pair("齐静春", 200);array.push_back(Person);Person = make_pair("老秀才", 300);array.push_back(Person);for(int i=0; i

运行实例:
在这里插入图片描述


八、map、multimap

图、查找表:map (底层为红黑树
map中所以元素都是pair;
pair中的第一个元素为key(键值),起到索引作用,第二个元素为value(实值);
map在插入数据时会按照键值进行升序排序,因此map也是关联式容器。
优点:
可以通过键值快速查找value。
map和multimap的区别:
map中不能出现重复的key,而multimap中可以(与set和multiset区别一样);
注意这里只限制key,而map中如果出现重复的value是可以的。

(一)初始化、赋值

初始化:默认构造和拷贝构造
赋值:operator=

void PrintMap(mapm)
{for (map::iterator it = m.begin(); it != m.end(); ++it){cout << "key->" << it->first << " value->" << it->second << endl;}cout << endl;
}void test04()
{// 创建map数组  --  底层为二叉树mapm1;   //  vs2022中不加const会报错// pairtmp;//tmp = make_pair(4, 40);m1.insert(pair (1, 10)); // 插入数据,插入过程中会自动按照key值排序m1.insert(pair(4, 40));m1.insert(pair(2, 20));m1.insert(pair(3, 30));PrintMap(m1);mapm2(m1);  //  拷贝构造PrintMap(m2);//  赋值mapm3;m3 = m1;PrintMap(m3);
}

运行实例:
在这里插入图片描述


(二)插入、删除

insert、erase、clear

在这里插入图片描述

void test05()
{// 这里讲解4中插入的方法mapm1;// 第一种m1.insert(pair(1, 10));// 第二种m1.insert(make_pair(3, 30));// 第三种m1.insert(map::value_type(2, 20));// 第四种m1[4] = 40;  //  key=4, value=40//  第四种一般用来插入数据,因为可以通过键值来访问value// 不建议用来访问数据,因为如果访问的键值不存在,编译器会自动创建 value为0的对组cout << m1[10] << endl;PrintMap(m1);
}

运行实例:
在这里插入图片描述


(三)查找、统计

find、count

同set


(四)大小、交换

size、empty、swap

同set


(五)排序

class MyCompare
{
public:bool operator()( int v1,  int v2)const{return v1 > v2;}
};void test08()
{mapm1;m1.insert(make_pair(1, 10));m1.insert(make_pair(2, 20));m1.insert(make_pair(3, 30));for (map::iterator it = m1.begin(); it != m1.end(); ++it){cout << "key->" << it->first << " value->" << it->second << endl;}cout << endl;
}

运行实例:
在这里插入图片描述


总结

查找:find
只有string类模板的find函数找到时返回值为下标,找不到则返回 string::npos
其他自带find函数以及标准函数返回值都为迭代器,找不到则返回 end() 。
单个数据访问:at
我们一般会觉得有了下标访问操作符就足够了,at会有些多余,
但是对于set、map这些容器是不能通过 [ ] 进行访问的,这时就需要at() 了,由此可知at() 更加通用。
迭代器
eg: vector v1;
vector::iterator it = v1.begin();
这里 it 就是一个迭代器,可以当做指针使用,但是实际上并不是指针,而是类模板,
迭代器通过重载指针的操作符 -> 、++、–等封装了一个指针;
是一个“可遍历STL( Standard Template Library)容器内全部或部分元素”的对象。
因此 it 不能使用 NULL初始化,而且v1.begin() 的返回值也不能赋给整形指针。
参考文章:迭代器和指针
resize 和 reserve
resize是调整大小,往大了调整后空位默认补0,
reserve是预开辟空间,但是此时的大小时没有改变的,比如说:
你现在有100块钱,银行说可以给你贷款50万,那么这50万就是你可以使用的,但是这些钱实际上还是属于银行的,你实际拥有的钱只有100块,你去相亲的时候不能说你现在拥有50万存款,
这里也是一样的,我们重新创建的变量,此时size=0, 我们reserve(100),这是“贷款”,并不是真的给你100的内存空间,你的实际大小还是0,
只有使用resize(100),调整了自身的大小之后才能够说我拥有50万的存款。
因此,在使用copy、merge等需要将数据移动到一个新的容器时,需要确保该容器拥有足够的空间,如果不够,就使用resize调整容器的大小。

大小
只有顺序表(数组)有容量这一说,链表是想要添加数据就找一块区域即可,因此可以说整个内存都是它的容量。
所以list、set、map这些只有size()函数,但都没有内置capacity() 函数。

声明:函数原型截图来源于黑马程序员的c++教学视频,本文也是在看过了视频之后进行的自我总结。

相关内容

热门资讯

喜欢穿一身黑的男生性格(喜欢穿... 今天百科达人给各位分享喜欢穿一身黑的男生性格的知识,其中也会对喜欢穿一身黑衣服的男人人好相处吗进行解...
发春是什么意思(思春和发春是什... 本篇文章极速百科给大家谈谈发春是什么意思,以及思春和发春是什么意思对应的知识点,希望对各位有所帮助,...
网络用语zl是什么意思(zl是... 今天给各位分享网络用语zl是什么意思的知识,其中也会对zl是啥意思是什么网络用语进行解释,如果能碰巧...
为什么酷狗音乐自己唱的歌不能下... 本篇文章极速百科小编给大家谈谈为什么酷狗音乐自己唱的歌不能下载到本地?,以及为什么酷狗下载的歌曲不是...
家里可以做假山养金鱼吗(假山能... 今天百科达人给各位分享家里可以做假山养金鱼吗的知识,其中也会对假山能放鱼缸里吗进行解释,如果能碰巧解...
华为下载未安装的文件去哪找(华... 今天百科达人给各位分享华为下载未安装的文件去哪找的知识,其中也会对华为下载未安装的文件去哪找到进行解...
四分五裂是什么生肖什么动物(四... 本篇文章极速百科小编给大家谈谈四分五裂是什么生肖什么动物,以及四分五裂打一生肖是什么对应的知识点,希...
怎么往应用助手里添加应用(应用... 今天百科达人给各位分享怎么往应用助手里添加应用的知识,其中也会对应用助手怎么添加微信进行解释,如果能...
客厅放八骏马摆件可以吗(家里摆... 今天给各位分享客厅放八骏马摆件可以吗的知识,其中也会对家里摆八骏马摆件好吗进行解释,如果能碰巧解决你...
苏州离哪个飞机场近(苏州离哪个... 本篇文章极速百科小编给大家谈谈苏州离哪个飞机场近,以及苏州离哪个飞机场近点对应的知识点,希望对各位有...