Classe lista concatenata doppia

Un puntatore, in ogni nodo, che punta al nodo precedente permette di ottimizzare il metodo pop_right().

Le operazioni di inserimento / rimozione in testa / coda hanno tutte complessità costante

  • append_left(x)
  • append_right(x)
  • x <– pop_left()
  • x <– pop_right()

e permettono di utilizzare la lista, in modo efficiente, sia come stack che come coda.

Classe nodo

Ogni nodo contiene due puntatori, prev e next

class Node:
    def __init__(self, info):
        self._info=info
        self._next=None
        self._prev=None

    def set_info(self, info): self._info=info
    def set_prev(self, prev): self._prev=prev
    def set_next(self, next): self._next=next

    def get_info(self): return self._info
    def get_prev(self): return self._prev
    def get_next(self): return self._next

Classe lista

La lista possiede due puntatori, alla testa e alla coda

class DL_List:           # Double-linked List
    def __init__(self):
        self._head=None
        self._tail=None

    def is_empty(self):
        return (self._head is None)

    def size(self):
        n=0
        nodo=self._head
        while(nodo is not None):
            nodo=nodo.get_next()
            n += 1
        return n

    def exists(self, info):
        nodo=self._head
        while(nodo is not None) and (nodo.get_info() != info):
            nodo=nodo.get_next()
        return (nodo is not None)

    def count(self, info):
        nodo=self._head
        num=0
        while(nodo is not None):
            if(nodo.get_info() == info):
               num += 1
            nodo=nodo.get_next()
        return num

    def index(self, info):
        nodo=self._head
        pos=0
        while(nodo is not None) and (nodo.get_info() != info):
            pos += 1
            nodo=nodo.get_next()

        if (nodo is None):
            raise ValueError("Il nodo %s non esiste" % (info))
        else:
            return pos

    def append_left(self, info):
        nodo=Node(info)
        nodo.set_prev(None)
        nodo.set_next(self._head)
        if(self.is_empty()):
            self._tail=nodo
        else:
            self._head.set_prev(nodo)
        self._head=nodo

    def append_right(self, info):
        nnodo=Node(info)
        nnodo.set_next(None)

        if(self.is_empty()):
            nnodo.set_prev(None)
            self._head=nnodo
        else:
            nnodo.set_prev(self._tail)
            self._tail.set_next(nnodo)
        self._tail=nnodo

    def pop_left(self):
        if(self.is_empty()):
            raise ValueError("Il nodo %s non esiste" %(info))
        else:
            nodo=self._head
            self._head=nodo.get_next()
            if(self.is_empty()):
                self._tail=None
            else:
                self._head.set_prev(None)
            return nodo.get_info()

    def pop_right(self):
        if(self.is_empty()):
            raise ValueError("Il nodo %s non esiste" % (info))
        else:
            nodo=self._tail
            self._tail=nodo.get_prev()
            if (self._tail is None):
                self._head = None
            else:
                self._tail.set_next(None)
            return nodo.get_info()

    def remove(self, info):
        nodo=self._head
        while(nodo is not None) and (nodo.get_info() != info):
            nodo=nodo.get_next()
        if(nodo is None):
            raise ValueError("Il nodo %s non esiste" %(info))
        else:
            prev=nodo.get_prev()
            next=nodo.get_next()
            if(prev is None) and (next is None):
                self._head=None
                self._tail=None
            elif(prev is None):
                self._head=next
                self._head.set_prev(None)
            elif(next is None):
                self._tail=prev
                self._tail.set_next(None)
            else:
                prev.set_next(next)
                next.set_prev(prev)

Test

stack=DL_List()
for x in range(10):
    stack.append_left(x)              # push(x)
while(not stack.is_empty()):
    print(stack.pop_left(), end=" ")  # pop()
print()

coda=DL_List()
for x in range(10):
    coda.append_left(x)               # enqueue(x)   
while(not coda.is_empty()):
    print(coda.pop_right(), end=" ")  # dequeue()

Dopo l’input la lista è la seguente

 Testa                                                 Coda
   |                                                     |
<- 9 <-> 8 <-> 7 <-> 6 <-> 5 <-> 4 <-> 3 <-> 2 <-> 1 <-> 0 ->

L’output dei due casi è

9 8 7 6 5 4 3 2 1 0
0 1 2 3 4 5 6 7 8 9