目录
1. 数组
1.1 一维数组
- 定义: dataType arrayName[arraySize];
- 初始化:
* int num[5] = {1, 2, 3, 4, 5};
* int num[] = {1, 2, 3, 4, 5};
- 函数定义:int fun(int num[5]);
- 函数调用:fun(num);
1.2 多维数组
- 定义: dataType arrayName[row][col]...;
- 初始化:
* 二维:
* int num[2][3] = {1, 2, 3, 4, 5, 6};
* int num[2][3] = {{1, 2, 3}, {4, 5, 6}};
* 三维:
* int num[2][3][4] = {1, 2, 3, 4, 1, 2, 3, 4, 1, 2, 3, 4, 1, 2, 3, 4, 1, 2, 3, 4, 1, 2, 3, 4};
* int num[2][3][4] = { {{1, 2, 3, 4}, {1, 2, 3, 4}, {1, 2, 3, 4}},
{{1, 2, 3, 4}, {1, 2, 3, 4}, {1, 2, 3, 4}}
};
- 函数定义:int fun(int num[2][3]);
- 函数调用:fun(num);
2. *字符串
2.1 C风格字符串
- 定义: char str[100];
- 初始化:
* char str[] = "C++";
* char str[4] = "C++";
* char str[] = {'C','+','+','\0'};
* char str[4] = {'C','+','+','\0'};
- 读取一行文本:
char str[100];
cin.get(str, 10); //表示将输入用str来接收,但只能保存9个字符(包括空格,因为最后有一个\0)
或者cin.getline(str, 10);
- 相关函数:
* strcpy(s, s1); //将s1中内容复制到s中, 一般要求s的长度大于s1,小于虽不会报错,
//但是感觉会数组越界,如以下程序
char s[] = "he";
cout << sizeof(s) <<endl;
char s1[] = "world";
strcpy(s, s1);
cout << s << endl;;
cout << sizeof(s);
//输出为:表明s的数组大小没有变化,但是s存储的是"world",疑惑?
3
world
3
* strncpy(s, s1, n); //指定s1中的前n个字符替换s的前n个字符,s中后面其他的会保留
* strcat(s, s1); //将s1字符串拼接到s后面
* strncat(s, s1, n);//将s1字符串前n个字符拼接到s后面
* strlen(s); //求字符串长度,不包括\0
* strcmp(s, s1); //比较字符串,s>s1返回1,s<s1返回-1,相等返回0,相当于做减法
* strcasecmp(s, s1);//忽略大小写比较字符串
* strncmp(s, s1, n);//比较指定长度字符串
* strchr(s, ch); // 在字符串中查找指定字符, 返回的是char*,首地址指向ch元素
* strrchr(s, ch); // 在字符串中反向查找,同上
* strstr(s, s1); // 查找字符串,找到了返回首地址char*,没找到返回nullptr
- 注意:
- char str[] = “C++”; C风格的字符串以\0结束,strlen(str)的结果为3,sizeof(str)的结果为4
- 在使用cin >> str输入时,遇到空格会结束,因此不能读取一整行的数据
- 在C字符串操作时,如strcpy(s, s1)中的s的容量尽量开辟大一些,以确保在操作后能存储下所有数据
- cin.get()和cin.getline()的区别,cin.get()不会忽略最后的换行符号,需要在调用一次cin.get(),然后再调用cin.get()读取下一行,而cin.getline()不用,参考这里
2.2 C++字符串对象string
- 定义: string str;
- 初始化:
* string str = "hello world";
* string str(s); //将s复制给str
* string str(n, ch); //生成n个ch字符的字符串
* string str(s.begin(), s.end()); //用迭代器之间的元素来初始化str,左闭右开,
//s.end()是指向s末尾的后一个位置
- 读取一行文本:
string str;
getline(cin, str); //默认以回车\n以结束标志
getline(cin, str, '#'); //可以设定以'#'为结束标志
- 相关函数:
* str.size() //返回字符串长度
* >, >=, <=, ==, != //字符串比较运算
* strA.compare(pos1, pos2, strB, pos3, pos4); //比较A[pos1, pos2)和B[pos3, pos4)
//A>B返回1,A<B返回-1,相等返回0,pos只能是数字,不能是迭代器,左闭右开
* str.push_back(ch); //在str后面插入一个字符ch
* str.append(s); //在str后面插入一个字符串s,也可使用+来拼接字符串
* str.insert(pos, s) //在str第pos个字符后添加字符串s
* str.erase(pos, n); //删除第pos个字符后面的n个字符,按下标的话,就是从pos下标开始删除n个字符
* str.erase(it1); //删除指定迭代器的字符
* str.erase(it1, it2); //删除迭代器[it1, it2)之间的字符,左闭右开
* s.replace(pos, n, str);//将s中从第pos个字符后的n个字符替换换成str,str的长度无限制,只是替换
* str = s.substr(pos, n); //将s中从第pos个字符后的n个字符来初始化str
* reverse(str.begin(), str.end()); //字符串反转 在algorithm库中
* str.find(s); //在str中查找第一次出现s字符/字符串的下标
* str.rfind(s); //在str中反向查找第一次出现s字符/字符串的下标
* sort(s.begin(),s.end()); //字符串排序默认升序
* sort(s.begin(),s.end(), greater<char>()); //降序
* sort(s.begin(),s.end(), cmp); //降序
bool cmp(char a, char b)
{
return a > b; //返回true就不交换
}
- 注意
- 在输入字符串使用cin和getline(cin, str)混用时,需要在cin语句后面添加cin.ignore(),将cin输入后留在输入流里面的\n忽略,不然直接调用getline(cin, str)会直接结束,他默认是以\n为结束标志, 参考这里
- sort()排序的返回类型是void
3. *vector向量
- 底层实现:数组,但是数组长度能动态扩充
- 初始化:
* vector<int> nums= {1, 2, 3, 4, 5};
* vector<int> nums1(nums); //用nums初始化nums1
* vector<int> nums(n, num); //生成n个num的容器
* vector<int> nums1(nums.begin(), nums.end()); //用迭代器之间的元素来初始化nums1
- 相关函数:
* 增
* nums.push_back(n); //再向量最后插入数字n
* nums.emplace_back(n); //省去了拷贝构造,效率会高一些
* nums.insert(nums.begin() + k, n); //在向量第k个元素后插入数字n
* nums.emplace(nums.begin() + k, n);//同上
* 删
* nums.clear(); //清空向量
* nums.pop_back(); //删除最后一个元素不返回
* nums.erase(nums.begin()+1,nums.begin()+3); //删除区间内元素,左闭右开,上面删除了第二个和第三个元素
* 改
* nums[i] = n; //直接使用下标修改
* nums.at(i); //访问数据,越界会抛出异常
* 查
auto it = find(nums.begin(), nums.end(), n);
if (it != nums.end()){ 找到了数字n,进行相关处理 }
* 其他
* >, >=, <=, ==, != //向量比较运算
* nums.empty(); //判断是否为空
* nums.back(); //返回最后一个元素
* nums.front(); //返回第一个元素
* nums.size(); //返回向量大小
* nums.resize(100, 1); //重新调整nums大小,多则删,少则补,其值为1
* sort(nums.begin(), nums.end()); //排序,默认升序
* reverse(nums.begin(), nums.end()); //反转
* 三种遍历方式
* 常规
for(int i = 0; i < nums.size(); i++){
cout << nums[i] << endl;
}
* 增强for循环
for(auto n : nums){
cout << nums[i] << endl;
}
* 迭代器
it的类型为vector<int>::iterator
for(auto it = nums.begin(); it != nums.end(), it++){
cout << *it << endl;
}
- 注意
- vector向量中的int类型可以替换,一般常见的类型,int,char,string,类对象等
4. *map容器
- 底层原理: 红黑树, unordered_map底层是哈希表,不排序
- 特点:
* 元素自动按照键排序
* 键的值唯一
- 相关函数:
* map<int, string> m; //定义
* m.insert(pair<int, string>(1, "frist")); //插入元素
* m[1] = "frist"; //插入元素
* m.erase(key); //删除元素,返回1表示删除成功
* m.find(key); //查找元素,没找到返回迭代器s.end()
* m.count(key); //返回0表示key不存在,返回1表示存在
* m.size(); //返回map长度
* m.empty(); //判断是否为空
- 按照值排序: 需要借助vector实现,运行一下程序需要iostream,map,vector,algorithm等C++库
bool cmp(pair<int, string> a, pair<int, string> b)
{
//return a.second == b.second ? a.first > b.first : a.second > b.second; //先按值降序,值相等按键降序 4CDE 3CDE 1BCD 2ABC
return a.second > b.second; //先按值降序,值相等键默认升序 3CDE 4CDE 1BCD 2ABC
}
int main()
{
map<int, string> m;
m[2] = "ABC";
m[1] = "BCD";
m[3] = "CDE";
m[4] = "CDE";
vector<pair<int, string>> vec(m.begin(), m.end());
sort(vec.begin(), vec.end(), cmp);
for (auto n :vec)
cout << n.first << n.second<< endl;
return 0;
}
- map和unordered_map存自定义key
"map"
由于map的键是需要排序的,在定义新的key时,需要指定两个元素大小的比较方式
* 1. 重载operator <()
class Person{
public:
string name;
int age;
Person(string n, int a){
name = n;
age = a;
}
bool operator<(const Person &p) const //注意这里的两个const
{//先按照年龄升序,年龄相同按姓氏升序
return (age < p.age) || (age == p.age && name < p.name) ;
}
};
定义:map<Person, int> group;
* 2. 重载operator()的类
struct MyCompare{ //Function Object 使用class定义也可以,但是下面的成员函数必须是public
bool operator()(const Person &p1, const Person &p2) const{
return (p1.age < p2.age) || (p1.age == p2.age && p1.name < p2.name);
}
};
定义:map<Person, int, MyCompare> group; //在同时定义了上面两种比较运算时,会优先选用重载operator()的类
"unordered_map"
需要实现哈希函数和相等的判断函数(==运算符)
* 重载operator()的类
class Person{
public:
string name;
int age;
Person(string n, int a){
name = n;
age = a;
}
bool operator==(const Person & p) const
{
return name == p.name && age == p.age;
}
};
struct hash_name{
size_t operator()(const Person & p) const{
return hash<string>()(p.name) ^ hash<int>()(p.age);
}
};
定义:unordered_map<Person, int, hash_name> ids; //不需要把哈希函数传入构造器
5. *set集合
- 底层原理: 红黑树
- 特点:
* 元素自动排序
* 元素唯一
- 相关函数:
* s.insert(key); //插入元素
* s.erase(key); //删除元素,返回1表示删除成功
* s.find(key); //查找元素,没找到返回迭代器s.end()
* s.count(key); //返回0表示key不存在,返回1表示存在
* 初始化和迭代器方法和vector类似
- vector去重:
vector<int> vec = {3, 4, 5, 5, 5};
set<int> st(vec.begin(), vec.end());
vec.assign(st.begin(), st.end());
6. *stack栈
- 特点: 是一种先进后出LIFO的数据结构
- 相关函数
* sk.empty(); //判断是否为空
* sk.size(); //返回栈大小
* sk.top(); //返回栈顶元素
* sk.push(); //压栈
* sk.pop(); //出栈,返回void
7. *queue队列
- 特点: 是一种先进先出FIFO的数据结构
- 相关函数
* qu.empty(); //判断是否为空
* qu.size(); //返回栈大小
* qu.front(); //返回队首元素
* qu.back(); //返回队尾元素
* qu.push(); //压入队尾
* qu.pop(); //弹出队尾元素
8. priority_queue优先队列
参考这里
自定义数据类型,和自定义map几乎一样,需要重新定义比较操作符,可参考
- 特点: 优先队列根据优先级弹出元素,即,优先级最高的元素首先弹出
- 初始化
* priority_queue<int> q; //默认是大顶堆
* priority_queue<int, vector<int>, less<int>> queMin; //大顶堆
* priority_queue<int, vector<int>, greater<int>> queMax; // 小顶堆
- 相关函数
* pqu.empty(); //判断是否为空
* pqu.size(); //返回栈大小
* pqu.top(); //返回队首元素
* pqu.push(); //压入优先队列
* pqu.pop(); //弹出队尾元素
9. deque双向队列
- 底层原理:deque是由一段一段的定量的连续空间构成。一旦有必要在
deque 前端或者尾端增加新的空间,便配置一段连续定量的空间,串接
在 deque 的头端或者尾端。Deque 最大的工作就是维护这些分段连续的
内存空间的整体性的假象,并提供随机存取的接口,避开了重新配置空
间,复制,释放的轮回,代价就是复杂的迭代器架构。
- 使用函数与vector容器类似,主要区别是从队首添加数据效率高,在排序时一般不用该数据结构,因为其迭代器复杂
- 常用函数:
* nums.emplace_back(n); //向末尾添加元素
** nums.emplace_front(n); //向队头添加元素
* nums.push_back(n); //向末尾添加元素
** nums.push_front(n); //向队头添加元素
* nums.pop_back(n); //删除末尾的元素
** nums.pop_front(n); //删除队头的元素
10. list列表
- 底层原理:由双向链表实现,列表元素按顺序访问,不支持随机访问
- 优点:在任意位置进行元素的插入、删除操作效率高
- 增删改的函数用法与vector类似
11. sort排序
- 基本使用
* 该方法在algorithm函数库中,是在原来的容器中排序vector<int> a;
* sort(a.begin(), a.end()); //默认升序
* sort(a.begin(), a.end(), greater<int>()); //降序排序
* 根据第三个参数改变排序方法,返回true表示不交换,返回false交换
- 案例
- 数组降序:
vector<int> a = {1, 2, 7, 4, 3, 6};
sort(a.begin(), a.end(), greater<int>()); //7 6 4 3 2 1
for (auto n : a)
cout << ' ' << n ;
- 使用cmp函数排序:
bool cmp(int a, int b)
{
return a > b;//降序
//return a < b;//升序
}
int main()
{
vector<int> a = {1, 2, 7, 4, 3, 6};
sort(a.begin(), a.end(), cmp); //7 6 4 3 2 1
for (auto n : a)
cout << ' ' << n ;
return 0;
}
- map排序(见map章节)