C++语言篇 第五章 一维数组

一、一维数组的定义

 数组就是一组相同类型的变量,它们往往都是为了表示同一批对象的统一属性,如一个班级所有同学的身高、全球所有国家的人口数等。 数组可以是一维的,也可以是二维或多维的。 

 

数组: 是一组具有相同数据类型 的变量的有序集合。
 
格式 : 类型标识符    数组名  [常量表达式];
 
 
 
数组名:用户定义的标识符,与变量名的定义规定一样。 数组名表示了一个存储区的首地址 (即第一个数组元素的地址)。
 
下标:下标从0开始   例如数组 a[10]的成员有     a[0] a[1] a[3] a[4] a[5] a[6] a[7] a[8] a[9],没有a[10];
 
数组定义时,常量表达式中不能有变量,必须是确定的整数。 常量表达式的值不能是实数。
#include<bits/stdc++.h>
using namespace std;
int main()
{   int a[n];
}

以上是错误的,下标不确定。

 
#include<bits/stdc++.h>
using namespace std;
int main()
{   int n;
    cin>>n;
    int a[n];
}

以上是正确的,下标值确定。

 

二、一维数组的存储结构

一个数组的所有元素都是连续存储的,例如:   int  a[10]; 
     
  数组元 素为:  a[0],a[1],a[2]…..a[9]  ;
 
所占空间为 : 类型长度*元素个数  =  4个字节  *  10  =  40字节;
  • 数组名a所指的地址与a[0]的相同, 即a=a[0]。

 

三、数组元素的引用形式

数组元素的引用:   数组名[下标]       如:    int  a[10];   a[0]=2;
 
说明:
 
(1) 下标可以是整型常量或整型表达式          如:   a[1]  ,  a[2*3]
 
(2)  数组定义为 int   a[5] , 数组长度为5        而下标在0 ---- 4之内, 即a[0] ---- a[4]
 
 如果对以上数组赋值   a[5] = 72 ;  编译时不会指出错误,  系统会将a[4]后下一个存储单元 赋值为72,  但这样可能会破坏数组以外其他变量的值。
 

四、一维数组的初始化

 

1、概念 : 在定义一维数组时对各元素指定初始值称为数组的初始化            如: int   a[5] = { 1 , 3 , 5 , 7 , 9 } ;
 
2、说明:
(1)初值用 {  } 括起来, 数据之间用逗号分开。
(2)对数组的全体元素指定初值,可以不指明数组的长度, 系统会根据{  }内数据的个数确定数组的长度。 
     如 :   int   a [ ] = { 1 , 3 , 5 , 7 , 9 } ;
 
 
3、对数组中部分元素指定初值 ,这时不能省略数组长度 。     如 :    int    a[5] = { 1 , 3 , 5 };
      这种方法仅对数组前三个元素依次进行了赋值。其余为0
4、  使数组中的全部元素初始值都为 0      
      如:    int  a[5] = { 0 , 0 , 0 , 0 , 0 } ;   
               int  a[5] = {  0 } ;
               int  a[5] = {     } ;               
               memset(a,0,sizeof(a));
 
 
5、数组相互间不能够进行赋值操作
       如果声明的是int a[MAXN],b[MAXN],是不能进行b=a的赋值操作  (Pascal语言可以的)
       如果要从数组a复制k个元素到数组b,可以这样做:memcpy(b,a,sizeof(int)*k)。
       如果数组a和b都是浮点型的,复制时要写成memcpy(b,a,sizeof(double)*k)。
       如果需要把数组a全部复制到数组b中,可以写得简单一些:memcpy(b,a,sizeof(a))。
       使用memcpy函数要包含头文件 cstring。
 
6、验证初始  (观察运行结果):
(1)主程序内定义 , 不初始化
#include<iostream>
using namespace std;
int main()
{ int a[6];
  for (int i=0;i<=9;i++)
     cout<<a[i]<<'\t';  
}
(2)主程序外定义,不初始化
#include<iostream>
using namespace std;
int a[6];
int main()
{ for (int i=0;i<=9;i++)
     cout<<a[i]<<'\t';  
}
 (3)主程序内初始化为{0} 
#include<iostream>
using namespace std;
int main()
{int a[6]={0};
 for (int i=0;i<=9;i++)
     cout<<a[i]<<'\t';  
}
(4)主程序内初始化为{  }
 
#include<iostream>
using namespace std;
int main()
{int a[5]={ };
 for (int i=0;i<=9;i++)
     cout<<a[i]<<'\t';  
}
(5)部分赋值的结果
#include<iostream>
using namespace std;
int main()
{int a[5]={1,2,5,3};
 for (int i=0;i<=9;i++)
     cout<<a[i]<<'\t';  
}
#include<bits/stdc++.h>
using namespace std;
int main()
{int a[6]={1,4,257};
 int b[6]={};
 memcpy(b,a,sizeof(a));
 for (int i=0;i<=9;i++)
        cout<<b[i]<<'\t';
}
 

五、一维数组的输入和输出

 

1、数组的输入和输出只能逐个对数组元素进行操作(字符数组例 外)
 
定义:int  a[10], i;
 

 

2、给数组“整体”赋值
 
(1)memset 函数
          memset 函数是给数组“按字节”进行赋值,一般用在 char 型数组中,如果是 int 类型的数组,一般赋值为 0 和 -1。使用前需要包含头文件:#include <cstring>。
(2)fill 函数
          fill 函数是给数组“按元素”进行赋值,可以是整个数组,也可以是部分连续元素,可以赋任何值。使用前需要包含头文件:#include <algorithm>。
 
#include <bits/stdc++.h>
using namespace std;
int main()
{   int a[7],b[7],c[7],d[7],i;
    memset(a,0,sizeof(a));   // 将a数组所有元素均赋值为0
    for(i = 0; i < 7; i++) cout << a[i] <<"  " ;
    cout << a[7] << endl; 
    memset(b,1,sizeof(b));  // 将 b 数组所有元素均赋值为二进制数 2^0+2^8+2^16+2^24=16843009
    for(i = 0; i < 7; i++) cout << b[i] <<"  " ;
    cout << b[7] << endl;
    memset(c,0,5);       //将 c 数组前 5个字节都赋值为 0,所以只能确定 c[0]等于0,其他元素值不确定
    for(i = 0; i < 7; i++) cout << c[i] <<"  " ;
    cout << c[7] << endl;
    fill(d,d+5,8);        //将 d 数组前 5 个元素都赋值为 8,其他元素值不确定
    for(i = 0; i < 7; i++) cout << d[i] <<"  " ;
    cout << d[7] << endl;
    return 0;
}

 

注意 :

      1、  memset(a,1,5) 是给前五个字节,每个字节赋值为1,  不是按每个数赋值, 其它的字节不确定。

      2、  fill(d,d+5,8);        //将 d 数组前 5 个元素都赋值为 8,其他元素值不确定
              fill 函数是给数组“按元素”进行赋值,可以是整个数组,也可以是部分连续元素,可以赋任何值。
 

 

六 、一维数组的插入删除

1、一维数组的插入
插入一个元素,需要先找到插入的位置(假设下标为 x),将这个元素及其之后的所有元素依次往后移一位(注意要从后往前进行操作),再将给定的元素插入(覆盖)到位置 x,如图所示。
 
 
2、一维数组的删除
删除某一个元素,也需要先找到删除的位置(假设下标为 x),将下标为 x+1 及其之后的所有元素依次向前移一位,覆盖原来位置上的元素,如图所示。
  例1、插队问题 
【问题描述】
有 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
 
【问题分析】
        n个人的排队情况可以用数组 q 表示,q[i]表示排在第 i 个位置上的人。定义数组时多定义一个位置,然后重复执行:q[i+1] = q[i],其中,i 从 n ~ x。最后再执行 q[x] = q[n+1],输出 q[1] ~ q[n]。
 
  例2、队伍调整 
【问题描述】
有 n 个人(每个人有一个唯一的编号,用 1~n 之间的整数表示)在一个水龙头前排队准备接水,现在第 x 个人有特殊情况离开了队伍,求第 x 个人离开队伍后的排队情况。
【输入格式】
第一行 1 个正整数 n,表示有 n 个人,2<n≤100。
第二行包含n个正整数,之间用一个空格隔开,表示排在队伍中的第1个到第n个人的编号。
第三行包含 1 个正整数 x,表示第 x 个人离开队伍,1≤x≤n。
【输出格式】
一行包含 n-1 个正整数,之间用一个空格隔开,表示第 x 个人离开队伍后的排队情况。
【输入样例】
7
7 2 3 4 5 6 1
3
【输出样例】
7 2 4 5 6 1
 
#include <bits/stdc++.h>
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 = x; i < n; i++) q[i] = q[i+1];
    n--;
    for(i = 1; i < n; i++) printf( " %d "  ,q[i]);
    printf(" %d\n "  ,q[n]);
    return 0;
}

 

 

 

七、一维数组程序设计举例

1: 输入n个成绩,求平均分

#include<bits/stdc++.h>
using namespace std;
int main( )
{  int s,n,i;
   float aver=0.0;
   cin>>n;
   for( i=0;i<n;i++ )
   {  cin>>s;	
      aver+=s;
   }
   aver/=n;
   cout<<aver;
}
例2:用一维数组求Fibonacci 数列
#include<bits/stdc++.h>
using namespace std;
int main()
{  int i;
   int f[20]={1,1};
   for (i=2;i<20;i++)
      f[i]=f[i-1]+f[i-2];
   for(i=0;i<20;i++)
   {  if(i%5==0)cout<<"\n";
      cout<<f[i]<<"\t";
   }
}

 
 
3: 输入一个数据,在已知数组中查找是否有该数据  (完善程序)
#include <iostream>
using namespace std;
main()
{  int  i , x ;
   int  a[10]={ 5, 8, 0, 1, 9, 2, 6, 3, 7, 4 };
   cin>>x;
   for ( i=0 ; i<10 ; i++)
       if (          ) 
       { cout<<"find!"<<endl;
          break;//退出循环,只能退出一层循环
       }
    if(             ) 
    cout<<"no  find!"<<endl;
}  
 
例4  输入n个数,要求程序按输入时的逆序把这n个数打印出来,已知整数不超过100个。也就是说,按输入相反顺序打印这n个数。
 
【分析】我们可定义一个数组a用以存放输入的n个数, 然后将数组a中的内容逆序输出。
#include<bits/stdc++.h>
using namespace std;
int a[100];
int main()
{  int x,n=0;
   while(scanf("%d",&x)==1) a[n++]=x; //相当{a[n]=x;n++;}
   for (int i=n-1;i>=1;--i)
   printf("%d ",a[i]); //注意%d后面有一个空格,保证行首行尾均无空格
   printf("%d\n",a[0]);
   return 0;
}

【说明】:

  1、语句int a[100]声明了一个包含100个整型变量的数组,它们是:a[0],a[1],a[2],…,a[99]。注意,没有a[100]。
  2、在上述程序中,数组a被声明在main函数的外面。只有放在外面时,数组a才可以开得很大;放在main函数内时,数组稍大就会异常退出。
       
 
例5  将a数组中第一个元素移到数组末尾,其余数据依次往前平移一个位置。
 
  【分析】为完成题目所要求的操作,其算法应该包括以下几个主要步骤:
 ①把第一个元素的值取出放在一个临时单元 temp中;
 ②通过 a[2]→a[1], a[3]→a[2], a[4]→a[3],……, a[n]→a[n-1],实现其余元素前移
    ③将 temp值送入a[n].
#include<bits/stdc++.h>
using namespace std; 
const int n=10;
int a[n],temp; 
int main()
{  cout<<"read "<<n<<" datas"<<endl;
   for (int i=0; i<n; ++i) cin>>a[i];
   temp=a[0];
   for (int i=0; i<n-1; ++i) a[i]=a[i+1];
   a[n-1]=temp;
   cout<<"Result:"<<endl;
   for (int i=0; i<n; ++i) cout<<setw(3)<<a[i];   //setw函数控制输出场宽
   return 0;	 
}

例6、 宾馆里有一百个房间,从1-100编了号。第一个服务员把所有的房间门都打开了,第二个服务员把所有编号是2的倍数的房间“相反处理”,第三个服务员把所有编号是3的倍数的房间作“相反处理”…,以后每个服务员都是如此。当第100个服务员来过后,哪几扇门是打开的。(所谓“相反处理”是:原来开着的门关上,原来关上的门打开。)

【分析】此题较简单,用a[1],a[2],…,a[n]表示编号为1,2,3,…,n的门是否开着。模拟这些操作即可,参考程序如下:
#include<bits/stdc++.h>
using namespace std; 
#define MAXN 100+10
int a[MAXN];
int main()
{  int n,k,first=1;
   memset(a,0,sizeof(a));//memset(a,0,sizeof(a))的作用是把数组a清零
   for(int i=1;i<=100;++i)
     for (int j=1;j<=100;++j)
       if (j%i==0) a[j]=!a[j];
   for (int i=1;i<=100;++i)
     if (a[i])  printf("%d ",i);      
}
#define MAXN 100+10 与const的区别:
1、 const会进行类型检查,更安全。
2、 const在编译时替换,占内存
3、define在预处理时替换,不占内存。
4、define定义的是真实的常量,不会被修改。
 
 
 
例7、 约瑟夫问题:N个人围成一圈,从第一个人开始报数,数到M的人出圈;再由下一个人开始报数,数到M的人出圈;输出依次出圈的人的编号。N,M由键盘输入。  
【分析】
(1)由于对于每个人只有出圈和没有圈两种状态,因此可以用布尔型标志数组存储游戏过程中每个人的状态。不妨用true表示出圈,false 表示没有出圈。
(2)开始的时候,给标志数组赋初值为false,即全部在圈内。
(3)模拟报数游戏的过程,直到所有的人出圈为止。 
 
算法模拟:
    设如果出局为 1 ,没有出局为 0
    设置一个变量,存储移动的位置, i
    设置一个变量,记录经过的没有出局的成员数   s
    设置一个变量,记录出局的人数   k
1 、定入一个足够大的数组;
2 、输入 n 为总人数,输入 m ,报到 m 出圈
3 、循环
      移动位置变量加一,
      如果移动位置变量大于 n( 总人数 ) 则变量变为一。
      如果 成员没有出局 s 加一
      如果    s=5,  s 0   输出这个 i 值,  记录出局人数的变量 K 加一
                          当前 i 变量所指的值置 1 (表示出局  )。
 4 、当 k 值为 n 时,退出。
#include<bits/stdc++.h>
using namespace std; 
int n,m,s,f,t;
bool a[101];                              //根据题意开出数组大小
int main()
{   cin>>n>>m;		                      //共n人,报到m出圈
    cout<<endl;
    for (t=1;t<=n;++t) a[t]=false;        //等同于memset(a,0,sizeof(a)),要调用cstring库
        f=0;  t=0;  s=0;                  //刚开始所有变量默认值也是0,或者用f=t=s=0;
        do
        {	++t;                          //逐个枚举圈中的所有位置
            if (t==n+1) t=1;	          //数组模拟环状,最后一个与第一个相连
            if (a[t]==false) ++s;         //第t个位置上有人则报数
            if (s==m)                     //当前报的数是m
            { s=0;                        //计数器清零
              cout<<t<<" ";               //输出出圈人的编号
              a[t]=true;                  //此处的人已出圈,设置为空
              f++;                        //出圈的人数增加一个
            }
        } while(f!=n);                    //直到所有的人都出圈为止
     return 0;
}

 

八、一维数组的元素排序

排序就是按照某个关键字的大小,将若干对象从小到大或者从大到小进行重新排列。关键字是对象的某一个属性,它可以是任何基本数据类型,甚至结构体等。
排序算法非常多,其中最基本的有选择排序、冒泡排序和插入排序三种。其本质上都是通过数组中的元素比较和交换来实现的,关键是数组下标的分析。
 
  例1、站队 
【问题描述】
给出 n 个同学的身高,请根据他们的身高升序排列并输出排序结果。
【输入格式】
第一行 1 个正整数 n,表示有 n 个同学的身高,2<n100
第二行包含 n 个正整数,之间用一个空格隔开,表示 n 个同学的身高。每个同学的身高都在 150~200 厘米之间。
【输出格式】
一行 n 个正整数,之间用一个空格隔开,表示 n 个同学根据身高升序排列的结果。
【输入样例】
7
180 170 176 160 155 150 160
【输出样例】
150 155 160 160 170 176 180  
 
 【问题分析】
算法1、选择排序
选择排序的基本思想是:每一趟从待排序的数据中,通过打擂比较选出最小元素,放在这些数据的最前面。这样,第一趟把 n 个数中(第 1 个到第 n 个)最小的放在第一个位置,第二趟把剩余的 n-1 个数中(第 2 个到第 n 个)最小的放在第二个位置,第三趟把剩余的 n-2 个数中(第 3 个到第 n 个)最小的放在第三个位,…… n-1 趟把剩下的 2 个数中(第 n-1 个到第 n 个)最小的放在第 n-1 个位置,剩下的最后一个数(第 n 个)一定最大,自然落在了第 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;
}

 

 算法2、冒泡排序

冒泡排序的基本思想是:从第一个数开始,依次不断比较相邻的两个元素,如果逆序就交换。这样,一趟排序结束后,最大的元素就放在了第 n 个位置了。对于样例数据,第一趟冒泡排序的过程如下: 
 
 

用同样的方法,第二趟把剩余的前 n-1 个数中最大的交换到第 n-1 个位置,第三趟把剩余的前 n-2 个数中最大的交换到第 n-2 个位置……经过 n-1 趟,排序结束。

 

//p5-5-1b,冒泡排序
#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; i < n; i++)
         for(j = 1; j <= n-i; 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;
}
对于冒泡排序,我们还可以做些算法优化。如果一趟排序下来,都没有任何逆序数对,即没有发生交换操作,则说明已经排好序了。此时,就可以立刻退出循环。
 
 
//p5-5-1c,优化后的冒泡排序
#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; i < n; i++){
                         bool flag = true;
                        for(j = 1; j <= n-i; j++)
                                     if(h[j] > h[j+1]){
                                           temp = h[j];
                                           h[j] = h[j+1];
                                           h[j+1] = temp;
                                           flag = false;
                                     }
                         if(flag) break;
    }
    for(i = 1; i < n; i++) cout << h[i] << "  ";
    cout << h[n] << endl;
    return 0;
}

  算法3、插入排序
插入排序的基本思想是:把所有待排序元素分成前后两段,前一段是已经排好序的,后一段是待排序的。每一趟都是把后一段的第一个数插入到前一段的某一个位置,保证前一段仍然是有序的。开始时,第 1 个数作为前一段肯定是有序的;第一趟,把第 2 个数插入进去,保证前 2个数有序;第二趟,把第 3 个数插入进去,保证前 3 个数有;…… n-1 趟,把第 n 个数插入进去,保证 n 个数都有序。  
 
 

 

//p5-5-1d,插入排序
#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、学习对象 
【问题描述】
n 个信息学选手站在一排,每个选手的位置依次用 1~n 表示,第 i 个信息学选手的编程能力用一个整数 H i 表示。每个信息学选手都希望找一个编程能力比自己高但又与自己编程能力最接近的选手学习,如果有多个符合条件的选手则选择位置在最前面的选手学习。请编程输出每位选手学习对象的位置,如果没有学习对象,则输出 0
【输入格式】
1 行一个正整数 n1n1000
2~n+1 行共 n 个正整数,依次表示每位选手的编程能力,1H i 1000000
【输出格式】
n 行,每行输出一个整数表示每个选手学习对象的位置。
 
【输入样例】
6
3
2
6
1
1
2
【输出样例】
3
1
0
2
2
1
【问题分析】
i个选手的学习对象就是从前往后查找一个选手j,要求Hi<HjHj要尽可能小(打擂台),如果j可以取多个值,则选取最小的值(保留前面)。
 
 
//p5-6-1
#include<iostream>
using namespace std;
int n,i,j,ans,maxh,h[1001];
int main(){
    cin >> n;
    for(i = 1; i <= n; i++) cin >> h[i];
    for(i = 1; i <= n; i++){
                ans = 0; maxh = 1000001;
                for(j = 1; j <= n; j++)
                          if(h[j] > h[i] && h[j] < maxh){
                                 ans = j; maxh = h[j];
                          }
                 cout << ans << endl;
    }
    return 0;
}

 

2、商品排序
【问题描述】
某商场的仓库中有 n 件商品,每件商品的价格在 0~1000 之间(价格为 0 的商品为赠品)。 现在商场经理要求将这 n 件商品按价格由低到高排序。请编程输 n 件商品排序后的情况。
【输入格式】
第一行一个正整数 n,表示有 n 件商品,1n100000。 接下来的 n 行,每行一个整数,表示第 i 件商品的价格。
【输出格式】
n 行,每行输出一个整数。
【输入样例】
5
1
8
1
2
2
【输出样例】
1
1
2
2
8
 
【问题分析】
本题可以选用学过的任意一种排序算法实现,但是测试程序发现超时,因为本题最多有 100000 件商品,三种排序都需要两层循环嵌套。
其实,分析数据发现一个重要特征:数据虽然很多,但是数据范围比较小。这种情况下,可以使用另外一种排序算法——桶排序。定义一个 int 型数组 num[1001]num[x]记录整数 x 出现的次数,初始化都为 0,每读到一个数 x,就执行 num[x] = num[x]+1。输出时,从 0 ~ 1000 穷举 x,每个输出 num[x]次。
//p5-6-2,桶排序
#include<iostream>
using namespace std;
int n,i,j,number,num[1001];
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;// 输出 num[i] 次 i
    return 0;
}

 

3、素数大酬宾
【问题描述】
某商场的仓库中有 n 种商品,每件商品按 1~n 依次编号。现在商场经理突发奇想,决定将编号为素数(质数)的所有商品拿出来搞优惠酬宾活动。请编程帮助仓库管理员将编号为素数的商品选出来。
【输入格式】
一行一个正整数 n,表示有 n 种商品,2n100000
【输出格式】
一行若干个正整数,表示若干种商品编号且每个编号均为素数,请从小到大输出,每两个数之间有一个空格。
【输入样例】
20
【输出样例】
2 3 5 7 11 13 17 19
 
算法1、穷举法
穷举商品编号 2~n,判断每个编号是否为素数。这种方法效率不高,一旦 n 大,程序就会超时。
//p5-6-3a
#include<iostream>
#include<cmath>
using namespace std;
int main(){
    int n,i,j; bool flag;
    cin >> n;
    cout << 2;
    for(i = 3; i <= n; i++){
             flag = true;
             for(j = 2; j <= sqrt(i); j++)
                      if(i % j == 0){flag = false;break;}
             if(flag) cout <<  “ “ << i;
    }
    cout << endl;
    return 0;
}
算法2、筛选法
筛选法又称为筛法,是由希腊著名数学家埃拉托色尼 Eratosthenes 出的。相比穷举法,筛选法的效率更高。以求 1~20 之内素数为例,具体步骤如下:
1 将所有数(2~n)放入筛子中,把 1 删除;
2 2 在筛中,将 2 的倍数 2420 删除(筛去);
3 3 在筛中,将 3 的倍数 6918 删除(筛去);
4 4 不在筛中,不执行删除(筛去)操作;
            ……
10 10 不在筛中,不执行删除(筛去)操作。
 
 
#include<iostream>
#include<cmath>
using namespace std;
int main(){
    int n,i,j;
    bool p[100001];
    for(i = 0; i <= 100000; i++) p[i] = true;
    p[1] = false;
    cin >> n;
    cout << 2;
    for(i = 2; i <= sqrt(n); i++)
         if(p[i])  for(j = 2; i*j <= n; j++) p[i*j] = false;
    for(i = 3; i <= n; i++)  if(p[i]) cout <<  “ “ << i;
    cout << endl;
    return 0;
}

 

二维数组

 

七、上机练习

 

1、与指定数字相同的数的个数【1.6编程基础之一维数组01】

    输出一个整数序列中与指定数字相同的数的个数。
输入:
    输入包含三行:
    第一行为N,表示整数序列的长度(N <= 100);
    第二行为N个整数,整数之间以一个空格分开;
    第三行包含一个整数,为指定的数字m。
输出:
    输出为N个数中与m相同的数的个数。
样例输入:
    3
    2 3 2
    2
样例输出:
    2
 
 
2、陶陶摘苹果【1.6编程基础之一维数组02】Noip2005普及组第1题
    陶陶家的院子里有一棵苹果树,每到秋天树上就会结出10个苹果。苹果成熟的时候,陶陶就会跑去摘苹果。陶陶有个30厘米高的板凳,当她不能直接用手摘到苹果的时候,就会踩到板凳上再试试。
    现在已知10个苹果到地面的高度,以及陶陶把手伸直的时候能够达到的最大高度,请帮陶陶算一下她能够摘到的苹果的数目。假设她碰到苹果,苹果就会掉下来。
输入:
    包括两行数据。第一行包含10个100到200之间(包括100和200)的整数(以厘米为单位)分别表示10个苹果到地面的高度,两个相邻的整数之间用一个空格隔开。第二行只包括一个100到120之间(包含100和120)的整数(以厘米为单位),表示陶陶把手伸直的时候能够达到的最大高度。
输出:
    包括一行,这一行只包含一个整数,表示陶陶能够摘到的苹果的数目。
样例输入:
    100 200 150 140 129 134 167 198 200 111
    110
样例输出:
    5
 
3.计算书费【1.6编程基础之一维数组03】
    下面是一个图书的单价表:
        计算概论 28.9元/本        数据结构与算法 32.7元/本
        数字逻辑 45.6元/本        C++程序设计教程 78元/本
        人工智能 35 元/本          计算机体系结构 86.2元/本
        编译原理 27.8元/本        操作系统 43元/本
        计算机网络 56元/本        JAVA程序设计 65元/本
    给定每种图书购买的数量,编程计算应付的总费用。
输入:
    输入一行,包含10个整数(大于等于0,小于等于100),分别表示购买的《计算概论》、《数据结构与算法》、《数字逻辑》、《C++程序设计教程》、《人工智能》、《计算机体系结构》、《编译原理》、《操作系统》、《计算机网络》、《JAVA程序设计》的数量(以本为单位)。每两个整数用一个空格分开。
输出:
    输出一行,包含一个浮点数f,表示应付的总费用。精确到小数点后一位。
样例输入:
    1 5 8 10 5 1 1 2 3 4
样例输出:
    2140.2
 
4、数组逆序重【1.6编程基础之一维数组04】
 
    将一个数组中的值按逆序重新存放。例如,原来的顺序为8,6,5,4,1。要求改为1,4,5,6,8。
 
输入:
    输入为两行:第一行数组中元素的个数n(1<n<100),第二行是n个整数,每两个整数之间用空格分隔。
输出:
    输出为一行:输出逆序后数组的整数,每两个整数之间用空格分隔。
样例输入:
    5
    8 6 5 4 1
样例输出:
    1 4 5 6 8
 
 
 
5、年龄与疾病【1.6编程基础之一维数组05】
 
    某医院想统计一下某项疾病的获得与否与年龄是否有关,需要对以前的诊断记录进行整理,按照0-18、19-35、36-60、61以上(含61)四个年龄段统计的患病人数占总患病人数的比例。
 
输入:
    共2行,第一行为过往病人的数目n(0<n<=100),第二行为每个病人患病时的年龄。
输出:
    按照0-18、19-35、36-60、61以上(含61)四个年龄段输出该段患病人数占总患病人数的比例,以百分比的形式输出,精确到小数点后两位。每个年龄段占一行,共四行。
样例输入:
    10
    1 11 21 31 41 51 61 71 81 91
样例输出:
    20.00%
    20.00%
    20.00%
    40.00%
 
6、校门外的树【1.6编程基础之一维数组06】Noip2005普及组第2题
    某校大门外长度为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
 
 
7、向量点积计算【1.6编程基础之一维数组07】
 
    在线性代数、计算几何中,向量点积是一种十分重要的运算。给定两个n维向量a=(a1,a2,...,an)和b=(b1,b2,...,bn),求点积a·b=a1b1+a2b2+...+anbn。
 
输入:
    第一行是一个整数n(1<=n<=1000)。
    第二行包含n个整数a1,a2,...,an。
    第三行包含n个整数b1,b2,...,bn。
    相邻整数之间用单个空格隔开。每个整数的绝对值都不超过1000。
输出:
    一个整数,即两个向量的点积结果。
样例输入:
    3
    1 4 6
    2 1 5
样例输出:
    36
 
8、开关灯【1.5编程基础之循环控制28】
 
   假设有N盏灯(N为不大于5000的正整数),从1到N按顺序依次编号,初始时全部处于开启状态;有M个人(M为不大于N的正整数)也从1到M依次编号。
    第一个人(1号)将灯全部关闭,第二个人(2号)将编号为2的倍数的灯打开,第三个人(3号)将编号为3的倍数的灯做相反处理(即将打开的灯关闭,将关闭的灯打开)。依照编号递增顺序,以后的人都和3号一样,将凡是自己编号倍数的灯做相反处理。
    请问:当第M个人操作之后,哪几盏灯是关闭的,按从小到大输出其编号,其间用逗号间隔。
 
输入:
    输入正整数N和M,以单个空格隔开。
输出:
    顺次输出关闭的灯的编号,其间用逗号间隔。
样例输入:
    10 10
样例输出:
    1,4,9
 
9、查找特定的值【1.9编程基础之顺序查找01】
 
    在一个序列(下标从1开始)中查找一个给定的值,输出第一次出现的位置。
 
输入:
    第一行包含一个正整数n,表示序列中元素个数。1 <=n<= 10000。
    第二行包含n个整数,依次给出序列的每个元素,相邻两个整数之间用单个空格隔开。元素的绝对值不超过10000。
    第三行包含一个整数x,为需要查找的特定值。x的绝对值不超过10000。
 
输出:
    若序列中存在x,输出x第一次出现的下标;否则输出-1。
 
样例输入:
    5
    2 3 6 7 3
    3
样例输出:
    2
 
10、不高兴的津津【1.9编程基础之顺序查找03】Noip2004普及组第1题
    津津上初中了。妈妈认为津津应该更加用功学习,所以津津除了上学之外,还要参加妈妈为她报名的各科复习班。另外每周妈妈还会送她去学习朗诵、舞蹈和钢琴。但是津津如果一天上课超过八个小时就会不高兴,而且上得越久就会越不高兴。假设津津不会因为其它事不高兴,并且她的不高兴不会持续到第二天。请你帮忙检查一下津津下周的日程安排,看看下周她会不会不高兴;如果会的话,哪天最不高兴。
输入:
    包括七行数据,分别表示周一到周日的日程安排。每行包括两个小于10的非负整数,用空格隔开,分别表示津津在学校上课的时间和妈妈安排她上课的时间。
输出:
包括一行,这一行只包含一个数字。如果不会不高兴则输出0,如果会则输出最不高兴的是周几(用1, 2, 3, 4, 5, 6, 7分别表示周一,周二,周三,周四,周五,周六,周日)。如果有两天或两天以上不高兴的程度相当,则输出时间最靠前的一天。
样例输入:                                 
    5 3                                          
    6 2
    7 2
    5 3
    5 4
    0 4
    0 6
   样例输出:
   3
11、最大值和最小值的差【1.9编程基础之顺序查找05】
 
    输出一个整数序列中最大的数和最小的数的差。
 
输入:
    第一行为M,表示整数个数,整数个数不会大于10000;
    第二行为M个整数,以空格隔开,每个整数的绝对值不会大于10000。
 
输出:
    输出M个数中最大值和最小值的差。
 
样例输入:
    5
    2 5 7 4 2
 
样例输出:
    5

 

12、不与最大数相同的数字之和【1.9编程基础之顺序查找07】
 
    输出一个整数数列中不与最大数相同的数字之和。
 
输入:
    输入分为两行:
    第一行为N(N为接下来数的个数,N <= 100);
    第二行N个整数,数与数之间以一个空格分开,每个整数的范围是-1000,000到1000,000。
 
输出:
    输出为N个数中除去最大数其余数字之和。
 
样例输入:
   3
   1 2 3
 
样例输出:
 
    3
 

13、白细胞计数【1.9编程基础之顺序查找08】

    医院采样了某临床病例治疗期间的白细胞数量样本n份,用于分析某种新抗生素对该病例的治疗效果。为了降低分析误差,要先从这n份样本中去除一个数值最大的样本和一个数值最小的样本,然后将剩余n-2个有效样本的平均值作为分析指标。同时,为了观察该抗生素的疗效是否稳定,还要给出该平均值的误差,即所有有效样本(即不包括已扣除的两个样本)与该平均值之差的绝对值的最大值。
    现在请你编写程序,根据提供的n个样本值,计算出该病例的平均白细胞数量和对应的误差。
输入:
    输入的第一行是一个正整数n(2 <n<= 300),表明共有n个样本。
    以下共有n行,每行为一个浮点数,为对应的白细胞数量,其单位为10^9/L。数与数之间以一个空格分开。
输出:
    输出为两个浮点数,中间以一个空格分开。分别为平均白细胞数量和对应的误差,单位也是10^9/L。计算结果需保留到小数点后2位。
样例输入:                                       
    5                                               
    12.0
    13.0
    11.0
    9.0
    10.0
样例输出:
   11.00 1.00
 
 
14、直方图【1.9编程基础之顺序查找09】
 
    给定一个非负整数数组,统计里面每一个数的出现次数。我们只统计到数组里最大的数。
    假设 Fmax(Fmax<10000)是数组里最大的数,那么我们只统计{0,1,2.....Fmax}里每个数出现的次数。
 
输入:
    第一行n是数组的大小。1 <= n <= 10000。
    紧接着一行是数组的n个元素。
输出:
    按顺序输出每个数的出现次数,一行一个数。如果没有出现过,则输出0。
    对于例子中的数组,最大的数是3,因此我们只统计{0,1,2,3}的出现频数。
 
样例输入:
    5
    1 1 2 3 1
样例输出:
    0
    3
    1
    1    
 
15、最长平台【1.9编程基础之顺序查找12】
 
    已知一个已经从小到大排序的数组,这个数组的一个平台(Plateau)就是连续的一串值相同的元素,并且这一串元素不能再延伸。例如,在 1,2,2,3,3,3,4,5,5,6中1,2-2,3-3-3,4,5-5,6都是平台。试编写一个程序,接收一个数组,把这个数组最长的平台找出 来。在上面的例子中3-3-3就是最长的平台。
 
输入:
    第一行有一个整数n,为数组元素的个数。第二行有n个整数,整数之间以一个空格分开。
 
输出:
    输出最长平台的长度。
样例输入:
    10
    1 2 2 3 3 3 4 5 5 6
 
样例输出:
 
    3   
 
16、整数去重【1.9编程基础之顺序查找13】
 
    给定含有n个整数的序列,要求对这个序列进行去重操作。所谓去重,是指对这个序列中每个重复出现的数,只保留该数第一次出现的位置,删除其余位置。
 
输入:
    输入包含两行:
    第一行包含一个正整数n(1 <= n <= 20000),表示第二行序列中数字的个数;
    第二行包含n个整数,整数之间以一个空格分开。每个整数大于等于10、小于等于100。
输出:
    输出只有一行,按照输入的顺序输出其中不重复的数字,整数之间用一个空格分开。
 
样例输入:
    5
    10 12 93 12 75
样例输出:
 
    10 12 93 75
 
17、铺地毯【1.9编程基础之顺序查找14】Noip2011提高组第1题
 
    为了准备一个独特的颁奖典礼,组织者在会场的一片矩形区域(可看做是平面直角坐标系的第一象限)铺上一些矩形地毯。一共有n张地毯,编号从1到n。现在将这些地毯按照编号从小到大的顺序平行于坐标轴先后铺设,后铺的地毯覆盖在前面已经铺好的地毯之上。地毯铺设完成后,组织者想知道覆盖地面某个点的最上面的那张地毯的编号。注意:在矩形地毯边界和四个顶点上的点也算被地毯覆盖。
 
    输入输出样例1说明:如下图,1号地毯用实线表示,2号地毯用虚线表示,3号用双实线表示,覆盖点(2,2)的最上面一张地毯是3号地毯。
 
    输入输出样例2说明:如下图,1号地毯用实线表示,2号地毯用虚线表示,3号用双实线表示,覆盖点(4,5)的最上面一张地毯是3号地毯。
 
 
输入:
    第一行,一个整数n,表示总共有n张地毯。
    接下来的n行中,第i+1行表示编号i的地毯的信息,包含四个正整数a,b,g,k,每两个整数之间用一个空格隔开,分别表示铺设地毯的左下角的坐标(a,b)以及地毯在x轴和y轴方向的长度。
    第n+2行包含两个正整数x和y,表示所求的地面的点的坐标(x,y)。
输出:
    输出共1行,一个整数,表示所求的地毯的编号;若此处没有被地毯覆盖则输出-1。
样例输入:                                                 样例输出:
样例 #1:                                                 样例 #1:
3                                                                 3
1 0 2 3
0 2 3 3
2 1 3 3
2 2
样例 #2:                                                样例 #2:
3                                                               -1
1 0 2 3
0 2 3 3
2 1 3 3
4 5
 
  • 12
    点赞
  • 63
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值