第五篇数组.docx
《第五篇数组.docx》由会员分享,可在线阅读,更多相关《第五篇数组.docx(22页珍藏版)》请在冰豆网上搜索。
第五篇数组
第五章数组
5.1数组的概念
数组是同类变量的有序集合
数组中的变量称为数组元素
不同的数组元素以不同的下标来区别,又称为下标变量
描述一数组中元素所需要的下标个数,称为数组的维数
如:
矩阵(二维)、双层汽车(三维)、时空结合:
层、行、列、时间(四维)
层、行、列、时间、日期(五维)
1.引例
2.
若我们要求一个班100个学生的平均成绩,然后统计高于平均分的人数。
按以前简单变量的使用和循环结构相结合,求平均成绩程序段如下:
aver=0
Fori=1To100
mark=InputBox("输入"+i+"位学生的成绩")
aver=aver+mark
Nexti
aver=aver/100
但若要统计高于平均分的人数,则无法实现。
mark是一个简单变量,存放的是最后一个学生的成绩。
已有知识解决方法:
再重复输入成绩,带来两个问题:
(1)输入数据的工作量成倍增加;
(2)若本次输入的成绩与上次不同,则统计的结果不正确。
解决此问题的根本方法,引入数组,始终保持输入的数据,一次输入,多次使用。
5.2静态数组及声明
由于数组在内存中要占用大量连续的存储单元,在使用数组前,必须说明数组的名类型和容量(维数大小),以便系统分配内存单元
数组不是一种数据类型,而是一组相同类型的变量的集合,数组必须先声明后使用。
两类数组:
·静态(定长)数组:
数组声明时指明维数和每一维的下标范围,在使用中,维数和下标范围不得改变
·动态数组:
数组声明时不指明维数和每一维的下标范围,仅用一对圆括号表示,可用REDIM语句对数组的维数和下标范围重新声明
1.静态数组及声明
形式:
Dim数组名(下标1[,下标2…])[As类型]
功能:
声明了数组的名、维数、大小、类型
维数:
几个下标为几维数组,最多60维。
下标:
[下界To]上界省略下界为0,必须为常数。
每一维大小:
上界-下界+1
数组大小:
每一维大小的乘积
界说明格式:
[下界to]上界,省略下界,缺省为0
注:
数组大小(元素个数)=每维元素数的乘积
每维元素数=上界-下界+1
如:
DIMYEAR(1900TO2010)ASINTEGER
DIMX(3TO5,7TO8)ASSTRING
DIMA(10)ASINTEGER
DIMB(2,3,1TO10)ASINTEGER(100个元素)
二维数组在内存连续存储区域中的排列采用行优先的原则
如:
X(3,7)、X(3,8)、X(4,7)、X(4,8)、X(5,7)、X(5,8)
例:
Dimmark(1to100)AsInteger
DimlArray(0To3,0To4)AsLong共有4×5个元素
等价于:
DimlArray(3,4)AsLong
注意:
(1)下界缺省为0,也可在重新定义数组的下界。
例如:
OptionBase1
(2)错误的声明,下标是变量
n=Inputbox(“输入n”):
Dimx(n)AsSingle
(3)在数组声明中的下标说明了数组的整体,即每维的大小;而在程序其他地方出现的下标表示数组中的一个元素。
两者写法形式相同,但意义不同。
例如:
Dimx(10)AsInteger'声明了x数组有11个元素
x(10)=100'对x(10)这个数组元素赋值
5.3动态数组及声明
动态数组指在声明数组时未给出数组的大小(省略括号中的下标),当要使用它时,随时用ReDim语句重新指出数组大小。
形式:
ReDim数组名(下标[,下标2…])[As类型]
例SubForm_Load()
Dimx()AsSingle
求若干个学生的平均分。
…
n=Inputbox(“输入n”)
ReDimx(n)
…
EndSub
说明:
•Dim、Private、Public变量声明语句是说明性语句,可出现在过程内或通用声明段;ReDim语句是执行语句,只能出现在过程内。
•在过程中可多次使用ReDim来改变数组的大小和维数。
•使用ReDim语句会使原来数组中的值丢失,可以在ReDim语句后加Preserve参数来保留数组中的数据。
使用Preserve只能改变最后一维的大小,前面几维大小不能改变。
ReDim中的下标可以是常量,也可以是有了确定值的变量。
•静态数组在程序编译时分配存储单元,动态数组在运行时分配存储单元。
如:
ReDimPreserveTestArr(Ubound(TestArr)+1)
ReDimPreserveThreeD(10,10,Ubound(ThreeD,3)+1)
OPTIONBASE语句
格式:
OptionBase1
如果缺省说明语句数组下标的下界,则系统默论的下标下界是0,但在实际使用数组时,很多人希望数组下标的下界从1开始,使用OptionBase语句,即可在窗体或标准模块中,将数组下标的缺省值下界设置为1。
该语句必须写在窗体或标准模块的所有过程之前,一个模块中只能出现一次OptionBase,且必须位于带维数的数组说明语句之前。
该语句将使模块中所有缺省说明下标下界为1。
5.4数组的基本操作
1.数组元素的赋初值
(1)用循环
Fori=1To10
iA(i)=0
Nexti
2)Array函数
DimibAsVariant
ib=Array("abc","def","67")
Fori=0ToUBound(ib)
Picture1.Printib(i);"";
Nexti
注意:
•利用Array对数组各元素赋值,声明的数组是可调数组或连圆括号都可省,并且其类型只能是Variant。
•数组的下阶为零,上界由Array函数括号内的参数个数可决定,也可通过函数Ubound获得。
2.数组的赋值
在VB6.0中,提供了数组直接对数组的赋值。
例如:
Dima()AsVariant,b()AsVariant,i%
a=Array(1,2,3,4,5)
ReDimb(UBound(a))
b=a
3.数组的输出
输出方阵sC中的下三角元素
Fori=0To4
Forj=0Toi
sc(i,j)=i*5+j
Printsc(i,j);"";
Nextj
Print'换行
NextI
4.求数组中最大元素及所在下标
DimMaxAsInteger,iMaxAsInteger
Max=iA
(1):
iMax=1
Fori=2To10
IfiA(i)>MaxThen
Max=iA(i)
iMax=i
EndIf
NextI
5.将数组中各元素交换
Fori=1To10\2
t=iA(i)
iA(i)=iA(10-i+1)
iA(10-i+1)=t
NextI
5.5控件数组
在一个窗体内可以包含多个同种类型的控件,比如:
有多个文本框,多个命令按钮等。
用户可以分别为这些同一类型的控件类对象命名,并编写响应不同事件的时间过程。
但用户也可以通过创建一个控件数组的方法使同一类型的控件共享同一事件过程。
一组相同类型的控件组成。
它们共用一个控件名,具有相同的属性,建立时系统给每个元素赋一个唯一的索引号(Index)。
控件数组共享同样的事件过程,通过返回的下标值区分控件数组中的各个元素。
例:
PrivateSubcmdName_Click(IndexAsInteger)
…
IfIndex=3then
‘处理第四个命令按钮的操作
EndIf
…
EndSub
1.在设计时建立控件数组
在窗体上画出控件,进行属性设置,这是建立的第一个元素
选中该控件,进行“Copy”进行若干次和“Paste”操作建立了所需个数的控件数组元素。
进行事件过程的编程。
2运行时添加控件数组
建立的步骤如下:
在窗体上画出某控件,设置该控件的Index值为0,表示该控件为数组,这是建立的第一个元素。
在编程时通过Load方法添加其余的若干个元素,也可以通过Unload方法删除某个添加的元素
格式:
LOAD控件数组对象名(index)
格式:
UNLOAD控件数组对象名(index)
每个新添加的控件数组通过Left和Top属性确定其在窗体的位置,并将Visible属性设置为True。
5.6自定义数据类型
一组不同类型变量的集合。
相当于C语言中的结构类型;Pascal中的记录类型。
1.自定义类型的定义
形式如下:
Type自定义类型名
元素名[(下标)]As类型名
…
[元素名[(下标)]As类型名]
EndType
例如,以下定义了一个有关学生信息的自定义类型:
TypeStudType
NoAsInteger'学号
NameAsString*20'姓名
SexAsString*1'性别
Mark(1To4)AsSingle'4门课程成绩
TotalAsSingle'总分
EndType
注意:
(1)自定义类型一般在标准模块(.BAS)中定义,默认是Public;在窗体必须是Private。
(2)自定义类型中的元素类型可以是字符串,但应是定长字符串。
(3)不要将自定义类型名和该类型的变量名混淆,前者表示了如同Integer、Single等的类型名,后者VB根据变量的类型分配所需的内存空间,存贮数据。
(4)自定义类型一般和数组结合使用,简化程序的编写。
2.自定义类型变量的声明和使用
(1)声明形式:
Dim变量名As自定义类型名
例DimStudentAsStudType
(2)引用
形式:
变量名.元素名
例表示Student变量中的姓名,第4门课程的成绩,则表示如下:
Student.Name,Student.Mark(4)
3.自定义类型数组的应用
利用自定义类型数组,编写一个输入、显示、查询程序。
5.7常用算法
(二)
1.统计
输入一串字符,统计各字母出现的次数,不区分字母大小写。
分析:
统计26个字母出现的个数,先声明一个具有26个元素的数组,每个元素的下标表示对应的字母,元素的值表示对应字母出现的次数。
从输入的字符串中逐一取出字符,转换成大写字符(不区分大小写),进行判断。
运行界面:
ForI=1Tole
c=UCase(Mid(Text1,I,1))
Ifc>="A"Andc<="Z"Then
j=Asc(c)-65+1
a(j)=a(j)+1
EndIf
NextI
2.大量数据的输入
输入一系列的数据,并将它们分离后存放在数组中。
对输入的数据允许修改和自动识别非数字数据。
分析:
(1)利用文本框输入和编辑数据,输入时去除非法数字。
(2)输入结束利用Rplace函数去除重复输入的分隔符;
(3)对利用Split函数按分隔符分离,放到数组中;
(4)还可利用Join函数将数组中各元素合并成一个字符串
3.数组排序(选择法)
数据排序(升序、降序)的主要操作:
数据比较、数据移动
排序前的数据是一序列,排序后的数据又形成新的序列。
因此,处理排序的合理数据结构是数组
(1)选择排序(SelectionSort)
选择排序的基本算法:
在所有未排序序列的数据中选择最小元素作为已排序子序列,再重复地从未排序子序列中选择最小元素,将其加入到已排序的序列,作为已排序子序列的最后一个元素,直到将未排序子序列中元素处理完毕。
A
(1)A
(2)…………A(n)
第1次选择:
A’
(1)使A’
(1)是A
(1)A
(2)…………A(n)的最小数
第2次选择:
A’
(1)A’
(2)使A’
(2)是A
(2)A(3)…………A(n)的最小数
………………………………………………………………………………………………………
第n-1次选择:
A’
(1)A’
(2)……A’(n-1)使A’(n-1)是A(n-1)A(n)的最小数
直接选择排序每一趟经过比较挑选出最小值,n个数的序列共需要n-1趟排序,因此可用两重循环实现。
例:
OptionBase1
PublicSubSORT(A()AsInteger)
DimIAsInteger,JAsInteger,TEMPAsInteger
ForI=1ToUBound(A)-1
ForJ=I+1ToUBound(A)
IfA(I)>A(J)Then
TEMP=A(I)
A(I)=A(J)
A(J)=TEMP
EndIf
NextJ
NextI
EndSub
PrivateSubForm_Click()
DimX(10)AsInteger
DimIAsInteger
Randomize
Print
ForI=1To10
X(I)=Int(90*Rnd+10)
NextI
CallSORT(X)
ForI=1To10
PrintX(I);
NextI
EndSub
优化的选择排序:
交换两个数据,效率低
设一个指针P,先让它指向未排序的第一个元素,然后使该变量的值是未排序中的最小元素的下标值(即指针指向最小元素),若指针指向的不是当前未排序中的第一个数,则将指针指向的元素与之交换,使它加入已排序子序列的最后一元素。
PublicSubSORT(A()AsInteger)
DimIAsInteger,JAsInteger,TEMPAsInteger,pAsInteger
ForI=1ToUBound(A)-1
p=I
ForJ=I+1ToUBound(A)
IfA(p)>A(J)Thenp=J
NextJ
IfI<>pThen
TEMP=A(I)
A(I)=A(p)
A(p)=TEMP
EndIf
NextI
EndSub
对已知存放在数组中的n个数,用选择法按递增顺序排序。
(1)从n个数的序列中选出最小的数(递增),与第1个数交换位置;
(2)除第1个数外,其余n-1个数再按
(1)的方法选出次小的数,与第2个数交换位置;
(3)重复
(1)n-1遍,最后构成递增序列。
Fori=1Ton-1
iMin=i
Forj=i+1Ton
IfiA(j)Nextj
t=iA(i):
iA(i)=iA(iMin):
iA(iMin)=t
NextI
(2)交换排序(BubbleSort)冒泡排序
交换排序算法:
一组放在A
(1),A
(2),...A(n)中。
比较未排序序列中的相邻两个数据,若是逆序,则交换他们的位置,否则比较下一对数据,直到全部数据排好为止。
这一轮比较交换过程称为一次起泡,使最大数落在最后。
A
(1)≤A
(2)不动
如果接着比较A
(2)(新)和A(3)……
A
(1)>A
(2)A
(1)和A
(2)交换
轮次比较交换次数
第1轮n-1次使A
(1),A
(2),...A(n)最大数移到A(n)
第2轮n-2次使A
(1),A
(2),...A(n-1)最大数移到A(n-1)
……………………………………………………………………………………
第n-1轮1次使A
(1),A
(2)最大数移到A
(2)
程序:
OptionBase1
PublicSubSORT(A()AsInteger)
DimIAsInteger,JAsInteger,TEMPAsInteger,pAsInteger
ForI=1ToUBound(A)-1
ForJ=1ToUBound(A)-I
IfA(J)>A(J+1)Then
TEMP=A(J)
A(J)=A(J+1)
A(J+1)=TEMP
EndIf
NextJ
NextI
EndSub
PrivateSubForm_Click()
DimX(10)AsInteger
DimIAsInteger
Randomize
Print
ForI=1To10
X(I)=Int(90*Rnd+10)
NextI
CallSORT(X)
ForI=1To10
PrintX(I);
NextI
EndSub
选择法排序在每一轮排序时找最小(递增次序)数的下标,出了内循环(一轮排序结束),再交换最小数的位置;而冒泡法排序在每一轮排序时只要将第一个与其它几个比较,只要次序不对,就交换,出了内循环,最小数已冒出。
排序进行的过程见下表。
Fori=1Ton-1'进行n-1轮比较
Forj=i+1Ton'从n~i个元素进行两两比较
IfiA(j)t=iA(j):
iA(j)=iA(i):
iA(i)=t
EndIf
Nextj'出了内循环,一轮排序结束,最小数已冒到最上面
Nexti
(3)插入排序(InsertionSort)
插入排序算法:
将未排序的数据按一定的规则逐一插入到已排序序列中的合适位置,直到将全部均插入为止。
A
(1),A
(2),...A(n)
将A
(1)看成一有序列,将A
(2),A(3),...A(n)看成一无序列。
以后每次从无序列中取第一个数(即有序列后的一个数),将其插入到有序列的合适位置,使之仍为一有序列,每进行一次,有序列增加一个数,无序列减少一个数。
重复n-1次,无序列为空列,有序列为n个数。
如何将无序列的第一个数A(I)(I=2、3……n)插入到有序列中?
|←…………………………有序列……………………………………→|←……无序列……→|
A
(1)
A
(2)
……
A(J)
A(J+1)
……
A(I-2)
A(I-1)
A(I)
……
A(n)
X
首先将A(I)与有序列中的最后一个数A(I-1)比较
(1)若A(I)≥A(I-1)则A
(1),A
(2),...A(I)构成新的有序列
(2)若A(I)<A(I-1)则继续同A(I-2)比较,依此类推,直到A(I)≥A(J)(A(J)为有序列中的一个数),此时将A(J+1)到A(I-1)之间的数依次向后移动一个单元,将A(I)放入A(J+1)中,使A
(1),A
(2),...A(I)构成新的有序列
程序:
'OptionBase1
PublicSubSORT(A()AsInteger)
DimIAsInteger,JAsInteger,TEMPAsInteger,pAsInteger
DimXAsInteger
ForI=2ToUBound(A)
X=A(I)'将插入位置和后移同时进行
J=I-1'从J=I-1开始向前测试A(J)
DoWhileX0
A(J+1)=A(J)'若A(J)>X则A(J)→A(J+1),
J=J-1'再测试前一个数,直到找到J,使X>A(J)再将X→A(J+1)
Loop
A(J+1)=X'将X插入到合适位置
NextI
EndSub
PrivateSubForm_Click()
DimX(10)AsInteger
DimIAsInteger
Randomize
Print
ForI=1To10
X(I)=Int(90*Rnd+10)
NextI
CallSORT(X)
ForI=1To10
PrintX(I);
NextI
EndSub
4.数组元素的插入与删除
(1)插入
在有序数组a(1ton)(原有n-1个元素)插入一个值Key元素,算法:
•查找要插入的位置k(1<=k<=n-1)
•腾出位置,把最后一个元素开始到第K个元素往后移动一个位置
•第k个元素的位置腾出,就可将数据Key插入
(2)删除
要找到欲删除的元素的位置k;然后从k+1到n个位置开始向前移动;最后将数组元素减1。
5.数组元素的检索
数据检索:
从一组数据中查找需要的数据
(1)顺序检索
顺序检索算法:
从一组数据的第一个开始逐个比较,直到找到该数据或能确定全部数据中没有要检索的数据。
程序:
PrivateSubForm_Click()
DimSEARCH(10)AsInteger
DimIAsInteger,XAsInteger
Randomize
ForI=1To10
SEARCH(I)=Int(Rnd*100+1)
NextI
X=Val(InputBox("INPUTADATA:
"))
ForI=1To10
IfSEARCH(I)=XThenExitFor
NextI
IfI<=10Then
Print"DATAISSEARCH(";I;")"
Else
Print"NOFIND!
"
EndIf
EndSub
(2)二分检索(拆半查找)
如被检索的数据是一组按某顺序排列的有序数,可采用效率较高的二分检索法。
设A
(1),A
(2),...A(n)按升序已排好序
LOW代表检索区间的首部:
设初值LOW=1
HIGH代表检索区间的尾部:
设初值HIGH=n
MID代表检索区间的中部:
设初值MID=INT((LOW+HIGH)/2)
设要检索的数据为X,利用MID将原有序列分成三个有序序列:
A(LOW),A
(2),...A(MID-1)
A(MID)
A(MID+1),A(MID+2),...A(HIGH)
(1)如果A(MID)=X则检索结束
(2)如果X>A(MID)则表明X可能在A(MID+1),A(MID+2),...A(HIGH)序列中