import typing class Node: def __init__(self, value): self.value = value self.prev = None self.next = None def __repr__(self): return f'Node({self.value})' def __eq__(self, other): if isinstance(other, Node): return self.value == other.value return False class DoubleLinkedList: def __init__(self): self.head: Node = None self.tail: Node = None def append(self, value): node = Node(value) if self.head is None: self.head = node else: self.tail.next = node node.prev = self.tail self.tail = node def iter(self, reverse=False): current = self.head if not reverse else self.tail while current: yield current current = current.next if not reverse else current.prev def __iter__(self): current = self.head while current: yield current current = current.next def pop(self, index: int = None): if self.head is None: raise IndexError('pop from empty list') length = len(self) # > 0 if index is None: index = -1 if index < 0: if index < -length: raise IndexError('pop index out of range') if length == 1: # only have one node, node.prev == node.next == None, no need to care about ref node = self.head self.head = self.tail = None return node.value # below code situation: have more than one node if index == -1: # the last node tail = self.tail tail.prev.next = None self.tail = tail.prev tail.prev = None # remove ref return tail.value elif index == -length: # the first node head = self.head self.head = head.next self.head.prev = None head.next = None return head.value else: # node in the middle position node = self[index] # we support negative index prev = node.prev next = node.next prev.next = next next.prev = prev node.prev = node.next = None return node.value else: if index > length - 1: raise IndexError('pop index out of range') if length == 1: node = self.head self.head = self.tail = None return node.value # below code situation: have more than one node if index == 0: # the first node head = self.head self.head = head.next self.head.prev = None head.next = None return head.value elif index == length - 1: # the last node tail = self.tail self.tail = tail.prev self.tail.next = None tail.prev = None return tail.value else: # node in the middle position node = self[index] prev = node.prev next = node.next prev.next = next next.prev = prev node.prev = node.next = None return node.value # __iter__ = iter def __getitem__(self, item): # for i, node in enumerate(self.iter(False if i > 0 else True), start=0 if i > 0 else 1): # if i == abs(item): # return node.value if not isinstance(item, int | slice): raise TypeError(f'LinkedList indices must be integers or slices, not{type(item)}') # sequence if isinstance(item, int): if item < 0: # index = -i - 1 for i, v in enumerate(self.iter(reverse=True)): if item == -i - 1: return v raise IndexError('Index Out of Bounds') # for loops detect the end of sequence else: for i, v in enumerate(self.iter()): if item == i: return v raise IndexError('Index Out of Bounds') # for loops detect the end of sequence else: # item is slice object dll = self.__class__() # construct a new instance item: slice indices = list(range(*item.indices(len(self)))) print('indices', indices, len(self)) # step > 0 indices [2, 4, 6] # step < 0 indices [6, 4, 2] for i in indices: dll.append(self[i].value) return dll # if item.start > item.stop: # [3,2,1] step<0 # for i,v in enumerate # else: # step>0 # for i, v in enumerate(self, start=0): # if i in indices: # dll.append(v.value) # append need value, not node # return dll def __setitem__(self, key, value): if not isinstance(key, int | slice): raise TypeError(f'LinkedList indices must be integers or slices, not{type(key)}') # sequence if isinstance(key, int): self[key] = Node(value) if isinstance(key, slice): if not isinstance(value, typing.Iterable): # slice require value to be an iterable, even if slice has one item raise TypeError('can only assign an iterable') if key.step == 0: raise ValueError('slice step cannot be zero') # slice does not judge step length = len(self) if not length: for v in value: self.append(v) indices = list(range(*key.indices(len(self)))) start = key.start stop = key.stop step = key.step step = 1 if step is None else step # step default to 1 if step > 0: if start is None: start = 0 if stop is None: stop = length else: if start is None: start = -1 if stop is None: stop = -length - 1 if not len(indices): # slice is null, turn into insert behavior, start position is key.start if start == 0 or start == -length: # the first node flag = False _tail = None # temp tail node for v in value: node = Node(v) if not flag: head = self.head self.head = node flag = True _tail = node # store temp tail node else: _tail.next = node node.prev = _tail _tail = node else: # concatenate self.tail and head if _tail is None: # len(value) == 0 return _tail.next = head head.prev = _tail elif start >= length: # append the value for v in value: self.append(Node(v)) else: # middle position _head = self[start] _tail = _head.prev for v in value: node = Node(v) _tail.next = node node.prev = _tail _tail = node _tail.next = _head _head.prev = _tail if step > 0: print('__setitem__', key, indices, start, stop, step) if step == 1: # adjacent, no need to care about numbers, -1 is not this case if start == 0: # the first node if stop >= length: # override the whole LinkedList for v in self: v.prev = v.next = None self.head = self.tail = None for v in value: node = Node(v) if self.head is None: self.head = node self.tail = node else: self.append(node) if step > 1: # not adjacent, require len(range(*key.indices(len(self)))) == len(value) ... def __len__(self): flag = False for i, _ in enumerate(self.iter()): flag = True if flag: return i + 1 return 0 def __reversed__(self): # it should return a new iterator object in reverse order, fall back to sequence __len__ __getitem__ print('__reversed__') for i in range(len(self) - 1, -1, -1): yield self[i] def remove(self, value, reverse=False): # enhancement, because we are DoubleLinkedList length = len(self) if not length: raise ValueError('empty!') node = Node(value) flag = False try: if reverse: for i, v in enumerate(self.iter(reverse=True), start=0): if node == v: # found self.pop(-i - 1) # convert to negative index break else: raise IndexError else: for i, v in enumerate(self.iter()): if node == v: self.pop(i) break else: raise IndexError except IndexError: raise ValueError(f'{value} not in list') from None def insert(self, index, value): length = len(self) node = Node(value) if length == 0: self.head = self.tail = node else: if index < 0: if index <= -length: # the first position head = self.head self.head = node node.next = head head.prev = node else: for i, v in enumerate(self.iter(reverse=True)): if index == -i - 1: prev = v.prev prev.next = node node.prev = prev node.next = v v.prev = node else: if index == 0: # the first position head = self.head self.head = node node.next = head head.prev = node elif index >= length: # the last position tail = self.tail self.tail = node tail.next = node node.prev = tail else: # the middle position for i, v in enumerate(self.iter()): if index == i: prev = v.prev prev.next = node node.prev = prev node.next = v v.prev = node def __repr__(self): # print(11, list(map(str, self))) # return ', '.join(map(str, self)) # print(22, list(self)) return f'[{", ".join(list(map(str, self)))}]' l = DoubleLinkedList() l.append(3) l.append(4) l.append(5) l.append(6) l.append(7) l.append(8) # l[0:0] = 'ab' # l[-len(l):0] = 'AB' l[3:3] = '' print(l) # dd = l[2:88:2] dd = l[-2:-20:-2] print('dd =', type(dd), dd) print('l =', l) print(list(reversed(l))) # print(l.pop(-2)) # print(l.pop()) # l.remove(4, reverse=True) # print(l.pop()) # l.insert(-10, 'a') # l.insert(-len(l), 'aa') # l.insert(-1, 'bb') # l.insert(len(l) - 1, 'bb') for n in l.iter(): print(n, type(n)) # for n in l.iter(reverse=True): # print(n, type(n)) # print(l[0], l[-1], l[3], l[-4]) # print(l[8]) # print(l[-5]) print(len(l)) ll = DoubleLinkedList() print(len(ll)) print(ll.__module__)
标签:node,head,Python,self,value,DoubleLinkedList,tail,prev From: https://www.cnblogs.com/dissipate/p/16876713.html