第4章 同类型批量数据管理的技巧—数组

本章视频教学录像:1小时2分钟

在实际应用过程中,将一批相互有联系、有一定顺序、同一类型和具有相同性质的数据采用集合进行定义和存储,这样的集合就是数组。数组在同类型批量数据管理中有着很广泛的应用。本章将带领读者从数组的基础开始循序渐进地学习。本章介绍数组的基本概念、基本操作和数组相关函数及语句,主要包括定长和动态数组和数组元素的输入、输出、插入、查找、删除等。

本章要点(已掌握的在方框中打钩)

□ 了解数组的基本概念和分类

□ 了解数组的引用和初始化

□ 掌握数组元素的插入、删除和查找

□ 熟悉数组元素的应用及排序

□ 了解数组相关的函数

□ 了解数组相关的语句

4.1 数组的概念

本节视频教学录像:10分钟

数组的英文名是“Array”。Array在英文中是“阵列”的意思。所谓“阵列”,就是一组集中的、排列有序的集合。数组并不是一种数据类型,而是一组相同类型的变量的集合,可用于存储和处理成组的有序数据,数组必须先声明后使用。每一个数组给定一个名称,叫作数组名;数组中的每一个数或变量被称为数组元素;一个数组中各个数组元素之间的区别用数组的下标来表示,放在数组名后面的括号内,因此,数组元素又被称为下标变量。

总体上数组可分为两类: 定长(静态)数组和动态(可变长)数组。

提示

数组和简单变量相比有以下几个特点。⑴ 数组的命名规则和简单变量的命名规则相同。⑵ 数组的数据类型和数组中所存储的数组元素的类型必须相同。⑶ 由于受到计算机硬件和软件条件的限制,数组中的元素个数必须是有限的。

4.1.1 定长数组及声明

定长数组是一组具有相同类型的变量的有序集合,集合中的变量称为数组元素。数组元素共用一个名字,通过下标来唯一标识自己。

在使用某个数组前,需要先声明该数组。对数组进行声明,应该包括数组名、维数、大小、类型以及作用域等。

数组声明语句的具体语法是:

      Dim|Private|Public|Static数组名([下界1 To]上界1,<[下界2 To]上界2,……>) [As数据类型]

对数组声明语句的说明如下。

Dim:声明普通局部数组。

Private:声明模块级数组。

Public:声明可在工程任何模块中使用的数组。

Static:声明静态数组。

As:用来说明数组元素的类型。声明时若没有指定数组的数据类型,则默认是变体型。

例如:

      Dim Private A(6 To 12)As lnteger      '数组A为私有整型一维数组,共7个元素,下标从6到12。
      Dim Public N(-3 to 6,9)      '声明数组N为公用二维数组,共有10*10=100个元素。

注意

在声明数组时,也可以使用类型说明符代替“[As数据类型]”,例如:

            Dim a$(10)      '字符串类型数组
            Dim b%(5,5)     '整型数组

4.1.2 动态数组及声明

有时我们并不能在编写程序的时候就确定数组中到底会存储多少元素,对于这种情况,一般的解决方法是对所有的数组都按照它可能的数组元素的最大值创建数组,但是这样会浪费很多存储空间。动态数组就是为了解决这个问题而产生的。动态数组中的数组元素个数不定,并且可以根据需要动态改变数组元素的个数。

可以按照下面的步骤创建一个动态数组。

⑴ 首先像前面定长数组的声明一样,先声明一个数组,但是不说明维数和界限。

      Dim|Private|Public|Static数组名() [As数据类型]

⑵ 然后在实际使用的时候用ReDim语句定制数组的维数和上下界,为数组分配实际的内存空间。

      ReDim [Preserve] 数组名(<维数说明>) [As类型]

使用ReDim语句时,需要遵循下面一些规则。

⑴ ReDim语句中的维界定义中的上下界可以是常量,也可以是有了确定值的变量。

⑵ ReDim语句只能出现在过程体内,为数组临时分配存储空间,当所在过程结束时,分配的存储空间就会释放。

⑶ 使用Redim语句时,如果不使用Preserve选项,原来数组中的值会丢失,即数组中的内容全部被重新初始化,当前存储在数组中的值会全部丢失。Visual Basic会重新将数组元素的值置为Empty(对Variant数组)、0(对Numeric数组)、零长度字符串(对String数组)或者Nothing(对于对象的数组)。如果希望改变数组大小又不丢失数组中的数据,使用具有Preserve关键字的ReDim语句就可以做到这点。

使用ReDim语句时,如果使用Preserve选项,则在对数组重新说明时,将会保留数组中原来的数据,但是不能改变维数,并且只能改变最后一维的大小,前面维的大小不能改变。

提示

⑴ 在动态数组ReDim语句中的下标可以是常量,也可以是确定值的变量。

⑵ 在过程中可以多次使用ReDim来改变数组的大小,也可改变数组的维数。

⑶ 每次使用ReDim语句都会使原来数组中的值丢失,可以在ReDim语句后加Preserve参数来保留数组中的数据,但只能改变最后一维的大小,前面几维大小不变。

4.2 数组基本操作

本节视频教学录像:34分钟

在数组的学习中,数组的应用是非常重要的一项内容,而这就需要我们了解数组的一些基本功能,熟练掌握一些数组的基本操作和实现。本小节就让我们来一起学习一些数组的基本操作。

4.2.1 数组的引用

数组元素的引用—数组名(下标)。

例如:求数组中的最大元素及所在下标。

      Dim Max As lnteger, iMax As lnteger
      Dim ia(1 to 10) as integer
      Max=iA(1):iMax=1
      For i=2 To 10
        lf iA(i)>Max Then
        Max=iA(i)
        iMax=i
      End lf
      Next l

4.2.2 数组的初始化

当数组被声明后,根据数组被声明的数据类型,数组中的元素将被赋予不同的默认值。

提示

⑴ 初始值与相应数组元素一对应,初始值相互之间用逗号隔开。

⑵ 初始化前对数组元素的定义不能是具体的数据类型,只能是Variant或默认类型。

⑶ 对于该数组可以不定义而直接由Array函数来确定。

⑷ 此种方法只能初始化一维数组。

4.2.3 数组元素的输入、输出

1. 数组元素的输入

对于数组元素较少的数组,可通过单个赋值语句进行输入操作;对于数组元素较多的数组,一般通过For语句、InputBox函数和文本框输入。

⑴ 通过InputBox函数输入适合输入少量数据

例如:

      01 Dim SB(3,4)As singer
      02   For i=0 To 3
      03   For j=0 To 4
      04    SB(i,j)=lnputBox("输入"&i&j&"的值")
      05   Next j
      06 Next i

⑵ 通过For语句输入

例如:

      01 Option Base 1           '默认下标下界为1
      02 DlM b(2,3)as single
      03 For i=1 to 2
      04   For i=1 to 3
      05     b(i,j)=inputbox("输入b(" & i &","& j &")的值")
      06   Next
      07 Next

⑶ 通过文本框控件输入

对大批量的数据输入,采用文本框和函数split()\join()进行处理,效率更高。

2. 数组的输出

数组的输出同样是以数组元素为操作对象,可通过Print方法来实现,也可用For…Next循环语句输出。

⑴ 通过For…Next循环语句实现输出

例如:

      01 For i=1 To 10
      02   Print A(i),             '在一行上显示
      03   Next l
      04 For i=1 To 100
      05   Print B(i),
      06   lf i Mod 10=0 Then Print         '每10个一行显示
      07 Next i

⑵ 通过print方法实现输出

例如:输出方阵中下三角元素。

      01 Dim sc(5,5)As lnteger,i As lnteger,j As lnteger
      02   For i=1 To 5
      03      For j=1 To 5
      04        sc(i,j)=i*j;      '数组赋初值
      05      Next
      06   Next
      07   For i=1 To 5
      08      For j=1 To i       '内循环控制每行输出的元素个数
      09        Print sc(i,j);     '以紧凑格式输出数组元素
      10      Next
      11      Print
      12   Next

4.2.4 数组元素的插入、删除和查找

数组元素的插入、删除操作一般是在已排序好的数组中插入或删除一个元素,使得插入或删除以后的数组还是有序的;这涉及到查找问题,在数组中先找到插入的位置或删除的元素,然后进行相应的操作。

1.数组中元素的插入

例如:设有一按升序排列的有n个元素的数组a(数组元素为整型),现将一个数“11”插入后,仍保持其有序。

解题思路:

⑴ 查找插入位置k(1≤k ≤n-1)。

⑵ 从n-1到k逐一往后移动一个位置,将第k个元素的位置腾出。

⑶ 将数据插入。

      01 Dim a(),i,k As lnteger
      02 Print"插入前:";
      03 Redim a(1 To 9)  '给数组元素赋值
      04 a=Array(2,4,6,8,10,12,14,16)
      05 For i=1 To 8
      06  Print a(i);
      07 Next
      08 For k=1 To 9    '查找插入的位置
      09  lf 10=a(k)Then Exit For
      10 Next
      11 For i=9 To k setp-1      '从k+1元素开始往前移动
      12  a(i+1)=a(i)
      13 Next
      14 a(k)=11
      15 Print"插入后:";
      16 For i=1 To 9
      17  Print a(i);
      18 Next

2. 数组中元素的删除

解题思路:

⑴ 查找欲删除的元素所在的位置k。

⑵ 从k+1到n个位置逐个往前移动。⑶ 将数组个数减1。

例如:删除数组一个元素。设数组的元素为(2,4,6,8,10,11, 12,14,16),删除其中的元素“11”。

      01 Dim a(),i,k As lnteger
      02 Print"插入前:";
      03 Redim a(1 To 9)  '给数组元素赋值
      04 a=Array(2,4,6,8,10,11,12,14,16)
      05 For i=1 To 9
      06  Print a(i);
      07 Next
      08 For k=1 To 9    '查找插入的位置
      09  lf 11=a(k)Then Exit For
      10 Next
      11 For i=k+1 To 9 '从k+1元素开始往前移动
      12  a(i-1)=a(i)
      13 Next
      14 Redim Preserve a(1 To 8)  '利用数组重新声明减少一个元素,但保持数组原来的值
      15 Print:Print       '显示插入后的数组元素
      16 Print"插入后:";
      17 For i=1 To 8
      18  Print a(i);
      19 Next

4.2.5 数组元素的应用及排序

排序就是将一组数按递增或递减的次序重新排列。常用的方法有选择法、冒泡法、插入法。

1. 选择法排序

算法描述:

设有n个数的数组a(1),a(2),…,a(n),要求按递增的次序排列。

首先设变量k用于存放当前最小数的下标,然后按下列步骤进行。

⑴ 从n个数中选出最小元素的下标,然后将最小数与第一个数交换位置,即a(k)与a(1)互换。先将a(k)与a(2)进行比较,k的初值为1,若a(2)<a(k),则将变量k指向2(k总是为较小元素的下标值);再将a(k) 与a(3)…a(n-1)、a(n)比较,并依次做出同样的处理,最终k为n个数中最小元素的下标,a(k)为最小的元素,此时将a(k)与a(1)互换。

⑵ 从除第一个数外,其余n-1个数按步骤⑴的方法选出次小的数,使a(k)与a(2)交换位置。先将k置为2,将a(k)与a(3)、a(4)、…、a(n-1)、a(n)比较,每当a(i)<a(k)时,置k为i,最后,k为第一轮余下的n-1个数中的最小数,将a(k)与a(2)互换。

⑶ 继续进行第三轮,第四轮…直到第n-1轮,余下的a(n)就是n个数中的最大值。

至此,n个数已从小到大顺序存放到数组a中。

2. 冒泡法排序

冒泡法在每一轮排序时将相邻的数比较,当次序不对就交换位置,冒泡法若有n个元素,则需要比较n-1轮,比较方向可以从右向左,也可以从左向右,而且每一轮都是从头比较到尾。

例如:将数组中的6个数,用冒泡排序法排序。

      01 Dim a(6)As lnteger
      02 Dim k,n,i,j,t As lnteger
      03 Randomize
      04 n=6
      05 For i=1 To n
      06 a(i)=lnt(Rnd*9)+1    '给数组6个元素赋值,0~9中的随机整数
      07 Label3.Caption=Label3.Caption+Str(a(i))
      08 Next
      09 '冒泡排序法
      10 For i=1 To n-1
      11   For j=n To i+1 Step-1
      12     lf a(j-1)>a(j)Then  '相邻元素比较
      13      t=a(j)
      14      a(j)=a(j-1)
      15      a(j-1)=t
      16     End lf
      17   Next
      18  Label4.Caption=Label4.Caption+Str(a(i)) '将排序结果显示在Label上
      19 Next
      20 Label4.Caption=Label4.Caption+Str(a(i))

4.3 数组相关函数及语句

本节视频教学录像:14分钟

数组相关函数及语句是数组的比较常用的实现方式,本小节让我们来认识和学习一些在数组中比较常用的数组相关函数及语句。

4.3.1 Array函数

Array函数格式:数组变量名=Array(数组元素值表)。

功能:把一组数据赋给数组中的每个元素。

说明:

⑴ 数组元素值表是一个用逗号分隔的值表,这些值构成数组的各元素值。

⑵ Array函数仅适用于一维数组,只能给Variant类型的变量赋值,赋值后的数组大小由参数的个数决定。

⑶ 使用array函数创建的数组,其下界受Option base语句指定的下界的限制。

⑷ 若不提供参数,则创建一个长度为0的数组。

提示

数组变量名是预先定义的数组名。在数组变量名后没有括号。采用变量定义形式,作为数组使用,类型为variant。

例如:要将1、2、3、4、5、6、7、8、9、10这些值赋给数组A,可以使用下面的方法。

      Dim A
      A = Array(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)

4.3.2 UBound函数和LBound函数

函数格式:

      LBound(数组名[,N])
      UBound(数组名['N])

功能:

LBound函数返回“数组名”指定的数组的第N维的下界。

UBound函数返回“数组名”指定的数组的第N维的上界。

说明:N为1表示第一维,N为2表示第二维,等等。如果省略N,则默认为1。

例如:要打印一维数组A的各个值,可以通过下面的代码实现。

      For l = LBound(A) To UBound(A)
          Print A(l);
      Next l

例如:要打印二维数组B的各个值,可以通过下面的代码实现。

      01 For l=LBound(B,1)To UBound(B,1)
      02   For J=LBound(B,2)To UBound(B,2)
      03     Print B(l,J);
      04   Next J
      05   Print
      06 Next l

4.3.3 Split函数

Split函数格式:Split(字符串表达式[,分隔符])

功能:以某个指定符号作为分隔符,将“字符串表达式”指定的字符串分离为若干个子字符串,以这些子字符串为元素构成一个下标从零开始的一维数组。

说明:“字符串表达式”用于指定要被分隔的字符串,“分隔符”是可选的,如果忽略,则使用空格作为分隔符。例如:

      Dim A
      A = Split("how are you", " ")

执行以上赋值之后:

      A(0)="how",A(1)="are",A(2)="you"。

也可以用Split函数给一个动态数组赋值。例如:

      Dim A() As String
      A = Split("how are you", " ")

4.3.4 Option Base语句

在模块级别中使用,用来声明数组下标的缺省下界。

语法:Option Base {0 | 1}

说明:由于下界的缺省设置是0,因此无需使用Option Base语句。如果使用该语句,则必须写在模块的所有过程之前。一个模块中只能出现一次Option Base,且必须位于带维数的数组声明之前。

注意 :Dim、Private、Public、ReDim以及Static语句中的To子句提供了一种更灵活的方式来控制数组的下标。不过,如果没有使用To子句显式地指定下界,则可以使用Option Base将缺省下界设为1。使用Array函数或ParamArray关键字创建的数组的下界为0,Option Base对Array或ParamArray不起作用。Option Base语句只影响位于包含该语句的模块中的数组下界。例如:

      01 Option base 1  '将缺省的数组下标设为1
      02 Dim LowerDim MyArray(20)
      03 TwoDArray(3,4) '声明数组变量
      04 Dim ZeroArray(0 To 5) '取代缺省的下标
      05 LBound   '使用函数来测试数组的下界
      06 Lower=LBound(MyArray) '返回1
      07 Lower=LBound(TwoDArray,2) '返回1
      08 Lower=LBound(ZeroArray)

【范例4-1】 编写代码以实现运行程序后单击窗体,在窗体上垂直输出1、2、3、4、5。

⑴ 启动Visual Basic 6.0,在弹出的【新建工程】对话框中选择【标准EXE】图标,然后单击【打开】按钮。

⑵ 在【Form1】窗体上单击鼠标右键,在弹出的快捷菜单中选择【查看代码】菜单项,进入代码窗口。

⑶ 在代码窗口中选择【Form】窗体的【Click】事件。

技巧

用鼠标双击窗体或者选择【视图】菜单下的【代码窗口】命令,也可以进入代码窗口。

⑷ 输入以下代码。

      01 Private Sub Form_Click()
      02  Dim l As lnteger '定义一个整型变量
      03  Dim a%(5)     '定义一个整型数组,并为数组设置元素个数
      04   For l=1 To 5  '从1至5开始循环运算
      05    a(l)=l       '为数组赋值
      06    Print a(l)     '输出数组中的元素值
      07   Next l '循环不结束,继续下一次循环
      08 End Sub

【运行结果】

保存程序,单击【启动】按钮,运行程序。用鼠标单击窗体,将会在窗体中垂直显示1、2、3、4、5等数字。

【拓展训练】

既然能输出“1、2、3、4、5”这几个数字,那么要想输出100~110这一系列数字也就不是一件很难的事了。

只需要对步骤⑷中的代码进行相关的修改就可以了(拓展代码2-1.txt)。

      01 Private Sub Form_Click()
      02  Dim l As lnteger '定义整型变量
      03  Dim a%(100 To 110)     '定义整型数组,并为其设置坐标上限和下限
      04  For l=100 To 110      '利用循环语句开始循环
      05   a(l)=l       '为数组赋值
      06   Print a(l)      '输入数组元素
      07  Next l  '循环条件为真,进行下一次循环
      08 End Sub

提示

在修改程序时,主要是对数组所定义的上界和下界进行了修改。如果对程序限界定义的过大,则会造成系统资源的浪费;如果对程序上界和下界定义过少,则会出现下标越界的严重错误。

运行后,单击窗体就会看到所需的结果。

4.4 高手点拨

本节视频教学录像:4分钟

在平时使用数组进行赋值时,以下一些常见的问题需要注意。

1. 只能将数据类型定义为可变类型

赋值的数据虽然可以有多种类型,但定义时必须将数据定义成可变型。若定义成其他类型,比如定义为整型:

      Dim a() As Integer
      A()=Array(1,3,5,10)

则系统会报告类型错误。就是说在利用Dim等进行定义时,除了Variant类型外,Integer等其他类型都不适合这种形式。

2. 数组定义时不要指定上、下界

比如要对10个数据进行赋值,不能将数组定义成:

      Dim s(10) As Variant

这样当利用Array函数赋值时系统将会报错。也就是说数组s()应定义成动态数组,不指定上下界,其上下界在用Array函数赋值时自动指定。

3. 有关数组的隐性声明

当使用数组的隐性声明形式时,即不对数组进行提前声明而直接使用Array函数赋值时,要注意此时数组名要省略其后面的括号,数组s()应写成s,即有:

      s=Array(...)

而如果写成s()=Array(...),系统将会报错。只要注意了以上几点,对数组的大量数据初始化问题就能得到顺利的解决。

4.5 实战练习

查找下标为0,上标为9的数组中值为“5”的元素索引值,若没有,则返回“找不到”。