mirror of
https://hub.njuu.cf/TheAlgorithms/Python.git
synced 2023-10-11 13:06:12 +08:00
Replace double_ended_queue.py (#5429)
* Add deque_from_scratch.py * added deque_from_scratch.py * add extend, extendleft and make comparison * updated operations list * fix doctest on Deque.__iter__ * pre-commit fix * time complexity comments, change type hints * pre-commit fix * added more doctests
This commit is contained in:
parent
672a0c8816
commit
2e955aea46
@ -1,57 +1,470 @@
|
||||
# Python code to demonstrate working of
|
||||
# extend(), extendleft(), rotate(), reverse()
|
||||
"""
|
||||
Implementation of double ended queue.
|
||||
"""
|
||||
from dataclasses import dataclass
|
||||
from typing import Any, Iterable
|
||||
|
||||
# importing "collections" for deque operations
|
||||
import collections
|
||||
|
||||
# initializing deque
|
||||
de = collections.deque([1, 2, 3])
|
||||
class Deque:
|
||||
"""
|
||||
Deque data structure.
|
||||
|
||||
# using extend() to add numbers to right end
|
||||
# adds 4,5,6 to right end
|
||||
de.extend([4, 5, 6])
|
||||
Operations
|
||||
----------
|
||||
append(val: Any) -> None
|
||||
|
||||
# printing modified deque
|
||||
print("The deque after extending deque at end is : ")
|
||||
print(de)
|
||||
appendleft(val: Any) -> None
|
||||
|
||||
# using extendleft() to add numbers to left end
|
||||
# adds 7,8,9 to right end
|
||||
de.extendleft([7, 8, 9])
|
||||
extend(iter: Iterable) -> None
|
||||
|
||||
# printing modified deque
|
||||
print("The deque after extending deque at beginning is : ")
|
||||
print(de)
|
||||
extendleft(iter: Iterable) -> None
|
||||
|
||||
# using rotate() to rotate the deque
|
||||
# rotates by 3 to left
|
||||
de.rotate(-3)
|
||||
pop() -> Any
|
||||
|
||||
# printing modified deque
|
||||
print("The deque after rotating deque is : ")
|
||||
print(de)
|
||||
popleft() -> Any
|
||||
|
||||
# using reverse() to reverse the deque
|
||||
de.reverse()
|
||||
|
||||
# printing modified deque
|
||||
print("The deque after reversing deque is : ")
|
||||
print(de)
|
||||
Observers
|
||||
---------
|
||||
is_empty() -> bool
|
||||
|
||||
# get right-end value and eliminate
|
||||
startValue = de.pop()
|
||||
|
||||
print("The deque after popping value at end is : ")
|
||||
print(de)
|
||||
Attributes
|
||||
----------
|
||||
_front: _Node
|
||||
front of the deque a.k.a. the first element
|
||||
|
||||
# get left-end value and eliminate
|
||||
endValue = de.popleft()
|
||||
_back: _Node
|
||||
back of the element a.k.a. the last element
|
||||
|
||||
print("The deque after popping value at start is : ")
|
||||
print(de)
|
||||
_len: int
|
||||
the number of nodes
|
||||
"""
|
||||
|
||||
# eliminate element searched by value
|
||||
de.remove(5)
|
||||
__slots__ = ["_front", "_back", "_len"]
|
||||
|
||||
print("The deque after eliminating element searched by value : ")
|
||||
print(de)
|
||||
@dataclass
|
||||
class _Node:
|
||||
"""
|
||||
Representation of a node.
|
||||
Contains a value and a pointer to the next node as well as to the previous one.
|
||||
"""
|
||||
|
||||
val: Any = None
|
||||
next: "Deque._Node" = None
|
||||
prev: "Deque._Node" = None
|
||||
|
||||
class _Iterator:
|
||||
"""
|
||||
Helper class for iteration. Will be used to implement iteration.
|
||||
|
||||
Attributes
|
||||
----------
|
||||
_cur: _Node
|
||||
the current node of the iteration.
|
||||
"""
|
||||
|
||||
__slots__ = ["_cur"]
|
||||
|
||||
def __init__(self, cur: "Deque._Node") -> None:
|
||||
self._cur = cur
|
||||
|
||||
def __iter__(self) -> "Deque._Iterator":
|
||||
"""
|
||||
>>> our_deque = Deque([1, 2, 3])
|
||||
>>> iterator = iter(our_deque)
|
||||
"""
|
||||
return self
|
||||
|
||||
def __next__(self) -> Any:
|
||||
"""
|
||||
>>> our_deque = Deque([1, 2, 3])
|
||||
>>> iterator = iter(our_deque)
|
||||
>>> next(iterator)
|
||||
1
|
||||
>>> next(iterator)
|
||||
2
|
||||
>>> next(iterator)
|
||||
3
|
||||
"""
|
||||
if self._cur is None:
|
||||
# finished iterating
|
||||
raise StopIteration
|
||||
val = self._cur.val
|
||||
self._cur = self._cur.next
|
||||
|
||||
return val
|
||||
|
||||
def __init__(self, iterable: Iterable = None) -> None:
|
||||
self._front = self._back = None
|
||||
self._len = 0
|
||||
|
||||
if iterable is not None:
|
||||
# append every value to the deque
|
||||
for val in iterable:
|
||||
self.append(val)
|
||||
|
||||
def append(self, val: Any) -> None:
|
||||
"""
|
||||
Adds val to the end of the deque.
|
||||
Time complexity: O(1)
|
||||
|
||||
>>> our_deque_1 = Deque([1, 2, 3])
|
||||
>>> our_deque_1.append(4)
|
||||
>>> our_deque_1
|
||||
[1, 2, 3, 4]
|
||||
>>> our_deque_2 = Deque('ab')
|
||||
>>> our_deque_2.append('c')
|
||||
>>> our_deque_2
|
||||
['a', 'b', 'c']
|
||||
|
||||
>>> from collections import deque
|
||||
>>> deque_collections_1 = deque([1, 2, 3])
|
||||
>>> deque_collections_1.append(4)
|
||||
>>> deque_collections_1
|
||||
deque([1, 2, 3, 4])
|
||||
>>> deque_collections_2 = deque('ab')
|
||||
>>> deque_collections_2.append('c')
|
||||
>>> deque_collections_2
|
||||
deque(['a', 'b', 'c'])
|
||||
|
||||
>>> list(our_deque_1) == list(deque_collections_1)
|
||||
True
|
||||
>>> list(our_deque_2) == list(deque_collections_2)
|
||||
True
|
||||
"""
|
||||
node = self._Node(val, None, None)
|
||||
if self.is_empty():
|
||||
# front = back
|
||||
self._front = self._back = node
|
||||
self._len = 1
|
||||
else:
|
||||
# connect nodes
|
||||
self._back.next = node
|
||||
node.prev = self._back
|
||||
self._back = node # assign new back to the new node
|
||||
|
||||
self._len += 1
|
||||
|
||||
# make sure there were no errors
|
||||
assert not self.is_empty(), "Error on appending value."
|
||||
|
||||
def appendleft(self, val: Any) -> None:
|
||||
"""
|
||||
Adds val to the beginning of the deque.
|
||||
Time complexity: O(1)
|
||||
|
||||
>>> our_deque_1 = Deque([2, 3])
|
||||
>>> our_deque_1.appendleft(1)
|
||||
>>> our_deque_1
|
||||
[1, 2, 3]
|
||||
>>> our_deque_2 = Deque('bc')
|
||||
>>> our_deque_2.appendleft('a')
|
||||
>>> our_deque_2
|
||||
['a', 'b', 'c']
|
||||
|
||||
>>> from collections import deque
|
||||
>>> deque_collections_1 = deque([2, 3])
|
||||
>>> deque_collections_1.appendleft(1)
|
||||
>>> deque_collections_1
|
||||
deque([1, 2, 3])
|
||||
>>> deque_collections_2 = deque('bc')
|
||||
>>> deque_collections_2.appendleft('a')
|
||||
>>> deque_collections_2
|
||||
deque(['a', 'b', 'c'])
|
||||
|
||||
>>> list(our_deque_1) == list(deque_collections_1)
|
||||
True
|
||||
>>> list(our_deque_2) == list(deque_collections_2)
|
||||
True
|
||||
"""
|
||||
node = self._Node(val, None, None)
|
||||
if self.is_empty():
|
||||
# front = back
|
||||
self._front = self._back = node
|
||||
self._len = 1
|
||||
else:
|
||||
# connect nodes
|
||||
node.next = self._front
|
||||
self._front.prev = node
|
||||
self._front = node # assign new front to the new node
|
||||
|
||||
self._len += 1
|
||||
|
||||
# make sure there were no errors
|
||||
assert not self.is_empty(), "Error on appending value."
|
||||
|
||||
def extend(self, iter: Iterable) -> None:
|
||||
"""
|
||||
Appends every value of iter to the end of the deque.
|
||||
Time complexity: O(n)
|
||||
|
||||
>>> our_deque_1 = Deque([1, 2, 3])
|
||||
>>> our_deque_1.extend([4, 5])
|
||||
>>> our_deque_1
|
||||
[1, 2, 3, 4, 5]
|
||||
>>> our_deque_2 = Deque('ab')
|
||||
>>> our_deque_2.extend('cd')
|
||||
>>> our_deque_2
|
||||
['a', 'b', 'c', 'd']
|
||||
|
||||
>>> from collections import deque
|
||||
>>> deque_collections_1 = deque([1, 2, 3])
|
||||
>>> deque_collections_1.extend([4, 5])
|
||||
>>> deque_collections_1
|
||||
deque([1, 2, 3, 4, 5])
|
||||
>>> deque_collections_2 = deque('ab')
|
||||
>>> deque_collections_2.extend('cd')
|
||||
>>> deque_collections_2
|
||||
deque(['a', 'b', 'c', 'd'])
|
||||
|
||||
>>> list(our_deque_1) == list(deque_collections_1)
|
||||
True
|
||||
>>> list(our_deque_2) == list(deque_collections_2)
|
||||
True
|
||||
"""
|
||||
for val in iter:
|
||||
self.append(val)
|
||||
|
||||
def extendleft(self, iter: Iterable) -> None:
|
||||
"""
|
||||
Appends every value of iter to the beginning of the deque.
|
||||
Time complexity: O(n)
|
||||
|
||||
>>> our_deque_1 = Deque([1, 2, 3])
|
||||
>>> our_deque_1.extendleft([0, -1])
|
||||
>>> our_deque_1
|
||||
[-1, 0, 1, 2, 3]
|
||||
>>> our_deque_2 = Deque('cd')
|
||||
>>> our_deque_2.extendleft('ba')
|
||||
>>> our_deque_2
|
||||
['a', 'b', 'c', 'd']
|
||||
|
||||
>>> from collections import deque
|
||||
>>> deque_collections_1 = deque([1, 2, 3])
|
||||
>>> deque_collections_1.extendleft([0, -1])
|
||||
>>> deque_collections_1
|
||||
deque([-1, 0, 1, 2, 3])
|
||||
>>> deque_collections_2 = deque('cd')
|
||||
>>> deque_collections_2.extendleft('ba')
|
||||
>>> deque_collections_2
|
||||
deque(['a', 'b', 'c', 'd'])
|
||||
|
||||
>>> list(our_deque_1) == list(deque_collections_1)
|
||||
True
|
||||
>>> list(our_deque_2) == list(deque_collections_2)
|
||||
True
|
||||
"""
|
||||
for val in iter:
|
||||
self.appendleft(val)
|
||||
|
||||
def pop(self) -> Any:
|
||||
"""
|
||||
Removes the last element of the deque and returns it.
|
||||
Time complexity: O(1)
|
||||
|
||||
@returns topop.val: the value of the node to pop.
|
||||
|
||||
>>> our_deque = Deque([1, 2, 3, 15182])
|
||||
>>> our_popped = our_deque.pop()
|
||||
>>> our_popped
|
||||
15182
|
||||
>>> our_deque
|
||||
[1, 2, 3]
|
||||
|
||||
>>> from collections import deque
|
||||
>>> deque_collections = deque([1, 2, 3, 15182])
|
||||
>>> collections_popped = deque_collections.pop()
|
||||
>>> collections_popped
|
||||
15182
|
||||
>>> deque_collections
|
||||
deque([1, 2, 3])
|
||||
|
||||
>>> list(our_deque) == list(deque_collections)
|
||||
True
|
||||
>>> our_popped == collections_popped
|
||||
True
|
||||
"""
|
||||
# make sure the deque has elements to pop
|
||||
assert not self.is_empty(), "Deque is empty."
|
||||
|
||||
topop = self._back
|
||||
self._back = self._back.prev # set new back
|
||||
self._back.next = (
|
||||
None # drop the last node - python will deallocate memory automatically
|
||||
)
|
||||
|
||||
self._len -= 1
|
||||
|
||||
return topop.val
|
||||
|
||||
def popleft(self) -> Any:
|
||||
"""
|
||||
Removes the first element of the deque and returns it.
|
||||
Time complexity: O(1)
|
||||
|
||||
@returns topop.val: the value of the node to pop.
|
||||
|
||||
>>> our_deque = Deque([15182, 1, 2, 3])
|
||||
>>> our_popped = our_deque.popleft()
|
||||
>>> our_popped
|
||||
15182
|
||||
>>> our_deque
|
||||
[1, 2, 3]
|
||||
|
||||
>>> from collections import deque
|
||||
>>> deque_collections = deque([15182, 1, 2, 3])
|
||||
>>> collections_popped = deque_collections.popleft()
|
||||
>>> collections_popped
|
||||
15182
|
||||
>>> deque_collections
|
||||
deque([1, 2, 3])
|
||||
|
||||
>>> list(our_deque) == list(deque_collections)
|
||||
True
|
||||
>>> our_popped == collections_popped
|
||||
True
|
||||
"""
|
||||
# make sure the deque has elements to pop
|
||||
assert not self.is_empty(), "Deque is empty."
|
||||
|
||||
topop = self._front
|
||||
self._front = self._front.next # set new front and drop the first node
|
||||
self._front.prev = None
|
||||
|
||||
self._len -= 1
|
||||
|
||||
return topop.val
|
||||
|
||||
def is_empty(self) -> bool:
|
||||
"""
|
||||
Checks if the deque is empty.
|
||||
Time complexity: O(1)
|
||||
|
||||
>>> our_deque = Deque([1, 2, 3])
|
||||
>>> our_deque.is_empty()
|
||||
False
|
||||
>>> our_empty_deque = Deque()
|
||||
>>> our_empty_deque.is_empty()
|
||||
True
|
||||
|
||||
>>> from collections import deque
|
||||
>>> empty_deque_collections = deque()
|
||||
>>> list(our_empty_deque) == list(empty_deque_collections)
|
||||
True
|
||||
"""
|
||||
return self._front is None
|
||||
|
||||
def __len__(self) -> int:
|
||||
"""
|
||||
Implements len() function. Returns the length of the deque.
|
||||
Time complexity: O(1)
|
||||
|
||||
>>> our_deque = Deque([1, 2, 3])
|
||||
>>> len(our_deque)
|
||||
3
|
||||
>>> our_empty_deque = Deque()
|
||||
>>> len(our_empty_deque)
|
||||
0
|
||||
|
||||
>>> from collections import deque
|
||||
>>> deque_collections = deque([1, 2, 3])
|
||||
>>> len(deque_collections)
|
||||
3
|
||||
>>> empty_deque_collections = deque()
|
||||
>>> len(empty_deque_collections)
|
||||
0
|
||||
>>> len(our_empty_deque) == len(empty_deque_collections)
|
||||
True
|
||||
"""
|
||||
return self._len
|
||||
|
||||
def __eq__(self, other: "Deque") -> bool:
|
||||
"""
|
||||
Implements "==" operator. Returns if *self* is equal to *other*.
|
||||
Time complexity: O(n)
|
||||
|
||||
>>> our_deque_1 = Deque([1, 2, 3])
|
||||
>>> our_deque_2 = Deque([1, 2, 3])
|
||||
>>> our_deque_1 == our_deque_2
|
||||
True
|
||||
>>> our_deque_3 = Deque([1, 2])
|
||||
>>> our_deque_1 == our_deque_3
|
||||
False
|
||||
|
||||
>>> from collections import deque
|
||||
>>> deque_collections_1 = deque([1, 2, 3])
|
||||
>>> deque_collections_2 = deque([1, 2, 3])
|
||||
>>> deque_collections_1 == deque_collections_2
|
||||
True
|
||||
>>> deque_collections_3 = deque([1, 2])
|
||||
>>> deque_collections_1 == deque_collections_3
|
||||
False
|
||||
|
||||
>>> (our_deque_1 == our_deque_2) == (deque_collections_1 == deque_collections_2)
|
||||
True
|
||||
>>> (our_deque_1 == our_deque_3) == (deque_collections_1 == deque_collections_3)
|
||||
True
|
||||
"""
|
||||
me = self._front
|
||||
oth = other._front
|
||||
|
||||
# if the length of the deques are not the same, they are not equal
|
||||
if len(self) != len(other):
|
||||
return False
|
||||
|
||||
while me is not None and oth is not None:
|
||||
# compare every value
|
||||
if me.val != oth.val:
|
||||
return False
|
||||
me = me.next
|
||||
oth = oth.next
|
||||
|
||||
return True
|
||||
|
||||
def __iter__(self) -> "_Iterator":
|
||||
"""
|
||||
Implements iteration.
|
||||
Time complexity: O(1)
|
||||
|
||||
>>> our_deque = Deque([1, 2, 3])
|
||||
>>> for v in our_deque:
|
||||
... print(v)
|
||||
1
|
||||
2
|
||||
3
|
||||
|
||||
>>> from collections import deque
|
||||
>>> deque_collections = deque([1, 2, 3])
|
||||
>>> for v in deque_collections:
|
||||
... print(v)
|
||||
1
|
||||
2
|
||||
3
|
||||
"""
|
||||
return Deque._Iterator(self._front)
|
||||
|
||||
def __repr__(self) -> str:
|
||||
"""
|
||||
Implements representation of the deque.
|
||||
Represents it as a list, with its values between '[' and ']'.
|
||||
Time complexity: O(n)
|
||||
|
||||
>>> our_deque = Deque([1, 2, 3])
|
||||
>>> our_deque
|
||||
[1, 2, 3]
|
||||
"""
|
||||
values_list = []
|
||||
aux = self._front
|
||||
while aux is not None:
|
||||
# append the values in a list to display
|
||||
values_list.append(aux.val)
|
||||
aux = aux.next
|
||||
|
||||
return "[" + ", ".join(repr(val) for val in values_list) + "]"
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
import doctest
|
||||
|
||||
doctest.testmod()
|
||||
|
Loading…
Reference in New Issue
Block a user