全国青少年信息学奥林匹克竞赛(信奥赛)备考实战之一维数组(应用技巧)
前面对数组的定义、初始化、遍历、修改和应用做了介绍,接下来对数组的应用技巧进一步讲解。
一、一维数组的应用技巧1:对数组进行初始化
数组的初始化方法通常有3种:
1、在定义数组时对全部数组元素赋予初值。例如: int a[10]={0,1,2,3,4,5,6,7,8,9};将数组元素的初值依次放在一对花括号内。经过上面的定义和初始化之后, a[0]=0, a[1]=1, a[2]=2, a[3]=3, a[4]=4, a[5]=5, a[6]=6,a[7]=7,a[8]=8,a[9]=9。
2、可以只给一部分元素赋值。例如: int a[10]={0,1,2,3,4};定义a数组有10个元素,但花括号内只提供5个初值,这表示只给前面5个元素赋初值,后5个元素值默认为0。
3、在对全部数组元素赋初值时,可以不指定数组长度。例如: int a[5]={1,2,3,4,5};可以写成int a[]={1,2,3,4,5};
除此之外还有一种更为快捷的写法,使用memset函数,该函数是基于对字节的操作(一个整型变量占4个字节的存储空间,每个字节是8位二进制数,那么一个整型变量是32位二进制数)。这种方法是给每个字节赋在[0,255]的值,那么首先来介绍sizeof函数,其作用是计算一个变量占多少字节。格式为:sizeof(变量名)。例如:
int a;
cout<<sizeof(a)<<endl;
运行结果:输出4,定义一个整型变量a,输出变量a所占的字节数,运行结果表示变量a占4个字节。
再如:
int a[105];
cout<<sizeof(a)<<endl;
运行结果:输出420,定义一个长度为105的整型数组,输出该数组所占的总字节数,运行结果表示数组a占420个字节(105*4)。
memset函数,其作用是将数组中每个字节都赋值一个数。格式为:
memset(数组名,要初始化的值赋值,sizeof(数组名))。
例如:
int a[105];
memset(a,0,sizeof(a));
定义一个长度为105的整型数组a,将数组a中的每个字节都赋值为0,一个整数类型占4个字节,由于每个字节都是0,则一个整型数字的结果就为0。
再如:
memset(a,1,sizeof(a));
将数组a中的每个字节都赋值为1,那么一个整型数字的结果是多少呢?这个问题好像不是很容易,同时把具体字节赋值过程完整地写出来,1写成8位二进制数就是00000001.一个整数是4个字节,每个字节都是00000001,则其32位二进制数就是00000001000000010000000100000001,转换为十进制数便是16843009.因此,数组的每一个存储空间的值是16843009。这里不少同学会误以为memset(a,1,sizeof(a));表示数组中所有变量都为1。下面给出几个一般的赋值结果:
1)、memset(a,0,sizeof(a));表示将数组中每个元素赋值为0;
2)、memset(a,-1,sizeof(a));表示将数组中每个元素赋值为-1;
3)、memset(a,127,sizeof(a));表示将数组中每个元素赋值为2139062143,这是一个很大的数,接近int类型的上限;
4)、memset(a,0x3f,sizeof(a));表示将数组中每个元素赋值为1061109567(0x3f是十六进制表示,等同于十进制的63,该数的2倍接近int类型的上限。
二、一维数组应用技巧2:打标记
下面通过例子来引入打标记的思想
问题描述:
假设现在有编号1-n的n个白色盘子,小明准备在一些盘子上涂颜色,可能会重复选择某一些盘子涂颜色,问最后哪些盘子还是白色,并按编号从小到大输出。
输入格式:
输入共包含两行:第一行包含两个整数n和m,n表示盘子的个数,m表示将进行m次涂色;第二行包含m个整数,整数之间用空格隔开,每个整数表示每次涂色的盘子编号,盘子可能重复。
输出格式:
输出一行,按编号从小到大输出没有涂颜色的盘子的编号,编号之间用空格隔开。
输入输出样例:
输入样例1 | 输出样例1 |
6 10 1 3 5 1 6 3 1 5 3 1 | 2 4 |
输入样例2 | 输出样例2 |
8 10 1 3 5 1 6 3 1 5 3 1 | 2 4 7 8 |
问题分析:
根据题意,刚开始盘子全部为白色,对盘子操作涂色,对于这一类问题采用打标记的思想,采用数组下标对应盘子的编号,数组元素的值表示颜色状态,即用数组a[i]表示编号为i盘子的涂色状态,a[i]=1(bool类型),表示涂了颜色(bool值为true),a[i]=0表示没有涂过颜色(bool值为 false),重复涂色的盘子最终状态依然为1。这样问题就变成了涂色的盘子标记为1,没有涂过色的盘子标记为0。假设盘子编号分别为1 2 3 4 5 6 …… n,起始状态都为白色,a[i]的值为0,表示都未涂过颜色,然后循环输入m次操作,将下标出现的数组元素表示涂色,这时将数组元素值修改为1,最后循环判断,如果a[i]为0,表示未涂色,依次输出i。具体程序代码如下:
#include<bits/stdc++.h>
using namespace std;
int main(){
bool a[105];//定义标记数组
memset(a,0,sizeof(a));//将标记数组的起始值设置为false
int n,m;//定义盘子数变量n和涂色次数m
cin>>n>>m;//输入n和m的值
for(int i=0;i<m;i++){//进行m次涂色操作
int tmp;//定义涂色的盘子编号变量tmp
cin>>tmp;//输入tmp的值
a[tmp] = 1; //修改该盘子的标记
}
for(int i=1;i<=n;i++){//从第1个盘子开始到最后一个盘子n
if(!a[i]){//判断该盘子的标记是否被修改过
cout<<i<<' ';//输出未涂色的盘子
}
}
return 0;
}