一维数组的定义:
数组就是一组相同类型的变量,他们往往都是为了表示同一批对象的统一属性。
数组可以是一维的,也可以是二维或多维的。
使用一维数组时,一般是从0开始编号,h[i]就表示第i+1个同学的身高,i称为下标变量。
例:读入50个同学的身高,语句就可以这样书写:for(i=0;i<=49;i++)cin>>h[i];
一维数组的定义:类型标识符 数组名[常量表达式];类型标识符可以是任何基本数据类型,也可以是结构体等构造类型;相同类型的数组可以一起定义。
注意:数组大小必须是值为正的量,不能为变量。一旦定义,不能改变大小。
数组定义后初值仍然是随机数。
一维数组的引用:数组定义好后,就可以“引用”数组中的任意一个元素。引用格式为“数组名[下标]”,如h[5],h[i*2+1]等。下标只能为整型常量或整型表达式,值必须在数组定义的下标范围内,否则会出现“下标越界错误”。
一维数组的存储结构:数组在计算机内存单元中是连续存储的。数组数定义在函数外。
一维数组的输入与输出:
键盘输入,例如:int h[100]; for(i=0;i<100;i++)cin>>h[i];
直接赋值,例如:int h[100],a[20]; for(i=0;i<100;i++) h[i]=0; for(i=0;i<20;i++) a[i]=i*2+1;
给数组“整体”赋值的函数:
(1)memset函数:memset函数是给数组“按字节”进行赋值,一般用在char型数组中,如果是int类型的数组,一般赋值为0和-1。使用前需要包含头文件:#include<cstring>例如:“memset(h,0,sizeof(h));”就是将h数组所有元素赋值为0。
(2)fill函数:fill函数是给数组“按元素”进行赋值,可以是整个数组,也可以是部分连续元素,可以赋任何值。使用前需要包含头文件:#include<algorithm>。例如,“fill(a,a+10,5);”就是将a数组的前10个元素赋值为5。
int a[10]={0,1,2,3,4,5,6,7,8,9};
int a[10]={0,1,2,3,4};//部分赋初值,后面的元素自动初始化为0
int a[ ]={1,2,3,4,5};//不定义数组长度,直接根据赋值个数定。
#include<iostream>
#include<cstring>
using namespace std;
int main(){
int a[10],b[10],c[10],d[10],i;
memset(a,0,sizeof(a));//将a数组所有元素金赋值为零
for(i=0;i<9;i++)cout<<a[i]<<" ";
cout<<a[9]<<endl;
memset(b,1,sizeof(b));//将必数组所有元素均赋值为二进制数2^0+2^8+2^16+2^24=16843009
for(i=0;i<9;i++)cout<<b[i]<<" ";
cout<<b[9]<<endl;
memset(c,0,5);//将c数组前五个字节都赋值为零,所以只能确定c[0]==0,其他元素值不确定
for(i=0;i<9;i++;)cout<<c[i]<<" ";
cout<<c[9]<<endl;
fill(d,d+5,8);//将d数组前五个元素都赋值为8,其他元素值不确定
for(i=0;i<9;i++)cout<<d[i]<<" ";
cout<<d[9]<<endl;
return 0;
}
一维数组的插入删除:
插入操作需要注意把数组下标定义得足够大。
例:插队问题(有n个人(每个人有一个唯一的编号,用一到n之间的整数表示)在一个水龙头前排队准备接水,现在第n个人有特殊情况,经过协商,大家允许他插队到第x个位置,输出第n个人插队后的排队情况。)
#include<cstdio>
using namespace std;
int main(){
int n,i,x,q[102];
scanf("%d",&n);
for(i=1;i<=n;i++)scanf("%d",&q[i]);
scanf("%d",&x);
for(i=n;i>=x;i--)q[i+1]=q[i];
q[x]=q[n+1];
for(i=1;i<n;i++)printf("%d",q[i]);
printf("%d\n",q[n]);
return 0;
}
一维数组的查找统计:
因为数组的查找操作,就是在一维数组中查找有没有某个元素,它的值等于指定的值x。常见的查找算法有顺序查找和二分查找。顺序查找就是按照从前往后的顺序,将数组中的元素依次与要查找的数x进行比较。如果数组中的元素是有序的(递增或者递减),也可以采用二分查找。二分查找又称折半查找,其优点是比较次数少,查找速度快。假设数组a[n]是严格递增,每个元素都是int型,现在要查x这个元素,则二分查找的算法框架可以这样写:
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个人排成一排,假设他们的身高均为正整数,请找出其中符合以下条件的人:排在他前面且比他高的人数与排在他后面血比他高的人数相等。)
#include<cstdio>
using namespace std;
int h[1001],n,i,j,ans,t1,t2;
int main(){
scanf("%d",&n);
for(i=1;i<=n;i++)scanf("%d",&h[i]);
for(i=1;i<=n;i++){
t1=t2=0;
for(j=1;j<i;j++)
if(h[j]>h[i])t1++;//排在他前面且比他高的人
for(j=i+1;j<=n;j++)
if(h[j]>h[i])t2++;//排在他后面写比他高的人数
if(t1==t2)ans++;
}
printf("%d\n",ans);
return 0;
}
注:全局统计在定义变量前赋初值,局部统计在统计开始前赋初值。
一维数组的元素排序:
排序就是按照某个关键字的大小,将若干对象从小到大或者从大到小进行重新排列。关键词是对象的某一个属性,它可以是任何基本数据类型,甚至结构体等。排序算法的三种:选择排序,冒泡排序和插入排序。本质上都是通过数组中的元素比较和交换来实现的。
例题:站队(给出n个同学的身高,请根据他们的身高升序排列并输出排序结果。)
选择排序:每一趟从待排序的数据中,通过打擂台比较选出最小元素,放在这些数据的最前面。
#include<iostream>
using namespace std;
int main(){
int n,i,j,k,temp,h[101];
cin>>n;
for(i=1;i<=n;i++)cin>>h[i];
for(i=1;i<=n;i++){
k=i;
for(j=i+1;j<=n;j++)
if(h[j]<h[k])k=j;//在i~n之间的最小元素
temp=h[i];
h[i]=h[k];
h[k]=temp;//将i~n之间的最小元素放到第i个位置
}
for(i=1;i<n;i++)cout<<h[i]<<" ";
cout<<h[n]<<endl;
return 0;
}
冒泡排序:从第一个数开始,依次不断比较相邻的两个元素,如果逆序就交换。
#include<iostream>
using namespace std;
int main(){
int n,i,j,temp,h[101];
cin>>n;
for(i=1;i<=n;i++)cin>>h[i];
for(i=1;j<=n-1;j++)
if(h[j]>h[j+1]){
temp=h[j];
h[j]=h[j+1];
h[j+1]=temp;
}
for(i=1;i<n;i++)cout<<h[i]<<" ";
cout<<h[n]<<endl;
return 0;
}
插入排序:把所有待排序元素分成前后两段,前一段是已经排好序的,后一段是待排序的。每一趟都是把后一段的第一个数插入到前一段的某一个位置,保证前一段仍然是有序的。
#include<iostream>
using namespace std;
int main(){
int n,i,j,k,temp,h[101];
cin>>n;
for(i=1;i<=n;i++)cin>>h[i];
for(i=2;i<=n;i++){
temp=h[i];
k=1;
while(h[k]<=temp&&k<i)k++;
for(j=i-1;j>=k;j--)h[j+1]=h[j];
h[k]=temp;
}
for(i=1;i<n;i++)cout<<h[i]<<" ";
cout<<h[n]<<endl;
return 0;
}
二维数组的定义和操作
二维数组的定义和初始化:类型标识符 数组名[常量表达式1][常量表达式2](常量表达式一的值表示第一维大小,常量表达式二的值表示第二维大小,常量表达式一和常量表达式二的乘积就是二维数组的元素个数。)
初始化:int a[2][3]={{1,2,3}{4,5,6}};//分行初始化
int a[2][3]={1,2,3,4,5,6};//不分行初始化
注意:在定义二维数组时,可以省略第一维的大小,但是第二维的大小不能省略。被省略的第一维大小根据初值的个数由系统来确定。
二维数组的存储及元素引用:二维数组的存储方式是行优先的连续存储。
二维数组的输入与输出:
例:回形方针(输入一个正整数n,输出n*n的回形方针。)
#include<iostream>
using namespace std;
int main(){
cin>>n;
for(i=1;i<=(n+1)/2;i=++)
for(j=1;j<=(n+1)/2;j++){
a[i][j]=min(i,j);
a[i][n=1-j]=a[n+1-i][j]=a[n+1-i][n+1-j];}
for(i=1;i<=n;i++){
for(j=1;j<=n-1;j++){
cout<<a[i][j]<<" ";}
cout<<a[i][n]<<endl;}
return 0;}
字符数组:
如果数据中的每个元素都是一个字符,这样的数组成为字符数组。一维字符数组又成为字符串。
字符串的末尾都会有一个空字符‘、n’。
注意:一个字符数组只存一段文字。
不带下标,读整体字符;带下标,读一个字符。
空格作为间隔符,不作为文字内容。
scanf不可输入带空格文字,gets可输入带空格文字。
给字符数组赋值的方法有很多,例如:用字符常量逐个初始化,用赋值语句逐个元素赋值,用scanf读入整个数组(scanf("%s",letter);),用scanf逐个元素读入,用cin输入整个数组,用cin逐个元素输入,用gets输入整个数组,用getchar逐个读入。
注意:scanf函数读取一个字符串时,是把回车符、空格符、tab符作为字符串的结束符号。
而gets仅以回车符结束输入,gets没有限制读取的字符串长度,如果输入的字符串太长可能会导致堆栈溢出。
一般使用下面这个函数来快速读取一个数字字符串:
int scan(){
int res=0,flag=0;
char ch;
if((ch=getchar())=='-')flag=1;
else if(ch>='0'&&ch<='9')res=ch-'0';
while((ch=getchar())>='0'&&ch<='9')
res=res*10+(ch-'0');
return flag?-res:res;
}
补充:sort函数为升序排列函数,使用时加头文件#include<algorithm>