【刷题】数据结构——STL【模板】

1 二元组:pair

pair<int, string> p, p1, p2;
p.first // 第一个元素(int)
p.second // 第二个元素(string)

p1 = make_pair(1, "2"); // 构造pair
p2 = {3, "4"}; // 构造pair(c++11)

// 支持比较运算,先按first排,再按second排
p1 < p2

pair<int, pair<int, int>> pp; // 三元组

2 变长数组:vector

采用倍增的思想,当元素个数超过大小时,将大小*2。
例如分配 1 0 3 10^3 103空间
那么第一次分配空间大小为:1
第二次分配空间大小为:2
第三次分配空间大小为:4
第四次分配空间大小为:8

第10次分配空间大小为:512
总共大小: 1 + 2 + 4 + . . . + 512 = 1023 1 + 2 + 4 + ... + 512=1023 1+2+4+...+512=1023

#include <iostream>
using namespace std;

#include <vector>

int main(){
	vector<int> a; // 定义一个vector
	vector<int> a(10); // 长度为10的vector
	vector<int> a[10]; //同上
	vector<int> a(10, 3); // 长度为10的vector,且每个数都是3
	//二维vector,大小是[10][100],初始化全为-0x3f3f3f3f
	vector< vector<int> > a(10, vector<int>(100, -0x3f3f3f3f)); 
	vector<int> a = {1, 2, 3, 4, 5}; // 定义一个vector,并给初始值
	
	// 遍历vector(其他set、map也可用)
	for (auto x : a) cout << x << endl; // (c++11才可用auto)
	for (vector<int>::iterator i = a.begin(); i != a.end(); i ++ ) cout << *i << endl;
	for (int i = 0; i < a.size(); i ++ ) cout << a[i] << endl; // 用[]是vector特有的
	
	a.size(); // 返回元素个数 时间O(1)
	a.empty(); // a为空返回true 时间O(1)
	a.clear(); // 清空a
	a.front(); // 返回a第一个数
	a.back(); // 返回a最后一个数
	a.push_back(1); // 向a末尾插入1
	a.pop_back(); // 删除a末尾的数
	a.resize(5); // 将a大小改成5
	
	a.assign(6, 9); // 给a赋值成6个9
	vector<vector<int>> b;
	b.assign(3, vector<int>(4, 1));	// b赋值成3 * 4的矩阵,每个值是1
	

	// 支持比较,按字典序比较,3333 < 444
	vector<int> b(4, 3); // 4个3
	vector<int> c(3, 4); // 3个4
	if (b < c) printf("b < c");
}


3 字符串:string

	string a = "abc"; // 创建字符串
	a += "def"; // 末尾添加字符串
	
	a.size(); // 返回元素个数 时间O(1),也可用a.length()
	a.empty(); // a为空返回true 时间O(1)
	a.clear(); // 清空a

	a.substr(1, 2); // 从下标1开始,长度为2的子串:bc
	a.substr(1, 200); // 超过长度则会输出到最后一个字母:bcdef
	a.substr(1); // 输出到最后一个字母:bcdef
	printf("%s\n", a.c_str()); // c_str()返回a的起始地址
	
	a = to_string(-123); // int转string
	int l1 = stoi(a); // string转int
	long l2 = stol(a); // string转long
	long long l3 = stoll(a); // string转long long

4 队列:

4.1 queue 普通队列

#include <queue>
	queue<int> a;

	a.size(); // 返回元素个数 时间O(1)
	a.empty(); // a为空返回true 时间O(1)
	a = queue<int>(); // 队列没有clear,构造新的来清空
	a.front(); // 返回队头
	a.back(); // 返回队尾
	a.push(1); // 向队头插入
	a.pop(); // 队尾弹出

4.2 priority_queue 优先队列

用堆实现

#include <queue>
	priority_queue <int> a; // 默认大根堆
	// 插入x时改成-x,可变成小根堆

	// 定义小根堆,参数分别是堆存的元素类型、堆实现方式(一般都是vector)、比较方式
	priority_queue <int, vector<int>, greater<int>> b; 

	a.size(); // 返回元素个数 时间O(1)
	a.empty(); // a为空返回true 时间O(1)
	a = priority_queue <int>() // 队列没有clear,构造新的来清空
	a.top(); // 返回堆顶
	a.push(1); // 向堆插入
	a.pop(); // 弹出堆顶

c++11的greater

template <class T> struct greater {
  bool operator() (const T& x, const T& y) const {return x>y;}
  typedef T first_argument_type;
  typedef T second_argument_type;
  typedef bool result_type;
};

与之相对的是less

template <class T> struct less {
  bool operator() (const T& x, const T& y) const {return x<y;}
  typedef T first_argument_type;
  typedef T second_argument_type;
  typedef bool result_type;
};

4.3 deque 双端队列

功能强大但效率很低

#include <deque>
	deque<int> a; 
	
	a.size(); // 返回元素个数 时间O(1)
	a.empty(); // a为空返回true 时间O(1)
	a.clear() // 清空a
	a.front() // 返回第一个元素
	a.back(); // 返回最后一个元素
	a.push_back(1) // 队尾插入元素
	a.pop_back() // 队尾删除元素
	a.push_front(1); // 队首插入元素
	a.pop_front(); // 队首删除元素
	a[1]; //支持[]取元素
	a.begin();
	a.end();

5 栈:stack

#include <stack>
	stack <int> a; 

	a.size(); // 返回元素个数 时间O(1)
	a.empty(); // a为空返回true 时间O(1)
	a = stack<int>() // 栈没有clear,构造新的来清空
	a.top(); // 返回栈顶
	a.push(1); // 栈顶插入
	a.pop(); // 栈顶弹出

6 红黑树(平衡二叉树):

6.1 set

不能有重复元素,插入重复元素将忽略

#include <set>

	set<int> a;

	a.size(); // 返回元素个数,时间O(1)
	a.empty(); // a为空返回true,时间O(1)
	a.clear(); // 清空a
	
	a.insert(1); // 插入一个数,时间O(log(n))
	a.find(1); // 查找一个数,不存在返回a.end()
 	a.count(1); // 返回某个数的个数
 	a.erase(1); // 删除所有等于1的结点,时间O(k + logn)
 	//a.erase(迭代器); // 删除迭代器
	
	a.insert(1);
	a.insert(2);
	a.insert(3);
	for (auto it : a) {  // c++11中可以用auto快速遍历
		cout << it << " ";  // 目前set里有1, 2, 3
	}
	cout << endl;
	
	set<int>::iterator it;
	int x = 2;
	it = a.lower_bound(x); // 返回>=x的第一个数的迭代器
	cout << *it << endl;  // 2 
	it = a.upper_bound(x); // 返回>x的第一个数的迭代器
	cout << *it << endl;  // 3 

6.2 map

#include <map>

	map<string, int> a;

	a.size(); // 返回元素个数,时间O(1)
	a.empty(); // a为空返回true,时间O(1)
	a.clear(); // 清空a
	
	a.insert({"a", 1}); // 插入一个pair,时间O(log(n)),重复会忽略
	a["b"] = 2; // 支持[]来插入元素,时间O(log(n)),重复会覆盖 
	if(a["b"] == 2); // 支持[]来通过key找value,时间O(log(n))
	
	
	
	for (auto it : a) {  // c++11中可以用auto快速遍历,这边的it是pair变量,不是迭代器 
		cout << it.first << " " << it.second << endl;  // first是key,second是value 
	}
	cout << endl;
	
	
	
	map<string, int>::iterator it;
	it = a.find("a"); // 查找一个pair,不存在返回a.end(),存在返回pair{"a", 1}的地址 
	cout << it->first << " " << (*it).second << endl; // 输出key和value: a 1
	
	
 	a.count("a"); // 返回key="a"的个数
 	a.erase("a"); // 删除所有key="a"的结点,时间O(k + logn)
// 	a.erase(迭代器); // 删除迭代器 例如a.erase(a.begin())删除第一个 
	
	a.lower_bound("a"); // 返回key>="a"的第一个迭代器
	a.upper_bound("a"); // 返回key>"a"的第一个迭代器
	
	it = a.lower_bound("b");
	cout << it->first << endl;  // 上面erase了a,map里只剩b,所以这边使用 lower_bound能查找到b("b"),如果使用 upper_bound("b")则会报错 


//
	unordered_map<int, int> map1;
    map1[0] = 0;
    map1[1] = 1;

    unordered_map<int, int> map2;
    map2[1] = 1;
    map2[0] = 0;

    if (map2 == map1) {	// 可以直接比较,但只能用==,不能用<或>
        cout << "相等" << endl;
    }

6.3 multiset

可以用重复元素
其他操作同set


6.4 multimap

可以用重复元素
其他操作同map


7 哈希表:

和上面操作一样,但增删改查时间是O(1)
不支持lower_bound()和upper_bound()
不支持迭代器的++、–

7.1 unordered_set

7.2 unordered_map

7.3 unordered_multiset

7.4 unordered_multimap

7.5 手写哈希值

遇上没法比较的对象,需要手写哈希值。

struct ptrCmp
{
    bool operator()(const char * s1, const char * s2) const {
        return strcmp(s1, s2) == 0;
    }
};
struct ptrHash
{
    size_t operator()(const char *str) const {
        size_t strLength = strlen(str);
        size_t hash = std::_Hash_impl::hash(str, strLength);
        return hash;
    }
};
unordered_map<char *, int, ptrHash, ptrCmp> mp;

8 压位:bitset

bool flag[1024];需要1024字节
如果压到位里,因为每位是8位,只需要128字节。

#include <bitset>
	bitset<10000> a; // 大小10000的bitset
	// 支持以下操作
	~, &, |, ^
	>>, <<
	==, !=
	[]
	
	a.count(); // 返回多少个1
	a.any(); // 判断是否至少有1个1
	a.none(); // 判断是否全为0

	a.set(); // 把所有变成1
	a.set(k, v); // 第k位变成v
	a.reset(); // 所有变成0
	a.flip(); // 所有位取反
	a.flip(k); // 第k位取反

9. sort

#include <algorithm>
using namespace std;
struct Node {
	int l, r;
	bool operator< (const Node &p) const //自定义比较函数
    {
		//按照r从小到大排序,r相等按l从大到小排序
        if(r != p.r)	return r < p.r; 
        else	return l > p.l;
    }
};
Node p[1005];

int main() {
	sort(p, p + n);
}
#include <algorithm>
using namespace std;
struct Node
{
    int l, r;
};
Node p[1005];
bool cmp(const Node &x, const Node &y) {
	return (x.r < y.r|| (x.r == y.r && x.l > y.l)); 
}
int main() {
	sort(p, p + n, cmp);
}
	vector<int>input = { 1, 5, 2, 1, 3, 2, 5 };
	//排序整个vector
	sort(input.begin(), input.end());
	//对任意区间进行排序,同样使用迭代器
	auto start = input.begin()+2;//下标对应2
	auto end = start +3;//下标对应5
	sort(start, end);//区间[2,5)进行排序

10.二分

#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;

// 自定义规则,数组从大到小
class my_comp {
public:
    bool operator()(const int& i, const int& j) {
        return i > j;
    }
};

int main() {
    int a[5] = {1,3,5,7,9};
    //从 a 数组中找到第一个 >= 3 的元素,如果所有元素都小于3,则返回数组末尾的后一个位置,该位置是越界的。
    int *l = lower_bound(a, a + 5, 3);
    int index_l = lower_bound(a, a + 5, 3) - a;
    cout << *l << " " << index_l << endl;	// 3 1

    //从 a 数组中找到第一个 > 3 的元素
    int *u = upper_bound(a, a + 5, 3);
    int index_u = upper_bound(a, a + 5, 3) - a;
    cout << *u << " " << index_u << endl;	// 5 2


	// 自定义排序方式,并在vector中搜索
    vector<int> v{9, 7, 5, 3, 1};	// 递减序列
    vector<int>::iterator iter = lower_bound(v.begin(), v.end(), 7 , my_comp());
    int index = lower_bound(v.begin(), v.end(), 7 , my_comp()) - v.begin();
    cout << *iter << " " << index ;	// 7 1
}
  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值