C++基础
内容基于w3schools中的c++教程
一些很少在CP中遇到的内容(class及一些相关概念)就不看了
C++ Data Types
Scientific Numbers:
double d1=1.14e4 //1.14*10^4 |
接下来,如何设置输出格式(指定小数位)?
|
ASCII characters:
只需注意A->65, a->97, 大写字母再前.
C++ string
A string in C++ is actually an object, there are some useful functions:
at()
: return an indexed character from a string ,same as str[x]
empty()
: checks whether a string is empty or not
substr(pos,len)
: return a part of string from pos(index) and last for len.
string str1="ciallo,senpai"; |
find()/rfind()
: return the index of the first/last occurrence of a str or char(if none,return )
size()/length()
: 完全等价,看从什么角度看待罢了. 前者容器,后者字符串
Tips:
- 如何在字符串中保留引号? use backslash.
\n
&\t
也干了. - 其它数据类型向string转换:
to_string()
- pop_back()也能用于string.
- 如何获取包含空格的输入?
string str="joe john" |
转化为字符串:
to_string()
范围大小写转换(
#include<algorithm><cctype>
):transtorm(str.begin(),str.end(),str.begin(),::toupper);
第三个参数为迭代器(类指针),transform函数被设计为面向范围操作. STL 的函数设计基于迭代器,使操作可扩展和高效.
toupper
位于全局命名空间(不在std
!!),需要显式地加上作用域解析符::
,避免冲突发生.
C++ Math
most powerful💪 functions:
max()/min()
:返回最大/小值
sqrt()
:开根号
round()
: 就近取整
及<cmath>
中的函数列表: clickhere
C++ Switch
嗯目前没怎么用过. 根据表达式的值选择执行的语句,通常和break
,default
关键字一起使用
enum in C++
如果在程序中用到常量,该怎么定义?
#define
(宏定义):全局有效,只是简单的文本替换,不好查错. const
:可以在特定的作用域中定义,只在该块范围内有效,避免了全局命名冲突.如果有多个常量,可以用enum
(一组常数)封装.
关于为什么叫枚举(enumerations),可能意为”专门列出”,或者…
enum Level{ |
C++ References
A reference variable is a “reference” to an existing variable, which created with the &
operator.
现在想想将一个变量传参给函数时,是否新建了一个变量?
引用变量和原始变量共享一个内存地址, 通过引用所做的任何操作直接影响到原始变量.
构造函数(Constructors)
就当作是在结构体和类中方便输入数据的函数吧()
一般建议使用初始化列表(Initializer list)
ClassName(parameters) : member1(initialValue1), member2(initialValue2), ... { |
C++ Data Structures
STL is a library that consist of different data structures and algorithms to effectively store and manipulate data.合理地选择可以带来更高的效率.
STL由容器,迭代器(iterators)和算法组成,算法通过迭代器访问和操作数据结构.
Vector
some useful functions:front()
/end()
,begin()
/end()
,push_back()
/pop_back()
at()
:在指定索引中访问元素,和下标访问等效,好处是越界访问会返回错误信息.
size()
: 返回元素数量
empty()
: 检查是否为空(返回bool值)
Loop through vector
for (auto x:v){cout<<x<<"\n";} //c++11及以上 |
- auto 的作用是让编译器自动推导 x 的类型,使代码更简洁灵活.
- 以上循环为拷贝操作,若要修改容器元素,需要使用引用
&
. 如果还想避免意外改动,还可以再加上const
for (int i = 0; i < v.size(); i++) {} |
List
和vector的主要区别在于支持开头添加元素,不支持随机访问(索引访问)
Add elements
special:在头部添加使用push_front()
只支持范围for循环和迭代器
Stacks
可以想象堆叠着的煎饼,只能处理顶部的元素(煎饼)bypop()
&push()
,即”LIFO(last in, first out)”
Queue
和堆栈相反,FIFO(first in, first out)
…
C++ Iterators
用来遍历容器
for (it=name.begin(),it!=name.end();++it){} |
冒泡优化
//improve |
使用 swapped
标志位,检测是否发生了交换。如果某次内循环没有交换,说明数组已经有序,可以提前退出外层循环,避免不必要的操作. 可以看出冒泡的教学意义,但真到要排序的时候,还是用sort函数.
string to int
其他数据类型转化为string类型时可以使用to_string()
函数,但字符型转化为整型呢? 利用ASCII 编码 的性质,进行ch - '0'
运算时,字符会隐式地被转换为它们对应的 ASCII 值,并进行整数运算。这在处理字符串和数字的混合数据时非常有用.
e.g.将string类型字符串转换为整型十进制数.
//将一个字符串转化为十进制整数 |
好啦,现在你获得了一个可以用于数学计算的数字!
Math
- (较)精确的pi
|
- 十的六次方表示为
1e6
格式化输出
保留指定位小数
|
std::fixed
:设置浮点数的表示方式为定点表示(即小数形式,而非科学计数法).如果没有std::fixed
,std::setprecision
会影响数字的总有效位数.流操控符的设置会一直影响之后的输出,直到被重新设置或流被刷新。
//使用完后重置格式
cout.unsetf(ios::fixed);
因为setprecision(设置精度)实在是有点难记,还是用printf罢
5.
6.阶乘的各种实现方法
递归:n!=n×(n−1)!
long long factor(int n){
if (n==0||n==1) return 1;
return n*factor(n-1);
}//使用尾递归优化
long long factorialTail(int n, long long result = 1) {
if (n == 0 || n == 1)
return result;
return factorialTail(n - 1, n * result); // 尾递归调用
}
7.获取两个变量中的较小(大)值
三元表达式
for (int i=1;i<=(s1<s2?s1:s2);i++)
min()
,max()
for (int i=1;i<=min(s1,s2);i++)
8.快捷头文件
包含所有常用的 C++ 标准库头文件,从而不用单独导入每个需要的头文件。
bits/stdc++.h
是 GCC 专用,并不是 C++ 标准的一部分,因此可能无法在非 GCC 编译器(如 MSVC、Clang)上运行。
9.shortening code
//shortening code by Macros |
11.获取保留空格的字符串
getline(cin,name); |
vector容器预先分配空间
由vector容器的动态增加原理,在处理大量输入时会导致庞大的内存开销.
解决:预先分配空间(Pre-allocating space)
cin>>n; |
Optimize Input/Output for faster I/O
ios::sync_with_stdio(false); |
FAQ
溢出和精度
棋盘中的矩阵
Fact:对于一个n*m规格的棋盘,其包含的矩阵数量为
unsigned long long rectNum(int m,int n){ |
Why?
For rectangles, any subgrid defined by two distinct horizontal lines and two distinct vertical lines forms a rectangle.
所以,原问题便转化为组合问题.
1.溢出问题
这里的乘法 (n+1)*(m+1)*m*n
可能会在乘法过程中溢出,因为所有乘法在计算时仍然会使用普通整型规则进行中间计算。因此,即使结果存储在 unsigned long long
中,可能已经溢出了。
solve:使用 1ULL
强制转换为 unsigned long long
In C++, when you multiply two integers, the multiplication happens with the type of the operands. If both operands are
int
(typically 32 bits), the result will also be treated as anint
, even if it’s stored in a larger type later.Here,
1ULL
forces the multiplication to be done inunsigned long long
space, avoiding overflow.It’s a common practice when dealing with large numbers or potential overflow in C++ arithmetic.
(Generated by ChatGPT 4o)
2.在(n+1)*(m+1)*m*n
中肯定存在两个偶数项,确保了结果总能被 4 整除,因此,整数除法的精度问题在这里不存在。
结构体还是函数?
结构体(或类)主要用于将多个相关变量组合在一起,表示一个逻辑实体。非常适合以下场景:
- 多个变量需要频繁一起使用,且这些变量之间有逻辑关系(如
point
包含x
和y
)。 - 操作多样化:结构体可以包含成员函数,对数据进行封装和操作。
- 数据共享与存储:多个实例表示不同的数据组时,如存储多个矩形板的信息。
函数更适合以下情况:
- 参与计算的变量数量较少,且这些变量没有内在的关联关系(如纯数学计算)。
- 一次性操作或逻辑简单:函数只做某一特定任务,不需要保存状态。
- 独立计算逻辑:函数可以被独立调用,不依赖结构体的成员变量。
总之, 变量数量和关联性是决定使用结构体还是函数的重要因素。结构体适合将相关数据和操作封装在一起,函数适合独立、简单的计算逻辑。
std::sort的比较函数
通过比较出生日期对通讯录进行排序
struct date{ |
提问:为什么不是返回a.bir<b.bir
?这可以吗?
std::sort
需要一个具体的比较函数来比较两个 pb
结构体的内容。要
简化逻辑,可以在结构体pb
中重载 operator<
//修改pb |
重载是什么?