C++ 之STL标准库学习笔记

前言

学习stl最好的办法就是刷算法题,因此这个学习笔记更准确来说是算法的学习笔记,但是主要应用的还是基本的stl知识,还并未涉及更多的数据结构知识。

容器与容器之间比较

相同的容器可以比较里面的内容只有当顺序 内容完全相同的时候就会返回true or false

#include <iostream>
#include <map>
#include <vector>
#include <string>  
#include <set>
#include <algorithm>
using namespace std;
int main() {
    set <int > s1;
    set <int > s2;
    vector <int > v1;
    vector <int > v2;
    for (int i = 0 ; i < 5 ; i ++) {
        s1.insert (i);
        s2.insert (i);
        v1.push_back(i);        // 0 1 2 3 4 
        v2.push_back(4 - i);        // 4 3 2 1 0
    }
    printf ("s1 == s2 ? %d \n" , s1 == s2);
    printf ("v1 == v2 ? %d \n" , v1 == v2);
    sort (v2.begin() , v2.end());
    printf ("v1 == v2 ? %d \n" , v1 == v2);
    return 0;
}

返回为
1
0
1

s1 == s2 ? 1
v1 == v2 ? 0
v1 == v2 ? 1

分别就代表true 跟false 因为vector中的元素虽然都相等但是顺序不一样还是回返回false的
然后重新排好顺序的时候就返回true了

string

string 输出方式

第一种 直接使用cout 来输出
第二种 string不能直接用printf函数输出
要利用一个函数 string.c_str(); 取到string 的首地址
然后再printf

string a = "asdf";
printf ("%s " , a.c_str());		//这样就可以了

string to int(float double)

当一个数字非常非常大的时候(超过十位数)可以利用string类型进行储存

  • 数字 1234567890987654321 此时假如用long long 的话既不美观而且后续数字更加大还是无法解决 此时就要用 :
    string num; cin >> num; 然后再进行处理

将string的数字转化成 int 可以使用 方法1

  1. stoi (string to int ) int num = stoi (num); 值得注意的事这个数字不能非常大

又或者方法2 这个方法优先使用!!!(当只有一个数字的时候或者每一位每一位判断的时候)

  • “5” 此时可以利用 字符串减去 ‘0’ 来得到int 5

string 大小写

string 的大小写转换 首先需要algorithm 头文件中的transform函数
注意transform有四个输入参数:

1:str.begin()字符串的起始地址;
2:str.end()字符串的终止地址;
3:str.begin()是转换之后,输出到原str字符串的起始地址;
4:转换操作,可以选择toupper,tolower。

#include <iostream> 
#include <string>
#include <algorithm>
 
using namespace std;
 
int main() {
    string src = "Hello World!";
    string dst;
 
    transform(src.begin(), src.end(), back_inserter(dst), ::toupper); //大写
    cout << dst << endl;
 
    transform(src.begin(), src.end(), dst.begin(), ::tolower); //小写
    cout << dst << endl;
 
	system("pause");
    return 0;
}
 
/*
输出结果:
HELLO WORLD!
hello world!
*/

以上那种为一下子全部进行转换的 除此之外还有stl中自带的toupper tolower函数
这个读入的形式是char

string a;

a = "hello world"
for (int i = 0 ; i < a.length() ; i ++) cout << toupper(a[i]);
输出的值就为HELLO WORLD
tolower同理

string 和 char的ASCII码输出

假如一个字符串中包含很多不同类型的字符
可以用hash[200]来记录次数

string a = "sa 432';l';f3[00";
    int hash [200] = {0};
    for (int i = 0 ; i < a.length() ; i ++) hash[a[i]] ++;
    for (int i = 0 ; i < a.length() ; i ++) {
        cout << a[i] << " " << hash[a[i]] << endl;
    }

这分别是每个字符出现的次数 因此可以用这个表来进行记录
原理是每个字符都有对应的ASCII码对应着
比如空格 “ ” 对应着 0;

在这里插入图片描述

当想输入一个字符串的ASCII码的时候最好是用 printf语句参考博客
注意 string字符串跟char字符的ASCII码不一样的!!!!即使是字母一样也是不一样的。

#include <iostream>
#include <string>

using namespace std;

int main (){
    char a ;
    int b;
    string c;

    cin >> a >> b >> c;

    printf ("the ascii code is : %d \n" , a);

    printf ("the string is %c \n" , b);

    printf ("the ascii code is : %d \n" , c);

    return 0;
}
结果
a 100 a     //输入的内容

//输出的内容
the ascii code is : 97
the string is d
the ascii code is : 6422000

string 增加append

增加字符串 可以利用append函数

//意思是对字符串a 增加 length长度的 字符串b

 stringa.append(length, stringb);

string 删除remove 跟 erase

erase 函数有两种用法

string a = "abcdefg";
a.erase(2);		//此时就删除了索引为2 的c了

a.erase(2 , 4);		//此时意思是从索引为2 的位置删除4个字符

假如想指定删除某一种字符的话就得配合remove函数使用

string a = "11123456";

a.erase(remove(a.begin() , a.end() , '1') , a.end()); 
// 意思是从a的起点 到a的终点中 删除 字符‘1’;

此时a为 "23456";

字符串反转函数

reverse(str.begin(),str.end());
// STL 反转函数 reverse() 的实现
    /*     template <class BidirectionalIterator>
     *     void reverse(BidirectionalIterator first, BidirectionalIterator last)
     *     {
     *         while ((first != last) && (first != --last))
     *             swap(*first++, *last);
     *     }
     */

字符串拷贝函数 substr

basic_string::substr
basic_string substr( size_type _Off = 0,size_type _Count = npos) const;
参数:
_Off ---- 所需的子字符串的起始位置。 字符 串中第一个字符的索引为 0,默认值为0.
_Count ---- 复制的字符数目
返回: 一个指定开始字符和指定长度的子字符串。

string.substr( ** 第一个参数是从哪一位开始截取 ** , **第二个参数是截取多少位 ** )

substr有2种用法:
假设:string s = "0123456789";
string sub1 = s.substr(5); //只有一个数字5表示从下标为5开始一直到结尾:sub1 = "56789"
string sub2 = s.substr(5, 3); //从下标为5开始截取长度为3位:sub2 = "567"

字符串查找函数

1.algorithm中的find()函数
返回值是目标元素的下标,找不到时返回值为迭代器结尾

string = "hello";
find(s.begin(), s.end(), 'o') == s.end()

2.string中的与find相关函数
string.find (char) 这个是最常用的
当找不到会返回 string::npos!!!!!!!!!!!!!!!!
经常搭配a.find (toupper(b[j])) != string::npos这行代码使用

string str1, str2;
	char c;
	str1.find(str2);//从串str1中查找时str2,返回str2中首个字符在str1中的地址
	
	str1.find(str2,5);//从str1的第5个字符开始查找str2

	str1.find(c);//在str1中查找字符o并返回第一个查找到的地址

    str1.find("str2",2 , 2);//从str1中的第二个字符开始查找of big的前两个字符

vector

vector 初始化

vector可以初始化成任何数!!!!!!!!
但是数组(不管全局不全局)都只能初始化成 0 !!!!!!

int q[n] = {1};
这句话就跟屁话一样没用的!!!!!!!

泪目
某个晚上因为这个点看了代码半个多钟

vector <int> v(n);
//可以直接初始化大小 , 也可以把别人数组直接搬过来

//假设已经有一个长度为 n 的数组q【n】了
vector <int> vv(q , q + n); 	//这样就能直接把数组复制过来了

有关vector的详细介绍转至bolg

这简单的说一下我的描述,当需要一个未定长度的数组时,就需要用到vector动态数组。

#include <vector>
// 引入头文件

//vector初始化
vector<int> v(size , value);
其中int 可以是任意类型 假如不给定value 默认为0

迭代器遍历vector

for (auto it = c.begin(); it != c.end(); it++) { // 使⽤用迭代器器的⽅方式访问vector
	cout << *it << " ";
}

多维数组的创建与使用

#include <iostream>
#include <vector>
using namespace std;
int main () {
    vector <vector<int> >  v; // 这个语句就是创建多维数组的意思
    for (int i = 0 ; i < 3 ; i ++) {
        vector <int > vv;
        for (int j = 0 ; j < 10 ; j ++) {
            vv.push_back(j);
        }
        v.push_back(vv);		//push_back 不仅可以放入基本数据类型 还可以放入 vector
    }
    for (int i = 0 ; i < v.size() ; i ++) {//这个v.size() 是一共有几个小vector 被放入 是个整型
        for (int j = 0 ; j < v[i].size() ; j ++) {//这个v[i].size() 就是每个小的有多少个元素了
            cout << v[i][j] << " ";
        }
        cout << endl;
    }
    return 0;
}

sort 函数

sort 函数在头文件 #include < algorithm > 里面,主要是对⼀一个数组进行排序( int arr[] 数组或者 vector 数组都行), vector 是容器,要用 v.begin() 和 v.end() 表示头尾;而 int arr[] 用 arr 表示数组的首地址, arr+n 表示尾部~

#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
bool cmp(int a, int b) { // cmp函数返回的值是bool类型
	return a > b; // 从⼤大到⼩小排列列
}

int main() {
	vector<int> v(10);
	for (int i = 0; i < 10; i++) {
		cin >> v[i];
	}
	sort(v.begin(), v.end());// 因为这⾥里里没有传⼊入参数cmp,所以按照默认,v从⼩小到⼤大排列列
	int arr[10];
	for (int i = 0; i < 10; i++) {
		cin >> arr[i];
	}
	sort(arr, arr + 10, cmp); // arr从⼤大到⼩小排列列,因为cmp函数排序规则设置了了从⼤大到⼩小
	return 0;
}

注意: sort 函数的 cmp 必须按照规定来写,即必须只是 > 或者 < ,比如: return a > b; 或者 return a < b; 而不能是 <= 或者 >= ,(实际上等于号加了也是毫无意义, sort 是不稳定的排序),否则可能会出现段错误~

用algorithm 中的 find函数进行查找值

参考博客

find (vec.begin(), vec.end(), 查找值)

#include <iostream>
#include <algorithm>
#include <vector>
 
int main()
{
    using namespace std;
 
    vector<int> vec;
 
    vec.push_back(1);
    vec.push_back(2);
    vec.push_back(3);
    vec.push_back(4);
    vec.push_back(5);
    vec.push_back(6);
 
    auto it = find(vec.begin(), vec.end(), 6);
 
    if (it != vec.end())
        cout<< *it << endl;
    else
        cout<<"can not find"<<endl;
 
    return 0;

假如没找到的话返回vec.end() 因此可以利用这个函数进行判断有无某个值

stack

stack详细描述
一般对stack 的使用都是用来逆序输出一个东西 比如

常用函数

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

//在栈中是用 push动作的
s.push(int a);

//访问栈顶
int b = s.top () ;

//删除栈顶
s.pop();

//while 循环遍历栈
while( !s.empty())    // 栈不为空的时候

题目
给定一句英语,要求你编写程序,将句中所有单词的顺序颠倒输出。

输入格式:
测试输入包含一个测试用例,在一行内给出总长度不超过 80 的字符串。字符串由若干单词和若干空格组成,其中单词是由英文字母(大小写有区分)组成的字符串,单词之间用 1 个空格分开,输入保证句子末尾没有多余的空格。

输出格式:
每个测试用例的输出占一行,输出倒序后的句子。

输入样例:
Hello World Here I Come

输出样例:
Come I Here World Hello

此时思路 当一直有字符串输入时 将字符串压入stack 然后最后除了第一个字符串其余的都先输出空格 然后再输出栈顶

代码实现:

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

int main (){
    stack <string> stc;
    string str;      
    while (cin >> str) stc.push(str);        //将string元素都压入stack里面   
    cout << stc.top();
    stc.pop();    
    while (!stc.empty()){            //当这个stack 不为空的时候
        cout << " " << stc.top();        
        stc.pop();
    }    
    cout << endl;    
    return 0;
}

注意while (!stc.empty()) 这个代码意思是当 stack 里面不为空的时候 在使用栈的时候经常需要使用!!!
并且在编译器中 while (cin >> str) 这一个语句一般是无法起到作用的因为会把你的回车字符也作为字符串进行读入 只有在oj上他们的输入文件是不以回车作为结束时才能运行。

set

关于set的常用技巧参考博客

set中的元素会自动的进行整理,并且当某元素已经存在于set里面的时候,
此时再进行插入set是没有用的,这就是算法题里面最好用的一个点,自动排序,唯一值等等。。。。

前言:set有自动排序,去除重复元素的优点,在一些题目中可以大大减少程序运行时间

set的一些常见操作

begin()返回指向第一个元素的迭代器(迭代器和指针用法类似)
count(x)返回x值元素的个数
empty()如果集合为空,返回true
end()返回指向最后一个元素的迭代器
eraser(x)删除集合中的x元素
find(x)返回一个指向被查找元素的迭代器
insert(y)把y插进集合,继续保持顺序
max_size()返回集合能容纳元素的最大限值
size()返回集合中元素的总个数
clear()清空集合中的元素
swap(st2)交换两个集合变量(注意这里是两个集合的变量,st2指的是第二个集合名)
其实set的大部分操作是与vector类似的,不过set不支持随机访问,必须要使用迭代器去访问。由于set放入一个元素就会调整这个元素的位置,把它放到合适的位置,所以set中只有一个insert插入操作。

set的高级操作(这些直接复制粘贴的,都不会)

对于集合来说,我们一般有并集、交集、差集、补集这几种操作,所以在set的操作中我们也有类似的集合操作,它们都在#include的头文件下:
std::set_intersection() :这个函数是求两个集合的交集。
std::set_union() :求两个集合的并集
std::set_difference():差集
std::set_symmetric_difference():得到的结果是 第一个迭代器相对于第二个的差集 并上第二个相对于第一个的差集

怎么输出set中的元素:

要想输出set元素,我们要定义一个迭代器:

set<int>::iterator it;
for(it=st.begin();it!=st.end();it++)
    cout << *it <<endl;

map

键值对
map 是键值对,比如一个人名对应一个学号,就可以定义一一个字符串 string 类型的人名为“键”,学
号 int 类型为“值”,如 map<string, int> m; 当然键、值也可以是其它变量类型~ map 会自动将所有的键值对按照键从小到大排序, map 使用用时的头文文件 #include 以下是 map 中常用的方法:

	#include <iostream>

	#include <map>

	#include <string>

	using namespace std;

	int main() {

	map<string, int> m; // 定义一一个空的map m,键是string类型的,值是int类型的

	m["hello"] = 2; // 将key为"hello", value为2的键值对(key-value)存入入map中

	cout << m["hello"] << endl; // 访问map中key为"hello"的value, 如果key不不存在,则返回0

	cout << m["world"] << endl;

	m["world"] = 3; // 将"world"键对应的值修改为3

	m[","] = 1; // 设立立一一组键值对,键为"," 值为1

	// 用用迭代器器遍历,输出map中所有的元素,键用用it->first获取,值用用it->second获取

	for (auto it = m.begin(); it != m.end(); it++) {

	cout << it->first << " " << it->second << endl;

	}

	// 访问map的第一一个元素,输出它的键和值

	cout << m.begin()->first << " " << m.begin()->second << endl;

	// 访问map的最后一一个元素,输出它的键和值

	cout << m.rbegin()->first << " " << m.rbegin()->second << endl;

	// 输出map的元素个数

	cout << m.size() << endl;

	return 0;
	}


map 中的find函数

用find函数来定位数据出现位置,它返回的一个迭代器,当数据出现时,它返回数据所在位置的迭代器,如果map中没有要查找的数据,它返回的迭代器等于end函数返回的迭代器

map<int, int> t;

if (t.find(key) != t.end()){ 	//当键被找的到时 返回的是迭代器 !!!!
	t.find(key) -> sencond;
}

map与其他容器的嵌套使用

#include <iostream>
#include <map>
#include <vector>
using namespace std;
int main() {
    map <int , vector<int> > m;			//在map里面放入vector
    for (int i = 0 ; i < 10 ; i ++)
        for (int j = 0 ; j < 5 ; j ++) {
            m[i].push_back(j);		//随后的用法跟两个分开是一样的
        }
    for (auto it = m.begin() ; it != m.end() ; it ++) {
        cout << it -> first << endl;
        for (int j = 0 ; j < it -> second.size() ; j ++) cout << it -> second[j] << " ";
        cout << endl;
    }
    return 0;
}

在这里插入图片描述

链表

pat乙级的链表题都比较简单
重点是理解并且背下来一个模板
比方说题目给出了的形式

Address Data NextAddress

00100 6 4
00000 4 99999
00100 1 12309
68237 6 -1
33218 3 00000
99999 5 68237
12309 2 33218

首先读入头节点 , 总共的节点数 ,以及某个参数K
然后创建data 数组来保存每个节点的数据
创建next数组来保存每个节点下一个节点的地址
创建list数组来保存按照初始顺序排好的地址数组

#include <iostream>
#include <algorithm>
using namespace std;
int main () {
    int head , n , k , tmp ;
    cin >> head >> n >> k;
    int data[100005] , next[100005] , list[100005];
    for (int i = 0 ; i < n ; i ++) {
        cin >> tmp;
        cin >> data[tmp] >> next[tmp];
    }
    int sum = 0;		//因为不确定有没有无用节点 所以要设定一个计数器
    while (head != -1) {
        list[sum ++] = head;
        head = next[head];
    }
	// 这就是读入数据 记录地址 并且整理顺序的方法了

cmath

#include <math.h>

//平方 pow()
int a = pow(4,2);// 4的平方=16
//开方
int b = pow(4,0.5);// 4的平方根=2
int c = sqrt(4);// 4的平方根=2
//整数绝对值
int c = abs(b-c);
//浮点数绝对值
double d = fabs(b-c);

如何判断一个数是不是素数

// 判断n是否为素数
bool isprime(int n) {
	if (n <= 1) return false;
	
	int sqr = int(sqrt(n * 1.0));
	for (int i = 2; i <= sqr; i ++)
		if (n % i == 0) return false;
	return true;
}

求一个数的最大公约数

辗转相除法 :
c++ :可以直接在algorithm 头文件中利用 __gcd (int a , int b)求出两个数的最大公约数
在c语言中 就要自己写这个函数了

int gcd (int a . int b) {
return b == 0 ? a : gcd (b , a % b);
}
  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值