I l@ve RuBoard Previous Section Next Section

17.15 Implementing a First-In First-Out Container

Credit: Sébastien Keim

17.15.1 Problem

You need a container that allows element insertion and removal, in which the first element inserted is also the first to be removed (i.e., a first-in first-out, FIFO, queue).

17.15.2 Solution

We can use a class to wrap a Pythonic implementation of a linked list:

class Fifo:
    def _ _init_ _(self):
        self.first = None
        self.last = None
    def append(self, data):
        node = [data, None]  # [payload, 'pointer'] "pair"
        if self.first is None:
            self.first = node
        else:
            self.last[1] = node
        self.last = node
    def pop(self):
        if self.first is None :
            raise IndexError
        node = self.first
        self.first = node[1]
        return node[0]

if _ _name_ _=='_ _main_ _':  # Run a test/example when run as a script:
    a = Fifo(  )
    a.append(10)
    a.append(20)
    print a.pop(0)
    a.append(5)
    print a.pop(0)
    print a.pop(0)

17.15.3 Discussion

Most likely, the best way to do a FIFO in Python is to use standard lists with append and pop(0) methods. Since lists are built-ins, they are usually far more efficient than this recipe, despite theoretical considerations of O(1) versus O(N) performance. If you want to try this, it's easy:

class FifoList:
    def _ _init_ _(self):
        self.data = []
    def append(self, data):
        self.data.append(data)
    def pop(self):
        return self.data.pop(0)

A quirky variation that ensures O(1) performance can be built on top of a dictionary:

class FifoList:
    def _ _init_ _(self):
        self.data = {}
        self.nextin = 0
        self.nextout = 0
    def append(self, data):
        self.nextin += 1
        self.data[self.nextin] = data
    def pop(self):
        self.nextout += 1
        result = self.data[self.nextout]
        del self.data[self.nextout]
        return result

I developed this recipe after I read an academic paper that said that double-linked lists were the natural way to create this kind of container (in contrast with stacks). I convinced myself that it was possible and quite natural to create a FIFO container with single-linked lists, instead. It suffices to have two references to first and last in the Fifo class itself. The class in the recipe's solution shows one way to build a single-linked list in Python via pairs that reference the actual data (also known as the payload) as their first item and use the second item to refer to another such pair (None being used as a null pointer here).

The append method builds such a pair (actually a two-item list) and threads it onto the list, altering the first and last attributes of self appropriately. The popmethod unthreads the node at the head of the list in a similar but mirrored way.

    I l@ve RuBoard Previous Section Next Section