1.STL基本概念
1.1简介
STL(Standard Template Library,标准模板库),STL 从广义上分为: 容器(container)
算法(algorithm) 迭代器(iterator),容器和算法之间通过迭代器进行无缝连接。STL 几乎
所有的代码都采用了模板类或者模板函数,这相比传统的由函数和类组成的库来说提
供了更好的代码重用机会。
STL六大组件简介:
容器:各种数据结构,如vector、list、deque、set、map等,用来存放数据
算法:各种常用的算法,如sort、find、copy、for_each。
迭代器:扮演了容器与算法之间的胶合剂,共有五种类型
仿函数:行为类似函数,可作为算法的某种策略。
适配器:一种用来修饰容器或者仿函数或迭代器接口的东西。
空间配置器:负责空间的配置与管理。配置器是实现了动态空间配置、空间管理、空间释放。
1.2 STL三大组件
1.容器:分为序列式容器和关联式容器两种。
2.算法:分为质变算法和非质变算法。
3.迭代器:分为以下五类:
输入迭代器 提供对数据的只读访问 只读,支持++、==、!=
输出迭代器 提供对数据的只写访问 只写,支持++
前向迭代器 提供读写操作,并能向前推进迭代器 读写,支持++、==、!=
双向迭代器 提供读写操作,并能向前和向后操作 读写,支持++、--,
随机访问迭代器 提供读写操作,并能在数据中随机移动 读写,支持++、--、[n]、-n、<、<=、>、>=
1.3 STL工作原理
#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
#include<string>
using namespace std;
template<class T>
class MyArr
{
public:
typedef T* iterantor;
public:
MyArr()
{
m_capacity = 10;
m_size = 0;
p = new T[m_capacity];
for (int i = 0; i < m_capacity; i++)
{
p[i] = i + 1;
m_size++;
}
}
T* begin()
{
return p;
}
T* end()
{
return p+m_size;
}
public:
T* p;
int m_capacity;
int m_size;
};
template<class T>
void printArr(T begin,T end)
{
for (;begin != end; ++begin)
{
cout << *begin << " ";
}
}
void test01()
{
MyArr<int> arr;
MyArr<int>::iterantor begina = arr.begin();
MyArr<int>::iterantor endd = arr.end();
printArr(begina,endd);
}
int main()
{
test01();
system("pause");
return 0;
}
1.4 STL的基本使用
#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
#include<string>
#include<vector>
#include<algorithm>
using namespace std;
void MyPrint(int val)
{
cout << val << " ";
}
void test01()
{
vector<int> v;
v.push_back(10);
v.push_back(20);
v.push_back(30);
v.push_back(40);
v.push_back(50);
vector<int>::iterator begin = v.begin();
vector<int>::iterator end = v.end();
for_each(begin, end, MyPrint);
}
class Test
{
public:
Test(string name,int age)
{
this->name = name;
this->age = age;
}
string name;
int age;
};
ostream& operator<<(ostream& cout, Test& t1)
{
cout << "姓名:" << t1.name << " 年龄:" << t1.age << endl;
return cout;
}
void test02()
{
vector<Test> v;
v.push_back(Test("张1", 18));
v.push_back(Test("张2", 17));
v.push_back(Test("张3", 19));
v.push_back(Test("张4", 21));
v.push_back(Test("张5", 20));
vector<Test>::iterator begin = v.begin();
vector<Test>::iterator end = v.end();
while (begin != end)
{
cout << *(begin);
++begin;
}
}
void test03()
{
vector<Test* > v;
Test* t1 = new Test("张1", 18);
Test* t2 = new Test("张2", 17);
Test* t3 = new Test("张3", 19);
Test* t4 = new Test("张4", 21);
Test* t5 = new Test("张5", 20);
v.push_back(t1);
v.push_back(t2);
v.push_back(t3);
v.push_back(t4);
v.push_back(t5);
vector<Test* >::iterator begin = v.begin();
vector<Test* >::iterator end = v.end();
while (begin != end)
{
cout << (*begin)->name<<" "<<(*begin)->age<<endl;
++begin;
}
delete t1;
delete t2;
delete t3;
delete t4;
delete t5;
}
void test04()
{
vector<vector<int>> v;
vector<int> v1;
vector<int> v2;
vector<int> v3;
vector<int> v4;
vector<int> v5;
for (int i = 0; i < 5; i++)
{
v1.push_back(i + 10);
v2.push_back(i + 10);
v3.push_back(i + 10);
v4.push_back(i + 10);
v5.push_back(i + 10);
}
v.push_back(v1);
v.push_back(v2);
v.push_back(v3);
v.push_back(v4);
v.push_back(v5);
vector<vector<int>>::iterator begin = v.begin();
vector<vector<int>>::iterator end = v.end();
while (begin != end)
{
vector<int>::iterator s_begin = (*begin).begin();
vector<int>::iterator s_end = (*begin).end();
while (s_begin != s_end)
{
cout << (*s_begin) <<" ";
++s_begin;
}
cout << endl;
++begin;
}
}
int main()
{
test04();
system("pause");
return 0;
}
2.容器
2.1 string容器
2.1.1 string容器基本概念
C风格字符串(以空字符结尾的字符数组)太过复杂难于掌握,不适合大程序的开发,
所以C++标准库定义了一种string类,定义在头文件<string>。
String和c风格字符串对比:
1.Char*是一个指针,String是一个类
string封装了char*,管理这个字符串,是一个char*型的容器。
2.String封装了很多实用的成员方法
查找find,拷贝copy,删除delete 替换replace,插入insert
3.不用考虑内存释放和越界
string管理char*所分配的内存。每一次string的复制,取值都由string类负责维护,
不用担心复制越界和取值越界等。
2.1.2 string容器的常用操作
1 string 构造函数
string();//创建一个空的字符串 例如: string str;
string(conststring& str);//使用一个string对象初始化另一个string对象
string(constchar* s);//使用字符串s初始化
string(int n, char c);//使用n个字符c初始化
2 string基本赋值操作
string&operator=(constchar* s);//char*类型字符串 赋值给当前的字符串
string&operator=(conststring&s);//把字符串s赋给当前的字符串
string&operator=(char c);//字符赋值给当前的字符串
string& assign(constchar *s);//把字符串s赋给当前的字符串
string& assign(constchar *s, int n);//把字符串s的前n个字符赋给当前的字符串
string& assign(conststring&s);//把字符串s赋给当前字符串
string& assign(int n, char c);//用n个字符c赋给当前字符串
string& assign(conststring&s, int start, int n);//将s从start开始n个字符赋值给字符串,如s=hello,那么n=3,start=1,那么是hel中从e开始赋值3-1个字符
3 string存取字符操作
char&operator[](int n);//通过[]方式取字符
char& at(int n);//通过at方法获取字符
4 string拼接操作
string&operator+=(conststring& str);//重载+=操作符
string&operator+=(constchar* str);//重载+=操作符
string&operator+=(constchar c);//重载+=操作符
string& append(constchar *s);//把字符串s连接到当前字符串结尾
string& append(constchar *s, int n);//把字符串s的前n个字符连接到当前字符串结尾
string& append(conststring&s);//同operator+=()
string& append(conststring&s, int pos, int n);//把字符串s中从pos开始的n个字符连接到当前字符串结尾
string& append(int n, char c);//在当前字符串结尾添加n个字符c
5 string查找和替换
int find(conststring& str, int pos = 0) const; //查找str第一次出现位置,从pos开始查找
int find(constchar* s, int pos = 0) const; //查找s第一次出现位置,从pos开始查找
int find(constchar* s, int pos, int n) const; //从pos位置查找s的前n个字符第一次位置
int find(constchar c, int pos = 0) const; //查找字符c第一次出现位置
int rfind(conststring& str, int pos = npos) const;//查找str最后一次位置,从pos开始查找
int rfind(constchar* s, int pos = npos) const;//查找s最后一次出现位置,从pos开始查找
int rfind(constchar* s, int pos, int n) const;//从pos查找s的前n个字符最后一次位置
int rfind(constchar c, int pos = 0) const; //查找字符c最后一次出现位置
string& replace(int pos, int n, conststring& str); //替换从pos开始n个字符为字符串str
string& replace(int pos, int n, constchar* s); //替换从pos开始的n个字符为字符串s
6 string比较操作
/*
compare函数在>时返回 1,<时返回 -1,==时返回 0。
比较区分大小写,比较时参考字典顺序,排越前面的越小。
大写的A比小写的a小。
*/
int compare(conststring&s) const;//与字符串s比较
int compare(constchar *s) const;//与字符串s比较
7 string子串
string substr(int pos = 0, int n = npos) const;//返回由pos开始的n个字符组成的字符串
8 string插入和删除操作
string& insert(int pos, constchar* s); //插入字符串
string& insert(int pos, conststring& str); //插入字符串
string& insert(int pos, int n, char c);//在指定位置插入n个字符c
string& erase(int pos, int n = npos);//删除从Pos开始的n个字符
9 string和c-style字符串转换
//string 转 char*
string str = "itcast";
constchar* cstr = str.c_str();
//char* 转 string
char* s = "itcast";
string sstr(s);
#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
#include<string>
using namespace std;
void test()
{
string::iterator it;
it++;
it--;
}
void test01()
{
string s1;
string s2(10, 'a');
string s3(s2);
string s4("helloworld");
}
void test02()
{
string s1;
s1 = "hello world";
cout << s1 << endl;
string s2;
s2.assign(s1);
s2.assign("world");
cout << s2 << endl;
}
void test03()
{
string s = "hello world";
for (int i = 0; i < s.size(); i++)
{
cout << s[i] << " ";
}
cout << endl;
for (int i = 0; i < s.size(); i++)
{
cout << s.at(i) << " ";
}
cout << endl;
}
void test04()
{
string s1 = "aaa";
s1 += "bbb";
s1 += 'c';
cout << s1 << endl;
s1.append("ddddd", 3);
cout << s1 << endl;
}
void test05()
{
string s = "abcdefgh";
cout << s.find('d') << endl;
cout << s.rfind('d') << endl;
cout << s.find('x') << endl;
s.replace(2, 4, "AAAAAAAAAAAAAAAAAAAAAAA");
cout << s << endl;
}
void test06()
{
string s1 = "hello";
string s2 = "hello";
const char* chr = "world";
if (s1.compare(s2) == 0)
cout << "s1==s2" << endl;
else
cout << "s1!=s2" << endl;
if (s2.compare(chr) == 0)
cout << "s2 == chr" << endl;
else
cout << "s2 != chr" << endl;
}
void test07()
{
string email = "helloworld@qq.com";
int pos = email.find('@');
string user = email.substr(0, pos);
cout << user << endl;
int pos1 = email.find('.');
string last_Name = email.substr(pos + 1, pos1-pos-1);
cout << last_Name << endl;
}
void test08()
{
string s = "aaa";
s.insert(2, "AAAAAAAA");
cout << s << endl;
s.insert(3, 5, 'B');
cout << s << endl;
s.erase(2, 3);
cout << s << endl;
}
void test09()
{
const char* str = "hello";
string s = string(str);
cout << s << endl;
const char* str1 = s.c_str();
cout << str1 << endl;
}
void test10()
{
string s = "abcde";
char& a = s[2];
char& b = s[3];
a = '1';
b = '2';
cout << "a:" << a << endl;
cout << "b:" << b << endl;
cout << s << endl;
cout << "字符串的原空间地址:" << (int*)s.c_str() << endl;
s = "dasfhjkboivnwiornjgbbgjflkg cmxm nlvkdfj";
cout << "字符串的空间地址:" << (int*)s.c_str() << endl;
}
void test11()
{
string s = "helloworld";
for (string::iterator it = s.begin(); it != s.end(); it++)
{
cout << *it << " ";
}
cout << endl;
for (string::reverse_iterator it = s.rbegin(); it != s.rend(); it++)
{
cout << *it << " ";
}
cout << endl;
}
int main()
{
test11();
system("pause");
return 0;
}
2.2 vector容器
2.2.1 vector容器基本概念
vector的数据安排以及操作方式,与array非常相似,两者的唯一差别在于空间的
运用的灵活性。Array是静态空间,一旦配置了就不能改变,要换大一点或者小一点
的空间,可以,一切琐碎得由自己来,首先配置一块新的空间,然后将旧空间的数
据搬往新空间,再释放原来的空间。Vector是动态空间,随着元素的加入,它的内
部机制会自动扩充空间以容纳新元素
2.2.2 vector的数据结构
Vector所采用的数据结构非常简单,线性连续空间,它以两个迭代器_Myfirst和_Mylast
分别指向配置得来的连续空间中目前已被使用的范围,并以迭代器_Myend指向整块连续
内存空间的尾端。
为了降低空间配置时的速度成本,vector实际配置的大小可能比客户端需求大一些,以
备将来可能的扩充,这边是容量的概念
2.2.3 vector常用接口
1 vector构造函数
vector<T> v; //采用模板实现类实现,默认构造函数
vector(v.begin(), v.end());//将v[begin(), end())区间中的元素拷贝给本身。
vector(n, elem);//构造函数将n个elem拷贝给本身。
vector(const vector &vec);//拷贝构造函数。
2 vector常用赋值操作
assign(beg, end);//将[beg, end)区间中的数据拷贝赋值给本身。
assign(n, elem);//将n个elem拷贝赋值给本身。
vector&operator=(const vector &vec);//重载等号操作符
swap(vec);// 将vec与本身的元素互换。
3 vector大小操作
size();//返回容器中元素的个数
empty();//判断容器是否为空
resize(int num);//重新指定容器的长度为num,若容器变长,则以默认值填充新位置。如果容器变短,则末尾超出容器长度的元素被删除。
resize(int num, elem);//重新指定容器的长度为num,若容器变长,则以elem值填充新位置。如果容器变短,则末尾超出容器长>度的元素被删除。
capacity();//容器的容量
reserve(int len);//容器预留len个元素长度,预留位置不初始化,元素不可访问。
4 vector数据存取操作
at(int idx); //返回索引idx所指的数据,如果idx越界,抛出out_of_range异常。
operator[];//返回索引idx所指的数据,越界时,运行直接报错
front();//返回容器中第一个数据元素
back();//返回容器中最后一个数据元素
5 vector插入和删除操作
insert(const_iterator pos, int count,ele);//迭代器指向位置pos插入count个元素ele.
push_back(ele); //尾部插入元素ele
pop_back();//删除最后一个元素
erase(const_iterator start, const_iterator end);//删除迭代器从start到end之间的元素
erase(const_iterator pos);//删除迭代器指向的元素
clear();//删除容器中所有元素
#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
#include<string>
#include<vector>
using namespace std;
void myPrintf(const vector<int> &v)
{
for (vector<int>::const_iterator it = v.begin(); it != v.end(); it++)
{
cout << *it << " ";
}
cout << endl;
}
void myReversePrintf(vector<int>& v)
{
for (vector<int>::reverse_iterator it = v.rbegin(); it != v.rend(); it++)
{
cout << *it << " ";
}
cout << endl;
}
void test01()
{
int arr[] = { 2,3,1,9,8 };
vector<int> v(arr, (arr + sizeof(arr)/sizeof(int)));
myPrintf(v);
myReversePrintf(v);
vector<int>v1(10, 6);
myPrintf(v1);
}
void test02()
{
vector<int> v;
v.assign(6, 10);
vector<int> v2;
v2.push_back(1);
v2.push_back(2);
v2.push_back(3);
myPrintf(v);
myPrintf(v2);
cout << "-------------" << endl;
v.swap(v2);
myPrintf(v);
myPrintf(v2);
}
void test03()
{
vector<int> v;
v.push_back(1);
v.push_back(2);
v.push_back(3);
cout << "Size:" << v.size() << endl;
cout << "Empty:" << v.empty() << endl;
v.resize(5);
cout << "Size:" << v.size() << endl;
myPrintf(v);
v.resize(20,11);
v.push_back(20);
myPrintf(v);
}
void test04()
{
vector<int> v;
v.reserve(10001000);
int* p = NULL;
int num = 0;
for (int i = 0; i < 10001000; i++)
{
v.push_back(i);
if (p != &v[0])
{
p = &v[0];
++num;
}
}
cout << "num = " << num << endl;
}
void test05()
{
vector<int> v;
v.push_back(1);
v.push_back(2);
v.push_back(3);
cout << v.front() << endl;
cout << v.back() << endl;
v.front() = 100;
v.back() = 300;
for (int i = 0; i < v.size(); i++)
{
cout << v[i] << endl;
}
}
void test06()
{
vector<int> v;
for (int i = 0; i < 5; i++)
{
v.push_back(i);
}
myPrintf(v);
v.insert(v.begin() + 1,2, 100);
myPrintf(v);
v.pop_back();
myPrintf(v);
v.erase(v.begin());
myPrintf(v);
v.erase(v.begin()+1,v.end()-1);
myPrintf(v);
v.clear();
myPrintf(v);
}
int main()
{
test06();
system("pause");
return 0;
}
2.3 deque容器
2.3.1 deque容器基本概念
Vector容器是单向开口的连续内存空间,deque则是一种双向开口的连续线性空间。
所谓的双向开口,意思是可以在头尾两端分别做元素的插入和删除操作
2.3.2 deque容器实现原理
Deque容器是连续的空间,至少逻辑上看来如此,连续现行空间总是令我们联想到
array和vector,array无法成长,vector虽可成长,却只能向尾端成长,而且其成长其实
是一个假象,事实上(1) 申请更大空间 (2)原数据复制新空间 (3)释放原空间 三步骤,
如果不是vector每次配置新的空间时都留有余裕,其成长假象所带来的代价是非常昂
贵的。
Deque是由一段一段的定量的连续空间构成。一旦有必要在deque前端或者尾端增加
新的空间,便配置一段连续定量的空间,串接在deque的头端或者尾端。Deque最大的工
作就是维护这些分段连续的内存空间的整体性的假象,并提供随机存取的接口,避开了
重新配置空间,复制,释放的轮回,代价就是复杂的迭代器架构。
既然deque是分段连续内存空间,那么就必须有中央控制,维持整体连续的假象,数
据结构的设计及迭代器的前进后退操作颇为繁琐。Deque代码的实现远比vector或list都
多得多。
Deque采取一块所谓的map(注意,不是STL的map容器)作为主控,这里所谓的map是
一小块连续的内存空间,其中每一个元素(此处成为一个结点)都是一个指针,指向另一段
连续性内存空间,称作缓冲区。缓冲区才是deque的存储空间的主体。
2.3.2 deque常用API
1 deque构造函数
deque<T> deqT;//默认构造形式
deque(beg, end);//构造函数将[beg, end)区间中的元素拷贝给本身。
deque(n, elem);//构造函数将n个elem拷贝给本身。
deque(const deque &deq);//拷贝构造函数。
2 deque赋值操作
assign(beg, end);//将[beg, end)区间中的数据拷贝赋值给本身。
assign(n, elem);//将n个elem拷贝赋值给本身。
deque&operator=(const deque &deq); //重载等号操作符
swap(deq);// 将deq与本身的元素互换
3 deque大小操作
deque.size();//返回容器中元素的个数
deque.empty();//判断容器是否为空
deque.resize(num);//重新指定容器的长度为num,若容器变长,则以默认值填充新位置。如果容器变短,则末尾超出容器长度的元素被删除。
deque.resize(num, elem); //重新指定容器的长度为num,若容器变长,则以elem值填充新位置,如果容器变短,则末尾超出容器长度的元素被删除。
4 deque双端插入和删除操作
push_back(elem);//在容器尾部添加一个数据
push_front(elem);//在容器头部插入一个数据
pop_back();//删除容器最后一个数据
pop_front();//删除容器第一个数据
5 deque双端插入和删除操作
at(idx);//返回索引idx所指的数据,如果idx越界,抛出out_of_range。
operator[];//返回索引idx所指的数据,如果idx越界,不抛出异常,直接出错。
front();//返回第一个数据。
back();//返回最后一个数据
6 deque插入操作
insert(pos,elem);//在pos位置插入一个elem元素的拷贝,返回新数据的位置。
insert(pos,n,elem);//在pos位置插入n个elem数据,无返回值。
insert(pos,beg,end);//在pos位置插入[beg,end)区间的数据,无返回值。
7 deque删除操作
clear();//移除容器的所有数据
erase(beg,end);//删除[beg,end)区间的数据,返回下一个数据的位置。
erase(pos);//删除pos位置的数据,返回下一个数据的位置。
#define _CRT_SECURE_NO_WARNINGS
#include<deque>
#include<string>
#include<iostream>
using namespace std;
void myPrintf(const deque<int>& v)
{
for (deque<int>::const_iterator it = v.begin(); it != v.end(); it++)
{
cout << *it << " ";
}
cout << endl;
}
void test()
{
deque<int>::iterator it;
it++;
it--;
}
void test01()
{
int arr[] = { 2,3,1,9,8 };
deque<int> d(arr, (arr + sizeof(arr) / sizeof(int)));
myPrintf(d);
deque<int> d1(10, 6);
myPrintf(d1);
deque<int> d2(d);
myPrintf(d2);
}
void test02()
{
int arr[] = { 2,3,1,9,8 };
deque<int> d(arr, (arr + sizeof(arr) / sizeof(int)));
myPrintf(d);
deque<int> d2;
d2.assign(d.begin(), d.end());
d2.push_back(100);
myPrintf(d2);
d.swap(d2);
myPrintf(d);
myPrintf(d2);
}
void test03()
{
deque<int> d;
cout << d.size() << endl;
if (d.empty() == true)
cout << "空!" << endl;
else
cout << "非空!" << endl;
d.resize(10, 7);
myPrintf(d);
}
void test04()
{
deque<int> d;
d.push_back(1);
d.push_back(2);
d.push_back(3);
d.push_front(666);
myPrintf(d);
d[0] = 200;
myPrintf(d);
d.at(1) = 800;
myPrintf(d);
d.pop_back();
d.pop_front();
myPrintf(d);
}
void test05()
{
deque<int> d;
d.push_back(10);
d.push_back(20);
d.push_back(30);
d.push_back(40);
d.push_back(50);
myPrintf(d);
d.insert(d.begin() + 1, 1000);
myPrintf(d);
d.insert(d.begin() + 1,2, 2000);
myPrintf(d);
deque<int> d1;
d1.push_back(1);
d1.push_back(2);
d1.push_back(3);
d.insert(d.begin(), d1.begin(), d1.end());
myPrintf(d);
cout << "---------------" << endl;
deque<int> d2;
d2.push_back(10);
d2.push_back(20);
d2.push_back(30);
d2.push_back(40);
d2.push_back(50);
deque<int>::iterator it = d2.erase(d2.begin() + 1, d2.end() - 1);
myPrintf(d2);
cout << *it << endl;
d2.clear();
myPrintf(d2);
}
int main()
{
test05();
system("pause");
return 0;
}
2.4 案例
十个评委分别给5名学生打分,去掉最高分再去掉最低分求和后取平均,就是这名学
生的最终成绩。
#define _CRT_SECURE_NO_WARNINGS
#include<deque>
#include<string>
#include<vector>
#include<iostream>
#include<algorithm>
#include<time.h>
using namespace std;
class Student
{
public:
Student(){}
Student(int score,string name)
{
this->score = score;
this->name = name;
}
int myScore()
{
return this->score;
}
string name;
int score;
};
void creatStu(vector<Student>& v)
{
string id_Str = "ABCDE";
for (int i = 0; i < 5; i++)
{
Student s;
s.score = 0;
s.name = "学生";
s.name += id_Str[i];
v.push_back(s);
}
}
void putScore(vector<Student> &v)
{
for (vector<Student>::iterator it = v.begin(); it != v.end(); it++)
{
deque<int> d;
for (int i = 0; i < 10; i++)
{
int score = rand() % 70 + 30;
d.push_back(score);
}
sort(d.begin(), d.end());
d.pop_back();
d.pop_front();
int sum = 0;
for (deque<int>::iterator dit = d.begin(); dit != d.end(); dit++)
{
sum += (*dit);
}
sum /= d.size();
it->score = sum;
}
}
void printStu(vector<Student>& v)
{
for (vector<Student>::iterator it = v.begin(); it != v.end(); it++)
{
cout << "姓名:" << (*it).name << " 分数:" << (*it).score << endl;
}
}
bool SortStu(Student &s1, Student& s2)
{
return s1.score > s2.score;
}
void stuScore(vector<Student> &v)
{
for (int i = 0; i < v.size(); i++)
{
for (int j = 0; j < v.size() - i - 1; j++)
{
if (v[j].score < v[j + 1].score)
{
Student temp = v[j];
v[j] = v[j + 1];
v[j + 1] = temp;
}
}
}
printStu(v);
}
void test()
{
srand((unsigned int)time(NULL));
vector<Student> v;
creatStu(v);
putScore(v);
stuScore(v);
}
int main()
{
test();
system("pause");
return 0;
}
2.5 stack容器
2.5.1 stack容器基本概念
stack是一种先进后出(First In Last Out,FILO)的数据结构,它只有一个出口,
stack容器允许新增元素,移除元素,取得栈顶元素,但是除了最顶端外,没有任
何其他方法可以存取stack的其他元素。
2.5.2 stack没有迭代器
Stack所有元素的进出都必须符合”先进后出”的条件,只有stack顶端的元素,才有
机会被外界取用。Stack不提供遍历功能,也不提供迭代器。
2.5.3 stack常用API
1 stack构造函数
stack<T> stkT;//stack采用模板类实现, stack对象的默认构造形式:
stack(const stack &stk);//拷贝构造函数
2 stack赋值操作
stack&operator=(const stack &stk);//重载等号操作符
3 stack数据存取操作
push(elem);//向栈顶添加元素
pop();//从栈顶移除第一个元素
top();//返回栈顶元素
4 stack大小操作
empty();//判断堆栈是否为空
size();//返回堆栈的大小
#define _CRT_SECURE_NO_WARNINGS
#include<string>
#include<stack>
#include<iostream>
#include<algorithm>
using namespace std;
void test01()
{
stack<int> s;
s.push(10);
s.push(20);
s.push(30);
s.push(40);
s.push(50);
while (!s.empty())
{
cout << s.top() << endl;
s.pop();
}
cout << "Size:" << s.size() << endl;
}
class Student
{
public:
Student(string name,int age)
{
this->age = age;
this->name = name;
}
string name;
int age;
};
void test02()
{
stack<Student> s;
s.push(Student("aaa", 20));
s.push(Student("bbb", 21));
s.push(Student("ccc", 19));
while (!s.empty())
{
cout << s.top().name<<" "<<s.top().age << endl;
s.pop();
}
cout << "Size:" << s.size() << endl;
}
int main()
{
test02();
system("pause");
return 0;
}
2.6 queue容器
2.6.1 queue容器基本概念
Queue是一种先进先出(First In First Out,FIFO)的数据结构,它有两个出口,
queue容器允许从一端新增元素,从另一端移除元素。
2.6.2 queue没有迭代器
Queue所有元素的进出都必须符合”先进先出”的条件,只有queue的顶端元素,才有
机会被外界取用。Queue不提供遍历功能,也不提供迭代器。
2.6.3 queue常用API
1 queue构造函数
queue<T> queT;//queue采用模板类实现,queue对象的默认构造形式:
queue(const queue &que);//拷贝构造函数
2 queue存取、插入和删除操作
push(elem);//往队尾添加元素
pop();//从队头移除第一个元素
back();//返回最后一个元素
front();//返回第一个元素
3 queue赋值操作
queue&operator=(const queue &que);//重载等号操作符
4 queue大小操作
empty();//判断队列是否为空
size();//返回队列的大小
#define _CRT_SECURE_NO_WARNINGS
#include<string>
#include<queue>
#include<iostream>
#include<algorithm>
using namespace std;
void test01()
{
queue<int> q;
q.push(10);
q.push(20);
q.push(30);
q.push(40);
q.push(50);
cout << "front:" << q.front() << endl;
cout << "back:" << q.back() << endl;
while (!q.empty())
{
cout << q.front() << endl;
q.pop();
}
cout << "Size:" << q.size() << endl;
}
class Student
{
public:
Student(string name, int age)
{
this->age = age;
this->name = name;
}
string name;
int age;
};
void test02()
{
queue<Student* > q;
q.push(new Student("aaa", 18));
q.push(new Student("bbb", 19));
q.push(new Student("ccc", 17));
q.push(new Student("ddd", 21));
q.push(new Student("eee", 20));
while (!q.empty())
{
Student* temp = q.front();
cout << q.front()->name<<" "<< q.front()->age << endl;
q.pop();
delete temp;
}
cout << "Size:" << q.size() << endl;
}
int main()
{
test02();
system("pause");
return 0;
}
2.7 list容器
2.7.1 list容器基本概念
链表是一种物理存储单元上非连续、非顺序的存储结构,数据元素的逻辑顺序是通过
链表中的指针链接次序实现的。链表由一系列结点(链表中每一个元素称为结点)组成,
结点可以在运行时动态生成。每个结点包括两个部分:一个是存储数据元素的数据域,另
一个是存储下一个结点地址的指针域。
list的好处是每次插入或者删除一个元素,就是配置或者释放一个元素的空间。因此,
list对于空间的运用有绝对的精准,一点也不浪费。而且,对于任何位置的元素插入或元
素的移除,list永远是常数时间。
List和vector是两个最常被使用的容器。
List容器是一个双向链表。
有以下优点:
1.采用动态存储分配,不会造成内存浪费和溢出
2.链表执行插入和删除操作十分方便,修改指针即可,不需要移动大量元素
3.链表灵活,但是空间和时间额外耗费较大
2.7.2 list容器的迭代器
List容器不能像vector一样以普通指针作为迭代器,因为其节点不能保证在同一块连续
的内存空间上。List迭代器必须有能力指向list的节点,并有能力进行正确的递增、递减、
取值、成员存取操作。所谓”list正确的递增,递减、取值、成员取用”是指,递增时指向下
一个节点,递减时指向上一个节点,取值时取的是节点的数据值,成员取用时取的是节
点的成员。
由于list是一个双向链表,迭代器必须能够具备前移、后移的能力
List有一个重要的性质,插入操作和删除操作都不会造成原有list迭代器的失效
2.7.3 list容器的数据结构
list容器不仅是一个双向链表,而且还是一个循环的双向链表
2.7.4 常用的list的API
1 list构造函数
list<T> lstT;//list采用采用模板类实现,对象的默认构造形式:
list(beg,end);//构造函数将[beg, end)区间中的元素拷贝给本身。
list(n,elem);//构造函数将n个elem拷贝给本身。
list(const list &lst);//拷贝构造函数。
2 list数据元素插入和删除操作
push_back(elem);//在容器尾部加入一个元素
pop_back();//删除容器中最后一个元素
push_front(elem);//在容器开头插入一个元素
pop_front();//从容器开头移除第一个元素
insert(pos,elem);//在pos位置插elem元素的拷贝,返回新数据的位置。
insert(pos,n,elem);//在pos位置插入n个elem数据,无返回值。
insert(pos,beg,end);//在pos位置插入[beg,end)区间的数据,无返回值。
clear();//移除容器的所有数据
erase(beg,end);//删除[beg,end)区间的数据,返回下一个数据的位置。
erase(pos);//删除pos位置的数据,返回下一个数据的位置。
remove(elem);//删除容器中所有与elem值匹配的元素。
3 list大小操作
size();//返回容器中元素的个数
empty();//判断容器是否为空
resize(num);//重新指定容器的长度为num,
若容器变长,则以默认值填充新位置。
如果容器变短,则末尾超出容器长度的元素被删除。
resize(num, elem);//重新指定容器的长度为num,
若容器变长,则以elem值填充新位置。
如果容器变短,则末尾超出容器长度的元素被删除。
4 list赋值操作
assign(beg, end);//将[beg, end)区间中的数据拷贝赋值给本身。
assign(n, elem);//将n个elem拷贝赋值给本身。
list&operator=(const list &lst);//重载等号操作符
swap(lst);//将lst与本身的元素互换。
5 list数据的存取
front();//返回第一个元素。
back();//返回最后一个元素。
6 list反转排序
reverse();//反转链表,比如lst包含1,3,5元素,运行此方法后,lst就包含5,3,1元素。
sort(); //list排序
#define _CRT_SECURE_NO_WARNINGS
#include<string>
#include<list>
#include<vector>
#include<iostream>
#include<algorithm>
using namespace std;
void test()
{
list<int>::iterator it;
it++;
it--;
}
void printLIst(const list<int>& mylist)
{
for (list<int>::const_iterator it = mylist.begin(); it != mylist.end(); it++)
{
cout << *it << " ";
}
cout << endl;
}
void test02()
{
list<int> mylist1(10,6);
list<int> mylist2(++mylist1.begin(), --mylist1.end());
printLIst(mylist1);
printLIst(mylist2);
}
bool myFun(int val)
{
return val > 400;
}
void test03()
{
list<int> mylist1;
mylist1.push_back(10);
mylist1.push_back(20);
mylist1.push_back(30);
mylist1.push_back(40);
mylist1.push_back(50);
mylist1.push_front(100);
mylist1.push_front(200);
mylist1.push_front(300);
mylist1.push_front(400);
vector<int> v;
v.push_back(1000);
v.push_back(2000);
v.push_back(3000);
mylist1.insert(mylist1.begin(), v.begin(), v.end());
printLIst(mylist1);
mylist1.remove(3000);
printLIst(mylist1);
mylist1.remove_if(myFun);
printLIst(mylist1);
}
void test04()
{
list<int> mylist1;
for (int i = 0; i < 5; i++)
{
mylist1.push_back(i);
}
cout << "Size:" << mylist1.size() << endl;
if (!mylist1.empty())
cout << "不为空!" << endl;
else
cout << "为空!" << endl;
mylist1.resize(3);
printLIst(mylist1);
}
void test05()
{
list<int> mylist1;
mylist1.assign(10, 10);
printLIst(mylist1);
cout << mylist1.front() << endl;
cout << mylist1.back() << endl;
list<int> mylist2;
for (int i = 0; i < 5; i++)
{
mylist2.push_back(i);
}
printLIst(mylist2);
mylist2.swap(mylist1);
cout << "----------------" << endl;
printLIst(mylist1);
printLIst(mylist2);
}
bool myFunc1(int val, int val1)
{
return val > val1;
}
void test06()
{
list<int> mylist1;
for (int i = 0; i < 5; i++)
{
mylist1.push_back(i+10);
}
printLIst(mylist1);
mylist1.reverse();
printLIst(mylist1);
mylist1.sort();
printLIst(mylist1);
mylist1.sort(myFunc1);
printLIst(mylist1);
}
int main()
{
test06();
system("pause");
return 0;
}
3.综合案例:记录进出电梯的人数并打印出来
#define _CRT_SECURE_NO_WARNINGS
#include<string>
#include<list>
#include<vector>
#include<ctime>
#include<queue>
#include<iostream>
using namespace std;
class Human
{
public:
string name;
};
void creatHuman(queue<Human>& q1, int num)
{
string hName = "ABCDEFGHIJKLMN";
int sum = rand() % 10;
for (int i = 0; i < sum; i++)
{
Human h;
char buffer[64] = { 0 };
sprintf(buffer, "%d", num);
string s(buffer);
h.name = "第";
h.name += s;
h.name += "层";
h.name += hName[i];
q1.push(h);
}
}
void printPushVecotr(vector<Human> &v)
{
for (vector<Human>::iterator it = v.begin(); it != v.end(); it++)
{
cout << "进出人员名字为:" << (*it).name << endl;
}
}
int pushHuman(list<Human> &mylist,queue<Human>&q,vector<Human>& pushH)
{
int temp = 0;
while (!q.empty())
{
if (mylist.size() >= 15)
{
break;
}
Human h = q.front();
pushH.push_back(h);
mylist.push_back(h);
q.pop();
temp++;
}
return temp;
}
int popHuman(list<Human>& mylist, vector<Human>& popH,int num)
{
int temp = 0;
if (num == 17)
{
while (!mylist.empty())
{
Human h = mylist.front();
popH.push_back(h);
mylist.pop_front();
temp++;
}
}
int n = rand() % 5;
if (n == 0)
{
return temp;
}
if (mylist.size() > 0 && mylist.size() >= n)
{
for (int i = 0; i < n; i++)
{
Human h = mylist.front();
popH.push_back(h);
mylist.pop_front();
temp++;
}
}
return temp;
}
void test()
{
srand((unsigned int)time(NULL));
list<Human> mylist;
int pushNum = 0;
int popNum = 0;
vector<Human> pushH;
vector<Human> popH;
for (int i = 0; i < 18; i++)
{
queue<Human> q1;
creatHuman(q1,i);
if (mylist.size() <= 15)
{
if (i < 17)
{
pushNum += pushHuman(mylist,q1, pushH);
}
}
if (mylist.size() > 0)
{
if (i > 1)
{
popNum += popHuman(mylist, popH, i);
}
}
printPushVecotr(pushH);
cout << "进电梯人数:" << pushNum << endl;
printPushVecotr(popH);
cout << "出电梯人数:" << popNum << endl;
}
}
int main()
{
test();
system("pause");
return 0;
}