• C++之STL容器(2/3)


    一.链表list

    1.创建

    list<int> iNum

    2.插入

    ①尾插法:push_back(data)

    iNum.push_back(1);

    ②头插法:  push_front(data)

    iNum.push_front(3);//头插法

    3.遍历

    ①不删除的方式遍历

    即用迭代器的方式进行遍历

    1. list<int>::iterator iter;
    2. for(iter=iNum.begin();iter!=iNum.end();iter++)
    3. {
    4. cout<<*iter<<" ";
    5. }

    ②删除方式遍历

    (可以从头部读一个删一个,也可以在尾部进行同样的操作,用back()访问元素&用pop_back进行删除)

    1. while(!iNum.empty())
    2. {
    3. cout<<iNum.front()<<" ";
    4. iNum.pop_front(); //头部删除
    5. }

    4.指定位置操作

    函数原型:iterator find(iterator begin,iterator end,data);返回的是一个迭代器,用auto偷懒(

    find没找的话,将返回end()所指向的位置。

    1. //函数原型:iterator find(iterator begin,iterator end,data);
    2. auto result=find(iNum.begin(),iNum.end(),2);
    3. //返回的是一个迭代器类型,此处是list<int>::iterator 类型
    4. //若没有找到,就是返回end结束的位置
    5. if(result==iNum.end())
    6. {
    7. cout<<"not find"<<endl;
    8. }
    9. iNum.insert(result,100);//该函数的作用是在result这个迭代器所指向的位置的前面插入100

    insert()需要传入两个参数,一个是迭代器类型,一个是需要插入的数据。插入的位置是在迭代器所指向位置的前面进行插入若需要在迭代器所指向位置后面进行插入,给这个迭代器位置+1即可。

    5.删除函数

    ①iNum.erase(迭代器)    

    会删除迭代器所指向的位置中的元素,然后原迭代器删除,返回一个新的迭代器,是指向原来所删除位置的下一个位置!!!(ps.  6.22终于理解了python列表的range()中的pop为什么删不干净了)

    ②区分三种写法(因为erase只能删除一个位置,所以此处需要删除所有指定的值)--"相同元素删除"

    写法一(×):

    1. int array[4]={1,2,2,3};
    2. list<int>data;
    3. for(list<int>::iterator iter=data.begin();iter!=data.end();iter++)
    4. {
    5. if(*iter==2)
    6. {
    7. data.erase(iter);
    8. }
    9. }

    报错:

     原因:当前迭代器已经被删除了,它无法再去做++运算。

    改进----

    写法二(×):

    1. int array[4]={1,2,2,3};
    2. list<int>data;
    3. for(list<int>::iterator iter=data.begin();iter!=data.end();iter++)
    4. {
    5. if(*iter==2)
    6. {
    7. iter=data.erase(iter);
    8. }
    9. }

    虽然不报错了。实际上iter在第一次被找到并按删除时,本身删完之后会++,在for里面也会++所以会跳过第一个2后面的2,于是会漏删一个。(删不干净)

    写法三(√):正确写法。

    1. int array[4]={1,2,2,3};
    2. list<int>data;
    3. for(list<int>::iterator iter=data.begin();iter!=data.end();)
    4. {
    5. if(*iter==2)
    6. {
    7. iter=data.erase(iter);
    8. }
    9. else
    10. {
    11. iter++;
    12. }
    13. }

    6.其他操作:

    reverse()   翻转链表函数。

    sort()         默认从小到大进行排序  

    1. #include<functional>
    2. iNum.sort(less<int>());
    3. iNum.sort(greater<int>());

     上面代码块中(需要包含头文件functional,less和greater都是类,()是里面被运算符重载过的)

            第一行是从小到大进行排序       <  -------less

            第二行是从大到小进行排序       > -------greater

    -------------以上:排序准则------------------

    swap()       交换

    7.操作自定义类型数据。

    list是无参构造,不能定长。

    需要注意的几个问题

    按照姓名进行查找find的写法(必须要自己写重载函数->需要按照什么查找就在重载函数里面按照该属性去实现。)

    ②按照age ||  name排序

            i)重载写法(利用已有的比较准则)(需要按照哪一个属性进行重载,就写哪一个重载)

    1. mmDate.sort(less<int>());//需要重载<
    2. mmDate.sort(greater<int>());//需要重载>

            ii)不采用重载方式,自己写比较准则

    1. //比较准则是一个函数指针,该函数的返回值是bool类型,两个参数
    2. bool compareByName(const MM&object1,const MM& object2)//比较准则
    3. {
    4. return object1.getName()<object2.getName();
    5. }
    6. mmDate.sort(compareByName);

    操作自定义类型数据相关代码:

    1. //操作自定义类型数据
    2. class MM
    3. {
    4. public:
    5. MM(string name, int age, int num) :name(name), age(age), num(num) {}
    6. void print()
    7. {
    8. cout << name << "\t" << age << "\t" << num << endl;
    9. }
    10. bool operator==(const string& name) const
    11. {
    12. return this->name == name;
    13. }
    14. bool operator<(const MM& object) const
    15. {
    16. return this->name < object.name;
    17. }
    18. string getName() const
    19. {
    20. return name;
    21. }
    22. int getAge() const
    23. {
    24. return age;
    25. }
    26. protected:
    27. string name;
    28. int age;
    29. int num;
    30. };
    31. bool compareByName(const MM& object1, const MM& object2)
    32. {
    33. return object1.getName() < object2.getName();
    34. }
    35. bool compareByAge(const MM& object1, const MM& object2)
    36. {
    37. return object1.getAge() < object2.getAge();
    38. }
    39. void testUserData()
    40. {
    41. list<MM> mmData;
    42. string name;
    43. int age;
    44. int num;
    45. while (1)
    46. {
    47. cout << "input MM:" << endl;
    48. cin >> name >> age >> num;
    49. mmData.push_back(MM(name, age, num));
    50. cout << "是否继续输入?" << endl;
    51. while (cin.get() != '\n');
    52. if (cin.get() == 'n')
    53. break;
    54. }
    55. cout << "姓名\t年龄\t编号" << endl;
    56. for (MM v : mmData)
    57. {
    58. v.print();
    59. }
    60. //二进制“==”: 没有找到接受“MM”类型的左操作数的运算符(或没有可接受的转换)
    61. auto result = find(mmData.begin(), mmData.end(), "name1");
    62. //重载方式
    63. mmData.sort(less<MM>()); //重载<
    64. //mmData.sort(greater<MM>()); //重载>
    65. //不采用重载方式,需要自己写比较准则
    66. mmData.sort(compareByName);
    67. mmData.sort(compareByAge);
    68. }

    注意:重载函数的写法与需求。

    这一行,我们的目标是按照姓名进行查找name1对应的位置, 在MM类中需要写的重载函数中传入的参数应该是const string类型!!! 而非一个对象!!!

     二、栈stack

    1.栈的相关原理:先进后出    注:无迭代器,是一个适配器

    2.相关操作:

    push(data)

    pop():  删除操作(无指定位置删除or插入)

    top() :获取栈顶元素

    size()和empty()

    1. #include <stack>
    2. #include <iostream>
    3. #include <string>
    4. using namespace std;
    5. void testStack()
    6. {
    7. //穿脱原则
    8. //FILO
    9. //1 2 3
    10. //3 2 1
    11. //push(data)
    12. //pop() 删除
    13. //top() 获取栈顶元素
    14. //size() empty();
    15. stack<int> intStack;
    16. for (int i = 0; i < 3; i++)
    17. {
    18. intStack.push(i);
    19. }
    20. while (!intStack.empty())
    21. {
    22. cout << intStack.top() << "\t";
    23. intStack.pop();
    24. }
    25. cout << endl;
    26. }

    3.应用:①中缀表达式的转换;②将一个数字转成二进制(代码见下)

    1. void NumTobinary(int data)
    2. {
    3. stack<int> bin;
    4. while (data)
    5. {
    6. bin.push(data % 2);
    7. data = data / 2;
    8. }
    9. if (bin.size() < 8)
    10. {
    11. for (int i = bin.size(); i < 8; i++)
    12. {
    13. bin.push(0);
    14. }
    15. }
    16. while (!bin.empty())
    17. {
    18. cout << bin.top();
    19. bin.pop();
    20. }
    21. cout << endl;
    22. //中缀和后缀表达式资料看看
    23. //a+b 中缀
    24. //ab+
    25. //a+b*c+d;
    26. }

     三、双向队列deque

    (即可代表栈,也可以代表队列)->用双向链表也可以描述这一操作

    1.插入操作同list(①尾插法②头插法)

    1. deque<int> deData;
    2. for (int i = 0; i < 3; i++)
    3. {
    4. deData.push_back(i); //尾插法入队
    5. deData.push_front(i); //头插法入队
    6. }

    2.此队列既可以从头部出来,也可以从尾部出来

    ①从头出来

    1. //从头出来
    2. void pop_front_dequeue(deque<int> dData)
    3. {
    4. while (!dData.empty())
    5. {
    6. cout << dData.front()<<" ";
    7. dData.pop_front();
    8. }
    9. cout << endl;
    10. }

    ②从尾部出来

    1. //从尾出来
    2. void pop_back_dequeue(deque<int> dData)
    3. {
    4. while (!dData.empty())
    5. {
    6. cout << dData.back() << " ";
    7. dData.pop_back();
    8. }
    9. cout << endl;
    10. }

    四、普通队列 queue

    双向队列用的较多(速度更快)

    1.原理:先进先出

    2.入队:push(data)

    3.获取队头元素: front()

    4.出队:pop()

    (注:若不想删除原容器改动,那么就函数传参生成拷贝本操作即可。)

    5.应用:层次遍历二叉树BFS(广度优先搜索)

    五、优先队列 priority_queue

    1.头文件可以写以下两个之一

    1. #include<concurrent_priority_queue.h>
    2. #include<queue>

    2.原理:需要另外一个容器充当容量(常用vector当做容器(无需传参数),array还需要传参数)

    (原型:第一个参数是存储的数据类型,第二个参数是容器(中间的那个=号是缺省值),第三个参数是排序准则,第四个个参数是类名)

    1. template <class _Ty,class _Container = vector<_Ty>,class _Pr = less<_Ty>>
    2. class my_priority_queue
    3. {
    4. public:
    5. protected:
    6. };

    按照特定的方式进行出队(按照数据的优先权出队)其实就是排好序再出队。

    3.创建优先队列的三种方式:

    1. //默认的方式,一级下面三种 都一样,大的先出队
    2. priority_queue<int> pqData;
    3. priority_queue<int,vector<int>> pqData2; //默认排序准则
    4. priority_queue<int,vector<int>,less<int>> pqData3; //所有参数都完整

    4.入队push()

    1. pqData.push(12);
    2. pqData.push(0);
    3. pqData.push(34);

    5.出队是默认从大到小(大的先出队)->default:  less<int>  (区别sort)

    1. priority_queue<int> pqData;
    2. while (!pqData.empty())
    3. {
    4. cout << pqData.top()<<" ";
    5. pqData.pop(); //出队
    6. }

    想让小的先出队 排序准则传参为  greater<int>

    1. priority_queue<int, vector<int>, greater<int>> pqDataG;
    2. pqDataG.push(12);
    3. pqDataG.push(0);
    4. pqDataG.push(34);
    5. while (!pqDataG.empty())
    6. {
    7. cout << pqDataG.top() << " ";
    8. pqDataG.pop(); //出队
    9. }

    6.应用:贪心算法、Huffman树

  • 相关阅读:
    第九届世界渲染大赛什么时候开始举办?
    Dockerfile编写实践篇
    HDU 3549 — Flow Problem 入门题
    Gloss优化
    ThreadLocal源码解析 2.ThreadLocalMap内核
    日志瘦身方法论
    生产者消费者模式进阶-设计模式-并发编程(Java)
    hive3.1decimal计算详细逻辑
    市值缩水90%以上,泛生子何以败退美股?
    LeetCode204,计算质数,线性筛
  • 原文地址:https://blog.csdn.net/zjjaibc/article/details/125402421