这是为了一个好朋友写的,大家也可以看看,欢迎批评指出。
学习内容我简单描述,然后本文主要讲述课后练习以及重点,因为不会很早写完,一直会更新,所以。。。慢慢看吧。
然后我们从for循环开始。
正文
for循环
格式
for(循环变量 = 初始值; 循环条件; 循环变量变化) { 代码1 代码2 ... 代码n }
举例说明
这个不用太在意,举个例子,若题目要你求100个数的和,那么怎么搞呢,如果像以前
cin>>a sum += a; cin>>a; sum += a; ...... cout<<a;
显然你是不能这么写的
然而用for语句以后
for(int i = 1/*定义循环变量、初始化(我个人认为在循环里面定义更合适)*/; i <= n/*条件(当i小于等于n)*/; i++/*i = i + 1*/) { cin>>a; sum += a; } cout<<sum;
循环的意义就是可以重复做同一个操作,Do you know?
先看几遍,看到会为止
然后应该有人会问 i 有啥用,这里面完全没有用到 i 啊?
有时候没用,但大部分会有用的,比如,让你求1到100的和(用for语句)
显然你可以这么写
for(int i = 1; i <= 100; i++) sum += i; //由于只有一条语句可以不用花括号(“{}”) cout<<sum;
然后就没有什么知识点了吧?进入下一个环节->
练习题库
1、洛谷P1035
2、洛谷P1423
3、洛谷P1424
4、洛谷P1980
注意!请独立思考
while与do while循环
格式
while
while(条件语句为真) { 代码1 代码2 ... 代码n }
do while
do { 代码1 代码2 ... 代码n }while(条件语句为真);
举例说明
其实我个人认为while也没什么用,主要是有些时候比for简洁,举个例子,若你要输入很多组数据,那么while语句就可以写成
while(cin>>a) { ... } 或者 while(scanf("%d", &a) != EOF) { ... }
补充
意思是当“文件没有读入结束时”
如果我们还在读入,”cin>>a“返回的值是1(true)
读入结束,已经读不到东西的时候,它会返回0(false)
在c++里面,1和0可以看为真或假,判断语句也可以这么写
if(b)//当b为真 ... if(!b)//当b为假 ...
暂时我还不知道for怎么写
还不理解的话,可以暂时认为for是用来做一定次数内的操作,而while可以用来做暂时不知道次数(或知道条件)的操作
虽然for语句也可以写成
for(;scanf("%d", &a) != EOF;) { ... }
但看起来while更好用一点,自己看得懂就好。。。但如果别人也看得懂就更好了
练习题库
暂无
循环测试
数组
格式
//定义 int a[N]; //其中“int”是数组类型,a是数组名,N常量,代表了数组的大小(有多少个变量) //注意:c++数组是从0开始的一般我们不用下标为0的空间,那么定义int a[2]只有a[0]和a[1]两个元素 /*赋值和其他变量一样,写作*/ a[i] = r /*r,任意值*/ /*i,下标,代表了是数组中的哪一个元素*/
举例说明
如果,让你读入n个数,n<=1000000,然后要求倒序输出,显然,我们必须把它给我们的每一个数字存起来,如果你不嫌麻烦,你可以
int a1,a2,a3,a4,a5,a6,...,a1000000;
但这样恐怕不行,这时候就可以用数组了,为此,我贴上上面题目的代码
#include <iostream> using namespace std; int a[1000000 + 10]; int main(int argc, char const *argv[]) { int n; cin>>n; for(int i = 1; i <= n; i++) cin>>a[i];//输入a数组的第i个元素(一般情况下不算a[0]) /*之前提到过i有什么用,现在就有用啦*/ for(int i = n; i >= 1; i--) cout<<a[i];//显而易见,倒着来输出 return 0; }
练习题库
二维数组
与一维数组一样,如果说一维是一条线,二维就是一个平面,但是真正用起来可要抽象得多,本文在此不再赘述。
格式
//定义二维 int a[N][N]; //其中“int”是数组类型,a是数组名,N常量,代表了数组的大小(有多少个变量),二维是N*N的矩阵 /*赋值和其他变量一样,写作*/ a[i][j] = r /*r,任意值*/ /*i,下标1,j,下标2.代表了是数组中的哪一个元素*/
举例说明
若题目要求你输入一个大小为N*M的矩阵,然后打印矩阵,则代码如下
#include<iostream> using namespace std; int main() { int a[100][100]; int n,m; cin>>n>>m; for(int i = 1; i <= n; i++) for(int j = 1; j <= m; j++) cin>>a[i][j]; for(int i = 1; i <= n; i++) { for(int j = 1; j <= m; j++) cout<<a[i][j]; cout<<endl; } }
练习题库
函数
函数是C++语法的最后一个章节,也是最难的一个章节,请认真阅读。
格式
函数类型 函数名(参数类型 参数 1;参数类型 参数 2) { 代码 }
举例说明
1、输入a,b;求a,b的最大值
//之前的写法 cin>>a>>b; if(a > b) cout<<a else cout<<b;
现在我们可以写一个专门的函数来实现这个功能
#include<iostream> using namespace std; int MAXN(int x,int y)//这里的x,y = 主函数的a,b { if(x > y) return x;//返回x,而不是输出,让主函数的c = x else return y;//返回y /*这里返回的值必须是int类型的数,返回到的地方就是调用它的地方*/ } int main() { //这是主函数的内容 cin>>a>>b; int c = MAXN(a,b);//调用函数MAXN(最大值函数),传参数a,b。c = 这个函数的返回值 //c++标准库函数和自己写的函数和数学里的函数(三角函数)一样,会有返回值或没有返回值 cout<<c; }
其实这里的代码相当于上面的代码,只是形式不同
那这样还比上面要多几行呢,这个东西有啥用?
其实当我们多次要使用到一段代码的时候,就可以使用函数
有几个知识点:
1、子函数(除了main函数之外的函数)必须写在主函数上,或者提前定义(推荐第一种)
2、函数可以不传参
3、void类型的函数指的是空函数,意思为没有返回值
有时候我们还可以用函数做复杂的调用,比如自己调用自己,叫做递归
递归
斐波那契数列(为了简便,我们后面管他叫“肥婆数列”),大家肯定不陌生吧,让你求肥婆数列的第N项,要求使用递归算法,怎么做?
#include<iostream> using namespace std; int f(int t)//代表肥婆数列的第t项 { //我们知道,第t项 = 第t-1项 + 第t-2项 //那么可以这么写: if(t == 1 || t == 2) return 1;//如果是第1和第2项返回1(他们的答案为1) return f(t - 1) + f(t - 2); //返回值为这一项的答案,然后t-1项又会调用t-2项和t-3项…… } int main() { cin>>n; cout<<f(n);//输出结果 }
递归的调用如图所示。但是作为一种优秀算法的同时,他的时间复杂度也很高,因为顾名思义,递归就是递过再回来时间复杂度大概为(因为我没学过,所以不清楚)O(n^2)。
所以有了递推。
不过他没什么用,我现在都已经忘了它是干嘛的了,所以本文不再赘述,若要了解请翻书。
搜索与回溯
搜索与回溯算法其实就是在递归上加了东西,搜索分为深度优先搜索和宽度优先搜索(或广度优先搜索),简称深搜和宽搜,英文简称为DFS(深搜)和BFS(宽搜)
我记得,搜索可以解决一部分的问题,最典型的是迷宫问题,其他的东西我忘得差不多了,但是迷宫问题却还记得
基本是这样的:给你一个N * M的地图,和其中的障碍物的位置,要求从x0,y0到x1,y1的最短距离
深搜,回溯的做法就是枚举每一条路径,然后求出最短距离,但他是有规律的找
/*我们设置地图中0可以走,1不能走*/ #include<cstdio> #include<algorithm> using namespace std; const int dx[4] = {1, -1, 0, 0}//两个数组枚举位置变化的可能性,枚举x轴 const int dy[4] = {0, 0, 1, -1}//枚举y轴 int mp[100][100]; int vis[100][100]; int k = 0x3f3f3f3f;//因为要最小值,所以初始值要赋最大值 void s(int x,int y) { if(x == x1 && y == y1)//如果已到达 { k = min(k,ans);//c++标准库函数,求最小值 return;//若想结束,那么可以直接返回,但仅限于void没有返回值 } for(int i = 0; i < 4; i++) { int nx = x + dx[i]; int ny = y + dx[i]; //这里两个变量指的是下一个遍历到的地方 if(nx > n || ny > m || nx < 1 || ny < 1 /*判断是否越界*/|| vis[nx][ny] == 1 || mp[nx][ny] == 1) /*vis数组判断是否走过*//*判断是否有障碍*/ continue;//非法访问,跳过 vis[nx][ny] = 1;//记录已访问 ans ++;//答案加一 s(nx,ny);//递归下一层 ans --;//回溯 vis[nx][ny] = 0;//设置未访问,这样才能保证从其他地方还可以访问这一点 } } int main() { int x0,y0,x1,y1; cin>>n>>m>>x0>>y0>>x1>>y1; for(int i = 1; i <= n; i++) for(int j = 1; j <= m; j++) cin>>mp[i][j]; s(x0,y0);//从当前点出发 cout<<k;//输出答案 }
这一部分代码可以慢慢阅读,或找几本书再来理解,因为时间原因,所以只能靠读者自己理解了
任务为AK洛谷新手村!
后记
不知不觉更新就完毕了,突然发现作为一个新手来看还是很难看懂的,也不如XC的课件那么详细,但同时我也自己复习了一遍所学的知识,我会继续努力的!
完