• 沒有找到結果。

图 6-17 例 6.11 的运行结果

说明:程序运行时,用户可以在组合框的列表框部分选择学生所在的系,也可以在文本 框部分输入项目列表中未列出的系。如果用户在“爱好”列表框中双击一个项目,则“已选爱 好”列表框中将自动出现该项目,表示用户选中了某个爱好。如果用户在“已选爱好”列表框 中双击一个项目,则该项目将自动消失,表示用户放弃了对某个爱好的选择。

该程序有许多需要完善的地方。例如用户在“爱好”列表框中反复双击同一个项目,则 该项目就会多次出现在“已选爱好”列表框中,造成对爱好的重复选择。解决方法是在向“已 选爱好”列表框中添加项目之前,先判断其中是否已存在该项目。如果是新项目就可以添加,

否则不予添加。部分代码如下:

Private Sub List1_DblClick()

Dim s As String, flag As Boolean, i%

s = List1.Text '从 List1 得到选中的项目 flag = False

For i = 0 To List2.ListCount - 1

If s = List2.List(i) Then '在 List2 中查找该项目 flag = True

Exit For End If Next i

If Not flag Then '所选项目是以前未选过的项目 List2.AddItem s '将该项目添加到 List2 中 End If

End Sub

思考:如果只安排一个“爱好”列表框,而没有“已选爱好”列表框,并且把列表框控 件的 MultiSelect 属性值设置为 1,即允许多选。此时应如何编写程序,使得可以显示用户在“爱 好”列表框中选择的多个项目?

6.9 程序举例

【例 6.12】采用选择排序法对 n 个整数按升序排序。

分析:在前面的章节中多次提到并利用了选择排序法,现在彻底阐明以及实现这个算法。

选择排序算法的基本思想是,在每一轮里把该轮第一个数与后面的数依次比较,如果第一个数

Private Sub Command1_Click()

Dim a() As Integer, n As Integer, i%, j%, t%

n = Val(Text1.Text) ReDim a(1 To n) For i = 1 To n

a(i) = Val(InputBox("请输入第" & i & "个数")) Next i

Picture1.Print "输出原数列"

j = 0

For i = 1 To n '输出原数列 Picture1.Print Tab(j * 6); a(i);

j = j + 1

If i Mod 5 = 0 Then Picture1.Print j = 0

t = a(i) 'a(i)与 a(j)交换 a(i) = a(j)

a(j) = t End If Next j Next i

Picture1.Print "输出排序之后的数列"

j = 0

For i = 1 To n '输出排序之后的数列 Picture1.Print Tab(j * 6); a(i);

j = j + 1

If i Mod 5 = 0 Then Picture1.Print j = 0

End If Next i End Sub

Private Sub Command2_Click() End

End Sub

运行程序,结果如图 6-18 所示。

图 6-18 例 6.12 的运行结果

说明:从提高程序的运行效率来看,每一轮中第一个数可以先不与后面的数交换,而是 定义一个标志 min 用来记录当前最小数的下标。在该轮结束后,第一个数再与该轮最小的数 交换。于是循环语句变为:

For i = 1 To n - 1 min=i

For j = i + 1 To n If a(min) > a(j) Then

min=j '记录当前最小数的下标

End If Next j

If i<>min Then '如果 a(i)就是当前最小数,则不必交换 t = a(i) 'a(i)与 a(min)交换

a(i) = a(min) a(min) = t

End If

例如有数列:[-5,-2,1,5,10,21,37,49,82],要查找的数是 37。首先选定中间数 10,由于 37>10,

因此下次查找范围应该在右半区即[21,37,49,82]。需要指出的是,本次的中间位置的数可以从 下次的查找范围中排除。在数列[21,37,49,82]中选定中间数 37,经过比较,判定查找成功。如 果查找范围不断缩小,最后仍未找到,则判定查找失败。

编程实现时,首先应定义一个动态整型数组 a 用来存放数列。其次应定义 3 个指示器 low、

mid 和 high,用来指示查找范围。其中 low 指示查找范围的第一个数,high 指示查找范围的最 后一个数,mid 指示查找范围的中间数,mid=(low+high)/2。在循环结构中判断要查找的数 m 与 mid 所指示的中间数 a(mid)是否相等,如果相等则查找成功;如果 m 小于 a(mid),说明查 找范围缩小为左半区,则 low 不变,high 变为 mid-1;如果 m 大于 a(mid),说明查找范围缩小 为右半区,则 low 变为 mid+1,high 不变;如果 low>high,则说明查找范围失效,查找失败。

Private Sub Command1_Click() Dim a() As Integer, i%, j%, m%, n%

Dim flag As Boolean, low%, high%, mid%

n = Val(Text1.Text) ReDim a(1 To n) For i = 1 To n

a(i) = Val(InputBox("请输入第" & i & "个数")) Next i

Picture1.Print "输出数列"

j = 0

For i = 1 To n '输出数列 Picture1.Print Tab(j * 6); a(i);

j = j + 1

If i Mod 5 = 0 Then Picture1.Print j = 0

Do While low <= high

mid = (low + high)/2 '计算中间数的位置 If a(mid) = m Then '中间数与 m 比较 flag = True '查找成功 Exit Do

ElseIf a(mid) > m Then

high = mid - 1 '查找范围缩小为左半区 Else

low = mid + 1 '查找范围缩小为右半区 End If

Loop

If flag = True Then '判断查找标志 Picture1.Print "找到"; m

Else

Picture1.Print "没有找到"; m End If

j = MsgBox("还要继续查询吗?", vbYesNo + vbquestin) Loop While j = 6

End Sub

Private Sub Command2_Click() End

End Sub

运行程序,结果如图 6-19 所示。

图 6-19 例 6.13 的运行结果

【例 6.14】判断用户输入的文本是否为回文。如果一个文本的逆序与原文完全相同,这 样的文本就称为回文,例如“level”、“2002”和“我是我”等。

分析:定义一个字符串变量 s,存放输入的文本。其次定义 2 个指示器 left 和 right,left 初始指示文本的第一个字符,right 初始指示文本的最后一个字符。在循环结构中反复判断 left 和 right 各自指示的字符是否相同,如果不同,显然不是回文;如果相同,则 left 不断加 1 向 右移动,而 right 不断减 1 向左移动。

Private Sub Command1_Click()

Dim s As String, left%, right%, flag As Boolean s = Text1.Text

left = 1

right = Len(s) flag = True

Do While left < right

If mid(s, left, 1) <> mid(s, right, 1) Then flag = False

Exit Do End If

left = left + 1 right = right - 1 Loop

If flag = True Then s = s + "是回文"

Else

s = s + "不是回文"

End If

Picture1.Print s End Sub

Private Sub Command2_Click() End

End Sub

运行程序,结果如图 6-20 所示。

图 6-20 例 6.14 的运行结果 说明:将在第 7 章给出判断回文的递归解法。

【例 6.15】Josephus 环问题。n 个孩子围成一圈,任意假定一个数 m。从第一个孩子开始,

以顺时针方向数,每数到第 m 个孩子时,他就离开这个圈子。孩子不断离开,圈子不断缩小,

最后剩下的一个孩子便是胜利者。请计算出胜利者的序号。

分析:显然要定义一个动态整型数组 a,存放这些孩子的序号,数组的长度就是孩子的个 数 n。该问题有两个难点需要解决。首先孩子是围成一个圈的,而数组元素是顺序排列的,表 达了一种线性的逻辑结构。如何在数到数组的末尾时,跳到数组的头部继续往下数?这可以通 过对元素下标求余加 1 的技巧解决,当数到数组尾部时,下一个数组元素的下标通过先对 n 求余再加 1,算得为 1,从而回到数组首部继续往下数。

其次是如何表示孩子离开圈子?当孩子离开圈子时,将数组 a 中与其对应的元素值(序号)

置为 0,表示这个孩子已离开圈子。这样继续数时如果发现这个孩子对应的数组元素值为 0,

说明他已出圈,就跳过此人不数。

Private Sub Command1_Click()

Dim a() As Integer, i%, j%, k%, m%, n%

n = Val(Text1.Text) ReDim a(1 To n) For i = 1 To n

a(i) = i '设置小孩序号 Next i

m = Val(InputBox("请输入 m")) j = 0

For i = 1 To n – 1 'n-1 个孩子出圈 k = 1 '从 1 开始数

Do While k <= m '数 m 个数 j = j Mod n + 1 '下标后移 If a(j) <> 0 Then

k = k + 1 End If Loop

Picture1.Print a(j); "号孩子出圈" '显示出圈的孩子 a(j) = 0 '孩子出圈

Next i

For i = 1 To n

If a(i) <> 0 Then '找到胜利者 Exit For

End If Next i

Picture1.Print "胜利者是"; a(i); "号孩子" '显示胜利者 End Sub

Private Sub Command2_Click() End

End Sub

运行程序,结果如图 6-21 所示。

图 6-21 例 6.15 的运行结果

说明:n-1 个孩子出圈之后,在数组 a 中只有一个元素的值不为 0,该元素就对应于胜利 者,元素的值则为胜利者的序号。在循环语句中不断地判断数组 a 元素的值是否不为 0,即可

找到胜利者。

Private Sub Command1_Click() Dim a() As Integer, n%, i%, j%, k%

n = Val(Text1.Text) ReDim a(1 To n, 1 To n)

Picture1.Print Next i

End Sub

Private Sub Command2_Click() End

End Sub

运行程序,结果如图 6-22 所示。

图 6-22 例 6.16 的运行结果

6.10 小结

本章主要讲解了一维数组、二维数组、动态数组以及字符串的处理方法。数组是同类型 相关数据的集合,它由一些元素组成。每一个元素可以存放一个数据,下标表示元素在数组中 的相对位置。通过循环结构可以对数组的元素进行统一的输入、输出和处理,其中循环控制变 量控制元素的下标从下界移动到上界。一般说来,对一维数组的处理应采用一重循环,对二维 数组的处理应采用二重循环。

动态数组的维数和长度可以用 ReDim 语句重新进行设置,但是数组的类型不能改变。如 果重新设置动态数组时使用了关键字 Preserve,则可以保留元素的值。记录类型是程序员自定 义的一种类型,它由一些基本类型的成员所组成,定义记录类型的关键字是 Type。字符串中 的各个字符之间存在着较为明显的位置关系,其处理方法与数组有一些相似之处。VB 语言提 供了很多字符串处理函数,常用的有 Len 函数、InStr 函数、Replace 函数和 Mid 函数等,分别 用于实现字符串的统计长度、查找、替换和截取等操作。

控件数组能够统一地组织和管理一批同属一类的控件,它们共用一个对象名。通过控件 对象的 Index 属性,可以实现对控件数组中任意一个控件元素的访问。列表框控件以项目列表 的形式显示数据,可以供用户进行选择,实现数据输入的标准化。组合框控件同时具有文本框 和列表框的一些特性,它在界面上显示时比列表框节省空间。组合框不仅可以接受标准化数据,

也可以接受用户在文本框部分输入的数据,具有很好的灵活性。列表框控件和组合框控件重要 的属性是 List、ListIndex、Text 和 Selected,重要的方法是 AddItem、RemoveItem 和 Clear。

此外,在案例程序中还介绍了选择排序和折半查找等常用算法,并对这些算法的原理以 及实现方法做了详细的分析。

习题

1.有数组定义语句 Dim a(7,-2 To 3) As Integer,数组 a 有多少个元素?

2.写出单击窗体后,下列程序段的运行结果。

Private Sub Form_Click()

Dim a(3, 5) As Integer, i As Integer, j As Integer For i = 1 To 3

For j = 1 To 5

a(i, j) = a(i - 1, j - 1) + i + j Next j

Next i

Print a(3, 4) End Sub

3.将一个长度为 10 的数列头尾颠倒,例如该数列原先为[1,2,3,4,5,6,7,8,9,10],处理后变 为[10,9,8,7,6,5,4,3,2,1]。

4.编写一个模拟掷骰子的程序,要求统计掷 100 次后骰子上各点出现的次数。

5.计算一个 4×4 矩阵的两个对角线之和。

6.完成一个 3×3 矩阵的转置(即行列互换)。

7.输入一个 3×3 矩阵各元素的值,找出每一行最大的数。

8.将一个字符串翻转,例如把字符串“abcd”翻转为“dcba”。

9.把两个已按升序排列的数列合并为一个新数列,该数列仍按升序排列。例如数列 a 是 [1,3,6,7,9],数列 b 是[2,4,5,8,10],合并之后的新数列是[1,2,3,4,5,6,7,8,9,10]。

10.把一个数插入到一个已按升序排列的数列 a 中,并使该数列仍按升序排列。例如数列 a 是[1,3,6,8,9,10],要插入的数是 4,合并之后的新数列是[1,3,4,6,8,9,10]。

11.输入一个句子,找出其中最长的单词。

12.找出一个 4×4 矩阵中的“鞍点”。所谓鞍点是指它在本行中的值最大,在本列中的 值最小。输出鞍点的行号和列号,如果找不到鞍点,则输出“no found”。

13.某班有学生 30 人,学习语文、数学和英语 3 门课程。输入所有学生各门课程的成绩,

输出单科成绩的最高分以及该班每门课的平均成绩。

14.输出魔方阵。所谓魔方阵,是指由自然数 1~n2(n 为奇数)组成的方阵,其各行、

14.输出魔方阵。所谓魔方阵,是指由自然数 1~n2(n 为奇数)组成的方阵,其各行、

相關文件