- C++
数据结构-学习
- 2023-12-12 23:29:10 @
vector, 变长数组,倍增的思想
size() 返回元素个数
empty() 返回是否为空
clear() 清空
front()/back()
push_back()/pop_back()
begin()/end()
[]
支持比较运算,按字典序
pair<int, int>
first, 第一个元素
second, 第二个元素
支持比较运算,以first为第一关键字,以second为第二关键字(字典序)
string,字符串
size()/length() 返回字符串长度
empty()
clear()
result.back() 返回栈顶
result.pop_back(), 出栈
result.push_back(digit),进栈
result.resize(n.length() - s); 重新赋值大小
substr(起始下标,(子串长度)) 返回子串
c_str() 返回字符串所在字符数组的起始地址
queue, 队列
size()
empty()
push() 向队尾插入一个元素
front() 返回队头元素
back() 返回队尾元素
pop() 弹出队头元素
priority_queue, 优先队列,默认是大根堆
size()
empty()
push() 插入一个元素
top() 返回堆顶元素
pop() 弹出堆顶元素
定义成小根堆的方式:priority_queue<int, vector<int>, greater<int>> q;
stack, 栈
size()
empty()
push() 向栈顶插入一个元素
top() 返回栈顶元素
pop() 弹出栈顶元素
deque, 双端队列
size()
empty()
clear()
front()/back()
push_back()/pop_back()
push_front()/pop_front()
begin()/end()
[]
set, map, multiset, multimap, 基于平衡二叉树(红黑树),动态维护有序序列
size()
empty()
clear()
begin()/end()
++, -- 返回前驱和后继,时间复杂度 O(logn)
set/multiset
insert() 插入一个数
find() 查找一个数
count() 返回某一个数的个数
erase()
(1) 输入是一个数x,删除所有x O(k + logn)
(2) 输入一个迭代器,删除这个迭代器
lower_bound()/upper_bound()
lower_bound(x) 返回大于等于x的最小的数的迭代器
upper_bound(x) 返回大于x的最小的数的迭代器
map/multimap
insert() 插入的数是一个pair
erase() 输入的参数是pair或者迭代器
find()
[] 注意multimap不支持此操作。 时间复杂度是 O(logn)
lower_bound()/upper_bound()
unordered_set, unordered_map, unordered_multiset, unordered_multimap, 哈希表
和上面类似,增删改查的时间复杂度是 O(1)
不支持 lower_bound()/upper_bound(), 迭代器的++,--
bitset, 圧位
bitset<10000> s;
~, &, |, ^
>>, <<
==, !=
[]
count() 返回有多少个1
any() 判断是否至少有一个1
none() 判断是否全为0
set() 把所有位置成1
set(k, v) 将第k位变成v
reset() 把所有位变成0
flip() 等价于~
flip(k) 把第k位取反
6 条评论
-
xrqmzl LV 1 SU @ 2024-5-7 15:47:14
map 和 make_pair使用方式:
#include <bits/stdc++.h> using namespace std; int main() { map<string, int> mapp; mapp["qian"] = 1; mapp["zhang"] = 2; cout << mapp["qian"] << " " << mapp["zhang"] << endl; mapp.insert({"zhang", 0}); //插入的key已存在,则不会改变 cout << mapp["qian"] << " " << mapp["zhang"] << endl; mapp.insert({"wang", 3}); mapp.insert({"xu", 4}); mapp.emplace("chen", 5); mapp.insert(make_pair("teacher", 22)); //如下是循环输出的代码, 默认按照key的字典序 for (const auto& pair : mapp) { cout << pair.first << " " << pair.second << " "; } cout << "\n"; //----find()函数 auto it = mapp.find("qian"); if (it != mapp.end()) { // 如果找到了,输出键和值 cout << "Found: " << it->first << " => " << it->second << endl; } else { // 如果没找到,输出相应信息 cout << "Key not found." << endl; } mapp.insert({"xu", 6}); //-----count()函数 size_t num = mapp.count("xu"); cout << num << endl; mapp["xu"] = 6; // 直接更新键 "xu" 的值为 6 for (const auto& pair : mapp) { cout << pair.first << " " << pair.second << " "; } cout << "\n"; // lower_bound() 函数,查找第一个不小于key的迭代器 auto it_low = mapp.lower_bound("right"); if (it_low != mapp.end()) { // 如果找到了,输出键和值 cout << "Found: " << it_low->first << " => " << it_low->second << endl; } else { // 如果没找到,输出相应信息 cout << "Key not found." << endl; } // upper_bound() 函数,查找大于key的迭代器 auto it_upper = mapp.upper_bound("wang"); if (it_upper != mapp.end()) { // 如果找到了,输出键和值 cout << "Found: " << it_upper->first << " => " << it_upper->second << endl; } else { // 如果没找到,输出相应信息 cout << "Key not found." << endl; } auto range = mapp.equal_range("wang"); if (range.first != range.second) { cout << "Found: " << range.first->first << " => " << range.first->second << endl; } else { cout << "No element found for 'wang'." << endl; } //-- erase() 函数,用来删除对应的key和value mapp.erase("zhang"); for (const auto& pair : mapp) { cout << pair.first << " " << pair.second << " "; } cout << "\n"; auto itt = mapp.find("qian"); mapp.erase(itt); //参数可以为迭代器 for (const auto& pair : mapp) { cout << pair.first << " " << pair.second << " "; } cout<<"\n"; //size()函数 size_t size = mapp.size(); cout<<size<<endl; //empty()函数 bool is_empty = mapp.empty(); cout<<is_empty<<endl; // 使用begin()和end()遍历map for (auto ittt = mapp.begin(); ittt != mapp.end(); ittt++) { std::cout << ittt->first << " " << ittt->second <<" "; } cout<<endl; mapp.clear(); bool empty = mapp.empty(); cout<<empty<<endl; cout << "\n"; return 0; }
-
2024-4-24 15:50:05@
优先队列
priority_queue
: 使用方式:#include <bits/stdc++.h> using namespace std; int main() { // 优先队列,默认是最大堆 priority_queue<int> pq; // 添加元素 pq.push(10); pq.push(20); pq.push(15); pq.push(5); // 依次移除元素 cout << "Priority Queue elements:" << endl; while (!pq.empty()) { cout << pq.top() << endl; // 打印最高优先级的元素 pq.pop(); // 移除元素 } return 0; }
优先队列的行为细节
- 优先级决定出队顺序:
- 优先队列中,元素的出队顺序完全由它们的优先级决定。这意味着具有最高优先级的元素总是最先被移除,而不考虑它们进入队列的顺序。
- 处理优先级相同的元素:
- 当多个元素具有相同的优先级时,大多数实现的优先队列(如 C++ 的
std::priority_queue
)并不保证这些元素的具体出队顺序。换言之,如果两个元素的优先级相同,哪个元素先被移除取决于底层堆的状态和元素在堆中的位置,而不是它们进入队列的顺序
- 当多个元素具有相同的优先级时,大多数实现的优先队列(如 C++ 的
与普通队列的比较
- 普通队列:
- 遵循严格的先进先出原则。先进队的元素无论优先级如何,都会先出队。
- 适用于确保按照严格的到达顺序处理元素的场景,如打印作业管理或银行客户排队。
- 优先队列:
- 仅由元素的优先级决定出队顺序。最高优先级的元素总是最先出队,与元素的进队顺序无关。
- 适用于需要基于优先级处理任务的场景,如操作系统的任务调度、网络路由中的数据包调度,或者任何需要快速访问最重要元素的场合。
因此,如果你的应用场景需要考虑进队顺序作为元素之间的次级排序依据,你可能需要自定义优先队列的行为,或者使用其他数据结构来维护进队顺序和优先级的关系
在 C++ 中的
priority_queue
,优先级通常是根据元素的自然顺序定义的,这基于元素类型的比较方法来决定。默认情况下,优先队列使用元素类型的operator<
来构建一个最大堆,这意味着最大的元素总被视为优先级最高的。如果你想改变优先级的定义,比如从最大堆改为最小堆或者定义自己的优先级规则,你可以通过提供一个自定义比较函数来实现。自然顺序
默认情况下,
priority_queue
使用元素的<
操作符来比较元素,从而维护一个最大堆结构。例如,如果你有一个priority_queue<int>
,那么较大的数字会被赋予更高的优先级,因为int
类型的<
操作符定义了自然的数值比较。自定义优先级
你可以通过提供自定义的比较函数来改变优先队列的行为,这可以通过两种方式实现:
- **使用函数对象(Functor)**:你可以定义一个类,实现
operator()
来指定比较逻辑。这允许你定义复杂的比较逻辑,不仅仅是简单的数据值比较。 - 使用 lambda 表达式:在 C++11 及之后的版本中,你可以使用 lambda 表达式来提供比较函数,使代码更加简洁
示例:定义一个最小堆
以下是一个使用
priority_queue
创建最小堆的示例,其中使用了自定义的比较器:#include <bits/stdc++.h> using namespace std; int main() { // 使用 greater<int> 来定义优先级,这会创建一个最小堆 priority_queue<int, vector<int>, greater<int>> minHeap; // 添加元素到优先队列 minHeap.push(10); minHeap.push(5); minHeap.push(15); cout << "队列按照从小到大顺序出队列:"; while (!minHeap.empty()) { cout << ' ' << minHeap.top(); // 将会按照最小值到最大值的顺序打印 minHeap.pop(); } cout << '\n'; return 0; }
在这个例子中,
greater<int>
是标准库中的一个比较类,它使得较小的元素被视为优先级更高,从而实现了最小堆的效果。你也可以定义自己的比较函数来实现更特定的优先级逻辑,例如基于对象的属性或者更复杂的规则
###如下自定义 优先级 代码解释
- Person 结构体:定义了一个包含姓名和年龄的简单结构。
- ComparePerson 函数对象:这是一个比较器,用于定义
priority_queue
的排序准则。在这个例子中,operator()
被定义为使得年龄较小的人物优先级更高。 - 优先队列的创建:我们使用
priority_queue
模板并提供三个参数:元素类型Person
、底层容器vector<Person>
和比较器ComparePerson
。这样设置后,队列将根据年龄从小到大的顺序优先出队。 - 添加和移除元素:元素被添加到队列中,并根据定义的比较规则排序。当我们访问和移除队列顶部元素时,总是获取到当前年龄最小的人物
#include <bits/stdc++.h> using namespace std; // 定义一个结构体来表示人物 struct Person { string name; int age; Person(string n, int a) : name(n), age(a) {} }; // 自定义比较函数对象 struct ComparePerson { bool operator()(const Person& p1, const Person& p2) { // 使得年龄小的人物优先级更高 return p1.age > p2.age; } }; int main() { // 创建一个优先队列,其中元素是Person结构,使用自定义的比较函数 priority_queue<Person, vector<Person>, ComparePerson> pq; // 添加几个人物到优先队列 pq.push(Person("Alice", 30)); pq.push(Person("Bob", 25)); pq.push(Person("Charlie", 35)); // 输出优先队列中的元素 cout << "按照年龄小的任务优先级更高的顺序出队:" << endl; while (!pq.empty()) { Person p = pq.top(); cout << p.name << " (" << p.age << ")" << endl; pq.pop(); } return 0; }
- 优先级决定出队顺序:
-
2024-4-24 15:26:00@
队列 queue的基本使用方法:
基本操作
队列支持几种基本操作,包括:
- push:在队列的末尾添加一个元素。
- pop:移除队列的第一个元素。
- front:访问队列的第一个元素。
- back:访问队列的最后一个元素。
- empty:检查队列是否为空。
- size:返回队列中的元素个数。
#include <bits/stdc++.h> using namespace std; int main() { queue<int> q; // 向队列添加元素 q.push(10); q.push(20); q.push(30); cout << "Front element: " << q.front() << endl; // 输出 10 cout << "Back element: " << q.back() << endl; // 输出 30 // 移除队列元素 q.pop(); cout << "New front element: " << q.front() << endl; // 输出 20 while(!q.empty()){ cout<<q.front()<<" "; q.pop(); } return 0; }
底层实现
queue
是一个容器适配器,它给予用户一种方式,可以只在一端增加元素,而在另一端删除元素。在 C++ 中,默认情况下,queue
使用deque
作为其底层容器,但也可以指定使用其他类型的容器,如list
。自定义底层容器
可以在定义
queue
时指定底层容器,例如使用list
作为底层容器:#include <bits/stdc++.h> using namespace std; queue<int, list<int>> myQueue;
选择不同的底层容器会影响队列操作的性能,因此应根据具体需求来选择最合适的容器类型
银行柜台服务模拟
程序演示顾客排队等待服务的过程,每个顾客在队列中等待服务,然后从队列中移除表示他们的服务已完成
#include <bits/stdc++.h> using namespace std; int main() { queue<string> bankQueue; // 创建一个队列存储顾客姓名 // 顾客按顺序到达并排队 bankQueue.push("Alice"); bankQueue.push("Bob"); bankQueue.push("Charlie"); bankQueue.push("Diana"); cout << "There are currently " << bankQueue.size() << " people in the queue.\n"; // 开始服务队列中的顾客 while (!bankQueue.empty()) { // 访问队首的顾客(即将得到服务的顾客) string currentCustomer = bankQueue.front(); cout << currentCustomer << " is being served." << endl; // 服务完成后,将该顾客从队列中移除 bankQueue.pop(); // 显示剩余顾客数量 cout << "There are now " << bankQueue.size() << " people in the queue.\n"; } cout << "All customers have been served!" << endl; return 0; }
代码解释
- 初始化队列:创建一个类型为
string
的queue
来存储顾客的名字。 - 顾客到达:使用
push()
方法将顾客按照到达的顺序添加到队列的末尾。 - 服务顾客:
- 使用
front()
方法获取队列前端的顾客,即当前正在被服务的顾客。 - 使用
pop()
方法移除已经服务完毕的顾客,即从队列前端移除元素。
- 使用
- 循环处理:当队列不为空时,继续服务新的队首顾客。
- 完成服务:队列为空时,表示所有顾客都已经得到服务,程序结束
-
2024-4-24 15:16:40@
栈stack 的定义和基本用法
定义了一个整型的栈
s
。默认情况下,stack
使用deque
作为其底层容器stack<int> s;
主要操作
- push():向栈顶添加一个元素。
- pop():从栈顶移除一个元素。
- top():访问栈顶元素。
- empty():检查栈是否为空。
- size():返回栈中的元素数量。
s.push(10); s.push(20); cout << "Top element: " << s.top() << endl; // 输出 20 s.pop(); cout << "New top element: " << s.top() << endl; // 输出 10
使用不同的底层容器
stack
默认使用deque
,但你也可以指定使用其他容器,如vector
或list
。这是通过模板参数实现的,选择哪种底层容器取决于你的具体需求,例如,使用vector
可能在访问栈顶元素时更快一些,而list
在删除元素时可能更高效#include <vector> #include <stack> stack<int, vector<int>> stackUsingVector; #include <list> stack<int, list<int>> stackUsingList;
如下是一个使用栈来判断括号是否匹配的代码例子:
#include <bits/stdc++.h> using namespace std; bool arePairs(char opening, char closing) { return (opening == '(' && closing == ')') || (opening == '{' && closing == '}') || (opening == '[' && closing == ']'); } bool areBalanced(const string& expr) { stack<char> s; for (char c : expr) { // 如果是开放括号,则推入栈中 if (c == '(' || c == '{' || c == '[') { s.push(c); } // 如果是闭合括号 else if (c == ')' || c == '}' || c == ']') { // 栈空或者栈顶括号不匹配,返回false if (s.empty() || !arePairs(s.top(), c)) { return false; } s.pop(); // 匹配则弹出栈顶元素 } } // 如果栈空,则所有括号匹配完成 return s.empty(); } int main() { string expression; cout << "请输入括号表达式: "; // 输入表达式 cin >> expression; if (areBalanced(expression)) { cout << "Balanced\n"; } else { cout << "Not Balanced\n"; } return 0; }
-
2024-4-24 15:01:31@
pair的基本使用方法:
定义和初始化
一个
pair
对象包含两个公共成员:first
和second
,分别代表pair
的第一个和第二个值pair<string, int> myPair; myPair.first = "example"; myPair.second = 42;
使用构造函数初始化
可以直接使用构造函数来初始化
pair
的两个成员:pair<string, int> pair1("text", 10);
make_pair
初始化make_pair
是一个辅助函数,可以自动推断参数的类型,从而创建pair
对象。auto pair2 = make_pair("text", 10);
应用场景:
在容器中使用
pair
在如map
或unordered_map
等关联容器中被广泛使用,这些容器内部实际存储的是键值对map<string, int> age; age["John"] = 30; for (const auto& p : age) { cout << p.first << " is " << p.second << " years old. \n"; }
函数返回多个值
函数可以通过返回
pair
来同时返回两个值pair<int, bool> func() { // 假设进行了一些处理 return make_pair(42, true); }
与其他类型结合
pair
可以与vector
、list
等容器结合使用,存储元素对,也可以是嵌套的pair
(例如pair<int, pair<string, int>>
),这在处理复杂数据结构时非常有用结构化绑定(C++17)
从 C++17 开始,可以使用结构化绑定来解构
pair
,这使得与pair
的工作更加直接和简洁: 这种方式允许你直接在声明时解开pair
的值,使得代码更清晰易读auto [name, score] = make_pair("Alice", 95); cout << name << " scored " << score << endl;
#include <bits/stdc++.h> using namespace std; // pair 相当于C++系统帮你定义好的含有2个变量的结构体,结构体的类型可以通过 // <类型1,类型2> // function :函数 pair<string,int> FunName(string str,int x){ str=str+"是:天才"; x+=10; return make_pair(str,x); } int main(){ pair<string,int> my; //定义的时候不赋初值 my.first="penghaoran"; my.second=55; pair<string,int> my2("kangchenyi",45);//定义的时候直接赋初值 auto my3=make_pair("zhuzanyu",35); string str; int n; cin>>str>>n; //pair<string,int> my4=FunName(str,n); auto my4=FunName(str,n); cout<<my4.first<<" 今年"<<my4.second<<"岁了"; return 0; }
-
2024-3-30 19:46:11@
vector 学习过程:
#include <bits/stdc++.h> using namespace std; int main(){ vector<int> a(10,3);//定义一个长度为10,初始化所有值为3的整型数组 vector<char> cc(20,'k');//定义一个长度为20,初始化所有值为'k的字符数组 vector<int> vec={1,2,3,4,5};//定义一个整型数组,初始化值为:1 2 3 4 5 int arr[]={3,5,7,9,11}; int len=sizeof(arr)/ sizeof(int);//取得普通整型数组的长度 //将arr这个整型数组的所有内容作为vec2的初始化元素 vector<int> vec2(arr,arr+len); int len2=vec2.size(); for(int i=0;i<len2;i++){ cout<<vec2[i]<<" "; } cout<<endl; vec2.push_back(100); //在vec2数组末尾添加一个整型数字 vec2.push_back(101); vec2.push_back(102); vec2.push_back(103); for(int i=0;i<vec2.size();i++){ // cout<<vec2[i]<<" "; //;原来方式 cout<<vec2.at(i)<<" "; //新方式取得数组元素的值 } cout<<endl; vec2.pop_back(); //删除数组元素最后一个值 for(int i=0;i<vec2.size();i++){ cout<<vec2.at(i)<<" "; //新方式 } vec2.clear(); //清空vec2/动态数组 的全部元素 cout<<endl<<"-----------------"; for(int i=0;i<vec2.size();i++){ cout<<vec2.at(i)<<" "; //新方式 } cout<<endl<<"-----------------"<<endl; if(vec2.empty()){ //判断该数组是否为空 cout<<"Vector is empty."<<endl; } vec2.push_back(50); vec2.push_back(75); vec2.push_back(150); if(vec2.empty()){ cout<<"Vector is empty."; }else{ cout<<"Vector is not empty:"<<endl; cout<<vec2.front()<<" "; //取得数组的第一个元素 cout<<vec2.back(); //取得数组的最后一个元素 } vec2.erase(vec2.begin()+3);//删除数组第2个元素 sort(vec2.begin(),vec2.end()); sort(a,a+n)//不是动态数组排序方法** **,其中N为数组的长度,下标从0开始 sort(a+1,a+n+1)//不是动态数组排序方法** **,其中N为数组的长度,下标从1开始 sort(a+2,a+n-2)//不是动态数组排序方法** **,其中N为数组的长度,下标从0开始,前面2个不参与排序,最后面2个也不参与排序 for(int i=0;i<vec2.size();i++){ cout<<vec2.at(i)<<" "; } for(int i=0;i<arr2.size();i++){ cout<<arr2.at(i)<<" "; } cout<<endl; sort(arr2.begin(), arr2.end(),cmp); // 将arr2数组从小到大排序 for(int i=0;i<arr2.size();i++){ cout<<arr2.at(i)<<" "; } cout<<endl; arr2.insert(arr2.begin()+2,9999); //在第3个元素之前插入数据9999 for(int i=0;i<arr2.size();i++){ cout<<arr2.at(i)<<" "; } return 0; }
- 1