STL主要包括这三个部分
然后第一节这边就简单教了一下通过迭代器来遍历输出数的两种方法,一个while,一个for
while (v != array1.end())
{
cout << *v << endl;
v++;
}
/*打印*/
for (vector::iterator It = array1.begin(); It != array1.end(); It++)
{
cout << *v << endl;
}
初始化vector的几种方法
vectorv1(10);
vectorv2(10, 2);
vectorv3(v1);
vectorv4(v2.begin(), v2.end());
vectorv5(v1.begin(), v1.begin() + 4);
int hello[10] = { 1,2,3,4,5,6,7 };
vectorv6(hello, hello + 2);
vector的一些内置函数,然后这边要着重区分一下reverse和resize这两个。
1、resize(n)
调整容器的长度大小,使其能容纳n个元素。
如果n小于容器的当前的size,则删除多出来的元素。
否则,添加采用值初始化的元素。
2、 resize(n,t)
多一个参数t,将所有新添加的元素初始化为t。
而reserver()的用法只有一种
reserve(n)
预分配n个元素的存储空间。
vectorv7, v8;
v7.assign(v1.begin(), v1.begin() + 4);//将一个容器数据复制给另一个容器
v8.assign(7, 4);
//auto &TMP = v8.front();
int &tmp = v8.front();
v8.push_back(111);//末尾填充数
int &TMP2 = v8.back();
int &tmp4 = v8[3];
v8.clear();
if (v8.empty())
{
cout << "空";
}
v8.assign(v1.begin(), v1.begin() + 114);//复制的范围
v8.pop_back();//删除最后一个元素
v8.erase(v8.begin(), v8.begin() + 2);//指定删除范围
v8.push_back(1111);
v8.insert(v8.begin() + 1,12);//注意这里是插入
int num1 = v8.size();//实际大小
int num2= v8.capacity();//预分配空间
v8.resize(100);//填充
v8.resize(70, 123);
v8.resize(100);
v8.reserve(60);//预分配扩容
v8.swap(v5);//整块内存直接交换
几种vector的访问方式
for (vector::iterator it=a1.begin(); it != a1.end(); it++)
{
cout << *it;
}
//访问方式2
for (int i = 0; i < a1.size(); i++)
{
cout << a1[i] << endl;
}
//访问方式3
for (auto &tmp : a1)
{
cout << tmp << endl;
}
vector的几个算法
sort排序是从小到大
sort(a1.begin(), a1.end());
reverse倒置,但补排序
reverse(a1.begin(), a1.end());
复制copy,但要提前开辟空间
vectorb1;
copy(a1.begin(), a1.end(),b1.begin());
查找find
auto pos = find(a1.begin(), a1.end(), 4);
---
string本质上是个容器,是个封装好的的类,遍历的方法和上面vector是一样的
for (string::iterator it = s.begin(); it!=s.end(); it++)
{
cout << *it << endl;
}
获取容器字符串数量,以及获取大小
int ssize =s.size();//注意这里不要写成sizeof这里的size是来计算有多少字符串的,不是计算空间大小的
int slength=s.length();
cout << ssize<
max_size和capacity
int smaxsize = s.max_size();
int scapacity = s.capacity();
方法 | 效果 |
size() | 返回容器的大小 |
empty() | 判断容器是否为空 |
max_size() | 返回容器最大的可以存储的元素 |
capacity() | 返回容器当前能够容纳的元素数量 |
int bempty = s.empty();
//下面这两个功能有点类似
s.c_str();//挺重要的
s.data();//内存地址
插入操作
char newstring[] = "ooos";
s.insert(2, newstring);
s.append(hellos);
erase和clear,erase()可以选择范围来清除,()里面存放数字,从0到该数字的内容保存其它清除
s.erase(3);//清除区域1
s.clear();
赋值操作
s = "new ";
s.assign("newa ");//这两种操作是一样的都能赋值
替换操作
char arraychar[] = "1";
char arraychar2[] = "2";
string hello = s.replace(0, strlen(arraychar), arraychar2);
cout << hello;
还有拷贝
s.copy(arraychar, strlen(arraychar) - 2); //变化的 是arryaychar,选择变化的长度
cout << arraychar;
查找元素所在位置
int pio = s.find("h");//这个是从前往后找,要想从后往前,rfind
cout << pio << endl;
查找元素首次出现的位置
string ppcc = "aa";
string ps = "psdaadaa";
int pos1 =ps.find_first_of(ppcc);
cout << pos1;
从字符串中截取一个片段
string c1 = ps.substr(2, 5);//截取开始位置,截取长度
cout << c1;
还有一个compare返回的是int,如果返回值=0,则两个字符串完全相同,是1则不相同
string s1 = "psdaadaa";
cout<
map容器
map容器包含一个key一个value,可以通过key插入value
mapmaphello;
maphello[3] = "asd";
cout << maphello[3] << endl;
遍历输出map的两种方法,一个是迭代器,另一个不理解直接记下来
for (auto &tmp : maphello)
{
if (tmp.first == 3)
{
cout << tmp.second << endl;
}
}
for (map::iterator it = maphello.begin(); it != maphello.end(); it++) {
if (it->first) {
cout << it->second;
break;
}
}
--
链表,就是个结构体变量
可以静态的创立链表,但更多是动态来创建链表
struct student {
int num;
float scote;
struct student *next;
};
int main() {
struct student a, b, c, *head,*p;
head = &a;
a.next = &b;
b.next = &c;
p = head;
do {
cout << p->num<scote << endl;
p = p->next;
} while (p != NULL);
}
最终是要将这个 指针转换成结构体变量
创建链表
struct node *createlist()
{
struct node*headnode = (struct node*)malloc(sizeof(struct node));//headnodde成为结构体变量
headnode->next = NULL;
return headnode;
}
创建节点以插入
struct node*createnode(int data)
{
struct node *newnode = (struct node*)malloc(sizeof(struct node));
newnode->data = data;
newnode->next = NULL;
return newnode;
}
打印节点,从第二个数开始打印
void printlist(struct node *headnode)
{
struct node *pmove = headnode->next;//从第二个数开始打印
while (pmove)
{
cout << pmove->data;
pmove = pmove->next;
}
}
删除节点
void deletenodebyappoinn(struct node*headnode, int posdata)
{
struct node*posnode = headnode->next;
struct node*posnodefront = headnode;
if (posnode == NULL)
{
cout << "列表为空" << endl;
}
while (posnode->data != posdata)
{
posnodefront = posnode;
posnode = posnodefront->next;
if (posnode == NULL)
{
cout << "没有找到相关消息" << endl;
return;
}
}
posnodefront->next = posnode->next;
free(posnode);
}
-------------
链表没法像vector这样写vector【1】,这样去查找。只能逐一节点去查找。
单向链表的遍历
fnodenode;
node.data = "hello1";
{
node.nest = new fnode();//都是先开辟空间然后存入数据
node.nest->data = "hello2";
node.nest->nest = new fnode();//这边直接nest,nest来指向下一个节点
node.nest->nest->data = "hello3";
node.nest->nest->nest = new fnode();
node.nest->nest->nest->data = "hello4";
}
fnode*nodeptr=&node;//创建一个指针指向上面这个的头部那么
//链表的遍历
while (nodeptr)
{
cout<data << endl;
nodeptr = nodeptr->nest;
}
打印
auto PrintfNode = [&]()
{
fnode* nodePtr = &node;
while (nodePtr)
{
cout << nodeptr->data << endl;
nodePtr = nodePtr->nest;
}
};
-----
下面是标准库的list的几个api
几种list的初始化方式
listnodelist;
listnodelist1({ "assd","weqwe","asd" });
listnodelist2 = nodelist1;
listnodelist2(nodelist1);
string a11[] = { "asd","w","d" };
几种插入方式
nodelist.push_front("D");
nodelist.push_back("E");
nodelist.emplace_back("F");//更高效,少拷贝一次
赋值方式
nodelist.assign({ "G","H","I" });//这个赋值是将原来的容器全部覆盖,覆盖上现在的值 nodelist2.assign(nodelist.begin(), nodelist.end());
nodelist2.assign(100, "ooo");
遍历方法
for (auto it = nodelist.begin(); it != nodelist.end(); it++)//这边begin可以写成cbegin,表示的是const,不可修改
{
cout << *it;
}
for (auto &tmp:nodelist)
{
cout << tmp;
}
(begin,end前面加上r可以逆序输出)
auto listv={1,234,5,6 };
for (auto it = rbegin(listv); it != rend(listv); it++) {
cout << *it;
}
插入
nodelist.insert(nodelist.begin(), "asd");
移除
nodelist12.remove(2);
nodelist12.remove_if([](int v) {return v >13; });
移除重复,但得重载操作符
nodelist12.unique();
struct FHJellp
{
FHJellp()
{
a = 0;
}
FHJellp(int newa)
:a(newa)
{
}
int a;
bool operator==(const FHJellp &v)
{
return a == v.a;
}
};
list llp;
llp.push_front(FHJellp(1));
llp.push_front(FHJellp(2));
llp.push_front(FHJellp(2));
llp.push_front(FHJellp(2));
llp.push_front(FHJellp(6));
llp.push_front(FHJellp(8));
llp.unique();
排序
升序
sort
降序
sort(greater())
--------
queue容器,先进先出
queue的几种初始化和上面的list和vector差不多
queueq2;
queueq3({ 1,2,3 });
queueq5(q3);
queue这边的遍历方法和前面的比较不同,需要用提出第一个元素并将其弹出的方式
while (!q3.empty())
{
int tempa = q3.front();
cout << tempa << endl;
q3.pop();//pop是将元素弹出
}
queue的插入,push和emplace这两个相当于尾插法
q3.push(4);
q3.emplace(100);
----------
stack容器和queue容器不一样的是先进的后出
初始化方式
stackstacktemp({ 1,2,3,4 });
stackstacktemp1(stacktemp);
stackstacktemp2 = stacktemp1;
stackstacktemp3;
vectorhello1({ 1,2,3,4,5,6, });
stack>stacktemp5(hello1);
输入的方式和上面其他几个容器一样
stacktemp.push(1);
stacktemp.push(1);
stacktemp.push(1);
stacktemp.push(1);
stacktemp.emplace(1);
stacktemp.emplace(2);
交换可以用标准库提供的方法也可以使用stack提供的API
stacktemp2.swap(stacktemp);
swap(stacktemp2, stacktemp);
遍历方式和上面的list一样
while (!stacktemp2.empty())
{
int topstack = stacktemp2.top();
cout << topstack << endl;
stacktemp2.pop();
}
-----------
set容器
set容器的几个特点,一个是自动排序,一个是里面的元素具有唯一性,还有一个就是关联
初始化方法
seta100({ 1,2,3,4,5,6 });
seta1001a1001(a100);
seta1002(a100.begin(), a100.end());
获取迭代器
auto cc11 = a100.begin();
auto cc22 = a100.end();
遍历的方式和list还有vector是一样的方法
for (auto &tmp : a100)
{
cout << tmp << endl;
}
for (set::iterator it=a100.begin();it!=a100.end();it++)
{
cout << *it<
添加元素
a100.emplace(102);
a100.emplace_hint(a100.cend(), 10);
最大容量
int maxsize = a100.max_size();
还有像map一样可以像查找位置获取pair
auto pair111 = a100.equal_range(6);
---------
forward—list单向链表
赋值
aaa.assign(3, 10);
去除
aaa.remove(10);
aaa.remove_if([](int a) {return a == 10; });
遍历
for (auto &tmp : aaa)
{
cout << tmp;
}
while (!aaa.empty())
{
int valueccc = aaa.front();
cout << valueccc << endl;
aaa.pop_front();
}
for (forward_list::const_iterator it = aaa.cbegin(); it !=aaa.cend(); it++)
{
cout << *it << endl;
}
插入
aaa.emplace_after(aaa.begin(),100);
aaa.emplace_front(20000);
删除
aaa.erase_after(aaa.begin());
将数据A直接迁移到数据B
forward_listdddd({ 3,4,5 });
aaa.splice_after(aaa.begin(), dddd);
-----
还有一个优先级对列, priority_queue<>ccc12就是可以从大到小来自动排序,可以放int,floa,chart等,也可以对自定义的数据类型来排序,但是得重载操作符(
添加,和上面常规的添加方法一样
priority_queueccc12;
ccc12.emplace(fhello(100));
ccc12.emplace(fhello(105));
ccc12.emplace(fhello(104));
ccc12.emplace(fhello(103));
遍历方式也一样
while (!ccc12.empty())
{
cout << ccc12.top().price<< endl;
ccc12.pop();
}
也可以对 自定义数据进行排序
struct fhello
{
fhello(int newprice)
:price(newprice)
{
}
friend bool operator <(const fhello &A, const fhello &B) {
return A.price < B.price;
}
string name;
int price;
};
priority_queueccc12;
ccc12.emplace(fhello(100));
ccc12.emplace(fhello(105));
ccc12.emplace(fhello(104));
ccc12.emplace(fhello(103));
---------------
哈希可以起到加密保护作用,适用在检测作弊等功能
两个哈希进行比较判断是否被篡改过,就可以来加密保护数据
哈希的两个API功能是一样的
hashh;
int ooo = 12;
auto oo1 = h._Do_hash(ooo);
auto oo2 = h(ooo);
if (oo1 == oo2)
{
cout << "ok";
}
----
multiset
和set很类似,在一个地方不同就是set每个元素必须不同,multiset可以接收相同元素
multisetmset({1,2});
mset.insert(100);
mset.insert(100);
mset.insert(100);
for (auto &tmp :mset)
{
cout << tmp << endl;
}
也能进行查找
auto autoccc = mset.find(100);
multimap
和map的差别也是允许插入多个相同的key,在使用查找的时候返回一般是第一个
-------
自建迭代器和容器
这个是自己创立的迭代器,要能实现++,--,!=,深拷贝还有读取元素等功能
template//ContainerType 是容器类型, ElementType是容器里的元素
class TIndexedContainerIterator
{
public:
typedef TIndexedContainerIterator TIterator;
//构造0
TIndexedContainerIterator(ContainerType &InContainer, int InIndex = 0)
:Container(InContainer)
, Index(InIndex)
{}
//深拷贝
TIndexedContainerIterator(const TIterator &InIterator)
: incontainer(InIterator.incontainer) ,
Index(InIterator.Index)
{
}
bool operator!=(const TIterator &InIterator)
{
return ContainerType[Index] != InIterator.container[InIterator.Index];
}
TIterator &operator++(int)
{
++Index;
retunn *this;
}
TIterator &operator--(int)
{
--index;
retunn *this;
}
TIterator &operator=(const InItertor)
{
Index = InItertor.Index;
Container = InItertor.Container;
return *this;
}
ElementType &operator*()
{
return *Container[Index];
}
protected:
ContainerType &incontainer;
int Index;//index是用来表示偏移量的
};
创立自己的容器
template
class TArray
{
public:
typedef TIndexedContainerIterator, ElementType> TIterator;//定义一个迭代器
TArray()// 动态分配
:Data(nullptr)
, Size(0)
, Allocation(10)
{
//动态分配内存
Data = (ElementType**)malloc(sizeof(int) * Allocation);//分配下标
memset(Data, 0, sizeof(int) * Allocation);
for (int i = 0; i < Allocation; i++)
{
Data[i] = (ElementType*)malloc(sizeof(ElementType));//用malloc是为了避免调用构造
memset(Data[i], 0, sizeof(ElementType));//memset函数一般用于清0,将这段内存全部赋0
}
}
int Num()
{
return Size;
}
void Add(ElementType&& InType)
{
Add(InType);
}
void Add(ElementType &InType)
{
if (Size >= Allocation)
{
//内存不够了 不够就分配
int LastAllocation = Allocation;
Allocation += 10;
Data = (ElementType**)realloc(Data, sizeof(int) * Allocation);
for (int i = LastAllocation; i < Allocation; i++)
{
Data[i] = (ElementType*)malloc(sizeof(ElementType));
memset(Data[i], 0, sizeof(ElementType));
}
}
memcpy(Data[Size], &InType, sizeof(ElementType));//如果空间没超,则直接进行复制分配
Size++;
}
void RemoveAt(int Index)
{
for (int i = Index + 1; i <= Size; i++)
{
memcpy(Data[i - 1], Data[i], sizeof(ElementType));
}
memset(Data[Size], 0, sizeof(ElementType));
Size--;
}
//获取具体元素,返回元素指针
ElementType *operator[](int Index)
{
return Data[Index];
}
TIterator Begin()
{
return TIterator(*this, 0);
}
TIterator End()
{
return TIterator(*this, Size);
}
~TArray()
{
for (int i = 0; i < Allocation; i++)
{
free(Data[i]);
}
free(Data);
}
protected:
ElementType** Data;//这相当于一个二维数组
int Size;//size表示二维数组里面真正有用的部分
int Allocation;//预分配的部分
};
在自己建立的容器存入数据可以这样操作
//实战迭代器,将结构体通过迭代器输入容器
struct FTestA
{
FTestA(){}
FTestA(int InA)
:ID(InA)
{
}
bool operator!=(const FTestA &A)
{
return A.ID != ID;
}
inline int GetID() { return ID; }//内敛函数优化
protected:
int ID;
};
TArray ArrayA;
FTestA A1(1);
ArrayA.Add(A1);
ArrayA.Add(FTestA(100));
//常规方法实现循环取出容器中的数
for (int i =0;i < ArrayA.Num();i++)
{
cout << ArrayA[i]->GetID() << endl;
}
//通过上面写的迭代器来输出数据
for (TArray::TIterator It = ArrayA.Begin();It != ArrayA.End();It++)
{
cout << (*It).GetID() << endl;
}
---
map和unordered_map的主要区别是map是有序的,核心是红黑树,,缺点就是空间占用率比较搞unordered_map是无序的,内部是 哈希,速度最快、
map的API
这两种方式都可以通过key来查找到对应的value
int element = aaa2.at(1);
int a = aaa2[3];
还可以通过count来计算一个容器里有没有重复的key
int c = aaa2.count(2);
还引入了一个桶的概念,bucket。key和value算是两个不同的桶。但是size只算一个
auto ccc111 = aaa2.bucket(10);//这个表示的是放在了哪哥桶里
auto ooooo = aaa2.bucket_count();//计算总共有几个桶
aaa2.rehash(ccc111);//rehash对桶进行哈希
load_factor()这个是计算size和桶的比列
auto vvvv = aaa2.load_factor();
还可以哈希加密
int ccc123 = aaa2.count(10);
auto HHHH11 = aaa2.hash_function();//直接进行哈希加密,相当于下面这两行
----
unordered_map
unordered_map的几个api
unordered_map的key值是不能重复的,所以不能用at,[]
判断是否相等
unordered_multimap aaa3;
auto ppp = aaa3.key_eq();
auto c1ccc1 = ppp(1, 1);
------------------
也可也这样
aaa3.key_eq()(1, 1)
---------
unordered_set
一样不接收相同元素,其他和set基本一样
清除
uset.erase(1123);
查找
auto ccc1234 = uset.find(123);
遍历
for (auto &Tmp : umset)
{
cout << Tmp << endl;
}
-------、
unordered_multiset
这个和multiset多了两个区别,一个是无序一个是有桶的概念