|
4 | 4 |
|
5 | 5 | from typing import Generic, Iterable, List, Optional, TypeVar
|
6 | 6 |
|
7 |
| -__all__ = ["SkewHeap"] |
8 |
| - |
9 | 7 | T = TypeVar("T")
|
10 | 8 |
|
11 | 9 |
|
12 | 10 | class SkewNode(Generic[T]):
|
13 |
| - """One node of the skew heap. Contains the value and references to two children.""" |
| 11 | + """ |
| 12 | + One node of the skew heap. Contains the value and references to |
| 13 | + two children. |
| 14 | + """ |
14 | 15 |
|
15 | 16 | def __init__(self, value: T) -> None:
|
16 | 17 | self._value: T = value
|
@@ -47,70 +48,137 @@ def merge(
|
47 | 48 | class SkewHeap(Generic[T]):
|
48 | 49 | """
|
49 | 50 | A data structure that allows inserting a new value and to pop the smallest
|
50 |
| - values. Both operations take O(logN) time where N is the size of the structure. |
51 |
| - - Wiki: https://en.wikipedia.org/wiki/Skew_heap |
52 |
| - - Visualisation: https://www.cs.usfca.edu/~galles/visualization/SkewHeap.html |
| 51 | + values. Both operations take O(logN) time where N is the size of the |
| 52 | + structure. |
| 53 | + Wiki: https://en.wikipedia.org/wiki/Skew_heap |
| 54 | + Visualisation: https://www.cs.usfca.edu/~galles/visualization/SkewHeap.html |
53 | 55 |
|
54 |
| - >>> SkewHeap.from_list([2, 3, 1, 5, 1, 7]).to_sorted_list() |
| 56 | + >>> SkewHeap([2, 3, 1, 5, 1, 7]).to_sorted_list() |
55 | 57 | [1, 1, 2, 3, 5, 7]
|
56 | 58 |
|
57 | 59 | >>> sh = SkewHeap()
|
58 |
| - >>> sh.insert(1) |
59 |
| - >>> sh.top() |
60 |
| - 1 |
61 |
| - >>> sh.insert(0) |
62 |
| - >>> sh.pop() |
63 |
| - 0 |
64 | 60 | >>> sh.pop()
|
65 |
| - 1 |
66 |
| - >>> sh.top() |
67 | 61 | Traceback (most recent call last):
|
68 | 62 | ...
|
69 |
| - AttributeError: Can't get top element for the empty heap. |
| 63 | + IndexError: Can't get top element for the empty heap. |
| 64 | +
|
| 65 | + >>> sh.insert(1) |
| 66 | + >>> sh.insert(-1) |
| 67 | + >>> sh.insert(0) |
| 68 | + >>> sh.to_sorted_list() |
| 69 | + [-1, 0, 1] |
70 | 70 | """
|
71 | 71 |
|
72 |
| - def __init__(self) -> None: |
| 72 | + def __init__(self, data: Optional[Iterable[T]] = ()) -> None: |
| 73 | + """ |
| 74 | + >>> sh = SkewHeap([3, 1, 3, 7]) |
| 75 | + >>> sh.to_sorted_list() |
| 76 | + [1, 3, 3, 7] |
| 77 | + """ |
73 | 78 | self._root: Optional[SkewNode[T]] = None
|
| 79 | + for item in data: |
| 80 | + self.insert(item) |
74 | 81 |
|
75 | 82 | def insert(self, value: T) -> None:
|
76 |
| - """Insert the value into the heap.""" |
| 83 | + """ |
| 84 | + Insert the value into the heap. |
| 85 | +
|
| 86 | + >>> sh = SkewHeap() |
| 87 | + >>> sh.insert(3) |
| 88 | + >>> sh.insert(1) |
| 89 | + >>> sh.insert(3) |
| 90 | + >>> sh.insert(7) |
| 91 | + >>> sh.to_sorted_list() |
| 92 | + [1, 3, 3, 7] |
| 93 | + """ |
77 | 94 | self._root = SkewNode.merge(self._root, SkewNode(value))
|
78 | 95 |
|
79 | 96 | def pop(self) -> T:
|
80 |
| - """Pop the smallest value from the heap and return it.""" |
| 97 | + """ |
| 98 | + Pop the smallest value from the heap and return it. |
| 99 | +
|
| 100 | + >>> sh = SkewHeap([3, 1, 3, 7]) |
| 101 | + >>> sh.pop() |
| 102 | + 1 |
| 103 | + >>> sh.pop() |
| 104 | + 3 |
| 105 | + >>> sh.pop() |
| 106 | + 3 |
| 107 | + >>> sh.pop() |
| 108 | + 7 |
| 109 | + >>> sh.pop() |
| 110 | + Traceback (most recent call last): |
| 111 | + ... |
| 112 | + IndexError: Can't get top element for the empty heap. |
| 113 | + """ |
81 | 114 | result = self.top()
|
82 | 115 | self._root = SkewNode.merge(self._root.left, self._root.right)
|
83 | 116 |
|
84 | 117 | return result
|
85 | 118 |
|
86 | 119 | def top(self) -> T:
|
87 |
| - """Return the smallest value from the heap.""" |
| 120 | + """ |
| 121 | + Return the smallest value from the heap. |
| 122 | +
|
| 123 | + >>> sh = SkewHeap() |
| 124 | + >>> sh.insert(3) |
| 125 | + >>> sh.top() |
| 126 | + 3 |
| 127 | + >>> sh.insert(1) |
| 128 | + >>> sh.top() |
| 129 | + 1 |
| 130 | + >>> sh.insert(3) |
| 131 | + >>> sh.top() |
| 132 | + 1 |
| 133 | + >>> sh.insert(7) |
| 134 | + >>> sh.top() |
| 135 | + 1 |
| 136 | + """ |
88 | 137 | if not self._root:
|
89 |
| - raise AttributeError("Can't get top element for the empty heap.") |
| 138 | + raise IndexError("Can't get top element for the empty heap.") |
90 | 139 | return self._root.value
|
91 | 140 |
|
92 | 141 | def clear(self):
|
| 142 | + """ |
| 143 | + Clear the heap. |
| 144 | +
|
| 145 | + >>> sh = SkewHeap([3, 1, 3, 7]) |
| 146 | + >>> sh.clear() |
| 147 | + >>> sh.pop() |
| 148 | + Traceback (most recent call last): |
| 149 | + ... |
| 150 | + IndexError: Can't get top element for the empty heap. |
| 151 | + """ |
93 | 152 | self._root = None
|
94 | 153 |
|
95 |
| - @staticmethod |
96 |
| - def from_list(data: Iterable[T]) -> SkewHeap[T]: |
97 |
| - """Get the sorted list from the heap. Heap will be cleared afterwards.""" |
98 |
| - result = SkewHeap() |
99 |
| - for item in data: |
100 |
| - result.insert(item) |
101 |
| - |
102 |
| - return result |
103 |
| - |
104 | 154 | def to_sorted_list(self) -> List[T]:
|
105 |
| - """Returns sorted list containing all the values in the heap.""" |
| 155 | + """ |
| 156 | + Returns sorted list containing all the values in the heap. |
| 157 | +
|
| 158 | + >>> sh = SkewHeap([3, 1, 3, 7]) |
| 159 | + >>> sh.to_sorted_list() |
| 160 | + [1, 3, 3, 7] |
| 161 | + """ |
106 | 162 | result = []
|
107 | 163 | while self:
|
108 | 164 | result.append(self.pop())
|
109 | 165 |
|
110 | 166 | return result
|
111 | 167 |
|
112 | 168 | def __bool__(self) -> bool:
|
113 |
| - """Check if the heap is not empty.""" |
| 169 | + """ |
| 170 | + Check if the heap is not empty. |
| 171 | +
|
| 172 | + >>> sh = SkewHeap() |
| 173 | + >>> bool(sh) |
| 174 | + False |
| 175 | + >>> sh.insert(1) |
| 176 | + >>> bool(sh) |
| 177 | + True |
| 178 | + >>> sh.clear() |
| 179 | + >>> bool(sh) |
| 180 | + False |
| 181 | + """ |
114 | 182 | return self._root is not None
|
115 | 183 |
|
116 | 184 |
|
|
0 commit comments