[Tutor] Making Doubly Linked List with Less Lines of Code.

Steven D'Aprano steve at pearwood.info
Thu Jan 1 00:57:36 CET 2015


On Tue, Dec 30, 2014 at 05:40:04PM -0500, wolfrage8765 at gmail.com wrote:
> On Tue, Dec 30, 2014 at 2:37 PM, Danny Yoo <dyoo at hashcollision.org> wrote:
> > If that's the case, then none of this requires linked list storage.
> >
> > Instead, we can represent this as a list of rows.  Each row element
> > would be itself a list of tiles.  In short, a matrix.  See:
> > https://docs.python.org/2/faq/programming.html#how-do-i-create-a-multidimensional-list
> 
> True, I could use a multidimensional list. And originally I was using
> a 2D list. But I wanted the ability to QUICKLY search across a row or
> up and down a column and so the added benefit of the linked list was
> that it simply requires me to access the next node reference.

[emphasis added]

Trust me on this, there is no linked list code you can write in 
Python that will be faster than using a list of lists.

Even in C, traversing a linked list is slower than array access, and 
Python is not C.


> > And finding neighboring tiles also wouldn't be too bad: Given a tile
> > at (i, j), we can find its neighbors through arithmetic (i plus or
> > minus one, j plus or minus one).
> 
>  From a coding perspective the linked list seemed simplier, because my
> other 2D list implementation required me to have a function that could
> map from any position to North, South, East, & West, plus it needed to
> perform bounds checking. Of course having the list now be doubly
> linked has added complexity.


Bounds checking is easy: cell [i, j] is in bounds if this is true:

    (0 <= i < NUM_ROWS) and (0 <= j < NUM_COLS)

Fast access to any cell is possible:

    array[i][j]

gives you access to the cell [i, j] effectively instantly, two 
array accesses, which is much, much faster than having to traverse a 
linked list:

    cell = array
    for x in range(i):
        cell = cell.next_row
    for x in range(j):
        cell = cell.next_col

(or whatever scheme you use for linking to the next row/column).


As far as memory consumption goes, I don't think there is any 
comparison. Here is a doubly-linked list of strings:

class Cell:
    __slots__ = ['data', 'next', 'prev']
    def __init__(self, data):
        self.data = data
        self.next = self.prev = None


x = y = Cell('alpha0')
for i in range(1, 10):
    y.next = Cell('alpha' + str(i))
    y.next.prev = y
    y = y.next



Now let's see how much memory it uses:

from sys import getsizeof
size = 0
y = x
while y is not None:
    size += getsizeof(y) + getsizeof(y.data)
    y = y.next


On my system, that gives size of 630 bytes.

Let's do the same for a list. This only takes two lines of code:

x = ['alpha' + str(i) for i in range(0, 10)]
size = getsizeof(x) + sum(getsizeof(s) for s in x)

On my system, that gives a size of 406 bytes, considerably smaller.


-- 
Steven


More information about the Tutor mailing list