Bidirectional linked list
Here is the code directly. If you have problems, see here.
class _DoublyLinkedBase(): """a base class poviding a boubly linked list representation""" class _Node(): __slots__ = '_element','_prev','_next' def __init__(self,element,prev,next): self._element = element self._prev = prev self._next = next def __init__(self): """create a empty list""" self._header = self._node(None,None,None) self._trailer = self._Node(None,None,None) self._header._next = self._trailer self._trailer._prev = self._header self._size = 0 def __len__(self): """return the number of elements in the list""" return self._size def is_empty(self): """return true if the list is empty""" return self._size==0 def _insert_between(self,e,predecessor,successor): """add element e between pre and suc""" newest = self._Node(e,predecessor,successor) predecessor._next = newest successor._prev = newest self._size += 1 return newest def _delete_node(self,node): """delete nonsentinel node from the list and return its element""" predecessor = node._prev successor = node._next predecessor._next = successor successor._prev - predecessor self._size -= 1 element = node._element # be helpful for python to delete the node node._prev = node._next = node._element = None return element
Location list class
It can not only index the elements before and after, but also have a location attribute.
The position here is not the well-known list numerical subscript, but can insert, delete and judge the contents of the front and rear elements according to the current position. We can distinguish it into absolute position and relative position.
Support__ itr__ (), we can use the for loop to implement traversal;
Support__ en__ And__ eq__, Can compare two nodes.
Let's start with some details of the following code. First, we add an internal definition class once again.
Deficiencies of previous classes:
The head node may be used to operate the two-way linked list, which is not friendly to users;
Need to provide a more powerful data structure
Therefore, on the basis of the previous node, we are equivalent to setting a shell: Position, which shows the user this type, while the internal processing uses the previous node.
Two parameters of position: container and node. Node is the node of our two-way linked list, but what is container?
It sounds like a container. Let's take a look at our calling function**_ make_position.
Pass in the parameter self, because in a linked list, self is the same, in our judgment node function_ validate * * is also useful.
Then say it again with some private functions.
_ make_position: encapsulate a node node into a position instance
_ validate: judge whether a location is a position instance (using isinstance function), whether it is the same linked list, and whether it is the head and tail nodes of a two-way linked list.
__ iter__ To traverse_ insert_between encapsulates the previous insertion function and processes the return value into a position instance.
In this way, there should be nothing to look at the code:
class PositionalList(_DoublyLinkedBase): class Position(): """an abstraction representing the location of a single element""" def __init__(self,container,node): """constructor should not be invoked by user""" self._container = container self._node = node def element(self): """return the element stored at this Position""" return self._node._element def __eq__(self,other): """return true if other is a Position representing the same location""" return type(other) is type(self) and other._node is self._node def __ne__(self,other): """return true if other is not representing the same lovation""" return not(self==other) def _validate(self,p): """return position's node, or raise appropriate error if invalid""" if not isinstance(p,self.Position): raise TypeError('p must be proper Position type') if p._container is not self: raise ValueError('p does not belong to this container') if p._node._next is None or p._node._prev is None: raise ValueError('p is no longer valid') return p._node def _make_position(self,node): """return position instance for given node(or None if sentinel)""" if node is self._header or node is self._trailer: return None else: return self.Position(self,node) def first(self): """return the first position in the list""" return self._make_position(self._header._next) def last(self): """return the last position in the list""" return self._make_position(self._trailer._prev) def before(self,p): """return the position just before position p""" node = self._validate(p) return self._make_position(node._prev) def after(self,p): """return the position just after position p""" node = self._validate(p) return self._make_position(node._next) def __iter__(self): """generate a forward iteration of the elements of the list""" cursor = self.first() while cursor is not None: yield cursor.element() cursor = self.after(cursor) def _insert_between(self,e,predecessor,successor): """add element between existing nodes and return new position""" node = super()._insert_between(e,predecessor,successor) return self._make_position(node) def add_first(self,e): """insert element e at the front of the list and return new position""" return self._insert_between(e,self._header,self._header._next) def add_last(self,e): """insert element e at rhe back of the list and return new position""" return self._insert_between(e,self._trailer._prev,self._trailer) def add_before(self,p,e): """insert """ original = self._validate(p) return self._insert_between(e,original._prev,original) def add_after(self,p,e): """insert element e into list after position p and return new position""" original = self._validate(p) return self._insert_between(e,original,original._next) def delete(self,p): """return and return the element oat pisition p""" original = self._validate(p) return self._delete_node(original) def replace(self,p,e): """replace the element at position p with e, and return the old element""" original = self._validate(p) old_value = original._element original._element = e return old_value