
4.2 一维数组
一维数组是数组中最为简单和常用的,由单个数据为成员构成的数组。如季节数组可以包含4个成员:春、夏、秋、冬。数组中的每一个元素都可以作为一个变量被访问。
4.2.1 一维数组简介
一维数组的声明同变量声明类似,声明中需要包含成员的数据类型和数组名,不同的是数组声明需要在数据类型后紧跟着一个中括号[]。如声明一个名为num的数组,使用代码如下:
int[] num;
上述代码中,int关键字指定该数组中的成员为int型的数据,int后面的中括号除了用于与其他变量或常量区分,还用于定义数组的长度,即数组中的元素数量。
int关键字与中括号之间没有空格,而中括号与数组名称之间有一个空格。数组需要初始化才能使用,这一点与变量的使用一样。
数组的长度需要在初始化时指定,可以将长度写在中括号中,也可为数组成员赋值,系统将根据数组的赋值为数组分配空间、确定数组的长度。如定义一个有着3个整型元素的数组num,格式如下:
int[] num=new int[3];
数组的赋值需要将数组成员放在{}内,每个元素之间用逗号隔开。如将数组变量num直接赋值,格式如下:
int[] num={1,2,3};
上述代码中,对数组的赋值,可将数组成员放在大括号“{}”中,每个成员之间使用逗号隔开。数组成员赋值时,其内部的成员必须符合数组的数据类型。数组元素也可以是变量,如分别定义整型变量a、b、c,并赋给数组num,格式如下:
int a, b, c; a = 0; b = 0; c = 0; int[] num = { a, b, c };
除了数组在声明时的直接赋值,数组在声明后不能直接赋值,而需要实例化后才能赋值。使用关键字new,如练习4-1所示。
【练习4-1】
声明整型数组num,实例化数组的长度为3,并赋值为{55,9,7},使用代码如下:
int[] num; num=new int[3]{55,9,7};
不能直接像变量赋值一样使用代码num={55,9,7};进行赋值。即使是使用new将对象实例化,也不能使用这样的语句。但是可以对实例化的数组成员单独赋值。即数组赋值只有三种形式:
□ 在声明时直接赋值。
□ 程序进行时使用new赋值。
□ 在数组被实例化后,对数组成员单独赋值。
由于一个数组有多个成员的排列,因此为确定到具体的一个成员,数组中有索引的概念。索引相当于图书的目录,为指定的内容标注一个方向。数组中的索引相当于其成员的编号,数组中的第一个成员索引为0,第二个成员索引为1,第n个成员的索引为n-1。使用索引来访问数组成员,如访问练习4-1中的第2个成员9,输出该成员的值,使用如下语句:
Console.Write(num[1]);
上述代码中,使用num[1]访问num数组的第2个成员9,其构成为:数组名、中括号、中括号内部的索引。这3个构成成分之间不需要有空格,上述代码的执行结果为9。
数组实际是类的一个对象,是基类Array的派生,可以使用Array的成员,如Length属性。关于类、对象、基类和派生等内容将在第5章和第6章介绍,本节只需学会如何使用Length属性获取数组长度。如获取数组num的长度并赋值给longnun,格式如下:
int longnum = num.Length;
4.2.2 数组遍历
数组的遍历即依照索引顺序,依次访问所有数组成员。数组的遍历可以使用循环语句,包括for循环、while循环等,以及专用于数组和数据集合的foreach in语句。
使用循环语句遍历数组,如为数组赋值或使用数组中的数据为其他变量赋值,如练习4-2所示。
【练习4-2】
声明整型数组num,实例化数组的长度为10,并将其成员依次赋值为1到10,使用代码如下:
int[] num; num = new int[10]; for (int i = 0; i < num.Length;i++ ) { num[i] = i + 1; } for (int i = 0; i < num.Length; i++) { Console.Write("{0} ",num[i]); }
执行结果为:
1 2 3 4 5 6 7 8 9 10
练习4-2使用第1个for循环将数组赋值,又使用第2个for循环输出数组的值。使用循环语句遍历数组方便、容易理解,C#提供了数组专用的遍历语句foreach in语句,在本书第3章简单提过,使用方法如练习4-3所示。
【练习4-3】
将数组num1赋值为{5,2,6,8,4,1,3,9,7},使用foreach in语句将数组成员输出,代码如下:
int[] num1 = { 5, 2, 6, 8, 4, 1, 3, 9, 7 }; foreach(int i in num1) { Console.Write("{0} ",i); }
执行结果为:
5 2 6 8 4 1 3 9 7
foreach in语句结构简单,在数组中的作用就是将数组成员顺序遍历。
4.2.3 数组排序
数组最常见的应用就是对数组成员的排序,这也是生活中对数据的重要处理。如将全班学生的成绩赋值给数组,并按成绩从大到小排列。
数组的排序将改变数组成员的原有索引,如将数组成员按照从小到大的顺序排序,则数组中数字最小的成员,在排序后,其索引被修改为0。常见的排序方式有以下几种。
□ 冒泡排序 将数据按一定顺序一个一个传递到应有位置。
□ 选择排序 选出需要的数据与指定位置数据交换。
□ 插入排序 在顺序排列的数组中插入新数据。
1. 冒泡排序
冒泡排序是最稳定的,也是遍历次数最多的排序方式。例如,将n个元素的数组数据从小到大排序:
冒泡排序将按照序号将数组中的相邻数据进行比较,每一次比较后将较大的数据放在后面。所有数据执行一遍之后,最大的数据在最后面。接着再进行一遍,直到进行n次,确保数据顺序排列完成,如练习4-4所示。
【练习4-4】
将数组value赋值为{15,4,1,2,8,33,22,26,30,19},通过冒泡排序将数组成员按从小到大的顺序排序,代码如下:
int[] value = { 15, 4, 1, 2, 8, 33, 22, 26, 30, 19 }; int max=0; for (int i = 9; i >= 0;i-- ) { for (int j = 0; j <i; j++) { if (value[j] > value[j + 1]) { max = value[j]; value[j]=value[j+1]; value[j+1]=max; } } } foreach (int i in value) { Console.Write("{0} ", i); }
执行结果为:
1 2 4 8 15 19 22 26 30 33
练习4-4通过内部循环将最大值一点一点移动到数组最后的位置。冒泡排序每移动一个最大值,接下来可以减少一次比较移动。因此,内部循环每执行一遍,执行次数减少一次。
冒泡排序准确性高,但执行语句多,数组要进行的比较和移动次数多。冒泡排序不会破坏相同数值元素的先后顺序,被称作是稳定排序。
2. 选择排序
选择排序为数组每一个位置选择合适的数据,如将数组从小到大排序,选择排序给第一个位置选择最小的,在剩余元素里面给第二个元素选择第二小的,以此类推,直到第n-1个元素,第n个元素不用选择了。
将数组按从小到大排序,选择排序将第一个元素视为最小的,分别与其他元素比较;当其他元素小于第一个元素,则交换它们的位置,并继续跟剩下的元素比较。直到确定第一个元素是最小的,再从第二个元素比较。直到倒数第二个元素与最后一个元素比较,如练习4-5所示。
【练习4-5】
将数组score赋值为{75,69,89,72,99,86,93,88,84,77},通过选择排序法将数组成员按从小到大的顺序排序,代码如下:
int[] score = { 75, 69, 89, 72, 99, 86, 93, 88, 84, 77 }; int max; for (int i = 9; i >= 0; i--) { for (int j = 0; j < i; j++) { if (score[j] > score[i]) { max = score[j]; score[j] = score[i]; score[i] = max; } } } foreach (int i in score) { Console.Write("{0} ", i); }
执行结果为:
69 72 75 77 84 86 88 89 93 99
练习4-5中将数组序号从小到大依次与最后一个元素比较,将较大值与最后一个元素交换数值,得到最后位置上的数值;接着将元素依次与倒数第二个元素比较,以此类推,直到与第2个数比较。
选择排序改变了数值相同元素的先后顺序,属于不稳定的排序。选择排序同样进行了较多的比较和移动。
4.2.4 插入数组元素
数组新元素的插入,将导致插入位置之后的元素依次改变原有序号。在指定位置插入新的元素,为保证原有元素的稳定,首先要将原有元素移位,再将新的元素插入指定位置。
插入时元素的移位与排序时的移位不同,插入使得数组改变了原有长度,存储数组的空间不足以让新元素的加入。
使用new关键字可以修改数组的长度,但这种修改相当于重新定义了数组,数组元素的值将会被定为默认值0,如练习4-6所示。
【练习4-6】
将数组int[] score = { 75, 69, 89, 72, 99, 86, 93, 88, 84, 77 }重新声明为11个值,并输出,代码如下:
int[] score = { 75, 69, 89, 72, 99, 86, 93, 88, 84, 77 }; score = new int[11]; foreach (int j in score) { Console.Write("{0} ", j); }
输出结果为:
0 0 0 0 0 0 0 0 0 0 0
可见数组的重新定义将失去原有元素值,只能通过新建数组来保存插入后的数组,如练习4-7所示。
【练习4-7】
将数组score的第(n+1)个位置插入数据73,使其成为新的数组score1,即score1[n]=73,实现代码如下:
int[] score = { 75, 69, 89, 72, 99, 86, 93, 88, 84, 77 }; int[] score1 = new int[11]; int n = 5; //在第n+1位置插入 int addnum = 73; //插入数值73 for (int i = 9; i >=n; i--) { score1[i + 1] = score[i]; if (i == n) { score1[n] = addnum; for (int j = n - 1; j >= 0; j--) { score1[j] = score[j]; } break; } } foreach (int j in score1) { Console.Write("{0} ", j); }
运行结果如下:
75 69 89 72 99 73 86 93 88 84 77
与原数组相比,第6个位置,原来86所在的位置插入了73。插入排序法在比较的基础上进行插入。
插入排序法是在一个有序的数组基础上,依次插入一个元素。如将数组从小到大排序,将新元素与有序数组的最大值比较,若新元素大,插入到字段末尾;否则与倒数第二个元素比较,直到找到它的位置,此时需要将该位置及该位置之后的元素序号发生改变,需要重新调整。
插入排序没有改变相同元素的先后位置,属于稳定排序法,但插入排序的算法复杂度高。具体步骤如练习4-8所示。
【练习4-8】
将数组score赋值为{75,69,89,72,99,86,93,88,84,77},通过插入排序法将数组成员按从小到大的顺序排序,代码如下:
int[] score = { 75, 69, 89, 72, 99, 86, 93, 88, 84, 77 }; int[] score0 = new int[10]; score0[0] = score[0]; int num = 0; for (int i = 1; i < 10; i++) { num = score[i]; if(num>score0[i-1]) { score0[i] = num;} for (int j = 0; j < i; j++) { if (score0[j] > num) { for (int k = (i - 1); k >= j; k--) { score0[k + 1] = score0[k]; } score0[j] = num; break; } } } foreach (int sco in score0) { Console.Write("{0} ", sco); }
练习4-8中先将原数组第一个元素赋给新数组,这样新数组可以视为只有一个元素的有序数组。将原数组的第二个元素与新数组中第一个元素比较后插入,新数组将有两个元素,直到原数组最后一个元素的插入。
在插入时首先判断插入元素是否比有序数组最后一个元素大,若插入元素最大,则直接放在有序数组最后,否则将依次跟有序数组元素相比较,找到合适的位置,将原有元素移位后,插入新元素。
4.2.5 删除数组元素
数组元素的删除相对容易,只需找到需要删除的元素的位置,并将该元素之后的元素移位即可。
数组元素的删除有两种:一种是根据元素的索引删除;另一种是在不知道索引的情况下,删除有着某个值的元素。
1. 根据索引删除元素
根据索引删除数组元素,其实质是:将该索引后面的成员依次前移,覆盖掉原有数据;最后将最后一个索引成员赋值为0(整型数组元素默认值为0)。由于数组的长度是不能变化的,因此成员的删除,只是将后面的成员移位。
【练习4-9】
有数组score {75,69,89,72,99,86,93,88,84,77},将数组中的第3个元素删除,使用代码如下:
int[] score = { 75, 69, 89, 72, 99, 86, 93, 88, 84, 77 }; int del=3; //删除第del个元素 for (int i = del; i < 10;i++ ) { score[i - 1] = score[i]; if (i == 9) { score[i] = 0; } } foreach (int sco in score) { Console.Write("{0} ", sco); }
执行结果为:
75 69 72 99 86 93 88 84 77 0
2. 删除指定元素值
删除指定元素值,需要先找出指定元素的位置再进行删除,或直接将原有数组改为不含删除元素值的新数组。
对于没有重复元素的数组,可以找出要删除的元素位置再删除,如练习4-10所示。
【练习4-10】
有数组score {75,69,89,72,99,86,93,88,84,77},将数组中元素值为88的元素删除,使用代码如下:
int[] score = { 75, 69, 89, 72, 99, 86, 93, 88, 84, 77 }; int delnum=88; //要删除的元素值 int del=0; for (int i = 0; i < 10; i++) { if (score[i] == delnum) { del = i; break; } } for (int i =( del+1) ; i < 10; i++) { score[i-1] = score[i]; if (i == 9) { score[i] = 0; } } foreach (int sco in score) { Console.Write("{0} ", sco); }
执行结果为:
75 69 89 72 99 86 93 84 77 0
若有重复的元素值,即使找出了元素位置,也不容易删除。可以将原数组为新数组赋值,遇到要删除的元素取消赋值并跳出。但这样产生的结果是,需要被删除的元素位置的值,被0取代。如练习4-11所示。
【练习4-11】
有数组score {75,69,89,74,99,86,93,74,84,77},将数组中元素值为74的元素删除,使用代码如下:
int[] score = { 75, 69, 89, 74, 99, 86, 93, 74, 84, 77 }; int delnum = 74; int[] score0 = new int[10]; for (int i = 0; i < 10; i++) { if (score[i] == delnum) { continue; } score0[i] = score[i]; } foreach (int sco in score0) { Console.Write("{0} ", sco); }
执行结果为:
75 69 89 0 99 86 93 0 84 77