第五单元 数组
之前学习了顺序结构,分支结构和循环结构,可以解决很多的复杂的问题。
但当数据较多时循环结构的循环重数会大大增多,这时会使写的程序非常繁琐,
并且有可能出现一些超时的问题。此时就能够突出学习数组的意义。
它能够解决很多繁琐的问题使数据存在一个数组中,
要用的时候就从中提取,可以大大减少程序的长度,
从而优化程序。
但是随之而来的问题是学习的数组难度大大升高。
第一课 一维数组的定义
①定义一维数组的格式为
类型标识符 数组名[常量表达式];
(类型标识符可以是任何基本数据类型,
也可以是结构体等构造类型,相同类型的数组可以一起定义)
②在使用一维数组时需注意:
下标是从零开始的,所以要额外注意下标越界的问题。
如:int a[5] 其中int基类型
意为定义了一个有五个int型元素的数组
int a[5]={11 12 13 14 15};
意为这五个元素分别赋值为括号中的数。
int a[ ]={11 12 13 14 15};
给了几个初值就有几个元素。
③如果要求一个数组所占的内存空间可以用sizeof函数
第二课 一维数组的输入与输出
主要是要掌握一维数组的输入与输出操作
并且学会应用一维数组解决一些实际的问题。
①一维数组的输入均是由循环语句实现,将批量的数据一次性输入到数组中
如:int h[100];
for(i=0;i<100;i++) cin>>h[i];
也可以直接赋值
②还提供了两个函数给数组整体赋值
⑴memset函数
一般都是用在char数组中
如果是int类型的数组,一般赋值为0和-1
使用前需要包含头文件:#include<cstring>
⑵fill函数
“按元素”进行赋值,使用前需要包含头文件:#include<algorithm>
例如:
校门外的树
某校大门外长度为L的马路上有一排树,每两棵相邻的树之间的间隔都是1米。我们可以把马路看成一个数轴,马路的一端在数轴0的位置,另一端在L的位置;数轴上的每个整数点,即0,1,2,……,L,都种有一棵树。
由于马路上有一些区域要用来建地铁。这些区域用它们在数轴上的起始点和终止点表示。已知任一区域的起始点和终止点的坐标都是整数,区域之间可能有重合的部分。现在要把这些区域中的树(包括区域端点处的两棵树)移走。你的任务是计算将这些树都移走后,马路上还有多少棵树。
输入
第一行有两个整数L(1 <= L <= 10000)和 M(1 <= M <= 100),L代表马路的长度,M代表区域的数目,L和M之间用一个空格隔开。接下来的M行每行包含两个不同的整数,用一个空格隔开,表示一个区域的起始点和终止点的坐标。
对于20%的数据,区域之间没有重合的部分;
对于其它的数据,区域之间有重合的情况。
输出
包括一行,这一行只包含一个整数,表示马路上剩余的树的数目。
样例输入
500 3
150 300
100 200
470 471
样例输出
298
#include<cstdio>
using namespace std;
int a[10001],n,m,x,y,s=0;//要保证下标绝对不会越界
int main()
{
scanf("%d%d",&n,&m);//n代表马路长度,m代表区域数目
for(int i=0;i<=n;i++)
a[i]=1; //输入了一个数组中元素均为1的数组
for(int i=1;i<=m;i++)
{
scanf("%d%d",&x,&y);
for(int j=x;j<=y;j++)
a[j]=0;//为了算移去了多少树,所以重新建立了一个数组
}
for(int i=0;i<=n;i++)
{
if(a[i]==1)
s++; //s是个计数变量
}
printf("%d",s);
return 0;
}
此题的难点在于区域之间可能有重合的部分,
第三课 一维数组的插入删除
学会数组元素的插入和删除操作并解决一些实际问题
要额外注意要把数组下标定义的足够大
【题目描述】
有 n 个人(每个人有一个唯一的编号,用 1~n 之间的整数表示)在一个水龙头前排队准备接水,现在第 n 个人有特殊情况,经过协商,大家允许他插队到第 x 个位置。输出第 n 个人插队后的排队情况。
【输入】
第一行 1 个正整数 n,表示有 n 个人,2<n≤100。
第二行包含 n 个正整数,之间用一个空格隔开,表示排在队伍中的第 1~ 第 n 个人的编号。
第三行包含 1 个正整数 x,表示第 n 个人插队的位置,1≤x<n。
【输出】
一行包含 n 个正整数,之间用一个空格隔开,表示第 n 个人插队后的排队情况。
【输入样例】
7
7 2 3 4 5 6 1
3
【输出样例】
7 2 1 3 4 5 6
代码
#include<cstdio>
using namespace std;
int a[101],n,x,t;
int main() {
scanf("%d",&n);
for(int i=1;i<=n;i++)
scanf("%d",&a[i]);//a[i]表示排在第i位上的人
scanf("%d",&x);
t=a[n];
for(int j=n;j>=x+1;j--)
a[j]=a[j-1]; //重复执行了a[j]=a[j-1];
a[x]=t;
for(int i=1;i<=n;i++)
printf("%d ",a[i]);
return 0; }
第四课 一维数组的查找统计
主要学会使用二分查找,如果用顺序查找工程量太大且容易超时,
使用二分查找比较次数少,查找速度快。
二分查找的方法:
int left =0,right=n-1;
int find=n;//find标记找到的位置,初始化为n,表示没找到。
while( left<= right){
int mid=(left+right)/2
if(a[mid]==x){//找到了,就标记位置,并退出循环
find=mid;
break;
}
if(x<a[mid]) right=mid-1;//x只能在左半部分
if(a[mid]<x) left=mid+1;//x只能在右半部分
}
if(find!=n)printf("%d\n",find);
else printf("not find\n");
二分查找:①找内容
②找到东西是有序的
局部统计一定在具体统计之前赋初值
不可以早赋,全局统计可以在定义变量时赋初值
如:
【题目描述】
有 N 个人排成一排,假设他们的身高均为正整数,请找出其中符合以下条件的人:排在他前面且比他高的人数与排在他后面且比他高的人数相等。
【输入】
第一行为一个正整数 N,1<N<1000,表示有多少个人。
下面 N 行,每行一个正整数,表示从前往后每个人的身高,假设每个人的身高≤10000。
【输出】
一行一个整数,表示满足这个条件的人数。
【输入样例】
4
1
2
1
3
【输出样例】
2
【样例说明】
第 3、第 4 个人满足条件。
代码
#include<cstdio>
using namespace std;
int i,j,k,s=0,t1,t2,n,a[1001];
int main() {
scanf("%d",&n);
for(i=1;i<=n;i++)
scanf("%d",&a[i]);
for(i=1;i<=n;i++) {
t1=t2=0; //统计之前赋初值
for(j=1;j<i;j++) {
if(a[j]>a[i])
t1++;//排在他前面且比他高的人数
}
for(k=i+1;k<=n;k++) {
if(a[k]>a[i])
t2++;//排在他后面且比他高的人数
}
if(t1==t2)
s++;//为了计这样的人有几个
}
printf("%d",s);
return 0; }
第五课 一维数组的元素排序
主要学习三种排序:选择排序、冒泡排序和插入排序这三种排序各有各的优点
最重要的是返回值
bool complare (int a,int b)
{return a>b//返回值
}真为ture,假为false
【题目描述】
某商场的仓库中有 n 件商品,每件商品的价格在 0~1000 之间(价格为 0 的商品为赠品)。现在商场经理要求将这 n 件商品按价格由低到高排序。请编程输出 n 件商品排序后的情况。
【输入】
第一行一个正整数 n,表示有 n 件商品,1≤n≤100000。
接下来的 n 行,每行一个整数,表示第 i 件商品的价格。
【输出】
n 行,每行输出一个整数。
【输入样例】
5
1
8
1
2
2
【输出样例】
1
1
2
2
8
此题的特点是数据太多,数据范围比较小
代码
方法一
运用了桶排序按照数据的取值范围(范围小,数据多)
#include<iostream>
using namespace std;
int num[1001],number,n,i,j;
int main() {
cin>>n;
for(i=1;i<=n;i++) {
cin>>number;
num[number]++; //记录整数number出现的次数
}
for(i=0;i<1001;i++) {
for(j=1;j<=num[i];j++)
cout<<i<<endl;
}
return 0; }
方法二
#include<cstdio>
using namespace std;
int a[1001],t,n,i,j;
int main() {
scanf("%d",&n);
for(i=1;i<=n;i++) {
scanf("%d",&t);
a[t]++;
}
for(i=0;i<1001;i++) {
for(j=1;j<=a[i];j++)
printf("%d\n",i);
}
return 0; }
第七课 二维数组的定义和操作
二维数组是为了解决一维数组遗留下来的问题
在二维数组中每一个元素就又是一个一维数组,在定义二维数组中不可以忽略掉第二维大小
①定义二维数组的一般格式为:
类型标识符 数组名[常量表达式1][常量表达式2]
一般可以把二维数组看成一张表格或一个矩阵
②在定义二维数组定义的同时可以进行初始化赋值,既可以分行初始化,也可以部分行初始化
③二维数组的储存方式是行优先的连续储存
引用二维数组的一个元素格式为
数组名[下标1][下标2]
例如:
cin>>h[3][1];h[3][1]=h[3][1]*2;cout<<h[3][1];
第八课 二维数组应用举例
【题目描述】
输入一个正整数 n,输出 n 行的数字三角形。其中,第 1 行为数字 1,第 2 行为数字 23,第 3行为数字 456,第 4 行为数字 7890,第 5 行为数字 12345,…
【输入】
一行一个正整数 n,1≤n≤100。
【输出】
n 行的数字三角形。
【输入样例】
4
【输出样例】
1
23
456
7890
代码
#include<cstdio>
using namespace std;
int a,b=1;
int main() {
scanf("%d",&a);
for(int i=1;i<=a;i++) {
for(int j=1;j<=i;j++) {
printf("%d",b%10);
b++;
}
printf("\n");
}
return 0;
}
它的具体实现采用了赋值法,对这个题分析可以发现,
对于右上角的每一个元素a[i][i]分析发现a[i][j]=j-i+1
第九课 数字方阵
主要是为了更好的解决数字方阵的问题,体会数组下标的运算。
第十课 字符数组
一个字符数组只能存一个或一段文字。用二维的字符数组可以存若干个
char str[10]只能存一段文字,此文字有10个字符
char str[10][100]10行每行不超过100个字符
不加下标表示读一段文字,加下标表示只读一个元素
空格作间隔符,读不进空格
如:
输入“hello world!”
输出为:
hello
world!
因为s1输出hello,s2输出了world
因为空格做了间隔符