cs_survival_kit.data_structures.abstract_list ¶
The list abstract data type that the guide's list structures implement.
A list is an ordered collection in which every element has a position. That
description says what a list does, not how it is stored, and the difference
is the point: DynamicArray keeps its elements in one contiguous block,
while a linked list chains nodes together. Both are lists; they differ in
what each operation costs.
AbstractList writes the shared contract down as a base class. Code written
against it, such as a benchmark, works with any implementation.
AbstractList ¶
Bases: ABC
An ordered collection of elements, each at a position from 0 upward.
The contract has two layers.
Six primitives are abstract. An implementation must supply all of
them, and they are the only places its storage is touched: len(a),
iteration, a[i], a[i] = x, insert and pop. A subclass that leaves
out any primitive cannot be instantiated.
Nine defaults are inherited. Each is written here once, in terms of
the primitives: append is insert at the end, prepend is insert at
0, pop_front and pop_back are pop at either end, remove is a scan
followed by pop, item in a and repr(a) are scans, reversed(a) is
one scan buffered and yielded backward, and reverse swaps a[i] with
a[n - 1 - i] inward from both ends. An implementation may override a
default, but it rarely needs to: the cost of each default is simply the
cost of the primitive it calls at that position, and an implementation
whose insert is O(1) at index 0 gets an O(1) prepend for free.
Two defaults deserve a closer look. reverse is only as cheap as
indexing, so a structure that cannot index in O(1) overrides it with an
algorithm suited to its storage. reversed(a) could have been written
the same way, as a[i] from the last position down, but that is
quadratic on a linked list. Instead it spends O(n) auxiliary space on a
buffer so that it is linear on every implementation. A structure that
can walk backward without the buffer, such as an array by index or a
doubly linked list by its backward links, overrides it to get the space
back.
Every index is a non-negative position. a[i], a[i] = x and pop
accept 0 <= index < len(a); insert also accepts index == len(a),
which adds at the end. Negative indices and slices are not part of the
contract.
Complexity
The interface fixes behaviour only. What each primitive costs is set by the implementation, and comparing those costs is what the implementations are for. Each one documents its own. The defaults cost whatever the primitive they call costs at that index:
| Operation | Defined in terms of |
|---|---|
append |
insert(len(a), item) |
prepend |
insert(0, item) |
pop_front |
pop(0) |
pop_back |
pop(len(a) - 1) |
remove |
one iteration to find the index, then pop |
item in a |
one iteration |
repr(a) |
one iteration |
reversed(a) |
one iteration into a buffer, yielded backward |
reverse |
n / 2 swaps, each two a[i] reads and two writes |
Examples:
The base class cannot be instantiated; an implementation can.
>>> AbstractList()
Traceback (most recent call last):
...
TypeError: Can't instantiate abstract class AbstractList...
>>> from cs_survival_kit.data_structures import DynamicArray
>>> isinstance(DynamicArray[int](), AbstractList)
True
The defaults come from the base class, so an implementation that writes only the six primitives supports every operation:
>>> a = DynamicArray[int]()
>>> a.append(2)
>>> a.prepend(1)
>>> a.append(3)
>>> a
DynamicArray([1, 2, 3])
>>> a.pop_front(), a.pop_back()
(1, 3)
>>> a.remove(2)
>>> len(a)
0
reversed walks the elements backward without changing the list;
reverse changes the list:
>>> a.append(1)
>>> a.append(2)
>>> list(reversed(a)), list(a)
([2, 1], [1, 2])
>>> a.reverse()
>>> list(a)
[2, 1]
- Data Structures
- Reference (cs-survival-kit 0.8.0) cs_survival_kit data_structures
__len__
abstractmethod
¶
Return the number of elements in the list.
Returns:
| Type | Description |
|---|---|
int
|
The number of elements, which is 0 for an empty list. |
__iter__
abstractmethod
¶
Iterate over the elements in position order.
Yields:
| Type | Description |
|---|---|
T
|
Each element, starting with the one at position 0. |
__getitem__
abstractmethod
¶
Return the element at position index.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
index
|
int
|
The position of the element. Must satisfy
|
required |
Returns:
| Type | Description |
|---|---|
T
|
The element at |
Raises:
| Type | Description |
|---|---|
IndexError
|
If there is no element at |
Source code in cs_survival_kit/data_structures/abstract_list.py
·
View on GitHub
__setitem__
abstractmethod
¶
Replace the element at position index with item.
Only overwrites an existing element; the length does not change. Use
insert to add one.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
index
|
int
|
The position of the element to replace. Must satisfy
|
required |
item
|
T
|
The new element. |
required |
Raises:
| Type | Description |
|---|---|
IndexError
|
If there is no element at |
Source code in cs_survival_kit/data_structures/abstract_list.py
·
View on GitHub
insert
abstractmethod
¶
Add item at position index, moving later elements along by one.
Afterwards self[index] is item and len(self) is one greater.
index == len(self) adds the item after the current last one.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
index
|
int
|
The position the new element will occupy. Must satisfy
|
required |
item
|
T
|
The element to add. |
required |
Raises:
| Type | Description |
|---|---|
IndexError
|
If |
Source code in cs_survival_kit/data_structures/abstract_list.py
·
View on GitHub
pop
abstractmethod
¶
Remove and return the element at position index.
Later elements move back by one, so afterwards len(self) is one
less and the element that was at index + 1 is at index.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
index
|
int
|
The position of the element to remove. Must satisfy
|
required |
Returns:
| Type | Description |
|---|---|
T
|
The element that was at |
Raises:
| Type | Description |
|---|---|
IndexError
|
If there is no element at |
Source code in cs_survival_kit/data_structures/abstract_list.py
·
View on GitHub
__contains__ ¶
Return whether item is in the list.
Checks the elements in position order and stops at the first match.
An element matches if it is item or equals it, the same rule that
list uses.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
item
|
object
|
The value to look for. |
required |
Returns:
| Type | Description |
|---|---|
bool
|
|
Complexity
- Time: one iteration, stopping at the first match
- Space: O(1)
Source code in cs_survival_kit/data_structures/abstract_list.py
·
View on GitHub
__repr__ ¶
Return a string showing the class name and the elements in order.
Returns:
| Type | Description |
|---|---|
str
|
A string such as |
Source code in cs_survival_kit/data_structures/abstract_list.py
·
View on GitHub
__reversed__ ¶
Iterate over the elements from the last position down to 0.
This is what the built-in reversed(a) calls. The list is not
changed; compare reverse, which some structures offer to rewire
themselves in place.
The default iterates forward once into a buffer, then yields the
buffer from its end. The buffer costs O(n) auxiliary space, and that
is a deliberate trade. The alternative, reading a[i] from the last
position down, needs no extra memory but is only as cheap as
indexing, which is quadratic on a linked list that walks to each
index. A linear default that every implementation can inherit beats
a constant-space default that some cannot afford. A structure that
can walk backward in O(1) space overrides this: an array reads by
index, and a doubly linked list follows its backward links.
The buffer is filled when iteration starts, not when reversed(a)
is called, and it is a snapshot: changes made to the list after the
first element has been yielded do not affect the rest.
Yields:
| Type | Description |
|---|---|
T
|
Each element, starting with the one at position |
Complexity
- Time: O(n), one iteration plus one pass over the buffer
- Space: O(n) for the buffer
Source code in cs_survival_kit/data_structures/abstract_list.py
·
View on GitHub
reverse ¶
Reverse the order of the elements in place.
Afterwards the element that was last is at position 0, and so on.
Compare reversed(a), which visits the elements backward and changes
nothing.
The default is the array algorithm: swap the first element with the
last, the second with the second-to-last, and so on, meeting in the
middle after n // 2 swaps. It needs nothing but indexing, so on an
array it is O(n) with O(1) extra space. A linked list cannot index
cheaply, so it overrides this with an algorithm suited to links: a
singly linked list re-points every next at the node before it, and
a doubly linked list swaps prev and next on every node.
Complexity
- Time:
n // 2swaps, each two reads and two writes ofa[i]at that index's cost - Space: O(1)
Source code in cs_survival_kit/data_structures/abstract_list.py
·
View on GitHub
append ¶
Add item to the end of the list.
Afterwards item is the last element and len(self) is one greater.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
item
|
T
|
The element to add. |
required |
Complexity
- Time: the cost of
insertat indexlen(self) - Space: the cost of
insertat indexlen(self)
- Data Structures
Source code in cs_survival_kit/data_structures/abstract_list.py
·
View on GitHub
prepend ¶
Add item to the front of the list.
Afterwards item is at position 0, every other element is one
position later, and len(self) is one greater.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
item
|
T
|
The element to add. |
required |
Complexity
- Time: the cost of
insertat index 0 - Space: the cost of
insertat index 0
- Data Structures
Source code in cs_survival_kit/data_structures/abstract_list.py
·
View on GitHub
pop_front ¶
Remove and return the first element.
Returns:
| Type | Description |
|---|---|
T
|
The element that was at position 0. |
Raises:
| Type | Description |
|---|---|
IndexError
|
If the list is empty. |
Complexity
- Time: the cost of
popat index 0 - Space: the cost of
popat index 0
- Data Structures
Source code in cs_survival_kit/data_structures/abstract_list.py
·
View on GitHub
pop_back ¶
Remove and return the last element.
Returns:
| Type | Description |
|---|---|
T
|
The element that was at position |
Raises:
| Type | Description |
|---|---|
IndexError
|
If the list is empty. |
Complexity
- Time: the cost of
popat indexlen(self) - 1 - Space: the cost of
popat indexlen(self) - 1
- Data Structures Doubly Linked List Working at the end
Source code in cs_survival_kit/data_structures/abstract_list.py
·
View on GitHub
remove ¶
Remove the first element that matches item.
Only the first match, scanning from position 0, is removed. An
element matches if it is item or equals it, as in item in a.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
item
|
T
|
The value to remove. |
required |
Raises:
| Type | Description |
|---|---|
ValueError
|
If no element matches |
Complexity
- Time: one iteration to find the match, plus the cost of
popat that index - Space: O(1)
- Data Structures Singly Linked List Finding an element