算法学习-以刷题为导向需要掌握的C++知识


笔者本来一直是用Java在力扣上进行刷题的,但是今天在牛客网上看到有人在华为笔试的时候,用Java怎么也通不过第一题,即使函数输出为空也提示“CPU运行时间超过限制”,但是用C++就能过。笔者遂开始重新学习下C++的常用api,先达到能在力扣上刷题看题解的程度。

本文参考:

C++刷题总结
菜鸟教程

结构体

参考了这篇博客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]{12};  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 关键字创建对象”两种方法的区别参考这篇博文,主要区别为:

  1. 使用 new 关键字创建的对象使用的是「堆空间」;而在局部、直接使用类名创建的对象则使用「栈空间」;
  2. 使用 new 关键字创建的对象会赋值给类指针,此对象可在多处使用;
  3. 使用 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容器

特点:

  1. 每个元素的值都唯一(没有重复的元素);
  2. 根据元素的值自动排列大小(有序性);
  3. 无法直接修改元素;

引入头文件:

#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容器

特点:

  1. 支持下标访问

引入头文件:

#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 >

作为C++程序员也需要了解的概念知识

  1. C++ std命名空间
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

互联网民工蒋大钊

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值