#include
#include
int mycmp(const char *s1, const char *s2);
int main(int argc, char const*argv[]){
char s1[] = "abc";
char s2[] = "Abc";
int i = (int *)'a';
int j = (int *)'A';
printf("strcmp(s1, s2)=%d\n", strcmp(s1, s2));
printf("'a'=%d 'A'=%d\n", i, j);
printf("%d\n", 'a' - 'A');
printf("s1-s2=%d\n", mycmp(s1, s2));
}
int mycmp(const char*s1, const char*s2){
int i = 0;
while(1){
if (s1[i]!=s2[i]){
break;
}else if(s1[i]=='\0'){
break;
}
i++;
}
strlen
size_t strlen(const char *str)
计算字符串 str 的长度,直到空结束字符,但不包括空结束字符。注意:这个函数的时间复杂度为O(n)
strcpy
char *strcpy(char *restrict dst, const *src)
把src字符串拷贝到dst位置。restrict表示 src和dst不重叠,返回dst。我们也可以编写与strcpy功能相同的函数,如下:
#include
#include
char *mycpy(char *dst, char *src);
char *mycpy2(char *dst, char *src);
int main()
{
char src[] = "hello";
char *dst = (char *)malloc(strlen(src) + 1);
mycpy2(dst, src);
printf("dst=%p\n", dst);
int i;
for (i = 0; i < strlen(src);i++){
printf("%c", dst[i]);
}
printf("\n");
free(dst);
}
char *mycpy(char *dst, char *src){
int i = 0;
while(src[i]!='\0'){
dst[i] = src[i];
i++;
}
dst[i] = '\0';
return dst;
}
char *mycpy2(char *dst, char *src){
char *ret = dst;
while(*src != '\0'){
*dst ++ = *src++;
}
*dst = '\0';
return ret;
}
memset
void *memset(void *str, int c, size_t n)复制字符 c(一个无符号字符)到参数 str 所指向的字符串的后n个字节,比如赋值1,则a[0]=20+ 28+216+224=16843009
该函数返回一个指向存储区 str 的指针。
#include
#include
int main ()
{
char str[50];
strcpy(str,"This is string.h library function");
puts(str);
memset(str,'$',7);
puts(str);
return(0);
}
memcpy
void *memcpy(void *str1, const void *str2, size_t n)
从存储区 str2 复制 n 个字节到存储区 str1
#include
#include
int main ()
{
const char src[50] = "http://www.runoob.com";
char dest[50];
memcpy(dest, src, strlen(src)+1);
printf("dest = %s\n", dest);
return(0);
}
标准库类型string
#include
#include
using namespace std;
int main()
{
string s1;
string s2 = s1;
string s3 = "hiya";
string s4(10, 'c');
}
#include
#include
using namespace std;
int main()
{
string s1;
cin >> s1;
cout << s1 << endl;
}
#include
#include
using namespace std;
int main()
{
string s1, s2;
cin >> s1 >> s2;
string s3 = s1 + ' ' + s2;
for(int i = 0; i < s3.size(); i++) cout << s3[i] << endl;
cout << endl;
for(char c: s3) cout << c << endl;
for(char &c: s3) c = 'a';
}
综合应用:
#include
#include
using namespace std;
int main()
{
string s1, s2;
cin >> s1 >> s2;
string s3 = s1 + ' ' + s2;
cout << s1 << endl;
cout << s2 << endl;
cout << s3 << endl;
printf("%s\n", s3.c_str());
}
reverse(array exe3)
reverse函数功能是逆序(或反转),多用于字符串、数组、容器。头文件是#include
reverse函数用于反转在[first,last)范围内的顺序(包括first指向的元素,不包括last指向的元素),reverse函数无返回值
#include
#include
#include
using namespace std;
int main()
{
vector<int> n = {1,2,3,4};
reverse(n.begin(), n.end());
for(auto c:n) cout << c << ' ';
cout << endl;
int a[] = {1,2,3,4,5};
reverse(a, a+5);
for(auto c:a) cout << c << ' ';
cout << endl;
string s1 = "hello";
string s2 = s1.substr(2,3);
cout << s2<<endl;
reverse(s1.begin(),s1.end());
cout << s1 << endl;
}
#include
#include
using namespace std;
int main()
{
int k, n, array[100];
scanf("%d", &n);
scanf("%d", &k);
for (int i = 0; i < n; i++){
scanf("%d", &array[i]);
}
reverse(array,array+n);
reverse(array, array+k);
reverse(array+k, array+n);
for(int i = 0; i < n; i++){
printf("%d\n",array[i]);
}
}
substr(acwing 773)
s.substr(pos, n)拷贝字符串,包含从s的pos下标到n-1处的字符
#include
using namespace std;
int main()
{
string a, b;
while(cin >> a >> b){
char c = a[0];
int max = 0;
for(int i = 1; i < a.size(); i++){
if(a[i] > c) {
c = a[i];
max = i;
}
}
cout << a.substr(0, max+1) + b + a.substr(max+1) << endl;
}
}
函数
PS:1.函数名称可以一样,只要参数类型不完全相同即可 2.函数参数可以有默认值,但需要把有默认值的参数写在后面
参数的传递
C++中可以传引用参数,当函数的形参为引用类型时,对形参的修改会影响实参的值。使用引用的作用:避免拷贝、让函数返回额外信息。
#include
using namespace std;
void f(int &x){
x = 5;
}
int main()
{
int x = 10;
f(x);
cout << x;
}
#include
using namespace std;
int main()
{
int a[4]={1,2,3,4};
for(auto c:a) c = 0;
for(int i = 0; i < 4; i++) cout << a[i] <<' ';
cout << endl;
for(auto &c:a) c = 0;
for(int i = 0; i < 4; i++) cout << a[i] <<' ';
}
多维数组的形参写法
多维数组中,除了第一维之外,其余维度的大小必须指定
void print(int (*a)[10]) {/* … */}
void print(int a[][10]) {/* … */}
#include
using namespace std;
void print(int n, int m, int (*a)[3]){
for(int i = 0; i < n; i++){
for(int j = 0; j < m ; j++) cout << a[i][j] << ' ';
cout << endl;
}
}
int main()
{
int a[3][3] = {
{1,2,3},
{4,5,6},
{7,8,9}
};
print(3,3,a);
}
函数递归(重点复习acwing 822和823)
#include
using namespace std;
int fac(int n){
if(n == 1) return 1;
return n*fac(n-1);
}
int main()
{
int n;
cin >> n;
cout << fac(n);
}
类和结构体
类中的变量和函数被统一称为类的成员变量。private后面的内容是私有成员变量,在类的外部不能访问;public后面的内容是公有成员变量,在类的外部可以访问。具体应用如下:
#include
using namespace std;
const int N = 10000;
class Person
{
private:
int age, height;
double money = 0;
string books[100];
public:
string name;
void say()
{
cout << "I'm" << ' ' << name << endl;
}
int set_age(int a)
{
age = a;
}
int get_age()
{
return age;
}
void add_money(double x)
{
money += x;
}
double get_money()
{
return money;
}
};
int main()
{
Person c;
c.name = "wzz";
c.say();
c.set_age(18);
cout << c.get_age() << endl;
c.add_money(100.0);
cout << c.get_money() << endl;
}
结构体
结构体和类的作用是一样的。不同点在于类默认是private,结构体默认是public。结构体的初始化方法如下
#include
using namespace std;
struct person{
int age, height;
double money;
person(){};
person(int _age, int _height) : age(_age), height(_height) {}
person(int _age, int _height, double _money){
age = _age;
height = _height;
money = _money;
}
};
int main()
{
person p(18,180,100);
cout << p1.age;
person p2(21,60);
cout << p2.age << endl;
}
#include
using namespace std;
struct person{
int age, height;
double money;
};
int main()
{
person p1= {18,180,100};
cout << p1.age;
}
链表的增删遍历
#include
using namespace std;
struct student{
int score;
student* next;
student(int _score) : score(_score), next(NULL){}
};
int main()
{
student* s1 = new student(20);
student* s2 = new student(30);
student* s3 = new student(40);
student* head = s1;
s1->next = s2;
s2->next = s3;
for(student* i = head; i; i = i->next) cout << i->score << ' ';
cout << endl;
student* i;
student *j;
int del_num;
cin >> del_num;
for(i = NULL, j = head; j; i = j, j = j->next){
if(j->score == del_num){
if(!i){
head = j->next;
free(j);
break;
} else{
i->next = j->next;
free(j);
break;
}
}
if(j->next == NULL) cout << "找不到指定值" << endl;
}
for(i = head; i; i = i->next) cout << i->score << ' ';
cout << endl;
student *p4 = new student(50);
for(i = head; i->next; i = i->next) ;
i->next = p4;
for(student* i = head; i; i = i->next) cout << i->score << ' ';
cout << endl;
}
STL容器
vector
vector是变长数组,支持随机访问,不支持在任意位置O(1)插入。为了保证效率,元素的增删一般应该在末尾进行。vector是基于倍增的思想去实现动态空间增长,N个数存入vector只需要运行(N/2+ N/4 + )次,时间复杂度为O(n)
#include
#include
using namespace std;
int main()
{
vector<int> a({1,2,3});
a.push_back(4);
for(auto c:a) cout << c << ' ';
cout << endl;
a.pop_back();
a.erase(a.end()-1);
for(auto c:a) cout << c << ' ';
cout<<endl;
printf("size = %d\nempty = %d", a.size(), a.empty());
printf("%d %d", a.front(), a.back());
}
队列queue
queue结构数据从尾部输入,从头部弹出 priority queue弹出元素为所有数中的最大值
循环队列 queue操作:push(从队尾插入); pop(从队头弹出); front(返回队头元素); back(返回队尾元素)
优先队列 priority_queue操作:push(把元素插入堆); pop(删除堆顶元素); top(查询堆顶元素(最大值))
#include
#include
using namespace std;
int main()
{
queue<int> p;
p.push(1);
p.push(2);
p.pop();
cout << p.front() <<endl;
cout << p.back() << endl;
priority_queue<int> b;
b.push(1);
b.push(3);
b.pop();
cout << b.top() << endl;
b = priority_queue<int>();
cout << b.size() << endl;
priority_queue<int,vector<int>,greater<int>> q;
struct Rec{
int a, b;
bool operator<(const Rec& t) const
{
return a < t.a;
}
};
priority_queue<Rec> d;
d.push({1,2});
d.push({2,4});
d.push({2,3});
cout << d.top().b;
}
栈stack
队尾插入,队尾弹出。支持操作push(向栈顶插入), pop(弹出栈顶元素), top(返回栈顶元素)
双端队列deque
双端队列deque是一个支持在两端高效插入或删除元素的连续线性存储空间。它就像是vector和queue的结合。与vector相比,deque在头部增删元素仅需要O(1)的时间,而vector在头部插入需要O(n),因为所有后面的元素都要移动一位;与queue相比,deque像数组一样支持随机访问。但因为常数较大,平均来看deque运行效率慢于vector和stack.
支持操作:; front/back(队头/队尾元素); push_back(在队尾加入); push_front(在队头加入); pop_back(删除队尾元素); pop_front(删除队头元素); clear(清空队列)
#include
#include
using namespace std;
int main()
{
deque<int> a;
a.push_back(1);
a.push_front(2);
for(auto c:a) cout << c << ' ';
cout << endl << a.front() << ' '<< a.back() << endl;
for(int i = 0; i < a.size(); i++) cout << a[i] << ' ';
cout << endl;
}
集合set
头文件set主要包括set和multiset两个容器,分别是“有序集合”和“有序多重集合”,即前者的元素不能重复,而后者可以包含若干个相等的元素。set和multiset的内部实现是一棵红黑树,它们支持的函数基本相同。
操作:
- begin/end:返回集合首、尾迭代器,时间复杂度均为O(1),begin()是指向集合中最小元素的迭代器,end()是指向集合中最大元素的下一个位置的迭代器。
- s.insert(x):把一个元素x插入到集合s中,时间复杂度为O(logn)。在set中,若元素已存在,则不会重复插入该元素,对集合的状态无影响。
- s.find(x):在集合s中查找等于x的元素,并返回指向该元素的迭代器。若不存在,则返回s.end()。时间复杂度为O(logn)。
- lower_bound/upper_bound:
- s.lower_bound(x) 查找大于等于x的元素中最小的一个,并返回指向该元素的迭代器。
- s.upper_bound(x) 查找大于x的元素中最小的一个,并返回指向该元素的迭代器。
- erase: 设it是一个迭代器,s.erase(it) 从s中删除迭代器it指向的元素,时间复杂度为O(logn)
- count: s.count(x) 返回集合s中等于x的元素个数,时间复杂度为 O(k +logn),其中k为元素x的个数。
- 迭代器iterator 设it是一个迭代器,例如
set::iterator it;
支持*
解除引用,仅支持++
,--
两个算数操作
若把it++
,则it会指向“下一个”元素。这里的“下一个”元素是指在元素从小到大排序的结果中,排在it下一名的元素。同理,若把it--
,则it将会指向排在“上一个”的元素。
#include
#include
using namespace std;
int main()
{
set<int> a;
multiset<int> b;
for(int i =0; i < 10; i++) a.insert(i);
set<int>:: iterator it = a.begin();
if(a.find(8) == a.end()) cout << "找不到"<< endl;
else it = a.find(8);
cout << *it << endl;
struct Rec{
int x, y;
bool operator<(const Rec &t) const
{
return x+y < t.x+t.y;
}
};
set<Rec> c;
c.insert({1,2});
c.insert({0,4});
cout<< c.begin()->x << endl;
}
map
map容器是一个键值对key-value的映射,其内部实现是一棵以key为关键码的红黑树。Map的key和value可以是任意类型,其中key必须定义小于号运算符。
size/empty/clear/begin/end均与set类似。
Insert/erase 与set类似,insert参数是pair,erase参数可以是数对也可以是key
find map.find(x)在变量名为h的map中查找key为x的二元组。
[] 操作符是map最吸引人的地方。我们可以很方便地通过h[key]来得到key对应的value,还可以对h[key]进行赋值操作,改变key对应的value。
#include
#include
using namespace std;
int main()
{
map<string,int> m;
m["hello"] = 2;
cout << m["hello"] << endl;
map<string, vector<int>> n;
n.insert({"a",{}});
n.erase("a");
n["b"] = vector<int>({1,2,3,4});
cout << n["b"][1] << endl;
map<string, vector<int>>::iterator it = n.find("b");
cout << it->second[1] << endl;
}
其它容器
unordered_set S;
底层实现是哈希表,时间复杂度为O(1)比set效率高。它除了内部元素无序之外,其他所有性质与set相同,因此除了lower_bound/upper_bound函数之外(因为是无序的)其余函数都可以使用,不支持二分。
unordered_multiset S1;
可以存储重复元素,实验原理为哈希表
unordered_map a
相比map优点是复杂度O(1)效率更高,缺点是不支持二分。
bitset b
定义长度为n的二进制串,可以像数组一样定义每一bit的值,还可以进行位运算
#include
#include
using namespace std;
int main()
{
bitset<5> a,b;
a[0] = 1;
a[1] = 1;
b[1] = 1;
a &= b;
cout << a.count() << endl;
a.set(3);
cout << a <<endl;
}
#include
using namespace std;
int main()
{
pair<string,int> a;
a = {"wzz",22};
cout << a.first <<' ' << a.second <<endl;
a = make_pair("wsx",21);
cout << a.first <<' ' << a.second <<endl;
}
常用库函数
reverse
#include
#include
#include
using namespace std;
int main()
{
vector<int> n = {1,2,3,4};
reverse(n.begin(), n.end());
for(auto c:n) cout << c << ' ';
cout << endl;
int a[] = {1,2,3,4,5};
reverse(a, a+5);
for(auto c:a) cout << c << ' ';
cout << endl;
}
unique——去重函数
返回去重之后的尾迭代器(或指针),仍然为前闭后开,即这个迭代器是去重之后末尾元素的下一个位置。该函数常用于离散化,利用迭代器(或指针)的减法,可计算出去重后的元素个数。
#include
#include
#include
using namespace std;
int main()
{
int a[] = {1,1,2,2,3,4,5,5};
int m = unique(a, a+8) - a ;
cout << m << endl;
for(int i = 0; i < m; i++) cout << a[i] << ' ';
cout << endl;
vector<int> b({1,1,2,2,3,4,5,5});
b.erase(unique(b.begin(),b.end()), b.end());
for(auto c: b) cout << c << ' ';
cout << endl;
}
random_shuffle 随机打乱
用法与reverse相同,用于生成随机数组
#include
#include
#include
#include
using namespace std;
int main()
{
srand(time(0));
vector<int> a({1,2,3,4,5});
random_shuffle(a.begin(),a.end());
for(auto c:a) cout << c << ' ';
cout << endl;
}
sort
对两个迭代器(或指针)指定的部分进行快速排序。可以在第三个参数传入定义大小比较的函数,或者重载“小于号”运算符。
#include
#include
#include
using namespace std;
bool cmp(int a, int b){
return a < b;