Array list implementation

BlitzMax Forums/BlitzMax Programming/Array list implementation

ziggy(Posted 2009) [#1]
Sometimes working with arrays is faster than working with linked lists, specially when you're going to get items with an specific index, etc... With this in mind, I've coded this array-based implementation of lists:

It takes the default Tlist as an 'interface' and implements all its functionality using an array in the background. You can get the array at any time using the ToArray() method, etc. Everything works like a charm except in one scenario. Whenever a real linked list swaps its contents with the arraybased list, the lined list loses it's contents, beouse it is using the _header inside the array list (wich is not really used in this scenario).
Any ideas how to avoid/fix this?
I know, the best idea would be to have a real generic collection class, and make Tlist and TListArray extend both the same base collection, so the swap is done calling generic methods, but this would mean a change in the current brl modules, wich I supose will not happen, so I'm looking for a workaround. Additionally, link based functions return unlinked links, that is link instances with the appropiate "value" but with a void pred and succ, becose in this scenario it has no sense.

Any ideas?


Czar Flavius(Posted 2009) [#2]
What would be good would be to have both an array and a list inside, and two flags to denote whether the array and/or list is up to date. You can then access elements using array-style (from a specific position), but first it checks the array is up to date. If it is not, it converts the list to the array first. When adding/removing elements it does so in the list (and in doing so flags the array as not up to date). But rather than updating the array after every change, it only needs to update after all list changes have completed and an access is made.

Hm does this make any sense? The intended advantage is you can add and remove from the middle of the data structure quickly like a list, and you can access a specific position relatively quickly like an array, giving the best of both worlds. Of course at the cost of some overhead when either the array or list needs to update from the other. This only happens when required - if adding elements, and then iterating through one-by-one the array storage is not required to update just yet.


ziggy(Posted 2009) [#3]
@Czar Flavius: The idea to have several 'list' implementations is that you can choose the faster one in every scenario. Lots of modern programing languages have linked list, key-vale pairs, lifo and fifo piles and array-lists. All of them sharing a base 'generic collection' class, so you can pass one or the other or the generic one on a function or whatever, but you can still decide if you need fast indexed acces (array list) a push-pull functionality (then use piles), a fast 'search' item then you use a key-value pair (like a tmap) collection, fast add/remove/resize list (linked lists) etc...
My attempt in the first post was to generate an array-list using the pre-existing tlist as the generic list, but now I'm not sure if it is the best idea. I should better make my own lists system and publish it on the module tweaks?


Tommo(Posted 2009) [#4]
Array resizing/slicing can be very very slow. I don't think to use it so often in insertion is a good idea.
In my opinion, linkedlist is born to be used for fast insertion/removal/iteration. Fast random access is not a must.
If I want a list which also has fast random accessed , I may combine a map/hashtable and a simple list to make a hybrid structure, and let each one do the job it's good at.


ziggy(Posted 2009) [#5]
@tommo: Of course. If you need fast insertion a linked list is your best friend. If you need fast random access a listarray is your best friend (even faster than a hashtable-based collection). Having choice of one or the other is then the best of the scenarios, isn't it? The point on this is that a list-array gives you access too to the underlayng array, so you can pre-scale the array and fill it with valus in a single operation if you want to, while you maintain the list-like access for interfacing.
All in all, this is not linkedlist vs arrays, it 'could be' opening the way BlitzMax handles collections or lists to a more generic way. In the same way we have a generic Stream class and all streams inherit the stream structure, I think it would be great to have a basic 'list' or 'collection' class, and leave linked lists as one of the implementations of collections in BlitzMax. Then users could happilly create their own (listarray, piles, key/value pair based lists, etc.)
I just think current design of collections is too restrictive in this respect. It's just a sort of idea/suggestion.


ziggy(Posted 2009) [#6]
After working on a complete implementation of LinkedLikst and ListArrays, I've done a small benchmark test, and I get this interesting results (on release mode)
Benchmark.
Adding 20000 items
Time to add 20000 items on a linked list: 4
Time to add 20000 items on a listArray list: 1509
Time to add 20000 items on a listArray list with FastAppendItems: 8

Benchmark.
Getting the values for 20000 indexed items
Time to index 20000 items on a linked list: 970
Time to index 20000 items on a ListArray list: 0

Benchmark.
EachIn iterations.
Time to EachIn iterate 100000 items on a linked list: 2
Time to EachIn iterate 100000 items on a ListArray list: 1
Time to EachIn iterate 100000 items on a ListArray internal array: 1

Depending on the usage of your data(random access vs object creation-destruction) you cah choose one implementation or the other.


ImaginaryHuman(Posted 2009) [#7]
I like using a linked list of arrays. That way you don't have to reslice, you just add on another link containing an extra array. I then use almost entirely array access, except where you need to go across link boundaries.