C++基础数据结构STL

在C++里有写好的标准模板库,我们称为STL库。它实现了集合、映射表、栈、队列等数据结构和排序、查找等算法。我们可以很方便地调用标准库来进行各类操作。


动态数组 vector

引用库

有时候想开一个数组,但是却不知道应该开多大长度的数组合适,因为我们需要用到的数组可能会根据情况变动,这个时候我们就需要用到动态数组了。
C++中的动态数组写作 vector,它的实现被写在 vector 的头文件中,并在所有头文件之后加上一句 using namespace std

#include <iostream>
#include <vector>

using namespace std;
int main()
{
    
    return 0;
}
构建一个动态数组

现在我们来构造一个动态数组,C++中直接构造一个vector 的语句为:

vector<T> vec;

这样我们定义了一个名为 vec 的储存 T 类型数据的动态数组。其中 T 是我们要储存的数据类型,可以是 int、float、double 或者其他自定义的数据类型等等。初始的时候 vec 是空的。

插入元素

C++中通过 push_back ( ) 方法在数组最后面插入一个新的元素

#include <iostream>
#include <vector>

using namespace std;

int main()
{
    vector<int> vec;

    vec.push_back(0);
    vec.push_back(1);
    vec.push_back(2);

    for(int i = 0; i < vec.size(); i++)
    {
        cout << vec[i] << endl;
    }

    return 0;
}
获取长度、访问元素、修改元素

C++ 中通过 size ( ) 方法获取 vector 的长度,通过 [ ] 操作直接访问 vector 中的元素,这一点和数组是一样的。

#include <iostream>
#include <vector>

using namespace std;

int main()
{
    vector<int> vec;

    vec.push_back(0);
    vec.push_back(1);
    vec.push_back(2);

    vec[1] = 2;
    vec[2] = 3;

    for(int i = 0; i < vec.size(); i++)
    {
        cout << vec[i] << endl;
    }

    return 0;
}
清空

C++需调用 clear( ) 来清空 vector 。
调用clear( ) 后,vector的size将变成0,但是它的容量 capacity 并未发生改变,clear只是删除数据,并未释放vector的内存。vector的clear( ) 不影响capacity,如果想要清空vector的元素,使用clear,如果想要释放vector的容量,可以使用swap。

vector<A>().swap(vec);
vec.swap(vector<A>());
C++ vector 方法总结
方法功能
push_back在末尾加入一个元素
pop_back在末尾弹出一个元素
size获取长度
clear清空
vector<int> v1(10);                 //v1有10个元素,每个都初始化为0
vector<int> v2{10};                 //v2有1个元素,该元素值为10
vector<int> v3(10, 1);              //v3有10个元素,每个都初始化为1

vector<string> v4(10);              //v4有10个默认初始化的元素
vector<string> v5{"xiebs"};         //v5有1个元素,该元素值为"xiebs"
vector<string> v6(10, "xiebs");     //v6有10个值为"xiebs"的元素

集合 set

集合是数学中的一个基本概念,通俗地讲,集合是由一些不重复的数据组成的。比如 { 1 , 2 , 3 } 就是一个有1,2,3的集合。C++的标准库中的集合支持高效的插入、删除和查询操作,这三个操作的时间复杂度都是 O(lgn),其中n是当前集合中元素的个数。如果用数组,虽然插入的时间复杂度是 O(1),但是删除合查询都是 O(n),此时效率太低。在C++中我们常用的集合是set

引用库

C++中的集合实现被写在 set 的头文件中,并在所有头文件之后加上一句 using namespace std

set<T> s;

这样我们定义了一个名为s的、储存T类型数据的集合,其中T是集合要储存的数据类型。初始的时候s是空集合

插入元素

C++中用 insert( ) 方法向集合中插入一个新的元素。
注意:如果集合中已经存在了某个元素,再次插入不会产生任何效果,集合中是不会出现重复元素的。

#include <set>
#include <string>
using namespace std;
int main()
{
    set<string> country;
    country.insert("China"); 		// {"China"}
    country.insert("America");  	// {"China", "America"}
    country.insert("France");   	// {"China", "America", "France"}
    
    return 0;
}
删除元素

C++中通过 erase( ) 方法删除集合中的一个元素,如果集合中不存在这个元素,不进行任何操作。

#include <set>
#include <string>
using namespace std;
int main() 
{
    set<string> country;  // {}
    country.insert("China"); // {"China"}
    country.insert("America"); // {"China", "America"}
    country.insert("France"); // {"China", "America", "France"}
    country.erase("America"); // {"China", "France"}
    country.erase("England"); // {"China", "France"}
    return 0;
}
查找元素

C++中如果你想知道某个元素是否在集合中出现,你可以直接用 count( ) 方法。如果集合中存在我们要查找的元素,返回 1 ,否则返回 0 。

#include <set>
#include <string>
#include <stdio.h>
using namespace std;
int main()
{
    set<string> country;
    country.insert("China"); 		// {"China"}
    country.insert("America"); 		// {"China", "America"}
    country.insert("France"); 		// {"China", "America", "France"}
    if (country.count("China")) 
    {
        printf("China belong to country");
    }
    
    return 0;
}
遍历元素

C++ 通过迭代器可以访问集合中的每个元素,迭代器就好比只想集合中的元素的指针。如果你不了解迭代器,你只需要先记住。

#include <set>
#include <string>
#include <iostream>
using namespace std;
int main()
 {
    set<string> country;  // {}
    country.insert("China"); // {"China"}
    country.insert("America"); // {"China", "America"}
    country.insert("France"); // {"China", "America", "France"}
    for (set<string>::iterator it = country.begin(); it != country.end(); ++it) 
    {
        cout << (*it) << endl;
    }
    return 0;
}

注意:在C++中遍历set是从小到大进行的。

清空

C++中只需要调用 clear( ) 方法就可以清空 set

方法功能
insert插入一个元素
erase删除一个元素
count判断元素是否在set中
size获取元素的个数
clear清空

映射 map

映射是指两个集合之间的元素的相互对应关系。通俗地说,就是一个元素对应另外一个元素。比如一个姓名的集合 {“Tom”, “Jone”, “Marry”},班级集合{1, 2}。姓名与班级之间可以有如下的映射关系:
class(“Tom”) = 1 , class(“Jone”) = 2 , class(“Marry”) = 1
我们称其中的姓名集合为 关键字集合(key) , 班级集合为 值集合(value)
在 C++ 中我们常用的映射是 map

引用库

C++中的map实现被写在 map 的头文件中,并在所有头文件之后加上一句 using namespac std

#include <map>
using namespace std;
构造一个映射

现在我们来构造一个映射
在C++中,我们构造一个 map 的语句为:

map<T1,T2> m;

这样我们定义了一个名为 m 的从 T1 类型到 T2 类型的映射。初始的时候 m 是空映射。

插入映射

在 C++ 中通过 insert( ) 方法向集合中插入一个新的映射,参数是一个 pair 类型的结构。这里需要用到另外一个 STL 模板 —— 元组(pair)。

pair<int,char>(1,'a');

定义了一个整数 1 和字符 a 的 pair。我们向映射中加入了新映射对的时候就是通过加入 pair 来实现的。如果插入的 key 之前已经有了 value,不会用插入的新的 value 替代原来的 value,也就是此次插入是无效的。

#include <map>
#include <string>
using namespace std;
int main() 
{
    map<string, int> dict;  // {}
    dict.insert(pair<string, int>("Tom", 1)); 		// {"Tom"->1}
    dict.insert(pair<string, int>("Jone", 2)); 		// {"Tom"->1, "Jone"->2}
    dict.insert(pair<string, int>("Mary", 1)); 		// {"Tom"->1, "Jone"->2, "Mary"->1}
    dict.insert(pair<string, int>("Tom", 2)); 		// {"Tom"->1, "Jone"->2, "Mary"->1}
    
    return 0;
}
访问映射

在 C++ 中访问映射合数组一样,直接用 [] 就能访问。比如 dict[“Tom”] 就可以获取 “Tom” 的班级了。而这里有一个比较神奇的地方,如果没有对 “Tom” 做过映射的话,此时你访问 dict[“Tom”] ,系统将会自动为 “Tom” 生成一个映射,其 value 为对应类型的默认值。并且我们可以之后再给映射赋予新的值,比如 dict[“Tom”] = 3 ,这样为我们提供了另一种方便的插入手段。当然有些时候,我们不希望系统自动为我们生成映射,这时候我们需要检测 “Tom” 是否已经有映射了,如果已经有映射再继续访问。这时候就需要用 count( ) 函数进行判断。

#include <map>
#include <string>
#include <stdio.h>
using namespace std;
int main()
 {
	map<string, int> dict;  // {}
	dict["Tom"] = 1; // {"Tom"->1}
	dict["Jone"] = 2; // {"Tom"->1, "Jone"->2}
	dict["Mary"] = 1; // {"Tom"->1, "Jone"->2, "Mary"->1}
	printf("Mary is in class %d\n", dict["Mary"]);
	printf("Tom is in class %d\n", dict["Tom"]);
    return 0;
}
查找关键字

在 C++ 中,如果你想知道某个关键字是否被映射过,你可以直接用 count( ) 方法。如果被映射过,返回 1 ,否则返回 0 。

#include <map>
#include <string>
#include <stdio.h>
using namespace std;
int main() 
{
    map<string, int> dict;  // {}
    dict["Tom"] = 1; // {"Tom"->1}
    dict["Jone"] = 2; // {"Tom"->1, "Jone"->2}
    dict["Mary"] = 1; // {"Tom"->1, "Jone"->2, "Mary"->1}
    if (dict.count("Mary"))
    {
        printf("Mary is in class %d\n", dict["Mary"]);
    } 
    else 
    {
        printf("Mary has no class");
    }
    return 0;
}
遍历映射

在 C++ 中,通过迭代器可以访问映射中的每个映射,每个迭代器的 first 值对应 key,second 值对应 value。

#include <map>
#include <string>
#include <iostream>
using namespace std;
int main() 
{
    map<string, int> dict;  	// {}
    dict["Tom"] = 1; 			// {"Tom"->1}
    dict["Jone"] = 2; 			// {"Tom"->1, "Jone"->2}
    dict["Mary"] = 1; 			// {"Tom"->1, "Jone"->2, "Mary"->1}
    for (map<string, int>::iterator it = dict.begin(); it != dict.end(); ++it) 
    {
        cout << it->first << " is in class " << it->second << endl;
    }
    return 0;
}
清空

C++ 中只需要调用 Clear( ) 即可清空 map。

C++中map常用方法总结
方法功能
insert插入一个元素
count判断关键字
erase删除关键字
size获取映射对个数
clear清空

栈 stack

实现一种 先进后出 的数据结构,是一个模板类。头文件 #include <stack>

用法 (以 int 型为例):

stack <int> s;             //定义一个int型栈

s.empty();                        //返回栈是否为空

s.size();                         //返回当前栈中元素的个数  

s.push();                         //在栈顶上堆进一个元素
 
s.pop();                          //删除掉栈顶上的元素

s.top();                          //返回栈顶的元素,并不会删除  

代码示例:

#include <iostream>
#include <stack>
using namespace std;

int main()
{

       stack<int> s;
       cout<<"stack empty?  "<<s.empty()<<endl;
       for(int i=0;i<5;i++)
       {
              s.push(i);        //入栈
       }

       cout<<"stack empty?  "<<s.empty()<<endl;
       cout<<"stack size:   "<<s.size()<<endl;
       cout<<endl;

       for(int i=0;i<5;i++)
       {
              cout<<"stack top:  "<<s.top()<<endl;
              s.pop();                 //出栈     
       }
       return 0;
} 

在这里插入图片描述


队列 Queue

实现一种 先进先出 的数据结构,是一个模板类。头文件 #include <queue>

用法 ( 以 int 型为例 ):

queue<int> Q;                  //定义一个int型队列

Q.empty();                      //返回队列是否为空

Q.size();                        //返回当前队列长度

Q.front();                       //返回当前队列的第一个元素

Q.back();                        //返回当前队列的最后一个元素

Q.push();                     //在队列后面插入一个元素, 比如插入数字5: Q.push(5)

Q.pop();                        //从当前队列里,移出第一个元素

代码示例:

#include <iostream>
#include <queue>

using namespace std;
int main()
{
       queue<int> Q;
       cout<<"queue empty?  "<<Q.empty()<<endl;

       for(int i=0;i<5;i++)
       {
              Q.push(i);        //进队列
       }

       cout<<"queue empty?  "<<Q.empty()<<endl;
       cout<<"queue size:   "<<Q.size()<<endl;
       cout<<endl;

       for(int i=0;i<5;i++)
       { 
              cout<<"queue front:  "<<Q.front()<<endl;    
              Q.pop();                //出队列
       }

       return 0;
}

在这里插入图片描述


双向链表 list

头文件:#include <list>

1、构造函数

list<int> a{1,2,3}
list<int> a(n)    			//链表中有n个元素,每个元素值都是0
list<int> a(n, m) 			//链表中有n个元素,每个元素值都是m
list<int> a(first, last) 	//声明一个链表,其元素的初始值来源于由区间所指定的序列中的元素,first和last是迭代器

2、begin() 和 end()

通过调用 list 容器的成员函数 begin() 得到一个指向容器起始位置的 iterator,可以调用 list 容器的 end() 数来得到 list 末端下一位置

3、push_back() 和 push_front()

使用 list 的成员函数 push_back 和 push_front 插入一个元素到 list 中。其中 push_back() 是从list 的末端插入,而 push_front() 是从 list 的头部插入

4、empty()

判断 list 是否为空

5、resize()

调用 resize(n) 将 list 的长度改为只容纳 n 个元素,超出的元素将被删除。如果 n 比 list 原来的长度长,那么默认超出的部分元素置为0。也可以用 resize(n, m) 的方式将超出的部分赋值为m

list<int>b{1, 2, 3, 4};
b.resize(2);				//list中输出元素:1,2

list<int>b{1, 2, 3, 4};
b.resize(6);				//list中输出元素:1,2,3,4,0,0

list<int>b{1, 2, 3, 4};
b.resize(6,9);				//list中输出元素:1,2,3,4,9,9

6、clear()

清空 list 中的所有元素

7、front() 和 back()

通过 front() 可以获得 list 容器中的头部元素,通过 back() 可以获得 list 容器的最后一个元素。注意:当 list 元素为空时,这时候调用 front() 和 back() 不会报错。因此在编写程序时,最好先调用 empty() 函数判断 list 是否为空,再调用 front() 和 back() 函数。

8、pop_back() 和 pop_front()

使用 pop_back() 可以删掉尾部第一个元素,pop_front() 可以删掉头部第一个元素。注意:list必须不为空,如果当 list 为空的时候调用 pop_back() 和 pop_front() 会使程序崩掉。

9、assign()

有两种使用情况:

— a.assign(n, val):将a中的所有元素替换成n个val元素

list<int> b{1,2,3,4,5};
b.assign(5,10);				//b中的元素变为10, 10, 10, 10, 10

a.assign(b.begin(), b.end())

list<int> a{6,7,8,9};
list<int> b{1,2,3,4,5};
b.assign(a.begin(),a.end());		//b中的元素变为6,7,8,9

10、swap()

交换两个链表。a.swap(b)和swap(a, b)都可以完成a链表和b链表的交换。

list<int>a{6,7,8,9};
list<int>b{1,2,3,4,5};
swap(a, b);  				//或a.swap(b),a中元素变为1,2,3,4,5 b中元素变为6,7,8,9

11、reverse()

可以实现 list 的逆置

list<int> b{1,2,3,4,5};
reverse(b.begin(),b.end());				//b中元素变为5,4,3,2,1

12、merge()

a.merge(b) 调用结束后b变为空,a中元素包含原来a和b的元素。

list<int>a{6,7,8,9};
list<int>b{2, 1, 3, 6, 5};
a.merge(b,greater<int>());				//a中元素变为:6,7,8,9,2,1,3,6,5
list<int>a{6,7,8,9};
list<int>b{2, 1, 3, 6, 5};
a.merge(b);								//a中元素变为:2,1,3,6,5,6,7,8,9

13、insert()

在指定位置插入一个或多个元素

a.insert(a.begin(),100);  					//在a的开始位置(即头部)插入100
a.insert(a.begin(),2, 100);     			//在a的开始位置插入2个100
a.insert(a.begin(),b.begin(), b.end());		//在a的开始位置插入b从开始到结束的所有位置的元素

14、erase()
删除一个元素或一个区域的元素

a.erase(a.begin());  				//将a的第一个元素删除
a.erase(a.begin(),a.end());  		//将a的从begin()end()之间的元素删除。

15、remove()函数

从list中删除元素

list<int>a{6,7,8,9,7,10};
a.remove(7);				//删除了a中所有值为7的元素,此时a中元素为6,8,9,10
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值