文章目录
笔者本来一直是用Java在力扣上进行刷题的,但是今天在牛客网上看到有人在华为笔试的时候,用Java怎么也通不过第一题,即使函数输出为空也提示“CPU运行时间超过限制”,但是用C++就能过。笔者遂开始重新学习下C++的常用api,先达到能在力扣上刷题看题解的程度。
本文参考:
结构体
参考了这篇博客C++ 结构体(struct)最全详解
有参构造和无参构造结构体:
struct node{
int data;
string str;
char x;
//注意构造函数最后这里没有分号哦!
node() :x(), str(), data(){} //无参数的构造函数数组初始化时调用
node(int a, string b, char c) :data(a), str(b), x(c){}//有参构造
};
力扣中常用的ListNode构造函数:
struct ListNode
{
int val;
ListNode* next;
ListNode() : val(0), next(nullptr) {}
ListNode(int x) : val(x), next(nullptr) {}
ListNode(int x, ListNode* next) : val(x), next(next) {}
};
数组
C++初始化语句:
//指定长度声明并初始化数组
double balance[5] = {1000.0, 2.0, 3.4, 7.0, 50.0};
//指定长度以后只初始化前面的元素
double balance[6] = {1000.0, 2.0, 3.4, 7.0, 50.0};
//不指定长度声明并初始化数组
double balance[] = {1000.0, 2.0, 3.4, 7.0, 50.0};
//先声明再初始化
int n[ 10 ];
n[0]=1
//动态分配了长度为 100 的数组 array
int* array = new int[100]; delete []array;
//动态分配长度为100的数组array初始化前两个元素
int* array = new int[100]{1,2}; delete []array;
//char数组的声明并初始化
char a1[] = {'C', '+', '+'}; // 初始化,没有 null
char a2[] = {'C', '+', '+', '\0'}; // 初始化,明确有 null
char a3[] = "C++"; // null 终止符自动添加
char a4[7] = "runoob"; //需要初始化6个字符+一个null的大小
需要和Java的初始化语句进行区分:
//1.
int[] a = {1,3};
//2. 不同于C++,[]内不能填大小
int[] a = new int[]{1,3};
//3.
int[] a = new int[2];
a[0] = 1;
a[1] = 3;
常用api:
int arr[10] = { 0,1,2,3,4,5,6,7,8,9 };
//reverse(iterator beg,iterator end); beg迭代器起点,end迭代器终点(不包含)
reverse(arr, arr + 10);
//排序
sort(a, a + 10);//默认升序排序
sort(v.begin(), v.end(), myComepare);//降序排序
bool myComepare(int v1,int v2)
{
return v1 > v2;
}
String类
参考博客C++中String 最全API详解
头文件引入:
#include<string>
常用操作:
String ans;
//在尾部加入c
ans.push_back(char c);
//去除尾部元素
ans.pop_back()
//返回pos开始的n个字符组成的字符串
ans.substr(int pos, int n )
//加强for循环
for (char c : s){}
//获取字符串长度
ans.length();
ans.size();
//如果是通过sizeof获取字符数组的长度,会把\0也算入
char arr[]="abcdefg"
//char arr[]={'a','b','c','d','e','f','g','\0'};字符数组和用字符数组定义字符串的区别
cout<<sizeof(arr) / sizeof(arr[0]);
常用常量
INT_MIN:-2147483648
INT_MAX:2147483647
LONG_MIN:-2147483648
LONG_MAX:2147483647
LLONG_MIN:-9223372036854775808
LLONG_MAX:9223372036854775807
同时要注意是补码表示,int和long占4字节32位(31位数字1位符号),INT_MIN-1=INT_MAX
。
类与对象
类的定义和方法定义:
class Clock {
private:
int hour;
int minute;
int second;
public:
void setime(int hour, int minute, int second);
void showtime();
Clock(int newh, int newm, int news);//有参构造函数
Clock();//默认无参构造函数
//方法定义
void study(){
cout<<"学习时间"<<endl;
}
};
//方法定义
void Clock::setime(int newhour, int newminute, int newsecond)
{
hour = newhour;
minute = newminute;
second = newsecond;
}
void Clock::showtime()
{
cout << "time" << " is " << hour << " : " << minute << " : " << minute << endl;
}
类的初始化:
int main()
{
//1.直接使用类名无参构造
Clock time1;
time1.showtime();
//2.直接使用类名有参构造
Clock time2(9, 27, 6);
time2.showtime();
//3.使用new关键词创建
Clock time3=new Clock();
time3->showtime();
}
其中“直接使用类名创建对象”和“使用 new 关键字创建对象”两种方法的区别参考这篇博文,主要区别为:
- 使用 new 关键字创建的对象使用的是「堆空间」;而在局部、直接使用类名创建的对象则使用「栈空间」;
- 使用 new 关键字创建的对象会赋值给类指针,此对象可在多处使用;
- 使用 new 关键字创建的对象在使用完成后,必须要「使用 delete 销毁该对象」,否则会造成内存泄露(new 申请的对象,只有调用到 delete 时才会执行析构函数);而直接使用类名创建的对象,则不需要手动销毁该对象,因为该类的「析构函数会自动执行」;
函数
返回类型 function_name( 参数列表 )
{
body of the function
}
函数中返回局部变量地址和引用的注意点:
返回局部变量地址,不要使用:
#include <iostream>
using namespace std;
//局部变量存放在栈区,不要在函数中返回局部变量的地址,函数退出后,局部变量的内存被系统自动释放
int* print()
{
int a = 10;
return &a;
}
int main()
{
int *p = print();
cout<<*p<<endl;//10 第一次打印正确的值,是因为编译器做了一次保留;
cout<<*p<<endl;//1 第二次这个数据就不会保留了;
return 0;
}
#include <iostream>
using namespace std;
//函数中申请堆区空间,由自己进行释放
//指针a是一个局部变量指针,存放在栈区空间中,但指向堆区内存
int* print()
{
int *a = new int(10);
return a;
}
int main()
{
int *p = print();//函数返回指针赋值给新的变量,函数局部变量a被自动释放
cout<<*p<<endl;// 10 堆区空间可以一直被使用,直到被释放;
cout<<*p<<endl;// 10
delete p; //释放堆
return 0;
}
返回局部变量的引用,不要使用:
#include <iostream>
using namespace std;
//不要返回局部变量的引用
//局部变量存放在栈区空间中,函数退出后栈区空间被自动释放
int& print()
{
int a = 10;
int &b = a;
return b;
}
int main()
{
int &a = print();
cout<<a<<endl;// 10 第一次编译器会保留函数的返回值
cout<<a<<endl;//1 第二次值就会被释放掉了,防止后面使用引用
return 0;
}
STL
容器使用参考博客刷题常用STL容器整理合集
算法使用参考博客C++STL常用算法详解,这个博主的博客将容器相关的知识总结得很好。
常用函数
#include<algorithm>
//求最大值/最小值
int m=max(a,b);
int m=min(a,b);
vector容器
头文件引入:
#include<vector>
常用api:
//声明一个空vector
vector<int> v1;
vector<vector<int>> v3;
//声明大小为size,初始值都为val
vector<int> v2(size,val);
//声明并初始化vector
vector<int> v4={1,2,3,4};
//尾部插入和尾部删除
v1.push_back(val);
v1.pop_back();
//首部插入20
v1.insert(v1.begin(),20)
//尾部插入3个20
v1.insert(v1.end(), 3, 20);
//清空所有元素
v1.clear();
//返回索引处元素
v1[0];
v1.at(0);
//返回首部元素和尾部元素
v1.front();
v1.back();
//返回元素个数
v1.size();
//排序 需要引入#include <algorithm>
sort(v1.begin(),v1.end());//从小到大
reverse(v1.begin(),v1.end(),comp); //从大到小
bool comp(int a,int b)
{
return a< b; //升序排列,如果改为return a>b,则为降序
}
//迭代器遍历访问
vector<int>::iterator it;//声明一个迭代器,来访问vector容器
for(it=v1.begin();it!=obj.end();it++)
{
cout<<*it<<" ";
}
//增强for遍历
for(auto i:v1){
cout<<i<<endl;
}
//二维数组定义
vector<vector<int> > obj(N); //定义二维动态数组大小N行
for(int i =0; i< obj.size(); i++)//动态二维数组为N行M列,值全为0
{
obj[i].resize(M);
}
//可以直接返回或者当作vector的情况
return {-1,-1}; //结果需要返回vector
return vector<int>{-1,-1};
return vector<int>{};
obj.push({-1,-1,1}) //obj为vector<vector<int>>类型
queue容器
头文件引入:
#include<queue>
常用api:
//声明一个队列
queue<int> que;
//判空
que.empty();
//判断大小
que.size();
//返回队首队尾元素
que.front();
que.back();
//队尾插入
que.push(val);
//删除队首,这只是删除,通常是que.front()查看队首元素,然后que.pop()出队列配合使用
que.pop();
deque容器
在STL中deque类似vector,并且支持随机访问;
头文件引入:
#include <deque>
常用api:
//声明一个双端队列
deque<int> que;
//判空
que.empty();
//判断大小
que.size();
//返回队首队尾元素
que.front();
que.back();
//队尾插入
que.push(val);
//元素出队,只是出队列并返回void,通常是que.front()查看队首元素,然后que.pop()出队列配合使用
que.pop();
//队首插入、队尾插入
que.push_back(val);
que.push_front(val);
//随机访问
que[i];
que.at(i);
stack容器
头文件引入:
#include<stack>
常用api:
//声明
stack<int> st;
//判断大小
st.size();
//判空
st.empty();
//压栈出栈
st.push(val);
//元素出栈,只是出栈并返回void,查看栈顶元素还需要先st.pop()
st.pop();
//查看栈顶元素
st.top();
set容器
特点:
- 每个元素的值都唯一(没有重复的元素);
- 根据元素的值自动排列大小(有序性);
- 无法直接修改元素;
引入头文件:
#include <set>
常用api:
//声明
set<int> s;
//判大小
s.size();
//判空
s.empty();
//清空
s.clear();
//返回容器中x的个数
s.count(x);
//插入x
s.insert(x);
//删除x
s.erase(x);
map容器
特点:
- 支持下标访问
引入头文件:
#include<map>
常用api:
//声明
map<int, string> myMap;
map<int,vector<int>> mp;
//使用{}进行初始化
map<int, string> myMap={{ 5, "张大" },{ 6, "李五" }}; //注意:C++11才开始支持括号初始化
//判大小
myMap.size();
//判空
myMap.empty();
//清空
myMap.clear();
//插入
myMap[2] = "李四"; //使用[ ]进行单个插入,若已存在键值2,则赋值修改,若无则插入。
myMap.insert(pair<int, string>(3, "陈二"));//使用insert和pair插入
//查询
//迭代器访问key
map<int, string>::iterator it = myMap.find(key);
string str=it->second;
//下标访问
int key=myMap[key].first;
int value=myMap[key].second;
//统计key值为key的个数
int num = myMap.count(key);
//删除
//迭代器删除1
map<int, string>::iterator it;
it = myMap.find(1);
myMap.erase(it);
//关键词删除1,删除了返回1,否则返回0
int flag = myMap.erase(1);
unordered_map
其基本的api操作同map
一致,主要是底层实现不同:
map: map底层是用红黑树实现的,因此其具有自动排序的功能,对于那些有排序要求的问题,会更高效一点。
unordered_map: 其底层是用哈希表实现的,对于查找问题会更加高效。
引入头文件:
#include < unordered_map >