循环结构、顺序结构、选择结构是结构化程序设计的3中基本方式。
“关系运算”就是“比较运算”,将两个数值进行比较,判断其比较的结果是否符合给定的条件。
用关系运算符将两个数值或数值表达式连接起来的式子,称关系表达式。
逻辑运算符优先级 !(非)-> &&(与)-> ||(或),即“!”为三者中最高。
用逻辑运算符将关系表达式或其他逻辑量连接起来的式子就是逻辑表达式。
if(表达式) “表达式”可以是关系表达式、逻辑表达式、数值表达式。
switch(表达式) “表达式”其值的类型应为整数类型(包括字符型)。
case 后面跟一个常量(或常量表达式)。
数组名[常量表达式]。常量表达式中可以包括常量和符号常量,不能包含变量。
如果在被调用的函数(不包括主函数)中定义数组,其长度可以是变量或非常量表达式。
实际参数 可以是 常量、变量、表达式
用数组元素作为实参时,向形参变量传递的是数组元素的值,而用数组名作函数实参时,向形参(数组名或指针变量)传递的是数组首元素的地址。
引用一个数组元素,可以用下面的两种方法:
(1)下标法,如 a[i] 形式;
(2)指针法,如 *(a+i) 或 *(p+i) 或 p[i] 。其中 a 是数组名, p 是指向数组元素的指针变量,其初值 p = a 。
其中 数组名 a 代表 数组首元素的地址, 它是一个指针型常量,它的值在程序运行期间是固定不变的,故 a++ 是无法实现的。
printf("%d", a[i]); // 数组元素用数组名和下标表示
printf("%d", *(a+i); // 通过数组名和元素符号计算元素地址,再找到该元素
// (a+i) 是 a 数组中序号为 i 的元素的地址, *(a+i) 是该元素的值
scanf("%d", &a[i]); // scanf("%d", a+i);
*p++; // *(p++)
由于 ++ 和 * 同优先级,结合方向为自右而左,因此它等价于 *(p++) 。先引用 p 的值, 实现 *p 的运算,然后再使 p 自增 1 。
*(++p);
先使 p 加 1, 再取 *p 。
若 p 初值为 a (即 &a[0]), 若输出 *(p++) 得到 a[0] 的值,而输出 *(++p) ,得到 a[1] 的值。
++(*p);
表示 p 所指向的元素值加 1,如果 p=a ,则 ++(*p) 相当于 ++a[0] ,若 a[0] 的值为3,则在执行 ++(*p) (即++a[0]) 后a[0]的值为4。注意:是元素a[0]的值加1,不是指针 p 的值加1 。
如果 p 当前指向数组 a 中第i个元素 a[i],则:
*(p--) 相当于 a[i--] ,先对 p 进行 "*" 运算(求 p 所指向的元素的值),再使p自减 。
*(++p)相当于a[++i] ,先使 P 自加再进行 “*“ 运算。
*(--p)相当于 a[--i] ,先使 p 自减再进行 “*” 运算。
总的来说,从右至左,谁先靠近 p 给谁和 p 一起加上括号。
实参数组名代表一个固定的地址,或者说是指针常量,但形参数组名并不是一个固定的地址,而是按指针变量处理。
指向 m 个元素组成的一维数组的指针变量
int *p;
如果 p 先指向 a[0] (即 p = &a[0] ) ,则 p+1 不是指向 a[0][1],而是指向 a[1] ,p的值以一维数组的长度为单位。
int a[3][4];
int (*p)[4];
p =a ; // p 指向0行。
一维数组a,这个 &a 表示一维数组的行地址。
int (*p)[4] 表示定义 p 为一个指针变量,它指向包含 4 个整数元素的一维数组。注意: *p 两侧的括号不可缺少,如果写成 *p[4] ,由于方括号 [] 运算级别高,因此 p 先与 [4] 结合,p[4] 是定义数组的形式,然后再与其那面的 * 结合, *p[4] 就是指针数组。
p = &a
(*p)[3] 代表 a[3] 的值。
二维数组的指针使用:
二维数组名(如a)是指向行的。因此 a+1 中的 "1" 代表一行中全部元素所占字节数。
a[0] 代表一维数组 a[0] 中第 0 列元素的地址,即 &a[0][0] 。也就是说, a[1] 的值是 &a[1][0] ,a[2] 的值是 &a[2][0] 。
a[i] 和 *(a+i) 等价。因此,a[0]+1 和 *(a+0)+1 都是 &a[0][1] 。 a[1]+2 和 *(a+1)+2 的值都是 &a[1][2] 。
*(a[0]+1) 就是 a[0][1] 的值。 同理,*(*(a+0)+1) 或 *(*a+1) 也是 a[0][1] 的值。
*(a[i]+j) 或 *(*(a+i)+j) 是 a[i][j] 的值。 请务必记住 *(a+i) 和 a[i] 是等价的。
a , a+i , a[i] , *(a+i) , *(a+i)+j , a[i]+j 都是地址。而 *(a[i]+j) 和 *(*(a+i)+j) 是二维数组元素 a[i][j] 的值。
a[2] , *(a+2) 2行0列元素地址
&a[2] , a+2 2行首地址
如果在定义局部变量时不赋初值,则对静态局部变量来说,编译时自动赋初值0(对数值型变量)或空字符‘/0’(对字符变量)。
两种# include指令形式的区别是用尖括号形式(如<stdio. h>)时,编译系统从存放C编译系统的子目录少去找所要包含的文件(如stdio.h).这称为标准方式。如果用双撇号形式(如"stdio. h"),在编译时,编译系统先在用户的当前目录(一般是用户存放源程序文件的子目录)中寻找要包含的文件,若找不到,再按标准方式在找。如果用# include指令是为了使用系统军函数,因而要包含系统提供的相应头文件,以用标准方式为宜.以提高效率。如果用户想包含的头文件不是系统提供的相应头文件,而是用户自己编写的文件(这种文件一般都存放在用户当前目录中),这时应当用双撇号形式,否则会找不到所需的文件如果该头文件不在当前目录中,可以在双撇号中写出文件路径(如# include "C.\temp\filel. h”),以便系统能从中找到所需的文件。
用“%s”格式输出字符串时,printf 函数中的输出项时字符数组名,而不是数组元素名。 例如:
char c[10] = {"China"}; // char c[10] = "China"
printf("%s",c);
scanf 函数中的输入项如果是字符数组名,不要再加地址符&,因为在C语言中数组名代表该数组的起始地址。
char str[13];
scanf("%S",str);
%s 格式,后接地址就能输出了。
int (*p)(int ,int ); 用来定义p 是一个指向函数的指针变量。最前面的 int 表示这个函数值(即函数返回的值)是整形的。
注意: *p 两侧的括号不可省略,表示 p 先与 * 结合,是指针变量,然后再与后面的 () 结合, () 表示是函数,即该指针变量不是指向一般的变量,而是指向函数。如果写成 int *p(int, int ) ,就声明成了一个 p 函数了(这个函数的返回值是指向整型变量的指针)。
指向结构体变量的指针:
为了使用方便和直观,C语言允许把 (*p).num 用 p->num 来代替,“->”代表一个箭头,p->num 表示 p 所指向的结构体变量中的 num 成员。同样,(*p).num 等价于 p->name 。“->” 称为指向运算符。
如果 p 指向一个结构体变量 stu ,以下3中方法等价:
1. stu.成员名(如 stu.num);
2. (*p).成员名(如 (*p).mum);
3. p->成员名(如 p->num)。
round() 函数://四舍五入算法
floor() //向下取整
ceil() //向上取整
set 容器函数 插入:s.insert(1);
判断是否在集合内:if(s.count(1)==1)cout<<"在集合内"<<endl;
atoi() 和 atol() 函数 将 char 数组变成数字
最大公约数gcd:
int gcd(int a,int b){
return b ? gcd(b, a%b) : a;
}
while ( b != 0 ) {
t = a%b;
a = b;
b = t;
}
最小公倍数lcm:
long long lcm(long long a, long long b)
{
return a / gcd(a, b) * b;
}
找约数:for循环遍历寻找
素数筛子:
#include<stdio.h>
int main() {
bool num[100001] = {false};
for(int i = 2; i <= 100000; i++){
if(!num[i]){
printf("%d\n",i);
for(int j = 2 * i; j < 100000; j = j + i)
num[j] = true;
}
}
}
一、 STL数据结构
1.vector
+使用要点:
-尾部插入和删除{push_back(),pop_back()},
-遍历{可以用for和int i=0 也可以用迭代器},
-排序{
!!对结构体的存储和排序非常容易考!!
struct type{
int x,y;
};
vector<type> data;
sort(data.begin(),data.end(),cmp())
cmp为可自定义的比较函数,这里先按x从小到大,x相同再按y从小到大排序
bool cmp(type a,type b){
if(a.x != b.x)return a.x < b.x;
return a.y < b.y;
}
}
#include <bits/stdc++.h>
using namespace std;
void main31(){
vector<int> v1;
cout << "length:" << v1.size() << endl;
v1.push_back(1);
v1.push_back(3);
v1.push_back(5);
cout << "length:" << v1.size() << endl;
cout << "头部元素" << v1.front() << endl;
//修改 头部元素
//函数返回值当左值 应该返回一个引用
v1.front() = 11;
v1.back() = 55;
while(v1.size() > 0){
cout << "尾部元素" <<v1.back(); //获取尾部元素
v1.pop_back(); //删除尾部元素
}
}
//vector的初始化
void main32(){
vector<int> v1;
v1.push_back(1);
v1.push_back(3);
v1.push_back(5);
v1.push_back(7);
vector<int> v2 =v1; //对象初始化
vector<int> v3(v1.begin(), v1.begin()+2);
}
void printV(vector<int> &v){
for(int i = 0; i < v.size(); i++){
cout << v[i] << " ";
}
}
//vector的遍历 通过数组的方式
void main33(){
vector<int> v1(10); //提前把内存准备好
for(int i = 0; i < 10; i++){
v1[i] = i+1;
}
/*
for(int i = 0; i < 10; i++){
printf("%d ", v1[i]);
}
*/
printV(v1);
}
//push_back()的强化记忆
void main34(){
vector<int> v1(10); //提前把内存准备好
v1.push_back(100);
v1.push_back(200);
cout << "size:" << v1.size() << endl;
printV(v1);
}
//迭代器
//当 it == v1.end()的时候,说明这个容器已经遍历完毕了
// end()的位置, 应该是 5的后面
//2 迭代器的种类
void main35(){
vector<int> v1(10);
for(int i = 0; i < 10; i++){
v1[i] = i+1;
}
//正向遍历
for(vector<int>::iterator it = v1.begin(); it != v1.end(); it++){
cout << *it << " ";
}
//逆序遍历
for(vector<int>::reverse_iterator rit = v1.rbegin(); rit != v1.rend(); rit++ ){
cout << *rit << " ";
}
}
//vector 删除
void main36(){
vector<int> v1(10);
for(int i = 0; i < 10; i++){
v1[i] = i+1;
}
//区间删除
v1.erase(v1.begin(),v1.begin()+3);
printV(v1);
//根据元素的位置 指定位置删除
v1.erase(v1.begin()); //在头部删除一个元素
printV(v1);
cout << endl;
// 根据元素的值
v1[1] = 2;
v1[3] = 2;
printV(v1);
cout << endl;
for(vector<int>::iterator it = v1.begin(); it != v1.end();){
if(*it == 2){
it = v1.erase(it); //当删除迭代器所指向的元素的时候,erase删除函数会让it自动下移动
}
else{
it++;
}
}
printV(v1);
cout << endl;
v1.insert(v1.begin(),100);
v1.insert(v1.end(), 200);
printV(v1);
}
//map元素的添加、遍历、删除基本操作
void main1101(){
map<int, string> map1;
//方法1
map1.insert(pair<int,string>(1,"teacher01"));
map1.insert(pair<int,string>(2,"teacher02"));
//方法2
map1.insert(make_pair(3,"teacher04"));
map1.insert(make_pair(4,"teacher05"));
//方法3
map1.insert(map<int,string>::value_type(5,"teacher05"));
map1.insert(map<int,string>::value_type(6, "teacher06"));
//方法4
map1[7] = "teacher07";
map1[8] = "teacher08";
// 容器的遍历
for(map<int,string>::iterator it = map1.begin(); it != map1.end(); it++){
cout << it->first << "\t" << it->second << endl;
}
cout << "遍历结束" << endl;
while(!map1.empty()){
map<int, string>::iterator it = map1.begin();
cout << it->first << "\t" << it->second << endl;
map1.erase(it);
}
}
2.map
+使用要点:
-理解键的唯一性,了解插入的数据会按键大小自动排序
-插入元素,两种方式{
map<int,int> m;
m[3] = 1;
或者
m.insert ( pair<int,int>(4,100) );//其中pair<>()是一种键值对数据结构
}
-使用迭代器遍历记录,删除记录(注意遍历时删除迭代器的失效问题)
// 容器的遍历
for(map<int,string>::iterator it = map1.begin(); it != map1.end(); it++){
cout << it->first << "\t" << it->second << endl;
}
cout << "遍历结束" << endl;
while(!map1.empty()){
map<int, string>::iterator it = map1.begin();
cout << it->first << "\t" << it->second << endl;
map1.erase(it);
}
3.set
+基本操作{
set<int> s;
插入:s.insert(1);
判断是否在集合内:if(s.count(1)==1)cout<<"在集合内"<<endl;
使用迭代器遍历:
for(set<int>::iterator it = set1.begin(); it != set1.end(); it++){
cout << *it << " ";
}
//删除集合
while(!set1.empty()) {
set<int>::iterator it = set1.begin();
cout << *it << " ";
set1.erase(set1.begin());
}
// 对基本的数据类型 set 能自动排序
void main92(){
set<int> set1;
set<int, less<int> > set2; // 默认情况下是这样
set<int, greater<int> > set3; //从大到小
for(int i = 0; i < 5; i++){
int tmp = rand();
set3.insert(tmp);
}
//从大到小
for(set<int, greater<int> >::iterator it = set3.begin(); it != set3.end(); it++){
cout << *it << endl;
}
}
//仿函数的用法
struct FuncStudent{
bool operator()(const Student &left, const Student &right){
if(left.age < right.age){ //如果左边的小 就返回真 从小到大按照年龄进行排序
return true;
}
else{
return false;
}
}
};
void main93(){
Student s1("s1" ,31);
Student s2("s2", 22);
Student s3("s3", 44);
Student s4("s4", 11);
set<Student, FuncStudent> set1;
set1.insert(s1);
set1.insert(s2);
set1.insert(s3);
set1.insert(s4);
//遍历
for(set<Student, FuncStudent>::iterator it = set1.begin(); it != set1.end(); it++){
cout << it->age << " " << it->name << endl;
}
}
}
4.Stack
+基本操作{
stack<Node *> s;
s.push(root);
Node *p = s.top();
s.pop();//注意,pop不会返回出栈的元素,需要用top先接受再出栈
if(!s.empty()){cout << "栈不空" << endl;}
}
#include <bits/stdc++.h>
using namespace std;
//栈模型
// 栈的算法和数据类型的
void main51(){
stack<int> s;
//入栈
for(int i = 0; i < 10; i++){
s.push(i+1);
}
cout << "栈的大小" << s.size() << endl;
//出栈
while(!s.empty()){
int temp = s.top(); //获取栈顶元素
cout << temp << " ";
s.pop(); //弹出栈顶元素
}
}
//teacher结点
class Teacher{
public:
int age;
char name[32];
void printT(){
cout << "age:" << age << endl;
}
};
void main52(){
Teacher t1, t2, t3;
t1.age = 31;
t2.age = 32;
t3.age = 33;
stack<Teacher> s;
s.push(t1);
s.push(t2);
s.push(t3);
while(!s.empty()){
Teacher tmp = s.top();
tmp.printT();
s.pop();
}
}
void main53(){
Teacher t1, t2, t3;
t1.age = 31;
t2.age = 32;
t3.age = 33;
stack<Teacher *> s;
s.push(&t1);
s.push(&t2);
s.push(&t3);
while(!s.empty()){
Teacher *p = s.top();
p->printT();
s.pop();
}
}
5.queue
+基本操作{
queue<string> q;
入队:q.push("1");
取队首:string x = q.front();
出对:q.pop();
}
#include <bits/stdc++.h>
using namespace std;
//队列中基本数据类型
void main61(){
queue<int> q;
q.push(1);
q.push(2);
q.push(3);
cout<< "队列的头部" << q.front() << endl;
cout << "队列的大小" << q.size() << endl;
while(!q.empty()){
int tmp = q.front();
cout << tmp << " ";
q.pop();
}
}
//队列的算法和 数据类型的分离
//teacher结点
class Teacher{
public:
int age;
char name[32];
void printT(){
cout << "age:" << age << endl;
}
};
void main62(){
Teacher t1, t2, t3;
t1.age = 31;
t2.age = 32;
t3.age = 33;
queue<Teacher> q;
q.push(t1);
q.push(t2);
q.push(t3);
while(!q.empty()){
Teacher tmp = q.front();
tmp.printT();
q.pop();
}
}
void main63(){
Teacher t1, t2, t3;
t1.age = 31;
t2.age = 32;
t3.age = 33;
queue<Teacher *> q;
q.push(&t1);
q.push(&t2);
q.push(&t3);
while(!q.empty()){
Teacher* tmp = q.front();
tmp->printT();
q.pop();
}
}
6.并查集
有时挺有用的数据结构,STL中没有实现,需要自己实现
7.二叉树的构造
最难的数据结构也是这个层次了,可以参考小虎的构造方法Node * createTree(int pre[],int in[],int l1,int h1,int l2,int h2)
二、字符串操作
1.字符与数字的转化
'3'-'0'=数字3
7+'0'=字符7
2.字符串与数字互相转化
sstream 可以实现相互转化
//sstream
#include <bits/stdc++.h>
using namespace std;
int main(){
stringstream ss;
string s;
long a,b;
cin >> a;
cin >> b;
ss << a*b;
ss >> s;
reverse(s.begin(),s.end());
a = atol(s.c_str());
a = round(3.4);
//atoi 将 char 数组变成数字
cout << a << endl;
return 0;
}
sprintf 可以实现各种类型->string //这是c中的函数
3.string类的操作
+初始化
//string 的初始化
void main21(){
string s1 = "aaaa";
string s2("bbbb");
string s3 = s2; //通过拷贝构造函数 来初始化对象s3
string s4(10,'a');
cout << "s1:" << s1 << endl;
cout << "s2:" << s2 << endl;
cout << "s3:" << s3 << endl;
cout << "s4:" << s4 << endl;
}
+取子串
s.substr(a,b)//从a位置向后取b个字符
+使用for和int i=0 或者 迭代器遍历字符串
void main22(){
string s1 = "abcdefg";
//1 数组方式
for(int i = 0; i < s1.length(); i++){
cout << s1[i] << " ";
}
//2 迭代器
for(string::iterator it = s1.begin(); it != s1.end(); it++){
cout << *it << " ";
}
cout << endl;
for(int i = 0; i < s1.length(); i++){
cout << s1.at(i) << " ";//排除异常
}
}
#include <bits/stdc++.h>
using namespace std;
//string 的初始化
void main21(){
string s1 = "aaaa";
string s2("bbbb");
string s3 = s2; //通过拷贝构造函数 来初始化对象s3
string s4(10,'a');
cout << "s1:" << s1 << endl;
cout << "s2:" << s2 << endl;
cout << "s3:" << s3 << endl;
cout << "s4:" << s4 << endl;
}
void main22(){
string s1 = "abcdefg";
//1 数组方式
for(int i = 0; i < s1.length(); i++){
cout << s1[i] << " ";
}
//2 迭代器
for(string::iterator it = s1.begin(); it != s1.end(); it++){
cout << *it << " ";
}
cout << endl;
for(int i = 0; i < s1.length(); i++){
cout << s1.at(i) << " ";//排除异常
}
}
//字符指针和string的转换
void main23(){
string s1 = "aaabbbb";
//1 s1===>char *
printf("s1:%s \n", s1.c_str());
//2 char*===>string
//3 s1的内容 copy buf中
char buf1[128] = {0};
s1.copy(buf1,3,0); //注意 只给你copy3个字符 不会变成C风格的字符串
cout << "buf1:" << buf1 << endl;
}
void main24(){
string s1 = "aaa";
string s2 = "bbb";
s1 = s1+s2;
cout << s1 << endl;
string s3 = "333";
string s4 = "444";
s3.append(s4);
cout << "s3:" << s3 << endl;
}
//字符串的查找和替换
void main25(){
string s1 = "wbm hello wbm 111 wbm 222 wbm 333";
//第一次 出现wbm index
int index = s1.find("wbm", 0); //位置下标 从0 开始
cout << "index: " << index << endl;
//案例1 求 wbm 出现的次数 ,每一次出现的数组下标
//返回str在字符串中第一次出现的位置(从index开始查找)。如果没找到则返回string::npos
int offindex = s1.find("wbm", 0);
while(offindex != string::npos ){
cout << "offindex:" << offindex << endl;
offindex = offindex + 1;
offindex = s1.find("wbm", offindex);
}
//案例2 把小写wbm===>WBM
string s3 = "aaa bbb ccc";
s3.replace(0,3,"AAA");
cout << "s3" << s3 << endl;
offindex = s1.find("wbm", 0);
while (offindex != string::npos){
cout << "offindex:" << offindex << endl;
s1.replace(offindex,3,"WBM");
offindex = offindex +1;
offindex = s1.find("wbm", offindex);
}
cout << "s1替换后的结果" << s1 << endl;
}
//截断(区间删除)和插入
void main26(){
string s1 = "hello1 hello2 hello1";
string::iterator it = find(s1.begin(), s1.end(),'l');
if(it != s1.end()){
s1.erase(it);
}
cout << "s1删除l以后的结果" << s1 << endl;
s1.erase(s1.begin(), s1.end());
cout << "s1全部删除:" << s1 << endl;
cout << "s1长度" << s1.length() << endl;
string s2 = "BBB";
s2.insert(0,"AAA"); //头插法
s2.insert(s2.length(),"CCC");
cout << s2 << endl;
}
void main27(){
string s1 = "AAAbbb";
//1函数的入后地址 2函数对象 3预定义的函数
transform(s1.bgein(), s1.end(), s1.begin(),toupper);
cout << "s1:"<< s1 << endl;
string s2 = "AAAbbb";
transform(s2.begin(),s2.end(), s1.begin(),tolower);
cout << "s2:" <<s2 <<endl;
}
注意:大整数等问题,一般可以通过字符串处理或者数组处理