VBA进阶:基础扩展17. 链表

链表是一种基本的数据结构。在C语言中,由于具有指针特性,因此很容易实现链表结构。在节点中存储数据和指针,使用指针指向下一个元素的地址,形成链表,如下图1所示。

图1

在VBA中,使用类模块,也可以实现链表结构。下面,以实现顺序链表为例来讲解如何使用VBA代码创建链表。

在VBE中,先插入两个类模块:ListItem类模块和List类模块。其中,ListItem类模块用于存放链表节点中的数据和指向下一个元素的指针;List类模块用于实现链表节点的添加、删除、遍历等操作。

ListItem类模块

ListItem类模块包含节点的数据值和指向下一节点的指针:

'节点元素值
Public Value As Variant
'指向下一个节点元素的指针
Public NextItem As ListItem

List类模块

List类模块中,声明了一个表示头节点的变量ListHead;包含3个方法:Add方法用来添加节点元素,Delete方向用来删除节点元素,ListAllItem方法遍历节点中所有元素;还有一个Find函数,用来查找值并确定是否将给定元素添加到相应位置或者是否删除给定元素。

首先,在模块开头声明表示头节点的变量:

'头节点
Dim ListHead As ListItem

Find函数

Function Find(ByVal varItem As Variant, _
    ByRef listCurrent AsListItem, _
    ByRef listPrevious AsListItem) As Boolean
    Dim bFound As Boolean
    '初始化当前节点为头节点
    bFound = False
    Set listPrevious =Nothing
    Set listCurrent =ListHead
    '链表不为空则循环
    Do While Not listCurrent Is Nothing
        '查找给定的值,如果当前值不是,则后移
        With listCurrent
            If varItem >.Value Then
                Set listPrevious = listCurrent
                Set listCurrent = .NextItem
            Else
                Exit Do
            End If
        End With
    Loop
    '如果找到,则返回True
    If Not listCurrent Is Nothing Then
        bFound =(listCurrent.Value = varItem)
    End If
    Find = bFound
End Function

假设要在已有链表中查找值5,下图2演示了Find函数的查找过程。

图2

Add方法

'添加节点元素
Public Sub Add(varValue As Variant)
    Dim listNew As NewListItem
    Dim listCurrent AsListItem
    Dim listPrevious AsListItem
    '新元素值
    listNew.Value = varValue
    '调用Find函数确定新元素位置
    Call Find(varValue,listCurrent, listPrevious)
    '如果链表存在节点,则将新元素节点链接到相应位置
    If Not listPrevious Is Nothing Then
        Set listNew.NextItem= listPrevious.NextItem
        Set listPrevious.NextItem = listNew
    Else
    '链表不存在节点,则该元素为头节点
        Set listNew.NextItem= ListHead
        Set ListHead =listNew
    End If
End Sub

假设要在上图2所示的链表中添加节点元素6,Add方法调用Find函数查找链表中是否存在元素值为6的节点,若不存在,则返回要添加的节点元素的位置,然后链接该节点至链表中。图3演示了代码的运行过程。

图3

Delete方法

'删除节点元素
Public Function Delete(varItem As Variant) As Boolean
    Dim listCurrent As ListItem
    Dim listPrevious As ListItem
    Dim bFound As Boolean
    '调用Find函数确定删除元素的位置
    bFound = Find(varItem,listCurrent, listPrevious)
    If bFound Then
        '删除中间的节点元素
        If Not listPrevious Is Nothing Then
            Set listPrevious.NextItem = listCurrent.NextItem
        Else
        '删除头节点元素
            Set ListHead =listCurrent.NextItem
        End If
    End If
    Delete = bFound
End Function

Delete方法与Add方法类似,在调用Find函数找到要删除元素的位置后,通过节点指针将删除元素从链表中脱离。

ListAllItem方法

'遍历链表
Public Sub ListAllItem()
    Dim listCurrent AsListItem
    Set listCurrent =ListHead
    '从头节点开始遍历
    Do While Not listCurrent Is Nothing
        Debug.Print listCurrent.Value
        Set listCurrent =listCurrent.NextItem
    Loop
End Sub

ListAllItem方法从头节点开始遍历链表,在立即窗口打印每个节点元素值。

测试链表

下面的代码先使用Add方法创建链表,然后再使用Add方法在已有链表中添加元素节点,最后使用Delete方法删除指定节点。

Sub TestList()
    Dim listTest As New List
    With listTest
        .Add 1
        .Add 3
        .Add 5
        .Add 7
        Call .ListAllItem
        Debug.Print "-----------"
        .Add 6
        Call .ListAllItem
        Debug.Print "-----------"
        .Delete 3
        .Delete 7
        Call .ListAllItem
    End With
End Sub

代码运行结果如下图4所示。

图4

下面是List类模块代码的图片版:

本文分享自微信公众号 - 完美Excel(excelperfect)

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2019-07-22

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏完美Excel

Excel VBA解读(137): 让使用用户定义函数的数组公式更快

Excel数组公式能够做很多令人惊讶的事情。除了在输入完后要按Ctrl+Shift+Enter组合键外,与普通公式一样。本文主要研究使用用户定义函数的数组公式。

13220
来自专栏完美Excel

Excel应用实践04:分页单独打印Excel表中的数据

在实际工作中,我们经常会遇到想将工作表中的数据(如下图1所示的“数据”工作表)导入到固定的表格(如下图2所示)中并打印。

6810
来自专栏完美Excel

Excel应用实践03:使用Excel进行个人计划执行记录与统计分析

一转眼,2019年已至4月,自从年初立下flag后,便努力朝着实现它的方向奔跑。有些执行得很好,比如每天更新完美Excel微信公众号,坚持每天学习,而有些则还没...

5720
来自专栏完美Excel

Excel VBA解读(134): 使用Excel函数提高自定义函数的效率

在上篇文章中,我们展示了自定义函数有效的方式是通过将单元格区域读取到Variant型数组来传递单元格区域数据。本文将介绍在自定义函数中最有效的方式是使用Exce...

15030
来自专栏完美Excel

Excel VBA解读(138): 自定义函数时使用字节数组实现更快的字符串处理

如果有很多行,要查找每行字符串第一个大写字母的位置,则使用数组公式会花费不少时间。

10920
来自专栏完美Excel

Excel VBA解读(146): 使用隐式交集处理整列

Excel有一个有趣且非常有效的技巧叫做隐式交集(Implicit Intersection),允许有效地使用大的命名区域和整列引用。

13530
来自专栏完美Excel

Excel VBA解读(135): 影响工作表公式中运用自定义函数效率的Bug及解决方法

在前面的两篇文章中,我们通过简单地修改VBA代码来使自定义函数运行得更快。本文将聚焦于Excel中会影响到自定义函数的Bug,并探讨如何避免它们。

14720
来自专栏完美Excel

VBA实用小程序50: 在指定的单元格中插入指定的形状

下面的自定义函数使用Shapes集合对象的AddShape方法及其参数,可以在指定的单元格中插入指定的形状。

16160
来自专栏完美Excel

Excel VBA解读(143): 在自定义函数中使用整列引用时,如何更有效率?

Excel用户经常发现在公式中使用整列的引用很方便,这样可避免每次添加新数据时都必须调整公式。因此,当编写用户自定义函数时,可能会使用:

16220
来自专栏完美Excel

Excel应用实践06:进行多条件统计

这是在知乎上看到的一个问题,我试着用VBA来解决。欢迎大家就自已使用Excel中遇到的问题或想要的解决方案提问,我将尽力解答。

9420

扫码关注云+社区

领取腾讯云代金券

年度创作总结 领取年终奖励