第7章数 组.docx
《第7章数 组.docx》由会员分享,可在线阅读,更多相关《第7章数 组.docx(39页珍藏版)》请在冰点文库上搜索。
![第7章数 组.docx](https://file1.bingdoc.com/fileroot1/2023-5/23/a73464d7-721d-4b46-b47d-a589702b4425/a73464d7-721d-4b46-b47d-a589702b44251.gif)
第7章数组
第7章数组
本章要求:
1.掌握数组的概念
2.掌握数组(一、二维)的定义及其引用,
3.掌握控件数组的建立及使用。
4.掌握与数组有关的常用算法,如排序、查找、插入等。
本章重点:
数组定义及引用方法,与数组有关的一些常用算法
本章难点L与数组有关的一些常用算法
7.1数组的概念
在实际应用中,常常需要处理相同类型的一批数据。
例如,为了处理100个员工的工资,可以用S
(1),S
(2),…,S(100)来分别代表每个员工的工资,其中S
(1)代表第一个员工的工资,S
(2)代表第二个员工的工资……。
在VB中,把一组相互关系密切的数据放在一起并用一个统一的名字作为标志,这就是数组。
数组中的每一个数据称为数组元素,用数组名和该数据在数组中的序号来标识。
序号又称为下标,数组元素又称为下标变量。
例如,S
(2)是一个数组元素,其中的S称为数组名,2是下标。
在使用数组元素时,必须把下标放在一对紧跟在数组名之后的括号中。
S(3)是一个数组元素,而S3是一个简单变量。
数组并不是一种数据类型,而是一组相同类型数据的集合。
用一个统一的名字(数组名)代表逻辑上相关的一批数据,每个元素用下标变量来区分;下标变量代表元素在数组中的位置。
其表示形式:
A
(1),A(10)
X(1,1),X1(1,10),X(2,10)
Y(0,0,0),Y(1,2,5)
VisualBasic中的数组分类:
Ø按数组的大小(元素个数)是否可以改变来分为:
定长数组、动态(可变长)数组。
Ø按元素的数据类型可分为:
数值型数组、字符串数组、逻辑数组、
日期型数组、变体数组等、对象数组。
Ø按数组的维数可分为:
一维数组、二维数组、多维数组
7.2数组的定义
7.2.1静态数组的声明
静态数组的声明语法是:
[Dim/Private/Public]数组名([下界To]上界,…)
[As数据类型]
例如:
DimCounter(1To14)AsInteger‘14个元素的局部数组。
PrivateSume(1To20)AsDouble‘20个元素的模块级数组。
说明:
(1)数组名的命名规则与变量的命名相同,但在同一过程中数组名不能和简单变量名同名,否则会出错。
(2)下标的最大值和最小值分别称为数组的上界和下界。
数组元素在上、下界内是连续的。
如:
DimA(-5To20)AsInteger
定义一个数组名为A,下界为-5,上界为20的一维数组,数据类型为整型,共有26个元素,即A(-5),A(-4),A(-3)…A(20)。
(3)缺省<下界>为0,若希望下标从1开始,可在模块的通用部分使用OptionBase语句将缺省<下界>设为1,其使用语法格式是:
OptionBasen
①OptionBasen语句用于指定数组的默认下界,参数n只能取0或1
②OptionBase语句只能用于窗体或模块的通用部分,不能出现在过程中,并且必须放在数组定义前。
(放在任何过程之外)
例如:
OptionBase1'将数组声明中缺省<下界>下标设为1
(4)如果省略As子句,则数组的类型为变体类型。
(5)数组中各元素在内存占一片连续的存储空间。
(6)一维数组的元素个数:
上界-下界+1;多维数组的元素个数等于每一维元素个数的乘积。
如:
Dimx(1To10,3,1To15)
这是一个三维数组,第一维的元素个数为10,第二维的元素个数为4,第三维的元素个数为15,故整个数组的元素个数为:
10×4×15=600个元素。
(7)关键字Public、Dim、Static、Private表示数组变量的作用范围,具体内容将在过程与函数一章进行讲解。
(8)在数组定义后未赋值前,对于数值型数组各元素的初始值为0;字符型数组初始值为空字符串;逻辑型数组初始值为False。
注意:
1、数组必须“先声明后使用”,声明一个数组就是声明其数组名、类型、维数和数组的大小。
2、数组的维数(即下标的个数)各维下标之间用逗号分开。
在VB中有一维数组、二维数组…最多可以达到60维
3、静态数组:
数组声明时,数组的大小固定的数组称为静态数组。
它指明了数组的维数和每一维的下标范围,在使用过程中,它的维数和下标范围将不得改变
4、动态数组:
数组声明时,不指明数组的维数和每一维的下标范围,仅用一对圆括号表示,这样的数组称为动态数组。
例7-1自动产生10个[100,200]之间的随机整数,然后输出这些数据。
PrivateSubForm_Click()
Dima(1To10)AsInteger
Fori=1To10
a(i)=100+Int(Rnd*101)
Printa(i);
Nexti
EndSub
7.2.2静态数组的定义
创建动态数组的步骤:
(1)用Public(公用数组)、Private(模块级数组)
或Dim(局部数组)在过程中声明数组。
给数组赋以一个空维数表,这样就将数组声明为动态数组。
(2)在过程中用ReDim语句为声明的动态数组分配空间。
说明:
若选择Preserve,则在对数组重新说明时,将会保留原数组中的元素的内容,并且只允许ReDim语句改变动态数组的最后一维的上限。
如:
OptionBase1
DimNamearray()ASstring
RedimStuarray(40,2)
RedimPreserveNamearray(40,UBound(Stuarray,2)+4)
例7-2动态数组使用举例
OptionBase1
PrivateSubForm_Click()
DimM()AsInteger
ReDimM(5)
Print"第一个redim";语句执行后
Fori=1To5
M(i)=i
PrintM(i);
Nexti
Print
ReDimM(10)
Print"第二个redim";语句执行后
Fori=1To5
M(i)=i
PrintM(i);
Nexti
Rem试试把此部分删除的结果
Fori=6To10
M(i)=2*i
PrintM(i);
Nexti
Print
ReDimM(12)
Print"第三个redim";语句执行后
Fori=1To10
M(i)=i
PrintM(i);
Nexti
Fori=11To12
M(i)=i
PrintM(i);
Nexti
Print
EndSub
7.2.3数组的清除
经过定义的数组将为其分配相应的存储空间,其大小不能改变。
为了重新初始化静态数组的元素,或者释放动态数组的存储空间,可以使用Erase语句。
格式:
Erase数组名[,数组名…]
功能:
重新初始化静态数组的元素;或者释放动态数组的存储空间。
说明:
①当Erase语句用于静态数组时:
各数组元素清空(即:
赋默认值);
②当Erase语句用于动态数组时:
将删除整个数组结构并释放该数组所占用的内存。
例题:
试验Erase语句的功能
PrivateSubForm_Click()
Dimtest(1to20)AsInteger
ForI=1to20
Test(i)=I
PrintTest(I);
Next
EraseTest
Print
Print“EraseTest()”
Print“NowtheTestArrayisFilledwithzeroes”
ForI=1to20
printTest(I);
Next
EndSub
7.3数组的基本操作
7.3.1数组元素引用
数组的引用通常是指对数组中的元素的引用。
数组元素的语法格式为:
数组名(下标[,下标]……)
其中,下标可以是常量、变量或表达式,但表达式的值必须介于定义数组时指定的下标的下界和上界之间,否则将导致“下标越界”的错误。
例如:
A
(1)=A
(2)+B
(1)+7′取数组元素运算
A(i)=B(i)′下标使用变量
B(i+1)=A(i+2)′下标使用表达式
C(3,4)=100′下标使用常量
7.3.2给数组元素赋初值
可以使用循环结构和Array函数给数组赋初值。
(1)使用循环结构
如给数组strName(100)的元素赋初值:
Fori=1To100
strName(i)=0
Next
(2)使用Array函数
Array函数用来为数组元素赋值,即把一个数据集读入某个数组,其语法格式为:
<变量名>=Array(<数据列表>)
OptionBase1
PrivateSubCommand1_Click()
StaticTest_str‘声明一个静态的变体变量
Test_str=Array(“One”,”Two”,”Three”,”Four”,5,6,7,8)
‘输出数组的第4个元素,以及数组的下界和上界
PrintTest_str(4),Lbound(Test_str),Ubound(Test_str)
EndSub
数组的输入一般可以通过文本框输入和InputBox函数输入。
例7-3输入输出一个5X5矩阵。
OptionBase1
PrivateSubForm_Click()
Dima(5,5)AsInteger
DimnAsInteger
Fori=1To5
Forj=1To5
n=n+1
a(i,j)=n
Nextj,i
Fori=1To5
Forj=1To5
PrintTab(j*5);a(i,j);
Nextj
Print
Nexti
EndSub
7.3.3数组元素的输出
输出数组元素与输出其它数据一样,可以使用标签的Caption或文本区域的text输出数组元素的值。
输出数组中的全部或部分元素,一般使用循环结构
7.3.4数组元素的复制
单个数组元素可以像简单变量一样,通过对其赋值,也可以把它的值赋给其他的变量或数组元素。
即数组元素之间可以互相复制,无论它们是否属于同一个数组或维数是否相同,但数组类型必须相同。
例如:
Dima(4,8)AsInteger,b(6,6)AsInteger
…
a(1,2)=b(1,1);a(2,3)=b(2,4)
b(4,4)=a(1,2)
例7-4–产生10个[10,100]之间的整数,将其存放到一维数组中,并输出到窗体。
OptionBase1
PrivateSubForm_Click()
Dima(10)AsInteger
Randomize
Fori=1To10
a(i)=Int(Rnd*91)+10
Nexti
Fori=1To10
Printa(i);
Nexti
EndSub
7.3.5与输入有关的几个函数
1.Array函数
Array函数可方便地对数组整体赋值,但它只能给声明为Variant的变量或仅由括号括起的动态数组赋值。
赋值后的数组大小由赋值的个数决定。
例如,要将1,2,3,4,5,6,7这些值赋值给数组a,可使用下面的方法赋值。
Dima()
A=array(1,2,3,4,5,6,7)
2.求数组的上界Ubound()函数、下界Lbound()函数
Ubound()函数和Lbound()函数
分别用来确定数组某一维的上界和下界值。
使用形式如下:
UBound(<数组名>[,])
LBound(<数组名>[,])
其中:
<数组名>:
数组变量的名称,遵循标准变量命名约定。
:
可选的;一般是整型常量或变量。
指定返回哪一维的上界。
1表示第一维,2表示第二维,如此等等。
如果省略默认是1。
7.4ForEach…Next语句
与For…Next语句类似,都是实现循环结构的语句。
但ForEach…Next语句是专用于数组和对象集合的。
其语法格式是:
ForEach成员In数组
循环体
[ExitFor]
…
Next成员
说明:
(1)成员:
为一个Variant变量,是为循环提供的,在ForEach…Next语句中代表数组中的每个元素,数组中有几个元素,此成员就重复使用几次,循环体就执行几遍。
(2)数组:
在此之前经过定义的数组,用在此处时仅仅是一个数组名,没有括号和上下界。
(3)ForEach…Next语句可以对数组元素进行读取、查询、输出等操作,它所重复执行的次数由数组中的元素个数决定。
此段ForEach…Next代码中因为数组Test有100个元素,循环体(Print语句)将执行100次,即要输出100次,但每次x的值都不同,x每次代表Test数组中的一个元素,所以这段代码的功能就是输出Test数组的所有元素。
(4)不能在ForEach…Next中使用用户自定义数据类型,因为Variant不能包含用户自定义类型。
例7-5产生100个100—999随机数,统计出能被7整除的数打印之。
OptionBase1
PrivateSubForm_Click()
Dimnums(1To100)AsInteger
Dimi,k,sAsInteger
Fori=1To100
nums(i)=Int(Rnd*900+100)
Nexti
ForEachkInnums
IfkMod7=0Then
s=s+1
Printk;
EndIf
Nextk
Print
Print"能被7整除的数据个数为:
";s
EndSub
7.5控件数组
1、控件数组的概念
一个窗体上可以包含多个同种类型的控件,可以通过创建控件数组的方法使同一类型的控件共享同一个事件过程。
使用控件数组的最大好处是编写的代码比较简单且易于维护。
控件数组:
是具有相同名称、类型以及事件过程的一组控件。
每一个控件具有一个唯一的索引(index)。
当数组中的一个控件识别某一事件时,它将调用此控件数组的相应事件过程,并把相应索引作为参数传递给事件过程。
一个控件数组至少应有一个元素,在控件数组中可用到的最大索引值为32767。
同一控件数组中的元素有自己的属性设置值。
2、控件数组的建立
控件数组中每一个元素都是控件,它的定义方式与普通数组不同。
可以通过以下两种方法建立控件数组。
方法一:
复制已有的控件并将其粘贴到窗体上。
方法二:
将窗体上已有的类型相同的多个控件的Name属性设置为同一值。
3、控件数组应用举例
建立了控件数组之后,控件数组中所有控件共享同一事件过程。
例如,假定某个控件数组含有10个标签,则不管单击哪个标签,系统都会调用同一个Click过程。
由于每个标签在程序中的作用不同,系统会将被单击的标签的Index属性值传递给过程,由事件过程根据不同的Index值执行不同的操作。
例7-6建立单选按钮数组,控制标签对齐方式。
PrivateSubOption1_Click(IndexAsInteger)
x=Index
SelectCasex
Case0
Label1.Alignment=0
Case1
Label1.Alignment=1
Case2
Label1.Alignment=2
EndSelect
EndSub
建立了控件数组之后,控件数组中所有控件共享同一事件过程。
例如,假定某个控件数组含有10个标签,则不管单击哪个标签,系统都会调用同一个Click过程。
由于每个标签在程序中的作用不同,系统会将被单击的标签的Index属性值传递给过程,由事件过程根据不同的Index值执行不同的操作。
。
7.6数组的应用
例7-7求数组中元素的最大最小值及其所在下标
设计思想:
该类问题实际上是完成数组的顺序查找,可以假设第一个元素为最大值,用Max保存该值,用L记录其位置1;从数组第二个元素开始,逐个与Max进行比较,直到数组的最后一个元素;一旦Max的值小于元素的值则将该元素值赋值给Max,同时将该元素所对应下标值赋值给L,最后输出Max和L。
OptionBase1
PrivateSubForm_Click()
Dima(1To20)AsInteger
Dimmax,min,maxl,minl,kAsInteger
Fori=1To20
a(i)=Int(Rnd*91+10)
Nexti
max=a
(1)
min=a
(1)
Fori=1To20
Printa(i);
Ifmaxmax=a(i)
maxl=i
ElseIfmin>a(i)Then
min=a(i)
minl=i
EndIf
Nexti
Print
Print"max=";max;"min=";min;"maxl=";maxl;"minl=";minl
EndSub
OptionBase1
PrivateSubForm_Click()
Dima(1To20)AsInteger
Dimmax,X,min,maxl,minl,kAsInteger
Fori=1To20
a(i)=Int(Rnd*91+10)
Nexti
max=a
(1)
min=a
(1)
ForEachXIna
PrintX;
Ifmaxmax=X
maxl=i
ElseIfmin>XThen
min=X
minl=i
EndIf
NextX
Print
Print"max=";max;"min=";min;"maxl=";maxl;"minl=";minl
EndSub
例7-8数组元素倒置
设计思想:
该类问题实际上将第1个元素和第n个元素交换,第I个元素和第n-I+1个元素交换,交换次数为n\2次。
PrivateSubForm_Click()
Dima(1To10)AsInteger
DimtempAsInteger,iAsInteger
Fori=1To10
a(i)=Int(Rnd*91+10)
Nexti
Print"交换前为:
"
ForEachkIna
Printk;
Nextk
Print
Fori=1To5
temp=a(i):
a(i)=a(11-i):
a(11-i)=temp
Nexti
Print"交换后为:
"
ForEachkIna
Printk;
Nextk
Print
EndSub
例7-9排序问题
数据的排序就是将一批数据由小到大(升序)或由大到小(降序)进行排列。
常用的有选择法、冒泡法。
(1)冒泡法排序:
v冒泡排序是常用的一种排序方法。
假设n个元素按递增的顺序排序,排序思想为:
v第一轮:
从数组的第一项开始,每一项(i)都与下一项(i+1)进行比较。
如果下一项的值较小,就将这两项的位置交换,直到最后第n-1与第n项进行比较,将最大的数排列在最后。
v第二轮:
从数组的第一项开始,每一项(i)都与下一项(i+1)进行比较。
如果下一项的值较小,就将这两项的位置交换,直到最后第n-2与第n-1项进行比较,将第二大的数排列在倒数第二位。
v依此类推,直到只有第一项与第二项进行比较交换,完成递增法排序。
(1)冒泡法排序(升序)程序:
Fori=1Ton-1
Forj=1Ton-i
Ifa(j)>a(j+1)Then
t=a(j)
a(j)=a(j+1)
a(j+1)=t
Endif
Nextj
Nexti
(2)选择法排序(升序):
v选择法排序是最为简单且易理解的算法,其基本思想是每次将最小(或最大)的数找出来放在序列的最前面。
假设按递增法将有n个数的数组A(1Ton)进行排列,步骤为:
(1)假定最小值Temp,将Temp与A
(2)进行比较,若A
(2)(1),则令Temp=A
(2),直到比较到A(n),这样Temp中就存放了A
(1)~A(n)中的最小数,将Temp所指向的元素与A
(1)进行交换,从而将A
(1)~A(n)中的最小数存放在数组的第1个位置。
(2)对除第1个数外的其余n-1个数再按步骤
(1)的方法选出次小的数,与第2个数交换位置。
(3)依次类推,经过n-1遍后构成递增序列。
v若要按递减次序排列,只要每次选最大的数即
选择法排序(升序)的程序:
Fori=1Ton-1
p=i
Forj=i+1Ton
Ifa(p)>a(j)Thenp=j
Nextj
t=a(i):
a(i)=a(p):
a(p)=t
Nexti
OptionBase1
PrivateSubCommand1_Click()
ConstN=10
Dima(N)AsInteger
Dimi,j,p,tempAsInteger
RandomizeTimer
Fori=1ToN
a(i)=Int(Rnd*91+10)
Nexti
Fori=1ToN-1
k=i
Forj=i+1ToN
Ifa(k)Nextj
temp=a(i)
a(i)=a(k)
a(k)=temp
Nexti
Fori=1ToN
Printa(i);
Nexti
EndSub
PrivateSubCommand2_Click()
ConstN=10
Dima(N)AsInteger
Dimi,j,p,tempAsInteger
RandomizeTimer
Fori=1ToN
a(i)=Int(Rnd*91+10)
Nexti
Fori=1ToN-1
Forj=1ToN-i
Ifa(j)>a(j+1)Then
temp=a(j)
a(j)=a(j+1)
a(j+1)=temp