C++基础和STL使用

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"
由于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章节)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值