主页
Featured image of post 程序设计——数组……

程序设计——数组……

程序设计课程中有关数组的知识点和例题讲解……

文章字数:4020
预计阅读时长: 分钟

一、什么是数组

1、与数学的联系——数列

关于数组,你可以就把他当作数学上的“数列”,用来存一系列的数。

数学上的一个数列\(a_i\)

\(i=1\)时,代表的是这个数列的第一个数\(a_1\),当\(i=3\)时,代表的是这个数列的第三个数\(a_3\)……
同时,这个数列可以叫数列\(a_i\),也可以叫\(b_i、{nico}_i\)……
可以用\(i\)来表示第几项(\(a_i\)),也可以用\(j\)来表示第几项(\(a_j\))……

2、与数学的不同

  1. 数学上的数列是从第一项开始的,也就是\(a_1\)代表的就是\(a\)这个数列的第一项。
    然而编程里的数组,却是从第零项开始的,也就是a[1]代表的是a这个数组里第二项,a[0]才是第一项
  2. 数学上的数列,我们不需要提前告诉这个数列中会有多少项。
    然而编程里的数组,我们需要提前告诉他这个数组里会有多少项,也就是int a[100]100的意思,代表可能会存100项。

3、编程中的数组

那么类比到我们编程里:

  • 这个\(a_i\)\(a\),就是程序里的这个数组的名字,专业名称叫“变量名”。
  • 这个\(a_i\)\(i\),就是程序里的这个数组的第几项,专业名称叫“下标”。

比如arr[5]代表的就是arr这个数组里的第6项

二、数组的声明

申明部分,也就是定义。如:

int arr[100];

int——代表的是这个数组的类型:即这个数组存的是一系列int类型的数。
arr——代表的是这个数组的变量名,之后用这个数组就是arr[2]arr[i]之类的形式。
[100]——代表的是这个数组的大小,也就是可能会存多少项。

对于数组大小的声明,必须为常量或者常量表达式

正确的例子:

int a[10];	//字面常量(常数)
int b[5 * 5];	//字面常量的表达式

const int len = 10;
int c[len];	//符号常量
int d[len * 2];	//符号常量的表达式

错误的例子:

int len = 10;
int a[len];	//len为变量,错误
int a[len + 5];	//len+5为变量相关的表达式,错误

三、数组的运用

1、对一个数组某个具体元素的运用

  1. 最简单的运用,我们直接把一个常数100存到arr数组里的第三项里:

    a[2] = 100;
    
  2. 要把一个变量val存到arr数组里的第一项里:

    a[0] = val;
    
  3. 要输出数组arr中的第二项

    cout << a[1];
    

2、对一个数组多个元素的运用

很多时候我们不止运用其中的某一个具体的数。
比如我们要向这个数组读入10个数,然后输出这10个数,这就涉及了多个元素的操作。

我们再类比数列,假如我们要对数列\(a_i\)的第一项到第十项求和:
用的是不是\(\sum_{i=1}^{10}a_i\)这个公式,
用个\(i\)来代表第几项,然后\(i=1\sim10\),把\(a_i\)累加起来。

类比到编程,同样用个i来代表第几项,然后i=0~9,把arr[i]累加起来存到sum里。

仍要注意到第一项是从0开始,所以是0~9!

  1. 对数组前十项求和
for (i=0; i<=9; i++)
	sum = sum + arr[i];

其中这里的涉及到从头到尾加起来的操作,
我们把对一个数组从头到尾进行某些操作叫做“遍历”。
以后会提到的概念注意一下。

那么类推一下,要向数组里读入\(10\)个数

  1. 读入十个数到数组前十项
for (i=0; i<=9; i++)
	cin >> arr[i];

然后再输出

  1. 输出数组中前十项
for (i=0; i<=9; i++)
	cout << arr[i] << " ";

总代码:

	int i, arr[100], sum = 0;
	cout << "请输入十个数:";
	for (i = 0; i <= 9; i++)
		cin >> arr[i];

	for (i = 0; i <= 9; i++)
		sum = sum + arr[i];

	cout << "你刚才输入的十个数为:" << endl;
	for (i = 0; i <= 9; i++)
		cout << "arr[" << i << "] = " << arr[i] << endl;

	cout << "总和为:" << sum;

效果为:

上述代码效果
上述代码效果


如果为先输入一个数n,然后读入n个数,只需要改下循环条件即可。

  1. 读入n个数到数组
int n;
cin >> n;
for (i = 0; i <= n-1; i++)	//注意读n个数是(i=0;i<=n-1),就像之前读10个数是(i=0;i<=9)
//也可以写成 for (int i = 0; i < n; i++),不过最好选择一种格式以后就这样写,不然可能会晕
	cin >> arr[i];

其余输出什么的同理。

3、对多个数组的运用

很多时候我们可能要从a数组拿出一些数放到b数组里,这个时候下标可能就会很疑惑。

比如我们可能会把arr数组里十个数放到b数组对应位置里。
这个时候数学表示就是\(b_i=arr_i(i=1\sim10)\)

  1. arr数组十个数放到b数组里
for (i=0; i<=9; i++)
	b[i] = arr[i];

但不一定每次都是刚好把arr的第i项放到b的第i项,也可能是比如:
arr的第五项开始,取5项(即a[4] ~ a[8],放到b的第十项后面(即(b[9] ~ b[13])。
要记住数组的下标不只是用i来表示,也可以用其他变量来表示。

因此我们可以定义两个变量jk,来分别表示两个数组arrb的下标。

刚开始令j = 4k = 9
开始取第一项放进b时,也就是b[9] = arr[4],这个时候就是b[k] = arr[j]
然后取第二项放进b时,也就是b[10] = arr[5]
因此我们就可以在放完一项后,让k = k + 1j = j + 1
这个时候的b[k] = arr[j],是不是就代表b[10] = arr[5]了。

  1. arr的第五项开始,取5项,放到b的第十项后面。
j = 4, k = 9;				//分别代表arr数组和b数组的下标
for (i=1; i<=5; i++)		//做5次循环,代表取5项
{
	b[k] = arr[j];
	k++;
	j++;
}

这里是比较难但很重要的点,如果分析也看不懂,可以手动模拟一下:
自己按照程序一行一行执行,在本子上画两行表格,一行代表arr数组,一行代表b数组;j=4时就用个箭头指向arr[4],j++则移动箭头指向arr[5]……
如果理解了,那数组差不多也都理解了。

四、例题讲解

选择“实验8”的第1题。

1、题目要求

实验8第一题
实验8第一题

2、数组的定义分析

因为要输入的是实数(小数),所以要用doublefloat类型。

然后有15个数,但注意到要把计算后的平均值存到a数组最后的a[15]里,即实际上为16个数,长度为16。

故定义数组:

double a[16];

3、数组刚开始的原样读入、原样输出和求平均值

如果认真看了之前的“数组的运用”,这里应该问题不大。
多的点就是要每行五个输出,并且域宽为10。

代码:

double sum = 0;			//求和变量注意清零

//读入部分
for (i = 0; i <= 14; i++)	//i=0~14,读入十五个数
{
	cin >> a[i];		//读入a[i]
	sum = sum + a[i];	//顺便对a[i]的所有项求和,方便后面求平均值
}

//求平均值部分
a[15] = sum / 15;		//求的总和除以个数,也就算的是平均值,放到题上要求的a[15]里

//输出部分
for (i = 0; i <= 14; i++)
{
	if ((i+1) % 5 == 0)
		cout << endl;
	//这里用如果(i+1)%5==0则换行,也就是i=5,10,15,...的时候换行,达成了每五个换行的效果
	//这个可以记下来,如果是每7个换行,就写 if (i%7 == 0) cout<<endl;
	cout << setw(10) << a[i];	//输出a[i],setw为设置域宽
}

4、调整a数组,以满足题目条件形式输出

因为我们要调整a数组里的数,最终输出a数组。
所以可以先把a数组里的所有数存到b数组里,然后再“遍历”b数组,判断某一个数b[i]跟平均值的关系,如果大于则放到a数组前面,小于则放到后面。

首先先来写怎么把a数组里的所有数存到b数组里,前面已经写过了这里直接写代码。

代码:

for (i = 0; i <= 14; i++)	//把a数组放到b数组里
{
	b[i] = a[i];
}

接下来就是难点了,判断出关系后,怎么样才能把b[i]放到a数组前面或者后面。
之前说过的,下标不一定只能用i,也可以定义新变量来表示下标。

于是我们可以定义两个变量beginend,分别代表a数组前面和后面的下标。
刚开始begin = 0, end = 14,分别代表最开始的前面的下标和后面的下标。

way_1
way_1

【注意a[15]为平均值】

然后遍历b数组,假如第一个数b[i]\(i=1\))为\(3\),小于平均值a[15]则该放到后面,也就是a[end]
先让a[end]=b[i]

way_2
way_2

然后再让end = end - 1

way_3
way_3

这样,当再次找到下个小于平均值的数时,则会放到当前的最后面处;
找到下个大于平均值的数时,则会放到当前的最前面处。
如图:

way_4
way_4

  • 代码:
	cout << "调整后的数据为:" << endl;

	for (i = 0; i <= 14; i++)	//把a数组放到b数组里
	{
		b[i] = a[i];
	}

  int begin = 0, end = 14;
	for (i = 0; i <= 14; i++)	//遍历b数组,跟平均数比较,放回a数组
	{
		if (b[i] < a[15])	//跟平均数比较
		{
			a[end] = b[i];
			end--;
		}
		else
  	{
  		a[begin] = b[i];
  		begin++;
  	}
  }

  for (i = 0; i <= 14; i++)	//输出a数组
  {
  	if (i % 5 == 0)
  		cout << endl;
  	cout << setw(10) << a[i];
  }

5、总代码

#include <iomanip>
#include <iostream>
using namespace std;
int main()
{
	int i;
	double a[16], b[16];
	double sum = 0.0;
	cout << "请输入15个实型数:" << endl;
	for (i = 0; i < 15; i++) //读入
	{
		cin >> a[i];
		sum = sum + a[i];
	}
	a[15] = sum / 15;		 //求平均值
	for (i = 0; i < 15; i++) //原样输出
	{
		if (i % 5 == 0 && i != 0) //【这里加了个i!=0的条件,防止最开始就换行
		{
			cout << endl;
		}
		cout << setw(10) << a[i];
	}

	cout << endl
		 << "调整后的数据为:" << endl;

	for (i = 0; i < 15; i++) //把a数组放到b数组里
	{
		b[i] = a[i];
	}

	int begin = 0, end = 14;
	for (i = 0; i < 15; i++) //遍历b数组,跟平均数比较,放回a数组
	{
		if (b[i] < a[15])
		{
			a[end] = b[i];
			end--;
		}
		else
		{
			a[begin] = b[i];
			begin++;
		}
	}

	for (i = 0; i < 16; i++) //输出a数组【注意这里是遍历输出整个a数组,即a[15]这个存的平均值也要输出,所以变成了(i = 0; i <16; i++)
	{
		if (i % 5 == 0 && i != 0)
			cout << endl;
		cout << setw(10) << a[i];
	}
}
  • 这里只讲的老师的第一种方法,更好理解一些。对于第二种方法可以自行尝试,跟这个大致相同,不懂也可以自己在草稿纸上模拟一下。

五、其他提示

  1. 数组的范围可以开大,但不能开小。
    意思就是尽管最多可能只有10个整数,你可以定义为int a[100],但不可以int a[9]
    推荐是比最多个数开稍微大一点,这样又可以偷懒想要开几个,又可以防止越界错误【本来只定义了15个,你访问了a[20]】。

  2. 因为编程里数组第一项是从a[0]开始的,比较反人类x……
    所以如果想按照数学习惯,完全可以从a[1]开始存数。

    比如读入15个数,原来可能写成

    for (i = 0; i <= 14; i++)
    	cin >> a[i];
    

    这样就是存在a[0]~a[14]里。

    你也可以写成符合我们习惯的

    for (i = 1; i <= 15; i++)
    	cin >> a[i];
    

    这样就是存在a[1]~a[15]里。

    不过选择好一种自己喜欢的就这么写,不要一会从\(0\sim14\)一会又\(1\sim15\),不然会很混乱。

  3. 没了。

  4. 有关排序的算法可能是常考点,各位可以自己去背一下。

以上。