C/C++ 第五讲 一维数组
5.1 数组的定义
问题:给定N个学生成绩,求高于平均分者
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| int k=0; float ave,sum=0,s1,s2,s3,s4,s5; cin>>s1>>s2>>s3>>s4>>s5; sum=s1+s2+s3+s4+s5; ave=sum/N; if(s1>ave) k++ .....
int k=0; float s[N], ave, sum=0; for (i=0;i<N;i++) { sum+=s[i]; } ave=sum/N; for(i=0;i<N;i++) if(s[i]>ave) k++;
|
数组的概念、特点
- 是同类型同性质的一组元素顺序存放构成的数据集合;
- 所有数据共用同一名字,通过下标区分;
- 循环控制下标来批量处理数据。
数组的定义
- 数组名代表数组在内存中的首地址,由系统自动分配;
- 整型常量表达式代表数组长度,此处不可用变量说明长度;
- 下标范围0~长度-1
1 2 3 4 5 6 7 8 9 10 11
| #define N 5 float s[N];
const int n=5; float s[n];
int n=5, s[n]; double d[]; float b[3.4]
|
数组的存储
元素的访问
数组名[下标]
- 数组元素相当于同类型的普通变量,可参与该类型变量允许的一切操作
- 对于数值型数组,只能操作数组元素,不能操作数组名
5.2 一维数组的初始化
问题:将十进制整数n转换成r(2~16)进制
例:
转换方法:
- n%r得到最低位存放进a[0];
- n=n/r,再进行n%r,得到倒数第二位a[1];
- 以此类推,直到n=0.
输出方法:
- 从数组最末元素向前输出。
- 制作对照表,将10-15转换为A~F。16进制所需数字的字母放在长度16的字符数组中
数组初始化
- 定义的同时允许对数组的部分或全部元素赋初值;
- 初值应被组织在
{}
内
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| int a[5]={0,2,4,6,8}
int a[]={0,2,4,6,8}
a[0]=0; a[1]=2; a[2]=4; a[3]=6; a[4]=8;
int a[10]={1,3,5,7,9}
int a[10]; a={1,3,5,7,9} int a[10]; a[10]={...} int c[3]={1,2,3,4}
|
数制转换:(10进制–>r进制)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| #include "iostream" using namespace std; int main() { int i=0,r,n,a[10]; char b[16]={'0','1','2',...,'A','B','C','D','E','F'} cin>>n>>r; do { a[i]=n%r; n=n/r; i++; }while(n!=0); for(--i;i>=0;--i) { n=a[i]; cout<<b[n]; } system("pause"); return 0; }
|
5.3 常用算法-选择法排序
例:N个成绩从大到小排序
选择法排序:
- N个数中选出MAX与第一个数交换位置;
- N-1数中选出MAX与第二个数交换位置;
- 以此类推,重复N-1遍。
- rand()函数
- 随机数范围:0~32767
- 原型在头文件stdlib.h
- 范围随机数:
rand()%(a+1)+b
(b~b+a)
- 求最高分
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| #define N 10 #include "iostream" using namespace std; int main() { int a[N],i ,max; for (i=0;i<N;i++) { a[i]=rand()%101; cout<<a[i]<<' '; } max=a[0]; for(i=1;i<N;i++) if (a[i]>max) max=a[i]; cout<<"max="<<max<<endl; system("pause"); return 0; }
|
- 求最高分位置
1 2 3 4
| imax=0; for(j=1;j<N;j++) if (a[j]>a[imax]) imax=j;
|
- 最高分放在首位
1 2 3
| int t=a[0]; a[0]=a[imax]; a[imax]=t;
|
- 次高分,次次高分……循环。(N-1遍)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| imax=1; for(j=2;j<N;j++) if (a[j]>a[imax]) imax=j; int t=a[1]; a[1]=a[imax]; a[imax]=t;
for(i=0;i<N-1;i++) { imax=i; for(j=i+1;j<N;j++) if (a[j]>a[imax]) imax=j; if (i!=imax) { int t=a[i]; a[i]=a[imax]; a[imax]=t; } }
|
5.4 冒泡法排序
例:对含N个元素的数组用冒泡法由小到大排序。
思想:
- 自a[0]始,两两相邻元素进行N-1次比较,若前>后则交换这对元素。一次遍历后最大的元素存在a[N-1]中;
1 2 3 4 5 6 7
| for(i=0;i<N-1;i++) if (a[i]>a[i+1]) { t=a[i]; a[i+1]=a[i]; a[i]=t; }
|
- 对a[0]~a[N-2]的N-1个数进行此操作,次大数存入a[N-2];
1 2 3 4 5 6 7 8
| for (j=0;j<N;j++) for(i=0;i<N-1-j;i++) if (a[i]>a[i+1]) { t=a[i]; a[i+1]=a[i]; a[i]=t; }
|
- 以此类推N-1次。
完整程序:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| #define N 10 #include "iostream" using namespace std; int main() { int a[N],i ,j,t; for (i=0,i<N;i++) { a[i]=rand()%101; cout<<a[i]<<' '; } for (i=0;i<N-1;i++) for(j=0;j<N-1-i;j++) if (a[j]>a[j+1]) { t=a[j]; a[j]=a[j+1]; a[j+1]=t; } cout<<"\n after sort: \n"; for(i=0;i<N;i++) cout<<a[i]<<' '; system("pause"); return 0; }
|
5.5 常用算法-插入与删除
插入
例:在递增数组a内插入数x,使插入后数组仍保持有序。
- 查找x应插入的位置k;
- 下标k的元素到最后的元素依次后移;
- x插入位置k。
1 2
| for(i=n-1;i>=k;i--) a[i+1]=[i];
|
完整程序:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| #define N 10 #include "iostream" using namespace std; int main() { int a[N],i,k,x,n; cout<<"递增输入数组中现有元素个数:"; cin>>n; for(i=0;i<n;i++) cin>>a[i]; cout<<"输入待插入数据:"; cin>>x; for(i=0;i<n;i++) if (x<a[i]) break; k=i; for(i=n-1;i>=k;i--) a[i+1]=[i]; a[k]=x; for(i=0;i<n+1;i++) cout<<a[i]<<' '; system("pause"); return 0; }
|
删除
例:查找数据x是否是数组a中元素,若是,删除第一次出现的该元素;否则提示“没找到”。
思想:
- 查找待删除元素的位置k;
- 若找到,下标k+1的元素到最后的元素依次后移;
- x插入位置k。
1 2
| for(i=k;i<n-1;i++) a[i]=a[i+1]
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| for(i=0;i<n;i++) if(x==a[i]) break; k=i; if(i==n) cout<<"未找到\n"; else { for(i=k;i<n-1;i++) a[i]=a[i+1]; for(i=0;i<n-1;i++) cout<<a[i]<<' '; }
|
5.6 常用算法-二分法查找
数据量大,顺序查找效率低
例:在长度为N按递增顺序排列的数组a中用二分法查找数key,找到、输出其位置;否则输出“没找到”。
思想:
low和high是查找区间的起终点下标,则初始状态:low=0, high=N-1;
求待查区间中间元素的下标mid=(low+high)/2,然后比较a[mid]和x决定后续查找范围;
当x==a[mid],查找完毕
当x>a[mid],修改low=mid+1
当x<a[mid],修改high=mid-1
重复2、3;若low>high则null
注:
- 二分法只适用于有序数组;
- 终止循环查找的两种情况:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| low=0; high=N-1; while(low<=high) { mid=(low+high)/2 if (x==a[mid]) break; else if(x>a[mid]) low=mid+1; else high=mid-1; } if(low>high) cout<<"没找到"<<endl; else cout<<mid<<endl;
|
例题
- N个学生,围成一圈,1-5报数,报到5的同学出圈。问最后剩下的一名同学起初序号为几?
a[i][j]
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| int a[N],k=0,i; int s=0; for(i=0;i<N;i++) a[i]=1; while(k!=N-1) { for(i=0;i<N;i++) { s=s+a[i]; if(s==5) { s=0; k++; a[i]=0; } } } cout<<i<<endl;
|