Я пытаюсь создать связанный список в VBA, который избегает:
- использование пользовательских классов.
- любые ком-объекты, такие как словарь
Ниже я реализовал (VBA, Excel 2016) такой список, используя только операторы VBA, используя коллекции в качестве контейнера для указателя и значения.
Эта реализация хорошо работает по сравнению с добавлением контейнеров в коллекцию (см. Функцию testcollection):
- функция LLadd способна добавить 5M элементов менее чем за 15 с по сравнению с 5 с для добавления 5M контейнеров в коллекцию
- Итог быстр <3s / 5M предметов </li>
- функция LLdelete позволяет избежать ошибки 28 «out of stackspace error», но занимает некоторое время.
Однако проблема заключается в том, что использование памяти довольно велико (5 миллионов элементов ~ 1 ГБ) по сравнению с 250 МБ, если вы используете коллекцию только значений (обратите внимание, что это не то, что здесь делает функция testCollection ... который также использует 1Gb).
Я просмотрел связанные списки, но мне не удалось найти минимальную реализацию, в которой не используются классы.
Есть ли способ повысить эффективность использования памяти в VBA, не прибегая к классам и объектам сценариев?
спасибо заранее!
Option Explicit
' L is an array with 3 elements that provide access to the linkled list'
' it thus represents the list, but is actually a tuple with
' L(0) the head or first element of the list'
' L(1) then last element to be replaced with the next element added'
' L(2) the current element (e.g when iterating)'
' each element C is a collection object with 2 elements'
'collections are able to be referenced (arrays are always copied)
' C(1): the link to the next element'
' C(2): the value'
Property Let LLadd(Lst, value)
'force Lst to exist'
try: On Error GoTo catch
If Lst(0) Is Nothing Then
catch: Lst = Array(Nothing, Nothing, Nothing)
End If
On Error GoTo 0
Dim c As New Collection
If Lst(0) Is Nothing Then 'add head twice'
c.Add value
Set Lst(0) = c
Set Lst(1) = Lst(0)
Else
c.Add value
Lst(1).Add c
Set Lst(1) = Lst(1)(2)
End If
End Property
'itterate through the items in de list, '
'maintain the index, and return value'
Function Iterating(L, Optional index, Optional value)
index = index + 1
If L(2) Is Nothing Then 'initialise iteration'
Set L(2) = L(0)
Iterating = True
index = 1
If Not IsMissing(value) Then value = L(2)(1)
ElseIf L(2) Is L(1) Then 'exit loop'
Iterating = False
Set L(2) = Nothing
If Not IsMissing(value) Then value = Empty
Else
Set L(2) = L(2)(2)
If Not IsMissing(value) Then value = L(1)(1)
Iterating = True
End If
End Function
'This function cleans up after the list, error 28 if you dont...'
Sub LLdelete(Lst)
Dim prev1, c
Set c = Lst(0)
While True
Set prev1 = c
Set c = c(2)
prev1.Remove 2
If c.Count = 1 Then
Set Lst = Nothing
Exit Sub
End If
Wend
End Sub
Sub testLL()
Dim L, i
For i = 1 To 5000000
LLadd(L) = i + 30
Next
i = 0
Dim s, value
While Iterating(L, i, value)
s = s + value
Wend
Debug.Print i, s
LLdelete L
End Sub
'add containers with links to a collection for comparrison'
Sub testcollection()
Dim L As New Collection, i, c As New Collection, d As Collection
For i = 1 To 5000000
Set c = New Collection
c.Add i + 33
L.Add c
If Not d Is Nothing Then d.Add c
Set d = c
Next
i = 0
Dim s, value
For Each c In L
i = i + 1
s = s + c(1)
Next
Debug.Print i, s
Set L = Nothing
End Sub
Примечание 1 : индекс в итерирующей функции на самом деле не требуется, он только для будущего использования
Примечание 2 : функция TestCollection предназначена для сравнения с коллекцией (это не совсем сопоставимо ...)
Примечание 3 : конечная цель состоит в том, чтобы предоставить больший контроль над каждым циклом (например, обратный foreach, для каждого шага 2 и т. Д., Для каждого с двумя списками одновременно (например, Zip (list1) , List2) в питоне)