数组

本文详细介绍了C++中一维数组的定义、元素引用、存储结构、输入输出、插入删除、查找操作以及排序算法。讲解了一维数组在内存中的连续存储特性,以及如何通过循环和下标进行元素操作。此外,还提到了常用的数组初始化、赋值方法,如memset和fill函数,并给出了一维数组在插入、删除和查找操作的具体步骤。最后,文章讨论了一维数组在实际问题中的应用,如插队问题和查找满足特定条件的人数问题,并给出了相关代码实现。

              数组

  • 一维数组的定义

1.定义一维数组的格式如下:

类型标识符  数组[名常量表达式];

   其中,类型标识符可以是任何基本数据类型,也可以是结构体等构造类型,相同类型的数组可以一起定义。数组名必须是合法的标识符。常量表达式的值即为数组元素的个数。

2.一维数组的元素引用

数组定义好后,就可以“引用”数组中的任意一个元素。引用格式为“数组名[下标]。其中,下标只能为整型常量或整型表达式,值必须在数组定义的下标范围内。

不能一次引用整个数组,只能逐个引用数组的单个元素。

3.一维数组的存储结构

数组在计算机内存单元中是连续存储的。程序一旦执行到数组的定义语句,就会开辟出若干字节的内存单元。

整个数组所占的内存大小等于数组元素类型的大小乘以数组元素的个数。C++还提供了一个sizeof函数,可以直接求出一个数组所占的内存空间。根据数组在内存单元中的首地址和数组类型,可以计算出该数组中任意第i个元素的起始地址。

  • 一维数组的输入与输出

1.一维数组的输入、输出等搡作,都是采用循环语句结合下标变化逐个元素进行。

批量数据一次性输入到一维数组中的一般两种方法:

(1)键盘读入

例如:   int h[100];

        for(i=0;i<100;i++)cin>>h[i];

(2)直接赋值

例如:     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;

2.C++里还提供了两个函数给数组“整体”赋值。

(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。

另外,C++还支持在定义数组的同时,给所有或者部分元素赋值。例如:

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};//不定义数组长度,直接根据赋值个数定

  • 一维数组的插入删除

在实际应用中,经常需要在数组中插入一个元素,或者删除数组中的某一个元素,称为数组的“插入”操作或者“删除”操作。①.插入一个元素,需要先找到插入的位置(假设下标为x),将这个元素及其之后的所有元素依次往后移一位(注意要从后往前进行操作),再将给定的元素插入(覆盖)到位置x。②.删除某一个元素,也需要先找到删除的位置(假设下标为x),将下标为x+1及其之后的所有元素依次向前移一位,覆盖原来位置上的元素。

插入或者删除一个区间(连续若干个数),只要重复以上单个元素的操作即可。另外,插入操作需要注意把数组下标定义的足够大。

插队问题:

有n个人(每个人有一个唯一的编号,用1~n之间的整数表示)在一个水龙头前排队准备接水,现在第n个人有特殊情况,经过协商,大家允许他插队到第x个位置。输出第n个人插队后的排队情况。P143

 #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);

    q[x]=q[n+1];

    for(i=1;i<n;i++) printf("%d",q[i]);

    printf("%d\n",q[n]);

    return 0;

}

  • 一维数组的查找操作

一维数组的查找操作,就是在一维数组中查找有没有某个元素,它的值等于指定的值x。查找操作的结果可能是一个没找到、找到一个或者找到很多个。

常见的查找算法有“顺序”查找和“二分”查找。

①顺序查找就是按照从前往后的顺序,将数组中的元素依次与要查找的数x进行比较。如果数组中的元素是有序的(递增或者递减),也可以采用二分查找。

②二分查找又称“折半”查找,其优点是比较次数少查找速度快。

比身高:

【问题描述】

有N个人排成一排,假设他们的身高均为正整数,请找出其中符合以下条件的人:排在他前面且比他高的人数与排在他后面且比他高的人数相等。

【输入格式】

第一行为一个正整数N,1<N<1000,表示有多少个人。

下面N行,每行一个正整数,表示从前往后每个人的身高,假设每个人的身高≤10000。

【输出格式】

     一行一个整数,表示满足这个条件的人数。

 #include <cstdio>

 using namespace std ; 

 int h[1001],n,i,,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;

}

  • 一维数组的元素排序

   “排序”就是按照某个关键字的大小,将若干对象从小到大或者从大到小进行重新排列。关键字是对象的某一个属性,它可以是任何基本数据类型,甚至结构体等。最基本的三个排序算法:选择排序、冒泡排序和插入排序。

   1.选择排序(站队)

  选择排序的基本思想是:每一趟从待排序的数据中,通过“打擂台”比较选出最小元素,放在这些数据的最前面。

   2.冒泡排序

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

   对于冒泡排序,还可以做些算法“优化”。如果一趟排序下来,都没有任何“逆序”数对,即没有发生“交换”操作,则说明已经排好序了。此时,就可以立刻退出循环。

   3.插入程序

   插入排序的基本思想是:把所有待排序元素分成前后两段,前一段是已经排好序的,后一段是待排序的。每一趟都是把后一段的第一个数“插入”到前一段的某一个位置,保证前一段仍然是有序的。

  • 一维数组的应用

桶排序:分析数据发现一个重要特征:数据虽然很多,但是数据范围比较小。这种情况下,可以使用桶排序算法。定义一个int型数组num[1001],num[x]记录整数x出现的次数,初始化都为0,每读到一个数x,就执行num[x]=num[x]+1输出时,从0~1000穷举x,每个x输出num[x]次。

  • 二维数组的定义与操作

⒈由前面介绍可知,一维数组的元素可以是任何基本数据类型,也可以是结构体。那么,如果一维数组的每一个元素又是一个一维数组,则称这种数组为“二维数组”。

2.定义二维数组的一般格式为:

  类型标识符  数组名[常量表达式1][常量表达式2];

常量表达式1的值表示第一维大小,常量表达式2的值表示第二维大小,常量表达式1和常量表达式2的乘积就是二维数组的元素个数。

3.初始化

  在二维数组定义的同时,可以进行初始化赋值。例如:

  int a[2][3]={{1,2,3},{4,5,6}};//分行初始化

  int a[2][3]={1,2,3,4,5,6};/不分行初始化

  a[2][3]表示2行3列的数组

  可以给数组的部分元素初始化,如:int a[2][3]={{1,2},{4}}

  在定义二维数组时,可以省略第一维的大小,但第二维的大小不能省略,被省略的第一维大小根据初值的个数由系统来确定。

4.二维数组的存储及元素引用

    因为二维数组本质上是一维数组的每一个元素又是一个一维数组,而计算机内部存储一维数组采用的是连续存储单元。所以,二维数组的存储方式是“行优先”的连续存储,先逐个存储第0行上的所有元素,再逐个存储第1行上的所有元素,依此类推。

引用二维数组的某一个元素,格式为:

 数组名[下标1]下标2]

5.二维数组的输入输出

二维数组的输入、输出操作也是针对每一个元素进行,结合两个维度的下标变化,用循环嵌套实现。

二维数组应用举例P170

  • 数字方阵

数字方阵就是一个行列数相等的二维数组,其中的每个元素都是数字。解决数字方阵问题一般有两种方法:解析法和模拟法。①解析法就是找出每一个方阵元素f[i][j]与i、j和数组规模n的通项公式,然后直接用两重循环给数组元素赋值,相对比较容易,一般用在初始化等场合。②模拟法就是把数字方阵看成一个动态的填数过程,把n²个数依次填入数组中,每填好一个数,就定位好下一个数的位置i和j。

螺旋方阵,蛇形方阵,拐角方阵

  • 字符数组

如果数组中的每个元素都是一个字符,这样的数组称为“字符数组”。有时,把一维字符数组又称为“字符串”。定义字符数组的方法与定义其他类型数组的方法类似。

需要注意的是,用sca入字符串时,会在字符串末尾自动添加一个空字符'/0'。而使用getchar等方法读入字符串时,则要在字符串后手工加'/0'。

有关字符数组的输入方式总结如下:gets函数用来输入一行字符串,仅以回车符结束输入,gets没有限制读取的字符串长度,如果输入的字符串太长可能会导致堆溢出;scanf函数用来读取一个字符串时,字符串中不能出现空格,因为scanf是以空格符、回车符、Tab符结束一次输入,但需要输入输出大量数据的时候,尽量不要使用scanf(包括printf),因为效率很低,容易超时;而getchar(包putchar)是非常高效的,所以实际使用时,能用scanf、getchar就别用gets。

 

  • 学习收获

本章学习了数组,一维数组和二维数组的定义与基本应用,通过做题来巩固所学的知识,在运用数组解决问题时,要注意数组的使用方式,减少因程序编写不当导致程序超时运行。同时也学会了数组与循环等语句的共同应用,便于自己用更简单的方法去解决难难的问题。

  • 感想

这是继循环结构后同样让人烦恼的应用,在做题的时候,总感觉不会用,知道用数组进行编写,但是总是常常感觉不对,用的不对,在做这一章题的时候,明显感觉循环结构的运用更熟悉了些,但在数组题还是很吃力,感觉头都快秃了,总是感觉自己写的程序没写错,也可以运行出题目中例子,但是提交不上。总的来说,还是需要我多看看书,理解理解题,在看看,熟悉一下数组。

 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值