C++ STL详解(2)

点击蓝字

47210f1a0f14588acdfd0aa8671aa209.png

关注我们

来源自网络,侵删

刷题时常用的STL

string

之前写过一篇 string 的简介但是不是特别全面,这里再补充说明一下。

size()

 返回字符串中字符的数量

#include<iostream>
#include<string>


using namespace std;


int main() {
  string str = "AC-fun";
  cout << str.size();
  // 输出结果:6
  return 0;
}

clear()

 清空一个字符串

#include<iostream>
#include<string>


using namespace std;


int main() {
  string s = "string";
  cout << s;
  s.clear(); // 清空一个字符串 
  cout << endl;
  cout << "清空后字符串的长度为:" << s.size() << endl;
  cout << "清空后字符串的内容为:" << s;
  return 0;
}

操作符(Operators)

 你可以用 ==, >, <, >=, <=, != 比较字符串,可以用 + 或者 += 操作符连接两个字符串,并且可以用 [] 获取特定的字符。

compare()

 compare() 函数以多种方式比较本字符串和 str,按照 字典序 进行排序。使用 this 代表当前字符串,str 代表与 this 比较的字符串。那么如果“ this > str” 则 返回值大于零;如果“this = str ” 那么 返回值等于零;如果 “this < str ”那么 返回值小于零。此函数也有多种比较方式,下面分别进行介绍。

  • 比较自己 (this) 和 str

#include<iostream>
#include<string>


using namespace std;


int main() {
  string str1 = "aaa", str2 = "ab";
  if (str1.compare(str2) > 0) cout << "str1 > str2";
  else if (str1.compare(str2) == 0) cout << "str1 = str2";
  else cout << "str1 < str2";
  
  // 输出结果:str1 < str2 
  return 0;
}
  • 比较 自己的子串 和 str
     子串以 index 索引开始(从 0 开始),长度为 length。形式为:str1.compare(index, length, str2) 表示比较 str1 的子串与 str2 的大小。

#include<iostream>
#include<string>


using namespace std;


int main() {
  string str1 = "abcdef", str2 = "ef";
  int flag = str1.compare(4, 2, str2);
  if (flag) cout << "str1 > str2";
  else if (flag == 0) cout << "str1 = str2";
  else cout << "str1 < str2";
  
  // 输出结果:str1 = str2 
  return 0;
}

        •比较 自己的子串 和 str的子串

 比较形式为:str1.compare(index, length, str2, index2, length2)。其中    index2 和 length2 引用 str,index 和 length 引用str1。如果不写   index2   则 str2 的子串以索引 0 开始,长度为 length2,str1 的子串以     index 开始,长度为 length。

#include<iostream>
#include<string>


using namespace std;


int main() {
  string str1 = "abcdef", str2 = "abef";
  int flag = str1.compare(4, 2, str2, 2, 2);
  if (flag) cout << "str1 > str2";
  else if (flag == 0) cout << "str1 = str2";
  else cout << "str1 < str2";
  
  // 输出结果:str1 = str2 
  return 0;
}

substr()

 substr()返回本字符串的一个子串,从index开始,长num个字符。形式为:str.substr(index, length)。如果不写参数 length 或者参数 length 超过了 str 的长度,那么就将从 index 开始之后的所有字符输出。

#include<iostream>
#include<string>


using namespace std;


int main() {
  string str = "AC-fun";
  cout << str.substr(3, 3);
  
  // 输出结果:fun
  return 0;
}

c_str()

 c_str() 函数返回一个指向正规 C 字符串的指针,即返回存储字符串的字符数组的起始地址。利用这个函数可以使用 printf() 函数来输出 string 字符串。

#include<iostream>
#include<string>
#include<cstdio>


using namespace std;


int main() {
  string str = "AC-fun";
  printf("%s", str.c_str());
  
  // 输出结果:AC-fun
  return 0;
}

find()

 在字符串中查找字符串。此函数有三种重载方式。下面分别进行介绍。

str1.find(string str2, int index)

 返回 str2 在字符串 str1 中第一次出现的位置(从index开始查找)如果不写 index 参数,则直接从 str1 的开头开始查找。如果找到了返回 **str2 ** 第一次出现的位置(下标从 0 开始);如果没找到则返回 string::npos。对于 string::npos C++ 的官方文档对它的解释为:

 static const size_t npos = -1; npos是一个静态成员常量值,对于 size_t 类型的元素,该常量的最大值可能。该值在字符串成员函数中用作len(或sublen)参数的值时,表示“直到字符串结尾”。作为返回值,通常用于表示没有匹配项。该常量定义为值 -1,这是因为 size_t 是无符号整数类型,因此它是此类型可能的最大可表示值。

 因此,在判断字符串有没有时,可以直接判断是否等于 string::npos,也可以判断是否等于 -1

#include<iostream>
#include<string>
#include<cstdio>


using namespace std;


int main() {
  string str1 = "AC-fun", str2 = "fun", str3 = "good";
  if (str1.find(str2, 0) != -1) cout << "Yes" << endl;
  if (str1.find(str3, 0) == string::npos) cout << "No";
  // 输出结果:Yes
  //       No
  return 0;
}
  • str1.find(char ch, int index)
     返回字符 ch 在字符串中第一次出现的位置(从 index 开始查找)。如果没找到就返回 string::npos

#include<iostream>
#include<string>
#include<cstdio>


using namespace std;


int main() {
  string str1 = "AC-fun";
  if (str1.find('-', 0) != -1) puts("Yes");
  else puts("No");
  // 输出结果:Yes
  return 0;
}

关于string的更多用法

 string还有很多函数,但是一般常用的函数就是以上提到的,想要学习更多用法请看:C++ API string

priority_queue

 priority_queue 优先队列总能 保证优先级最高的元素位于队头,最重要的原因是其底层采用 堆 数据结构存储结构。STL 的优先队列默认是 大根堆,即最大的元素总是位于队头。其操作方式与队列 queue 基本相同。优先队列的头文件也是 #include<queue>。时间复杂度为:O(nl o g n lognlogn)。

push()

 插入元素,并对底层容器排序。

#include<iostream>
#include<queue>


using namespace std;


int main() {
  priority_queue<int> heap;
  heap.push(1);
  heap.push(2);
  heap.push(3);
  
  // 使用 top() 访问堆顶元素
  cout << heap.top();
  // 输出结果:3 
  return 0;
}

top()

 访问堆顶元素。演示代码同 push()。

empty()

 检查底层的容器是否为空。若底层容器为空则为 true ,否则为 false 。

size()

 返回底层容器中的元素个数,即 heap.size()。

#include<iostream>
#include<queue


using namespace std;


int main() {
  priority_queue<int> heap;
  heap.push(1);
  heap.push(2);
  heap.push(3);
  cout << heap.size(); 
  // 输出结果:3 
  return 0;
}

pop()

 弹出堆顶元素。

#include<iostream>
#include<queue>


using namespace std;


int main() {
  priority_queue<int> heap;
  heap.push(1);
  heap.push(2);
  heap.push(3);
  cout << "当前堆顶元素为:" << heap.top() << endl; 
  // 弹出堆顶元素 
  heap.pop();
  cout << "当前堆顶元素为:" << heap.top();
  return 0;
}

如何定义小根堆

 第一种方式是可以直接插入 -x,那么就可以直接利用大根堆创建了小根堆,输出的时候输出 -x 即可。
 第二种方式是使用 priority_queue 提供的方法。

#include<iostream>
#include<queue>
#include<vector>


using namespace std;


int main() {
  // 定义一个小根堆 
  priority_queue<int, vector<int>, greater<int> > heap; 
  heap.push(1);
  heap.push(2);
  heap.push(3);
  cout << "当前堆顶元素为:" << heap.top() << endl; 
  return 0;
}

堆排序

 堆是一棵 完全二叉树 ,可以使用数组模拟堆的实现。可以使用一维数组 h[] 来进行存储,对于根节点 x ,它的左儿子的下标为 x ∗ *∗ 2,右儿子的下标为 x ∗ *∗ 2 + 1。

    构建一个小跟堆其中最关键的一个函数就是 down() 函数。只要当前的根节点不是最小的元素那么就将其向下移动。直到当前的根节点是最小的元素。代码及主要思路如下:

void down(int u) {
    int t = u;
    //  找出根、左、右三个点做小的那个点
    if (2 * u <= cnt && h[2 * u] < h[t]) t = 2 * u; 
    // 首先判断一下当前的根节点有没有左孩子,如果有判断一下根节点和左孩子的大小
    if (2 * u + 1 <= cnt && h[2 * u + 1] < h[t]) t = 2 * u + 1;
    // 然后再判断一下当前根节点有没有右孩子,如果有判断一下上一步比较出来的做小值和当前右孩子的值的大小
    if (u != t) {
        swap(h[u], h[t]);
        // 此时原来的元素 h[u] 就被换到了下标为 t 的数组中,所以继续 down(t)
        down(t);
    }
}

那么如何弹出栈顶元素呢?只要将第一个元素与最后一个元素交换,然后将指向堆中最后一个指针向前移动一个,再 down(1) 即可。这样就可以在删除时一直保证堆顶元素时最小的元素。

完整代码:

#include<iostream>
#include<cstdio>
#include<algorithm>


using namespace std;


const int N = 100010;
int n, m;
int h[N], cnt;  // 最好不要使用 size 作为变量,因为有的头文件里会有size函数,容易冲突


void down(int u) {
    int t = u;
    //  找出根、左、右三个点做小的那个点
    if (2 * u <= cnt && h[2 * u] < h[t]) t = 2 * u; 
    // 首先判断一下当前的根节点有没有左孩子,如果有判断一下根节点和左孩子的大小
    if (2 * u + 1 <= cnt && h[2 * u + 1] < h[t]) t = 2 * u + 1;
    // 然后再判断一下当前根节点有没有右孩子,如果有判断一下上一步比较出来的做小值和当前右孩子的值的大小
    if (u != t) {
        swap(h[u], h[t]);
        // 此时原来的元素 h[u] 就被换到了下标为 t 的数组中,所以继续 down(t)
        down(t);
    }
}


int main() {
    scanf("%d%d", &n, &m);
    for (int i = 1; i <= n; i++) scanf("%d", &h[i]);
    cnt = n;
    for (int i = n / 2; i; i--) down(i);
    // 先输入再维护小根堆的时间复杂度为 O(n),而一边输入一边维护的时间复杂度为 Nlog(N)
    while (m--) {
        printf("%d ", h[1]);
        h[1] = h[cnt];
        cnt--;
        down(1);
    }
    return 0;
}

未完待续,持续更新中……

 
 
 
 

c97ef1667fa07c541efcd62232ca95f1.gif

如果你年满18周岁以上,又觉得学【C语言】太难?想尝试其他编程语言,那么我推荐你学Python,现有价值499元Python零基础课程限时免费领取,限10个名额!
▲扫描二维码-免费领取

e7f756e24e4aa57de83fc3f454b42f15.gif

戳“阅读原文”我们一起进步

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值