HiveBrain v1.2.0
Get Started
← Back to all entries
patterncsharpMinor

A simple unrolled linked list implementation

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
implementationsimpleunrolledlistlinked

Problem

I tried to implement an unrolled linked list in C#. I only needed to add things and clear the whole list so I didn't implement IList (I tried but it was getting too complex, so I postponed it).

Why I did it?

I needed a collection that should be able to handle millions of items and I was getting OutOfMemoryExceptions when I tried List since it needs sequential memory to hold everything in one array.

I tried LinkedList but it was too slow. I don't need to enumerate backwards or expose the node class publicly. I also know the size of blocks that I want to keep my items in, so I wrote this:

```
public sealed class UnrolledLinkedList : IEnumerable
{
// Fields
private int _Count;
private Node _FirstNode;
private Node _LastNode;
private int _LastNodeCount;
private int _NodeCount;
private readonly int _NodeSize;

// Properties
public int Count { get { return _Count; } }

// Constructors
public UnrolledLinkedList(int nodeSize)
{
_NodeCount = 1;
_NodeSize = nodeSize;
_FirstNode = _LastNode = new Node(nodeSize);
}
public UnrolledLinkedList() : this(8) { }

// Fuctions
public void Add(T item)
{
if (_LastNodeCount == _NodeSize)
{
_LastNode = (_LastNode.Next = new Node(_NodeSize));
_LastNode.Items[0] = item;
_LastNodeCount = 1;
_NodeCount++;
}
else _LastNode.Items[_LastNodeCount++] = item;
_Count++;
}
public void Clear()
{
_FirstNode = _LastNode = new Node(_NodeSize);

// Edit: Just added these:
_Count = 0;
_LastNodeCount = 0;
_NodeCount = 1;
}

public IEnumerator GetEnumerator()
{
var current = _FirstNode;
if (current == null)
yield break;

for (; ; )
{
if (current.Next == null)
{
for (int i = 0; i < _LastNodeCount; i++)
yield re

Solution

I would change GetEnumerator as follows:

public IEnumerator GetEnumerator()
{
    for (var current = _FirstNode ; current != null ; )
    {
        var last = current.Next == null ? _NodeSize : _LastNodeCount;
        for (var i = 0 ; i != last ; i++) {
            yield return current.Items[i];
        }
        current = current.Next;
    }
}


I would also remove _NodeCount, because you are maintaining it, but not using it anywhere to make decisions.

Finally, since you always insert an item in a Node, I would make Node's constructor accept the value T to be placed in Items[0], rather than keeping that code in the Add method.

Code Snippets

public IEnumerator<T> GetEnumerator()
{
    for (var current = _FirstNode ; current != null ; )
    {
        var last = current.Next == null ? _NodeSize : _LastNodeCount;
        for (var i = 0 ; i != last ; i++) {
            yield return current.Items[i];
        }
        current = current.Next;
    }
}

Context

StackExchange Code Review Q#17670, answer score: 6

Revisions (0)

No revisions yet.