diff --git a/LICENSE b/LICENSE index 3f75c4b..dc5bc12 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ BSD 3-Clause License -Copyright (c) 2023, The Open University +Copyright (c) 2024, The Open University All rights reserved. Redistribution and use in source and binary forms, with or without diff --git a/README.md b/README.md index 823ed57..a638874 100644 --- a/README.md +++ b/README.md @@ -3,75 +3,139 @@ - is easy to install, use and understand - adheres to good coding practices. +To learn what the library provides and how to use it, see https://dsa-ou.github.io/paddles. + +The rest of this file documents how the library is developed, +in case you want to contribute. + +## Licence +The code and text in this repository are Copyright © 2024 by The Open University, UK. +The code is licensed under a [BSD 3-clause licence](LICENSE.MD). +The text is licensed under a +[Creative Commons Attribution 4.0 International Licence](http://creativecommons.org/licenses/by/4.0). + +By contributing code or documentation to this repository, +you agree to transfer the copyright of your contribution to The Open University, UK, +and that your contribution will be subject to the above licence. + +## Environment +We use Python 3.10 and the [poetry](https://python-poetry.org) packaging and dependency manager. +To set up the environment: +- if you don't have Python 3.10, [install it](https://www.python.org/downloads/release/python-31011/) +- if you don't have `poetry`, [install it](https://python-poetry.org/docs/#installing-with-the-official-installer) +- clone this repository +- open a terminal and go to the folder to where you cloned this project +- enter `poetry install` + +This installs the software needed to develop `paddles`, in a new +[virtual environment](https://docs.python.org/3/glossary.html#term-virtual-environment), +in order to not interfere with your existing Python projects. + +To use the environment, while developing `paddles`, enter `poetry run C` +to execute command `C` in the virtual environment for `paddles`. + +Alternatively, you can enter `poetry shell` to activate the environment, and +then you can just enter `C` to execute the command. +To deactivate the environment, enter `exit`. + +In the rest of this document, the notation `[poetry run] C` means that you should enter +- `poetry run C` if you haven't activated the environment with `poetry shell` +- `C` if you have. + +To finish the setup, you may optionally enter `[poetry run] pre-commit install` +to install pre-commit hooks (scripts that are run when committing changes to a repository). +Our environment has configured hooks that test, check and format your code and +generate the documentation before you commit your changes to the repository. + +This project folder contains the following files and subfolders: + +- `README.md`: this file +- `LICENSE`: the code licence +- `pyproject.toml`: project configuration +- `poetry.lock`: list of the packages installed by `poetry install` +- `.pre-commit-config.yaml`: list of pre-commit hooks +- `paddles/`: subfolder with the library's code +- `tests/`: subfolder with the test code +- `docs/`: subfolder with the documentation generated from the library code + ## Testing -The library is tested with [pytest](https://pytest.org). +We use [pytest](https://pytest.org) to test `paddles`. The unit tests are in the `tests` subfolder, with one test file per library module. There's at least one test function per creator or modifier method. There are no test functions for inspector methods: they are indirectly tested by using them for closed-box (black-box) testing of the modifiers. -Each test file has the same structure: helper functions, -fixtures (functions that generate test data), tests for creator methods, -tests for modifier methods, used separately, and finally tests for combined use of modifiers. +Each test file contains, in this order: +1. helper functions +1. fixtures (functions that generate test data) +1. tests for creator methods +1. tests for modifier methods, used separately, and finally +1. tests for combined use of modifiers. -There are also simple interactive examples of how to use a class in that class's docstring, -in folder `paddles`. These are used as [doctests](https://docs.python.org/3.10/library/doctest.html). +Additionally, there are simple interactive examples of how to use a class in that class's docstring, +in subfolder `paddles`. These are used as [doctests](https://docs.python.org/3.10/library/doctest.html). -To run all tests, the doctests in `paddles` and the unit tests in `tests`, open a terminal, -go the project's main folder, i.e. the parent of `tests`, and enter `poetry run pytest`. -This will produce a report of which tests passed and which failed. -Any library code lines that weren't executed by the tests are also reported. -(We aim for 100% coverage.) +To run all tests, i.e. the doctests in `paddles` and the unit tests in `tests`, +enter `[poetry run] pytest`. +This will produce a report of which tests passed, which failed, and which +library code lines weren't executed. (We aim for 100% coverage.) If two implementations of the same ADT use different messages for the same exception for the same method, the tests fail. ## Linting -We check and format our code with [ruff](https://astral.sh/ruff). +We check and format all code (library and tests) with [ruff](https://astral.sh/ruff). -Open a terminal in the main project folder and enter `poetry run ruff check`. -The checked style rules are given [here](https://docs.astral.sh/ruff/rules), -with further explanations when you click on a rule's name. +To check the code against over 700 style rules, enter `[poetry run] ruff check`. +If `ruff` reports rule violations, open the [rules page](https://docs.astral.sh/ruff/rules), +search for the reported rule number (e.g. E101), and click on the rule name +(e.g. mixed-spaces-and-tabs) next to it in the page. +This will open a new page explaining the violated rule and its rationale, with an example, +like [this](https://docs.astral.sh/ruff/rules/mixed-spaces-and-tabs/). -To automatically fix violations, if possible, add the command line options -`--fix --unsafe-fixes` and check the changes made by `ruff`. +To automatically fix violations, when possible, +enter `[poetry run] ruff check --fix --unsafe-fixes` and double-check +the modifications made by `ruff`. To automatically ignore the flagged code lines for a particular file, -enter `poetry run ruff check path/to/file.py --add-noqa`. +enter `[poetry run] ruff check path/to/file.py --add-noqa`. This will add comments of the form `# noqa: ...` where `...` is the number of the violated rule. + This should be used sparingly. For example, in the test files, the fixtures that generate classes are on purpose named with initial uppercase, as classes are, which violates the rule that function names and arguments should be in lowercase. -Finally, enter `poetry run ruff format` to format all the code. +Finally, enter `[poetry run] ruff format` to format the code. ## Type checking We type check the code with [pytype](https://google.github.io/pytype). -Enter `poetry run pytype .` to type check all code. +Enter `[poetry run] pytype .` (note the dot) to type check all code. ## Documenting -We use [pydoc](https://pydoc.dev) to generate the documentation from the docstrings. - -To check the documents during development, enter `poetry run pdoc paddles &` -to open a live site with the documentation. Any changes to docstrings of -library files are immediately reflected in the site, upon saving the files. - -## Pre-commit hooks -If you enter `poetry run pre-commit install`, every time you commit your code, -these steps are done automatically on the _staged_ files only: -1. test the code -2. check the code for any type or style violations -3. format the code -4. generate the documentation. - -If a test or check fails in steps 1 and 2 or a file is modified in steps 3 and 4, +We use [pdoc](https://pdoc.dev) to generate the documentation from the docstrings. + +To check the documents during development, enter `[poetry run] pdoc paddles &` +to open a live site with the documentation. Any changes to the docstrings of +the library files are immediately reflected in the site, upon saving the files. + +## Comitting +If you installed the pre-commit hooks when setting up the [environment](#environment) +then every time you commit your code, +these steps are done automatically on the _staged_ files: +1. test the code with `pytest` +2. type check the code with `pytype` +3. check (but _don't_ fix) the code with `ruff` +4. format the code with `ruff` +5. generate the documentation with `pdoc`. + +If a test or check fails in steps 1–3 or if a file is modified in steps 4–5, then the commit doesn't go ahead. This allows you to review the errors and the automatically applied changes, stage the modified files, and commit again. -Due to the automated four steps, each commit takes several seconds to complete. -But when it does, you know that your code hasn't broken existing tests, +Due to the automated steps, each commit takes many seconds to complete. +But when it successfully completes, you know that your code hasn't broken existing tests, isn't poorly formatted, and has up-to-date documentation. \ No newline at end of file diff --git a/docs/paddles.html b/docs/paddles.html index a0fb4e6..0888d14 100644 --- a/docs/paddles.html +++ b/docs/paddles.html @@ -50,14 +50,16 @@
paddles
is a pedagogical algorithms and data structures library.
It currently implements the Stack, Queue and Deque abstract data types (ADTs).
+It currently implements the Stack, Queue and Deque abstract data types (ADTs).
+ +The code repository is at https://github.com/dsa-ou/paddles. +The formatted documentation is at https://dsa-ou.github.io/paddles.
The code and text in this repository are -Copyright © 2024 by The Open University, UK. -The code is licensed under a BSD-3-clause licence. -The text is licensed under a +
paddles
is Copyright © 2024 by The Open University, UK.
+The code is licensed under a BSD-3-clause licence.
+The documentation is licensed under a
Creative Commons Attribution 4.0 International Licence.
1"""`paddles` is a pedagogical algorithms and data structures library. 2 - 3It currently implements the Stack, Queue and Deque **abstract data types (ADTs)**. + 3It currently implements the Stack, Queue and Deque abstract data types (ADTs). 4 - 5## Licence - 6 - 7The code and text in this repository are - 8Copyright © 2024 by The Open University, UK. - 9The code is licensed under a [BSD-3-clause licence](../LICENSE.MD). -10The text is licensed under a -11[Creative Commons Attribution 4.0 International Licence](http://creativecommons.org/licenses/by/4.0). -12""" + 5The code repository is at https://github.com/dsa-ou/paddles. + 6The formatted documentation is at https://dsa-ou.github.io/paddles. + 7 + 8## Licence + 9 +10`paddles` is Copyright © 2024 by The Open University, UK. +11The code is licensed under a [BSD-3-clause licence](https://github.com/dsa-ou/paddles/blob/main/LICENSE). +12The documentation is licensed under a +13[Creative Commons Attribution 4.0 International Licence](http://creativecommons.org/licenses/by/4.0). +14"""
The Deque ADT models a line of objects that can be accessed, added to and -removed from either end of the line +removed from either end of the line. A deque can be used as a stack or as a queue.
A deque, pronounced 'deck' and short for 'double-ended queue', is a sequence -where only the members at both ends of the sequence. +where only the members at both ends of the sequence (called the front and the back of the queue) can be accessed and removed. New members can only be added at the front or at the back.
@@ -117,10 +117,13 @@Consider using a deque when you need to simulate a line of objects that can be accessed -from both ends, like cars on a ferry. -On one shore, cars leave the ferry from the front and new ones board it from the front. -On the other shore, cars leave and board the ferry from the back.
+Consider using a deque when you need to simulate a queue where
+ +56class LinkedListDeque: - 57 """An implementation of the Deque ADT, using a doubly-linked list. - 58 - 59 Besides the ADT's operations, this class provides two convenience operations: - 60 - create a non-empty deque from a given sequence - 61 - convert a deque to a string, to see its members listed from front to back. - 62 - 63 >>> from paddles.deque import LinkedListDeque - 64 >>> deque = LinkedListDeque("abc") # create a non-empty deque - 65 >>> deque.size() # number of members - 66 3 - 67 >>> deque.take_front() # remove and return the front member - 68 'a' - 69 >>> deque.take_back() # remove and return the back member - 70 'c' - 71 >>> deque.front() == deque.back() == 'b' # return the front and back members - 72 True - 73 >>> deque.add_back("C") # add a new member at the back - 74 >>> deque.add_front("A") # add a new member at the front - 75 >>> print(deque) # str(deque) also possible - 76 LinkedListDeque(['A', 'b', 'C']) - 77 """ - 78 - 79 def __init__(self, sequence: Sequence[Any] = []) -> None: - 80 """Initialize the deque with the members of `sequence`. - 81 - 82 The members are added to the deque in the order they are in `sequence`. - 83 To create an empty deque, call `LinkedListDeque()` or `LinkedListDeque([])`. - 84 - 85 Complexity: O(len(`sequence`)) - 86 """ - 87 self._head = None - 88 self._tail = None - 89 self._length = 0 - 90 if sequence: - 91 for item in sequence: - 92 self.add_back(item) - 93 - 94 def __str__(self) -> str: - 95 """Return a string representation of the deque. - 96 - 97 The string is 'LinkedListDeque([front member, ..., back member])'. - 98 - 99 Complexity: O(self.size()) -100 """ -101 strings = [] -102 current = self._head -103 while current: -104 strings.append(repr(current[DATA])) -105 current = current[NEXT] -106 return f"LinkedListDeque([{', '.join(strings)}])" -107 -108 def size(self) -> int: -109 """Return how many members the deque has. -110 -111 Complexity: O(1) -112 """ -113 return self._length -114 -115 def front(self) -> Any: -116 """Return the item at the front of the deque, without removing it. -117 -118 Raise `ValueError` if the deque is empty. -119 -120 Complexity: O(1) -121 """ -122 if self.size() == 0: -123 msg = "can't access the front of an empty deque" -124 raise ValueError(msg) -125 return self._head[DATA] -126 -127 def back(self) -> Any: -128 """Return the item at the back of the deque, without removing it. -129 -130 Raise `ValueError` if the deque is empty. -131 -132 Complexity: O(1) -133 """ -134 if self.size() == 0: -135 msg = "can't access the back of an empty deque" -136 raise ValueError(msg) -137 return self._tail[DATA] -138 -139 def add_front(self, item: Any) -> None: -140 """Put `item` at the front of the deque. -141 -142 Complexity: O(1) -143 """ -144 node = [None, item, self._head] -145 if self.size() == 0: -146 self._tail = node -147 else: -148 self._head[PREV] = node -149 self._head = node -150 self._length += 1 -151 -152 def add_back(self, item: Any) -> None: -153 """Put `item` at the back of the deque. -154 -155 Complexity: O(1) -156 """ -157 node = [self._tail, item, None] -158 if self.size() == 0: -159 self._head = node -160 else: -161 self._tail[NEXT] = node -162 self._tail = node -163 self._length += 1 -164 -165 def take_front(self) -> Any: -166 """Remove and return the item at the front of the deque. -167 -168 Raise `ValueError` if the deque is empty. -169 -170 Complexity: O(1) -171 """ -172 if self.size() == 0: -173 msg = "can't remove a member from an empty deque" -174 raise ValueError(msg) -175 item = self._head[DATA] -176 self._head = self._head[NEXT] -177 self._length -= 1 -178 if self.size() == 0: -179 self._tail = None -180 else: -181 self._head[PREV] = None -182 return item -183 -184 def take_back(self) -> Any: -185 """Remove and return the item at the back of the deque. -186 -187 Raise `ValueError` if the deque is empty. -188 -189 Complexity: O(1) -190 """ -191 if self.size() == 0: -192 msg = "can't remove a member from an empty deque" -193 raise ValueError(msg) -194 item = self._tail[DATA] -195 self._tail = self._tail[PREV] -196 self._length -= 1 -197 if self.size() == 0: -198 self._head = None -199 else: -200 self._tail[NEXT] = None -201 return item +@@ -538,20 +542,20 @@57class LinkedListDeque: + 58 """An implementation of the Deque ADT, using a doubly-linked list. + 59 + 60 Besides the ADT's operations, this class provides two convenience operations: + 61 - create a non-empty deque from a given sequence + 62 - convert a deque to a string, to see its members listed from front to back. + 63 + 64 >>> from paddles.deque import LinkedListDeque + 65 >>> deque = LinkedListDeque("abc") # create a non-empty deque + 66 >>> deque.size() # number of members + 67 3 + 68 >>> deque.take_front() # remove and return the front member + 69 'a' + 70 >>> deque.take_back() # remove and return the back member + 71 'c' + 72 >>> deque.front() == deque.back() == 'b' # return the front and back members + 73 True + 74 >>> deque.add_back("C") # add a new member at the back + 75 >>> deque.add_front("A") # add a new member at the front + 76 >>> print(deque) # str(deque) also possible + 77 LinkedListDeque(['A', 'b', 'C']) + 78 """ + 79 + 80 def __init__(self, sequence: Sequence[Any] = []) -> None: + 81 """Initialize the deque with the members of `sequence`. + 82 + 83 The members are added to the deque in the order they are in `sequence`. + 84 To create an empty deque, call `LinkedListDeque()` or `LinkedListDeque([])`. + 85 + 86 Complexity: O(len(`sequence`)) + 87 """ + 88 self._head = None + 89 self._tail = None + 90 self._length = 0 + 91 if sequence: + 92 for item in sequence: + 93 self.add_back(item) + 94 + 95 def __str__(self) -> str: + 96 """Return a string representation of the deque. + 97 + 98 The string is 'LinkedListDeque([front member, ..., back member])'. + 99 +100 Complexity: O(self.size()) +101 """ +102 strings = [] +103 current = self._head +104 while current: +105 strings.append(repr(current[DATA])) +106 current = current[NEXT] +107 return f"LinkedListDeque([{', '.join(strings)}])" +108 +109 def size(self) -> int: +110 """Return how many members the deque has. +111 +112 Complexity: O(1) +113 """ +114 return self._length +115 +116 def front(self) -> Any: +117 """Return the item at the front of the deque, without removing it. +118 +119 Raise `ValueError` if the deque is empty. +120 +121 Complexity: O(1) +122 """ +123 if self.size() == 0: +124 msg = "can't access the front of an empty deque" +125 raise ValueError(msg) +126 return self._head[DATA] +127 +128 def back(self) -> Any: +129 """Return the item at the back of the deque, without removing it. +130 +131 Raise `ValueError` if the deque is empty. +132 +133 Complexity: O(1) +134 """ +135 if self.size() == 0: +136 msg = "can't access the back of an empty deque" +137 raise ValueError(msg) +138 return self._tail[DATA] +139 +140 def add_front(self, item: Any) -> None: +141 """Put `item` at the front of the deque. +142 +143 Complexity: O(1) +144 """ +145 node = [None, item, self._head] +146 if self.size() == 0: +147 self._tail = node +148 else: +149 self._head[PREV] = node +150 self._head = node +151 self._length += 1 +152 +153 def add_back(self, item: Any) -> None: +154 """Put `item` at the back of the deque. +155 +156 Complexity: O(1) +157 """ +158 node = [self._tail, item, None] +159 if self.size() == 0: +160 self._head = node +161 else: +162 self._tail[NEXT] = node +163 self._tail = node +164 self._length += 1 +165 +166 def take_front(self) -> Any: +167 """Remove and return the item at the front of the deque. +168 +169 Raise `ValueError` if the deque is empty. +170 +171 Complexity: O(1) +172 """ +173 if self.size() == 0: +174 msg = "can't remove a member from an empty deque" +175 raise ValueError(msg) +176 item = self._head[DATA] +177 self._head = self._head[NEXT] +178 self._length -= 1 +179 if self.size() == 0: +180 self._tail = None +181 else: +182 self._head[PREV] = None +183 return item +184 +185 def take_back(self) -> Any: +186 """Remove and return the item at the back of the deque. +187 +188 Raise `ValueError` if the deque is empty. +189 +190 Complexity: O(1) +191 """ +192 if self.size() == 0: +193 msg = "can't remove a member from an empty deque" +194 raise ValueError(msg) +195 item = self._tail[DATA] +196 self._tail = self._tail[PREV] +197 self._length -= 1 +198 if self.size() == 0: +199 self._head = None +200 else: +201 self._tail[NEXT] = None +202 return itemImplementations
79 def __init__(self, sequence: Sequence[Any] = []) -> None: -80 """Initialize the deque with the members of `sequence`. -81 -82 The members are added to the deque in the order they are in `sequence`. -83 To create an empty deque, call `LinkedListDeque()` or `LinkedListDeque([])`. -84 -85 Complexity: O(len(`sequence`)) -86 """ -87 self._head = None -88 self._tail = None -89 self._length = 0 -90 if sequence: -91 for item in sequence: -92 self.add_back(item) +@@ -576,12 +580,12 @@80 def __init__(self, sequence: Sequence[Any] = []) -> None: +81 """Initialize the deque with the members of `sequence`. +82 +83 The members are added to the deque in the order they are in `sequence`. +84 To create an empty deque, call `LinkedListDeque()` or `LinkedListDeque([])`. +85 +86 Complexity: O(len(`sequence`)) +87 """ +88 self._head = None +89 self._tail = None +90 self._length = 0 +91 if sequence: +92 for item in sequence: +93 self.add_back(item)Implementations
108 def size(self) -> int: -109 """Return how many members the deque has. -110 -111 Complexity: O(1) -112 """ -113 return self._length +@@ -603,17 +607,17 @@109 def size(self) -> int: +110 """Return how many members the deque has. +111 +112 Complexity: O(1) +113 """ +114 return self._lengthImplementations
115 def front(self) -> Any: -116 """Return the item at the front of the deque, without removing it. -117 -118 Raise `ValueError` if the deque is empty. -119 -120 Complexity: O(1) -121 """ -122 if self.size() == 0: -123 msg = "can't access the front of an empty deque" -124 raise ValueError(msg) -125 return self._head[DATA] +@@ -637,17 +641,17 @@116 def front(self) -> Any: +117 """Return the item at the front of the deque, without removing it. +118 +119 Raise `ValueError` if the deque is empty. +120 +121 Complexity: O(1) +122 """ +123 if self.size() == 0: +124 msg = "can't access the front of an empty deque" +125 raise ValueError(msg) +126 return self._head[DATA]Implementations
127 def back(self) -> Any: -128 """Return the item at the back of the deque, without removing it. -129 -130 Raise `ValueError` if the deque is empty. -131 -132 Complexity: O(1) -133 """ -134 if self.size() == 0: -135 msg = "can't access the back of an empty deque" -136 raise ValueError(msg) -137 return self._tail[DATA] +@@ -671,18 +675,18 @@128 def back(self) -> Any: +129 """Return the item at the back of the deque, without removing it. +130 +131 Raise `ValueError` if the deque is empty. +132 +133 Complexity: O(1) +134 """ +135 if self.size() == 0: +136 msg = "can't access the back of an empty deque" +137 raise ValueError(msg) +138 return self._tail[DATA]Implementations
139 def add_front(self, item: Any) -> None: -140 """Put `item` at the front of the deque. -141 -142 Complexity: O(1) -143 """ -144 node = [None, item, self._head] -145 if self.size() == 0: -146 self._tail = node -147 else: -148 self._head[PREV] = node -149 self._head = node -150 self._length += 1 +@@ -704,18 +708,18 @@140 def add_front(self, item: Any) -> None: +141 """Put `item` at the front of the deque. +142 +143 Complexity: O(1) +144 """ +145 node = [None, item, self._head] +146 if self.size() == 0: +147 self._tail = node +148 else: +149 self._head[PREV] = node +150 self._head = node +151 self._length += 1Implementations
152 def add_back(self, item: Any) -> None: -153 """Put `item` at the back of the deque. -154 -155 Complexity: O(1) -156 """ -157 node = [self._tail, item, None] -158 if self.size() == 0: -159 self._head = node -160 else: -161 self._tail[NEXT] = node -162 self._tail = node -163 self._length += 1 +@@ -737,24 +741,24 @@153 def add_back(self, item: Any) -> None: +154 """Put `item` at the back of the deque. +155 +156 Complexity: O(1) +157 """ +158 node = [self._tail, item, None] +159 if self.size() == 0: +160 self._head = node +161 else: +162 self._tail[NEXT] = node +163 self._tail = node +164 self._length += 1Implementations
165 def take_front(self) -> Any: -166 """Remove and return the item at the front of the deque. -167 -168 Raise `ValueError` if the deque is empty. -169 -170 Complexity: O(1) -171 """ -172 if self.size() == 0: -173 msg = "can't remove a member from an empty deque" -174 raise ValueError(msg) -175 item = self._head[DATA] -176 self._head = self._head[NEXT] -177 self._length -= 1 -178 if self.size() == 0: -179 self._tail = None -180 else: -181 self._head[PREV] = None -182 return item +@@ -778,24 +782,24 @@166 def take_front(self) -> Any: +167 """Remove and return the item at the front of the deque. +168 +169 Raise `ValueError` if the deque is empty. +170 +171 Complexity: O(1) +172 """ +173 if self.size() == 0: +174 msg = "can't remove a member from an empty deque" +175 raise ValueError(msg) +176 item = self._head[DATA] +177 self._head = self._head[NEXT] +178 self._length -= 1 +179 if self.size() == 0: +180 self._tail = None +181 else: +182 self._head[PREV] = None +183 return itemImplementations
184 def take_back(self) -> Any: -185 """Remove and return the item at the back of the deque. -186 -187 Raise `ValueError` if the deque is empty. -188 -189 Complexity: O(1) -190 """ -191 if self.size() == 0: -192 msg = "can't remove a member from an empty deque" -193 raise ValueError(msg) -194 item = self._tail[DATA] -195 self._tail = self._tail[PREV] -196 self._length -= 1 -197 if self.size() == 0: -198 self._head = None -199 else: -200 self._tail[NEXT] = None -201 return item +diff --git a/docs/search.js b/docs/search.js index a2072b1..8b6eb2c 100644 --- a/docs/search.js +++ b/docs/search.js @@ -1,6 +1,6 @@ window.pdocSearch = (function(){ /** elasticlunr - http://weixsong.github.io * Copyright (C) 2017 Oliver Nightingale * Copyright (C) 2017 Wei Song * MIT Licensed */!function(){function e(e){if(null===e||"object"!=typeof e)return e;var t=e.constructor();for(var n in e)e.hasOwnProperty(n)&&(t[n]=e[n]);return t}var t=function(e){var n=new t.Index;return n.pipeline.add(t.trimmer,t.stopWordFilter,t.stemmer),e&&e.call(n,n),n};t.version="0.9.5",lunr=t,t.utils={},t.utils.warn=function(e){return function(t){e.console&&console.warn&&console.warn(t)}}(this),t.utils.toString=function(e){return void 0===e||null===e?"":e.toString()},t.EventEmitter=function(){this.events={}},t.EventEmitter.prototype.addListener=function(){var e=Array.prototype.slice.call(arguments),t=e.pop(),n=e;if("function"!=typeof t)throw new TypeError("last argument must be a function");n.forEach(function(e){this.hasHandler(e)||(this.events[e]=[]),this.events[e].push(t)},this)},t.EventEmitter.prototype.removeListener=function(e,t){if(this.hasHandler(e)){var n=this.events[e].indexOf(t);-1!==n&&(this.events[e].splice(n,1),0==this.events[e].length&&delete this.events[e])}},t.EventEmitter.prototype.emit=function(e){if(this.hasHandler(e)){var t=Array.prototype.slice.call(arguments,1);this.events[e].forEach(function(e){e.apply(void 0,t)},this)}},t.EventEmitter.prototype.hasHandler=function(e){return e in this.events},t.tokenizer=function(e){if(!arguments.length||null===e||void 0===e)return[];if(Array.isArray(e)){var n=e.filter(function(e){return null===e||void 0===e?!1:!0});n=n.map(function(e){return t.utils.toString(e).toLowerCase()});var i=[];return n.forEach(function(e){var n=e.split(t.tokenizer.seperator);i=i.concat(n)},this),i}return e.toString().trim().toLowerCase().split(t.tokenizer.seperator)},t.tokenizer.defaultSeperator=/[\s\-]+/,t.tokenizer.seperator=t.tokenizer.defaultSeperator,t.tokenizer.setSeperator=function(e){null!==e&&void 0!==e&&"object"==typeof e&&(t.tokenizer.seperator=e)},t.tokenizer.resetSeperator=function(){t.tokenizer.seperator=t.tokenizer.defaultSeperator},t.tokenizer.getSeperator=function(){return t.tokenizer.seperator},t.Pipeline=function(){this._queue=[]},t.Pipeline.registeredFunctions={},t.Pipeline.registerFunction=function(e,n){n in t.Pipeline.registeredFunctions&&t.utils.warn("Overwriting existing registered function: "+n),e.label=n,t.Pipeline.registeredFunctions[n]=e},t.Pipeline.getRegisteredFunction=function(e){return e in t.Pipeline.registeredFunctions!=!0?null:t.Pipeline.registeredFunctions[e]},t.Pipeline.warnIfFunctionNotRegistered=function(e){var n=e.label&&e.label in this.registeredFunctions;n||t.utils.warn("Function is not registered with pipeline. This may cause problems when serialising the index.\n",e)},t.Pipeline.load=function(e){var n=new t.Pipeline;return e.forEach(function(e){var i=t.Pipeline.getRegisteredFunction(e);if(!i)throw new Error("Cannot load un-registered function: "+e);n.add(i)}),n},t.Pipeline.prototype.add=function(){var e=Array.prototype.slice.call(arguments);e.forEach(function(e){t.Pipeline.warnIfFunctionNotRegistered(e),this._queue.push(e)},this)},t.Pipeline.prototype.after=function(e,n){t.Pipeline.warnIfFunctionNotRegistered(n);var i=this._queue.indexOf(e);if(-1===i)throw new Error("Cannot find existingFn");this._queue.splice(i+1,0,n)},t.Pipeline.prototype.before=function(e,n){t.Pipeline.warnIfFunctionNotRegistered(n);var i=this._queue.indexOf(e);if(-1===i)throw new Error("Cannot find existingFn");this._queue.splice(i,0,n)},t.Pipeline.prototype.remove=function(e){var t=this._queue.indexOf(e);-1!==t&&this._queue.splice(t,1)},t.Pipeline.prototype.run=function(e){for(var t=[],n=e.length,i=this._queue.length,o=0;n>o;o++){for(var r=e[o],s=0;i>s&&(r=this._queue[s](r,o,e),void 0!==r&&null!==r);s++);void 0!==r&&null!==r&&t.push(r)}return t},t.Pipeline.prototype.reset=function(){this._queue=[]},t.Pipeline.prototype.get=function(){return this._queue},t.Pipeline.prototype.toJSON=function(){return this._queue.map(function(e){return t.Pipeline.warnIfFunctionNotRegistered(e),e.label})},t.Index=function(){this._fields=[],this._ref="id",this.pipeline=new t.Pipeline,this.documentStore=new t.DocumentStore,this.index={},this.eventEmitter=new t.EventEmitter,this._idfCache={},this.on("add","remove","update",function(){this._idfCache={}}.bind(this))},t.Index.prototype.on=function(){var e=Array.prototype.slice.call(arguments);return this.eventEmitter.addListener.apply(this.eventEmitter,e)},t.Index.prototype.off=function(e,t){return this.eventEmitter.removeListener(e,t)},t.Index.load=function(e){e.version!==t.version&&t.utils.warn("version mismatch: current "+t.version+" importing "+e.version);var n=new this;n._fields=e.fields,n._ref=e.ref,n.documentStore=t.DocumentStore.load(e.documentStore),n.pipeline=t.Pipeline.load(e.pipeline),n.index={};for(var i in e.index)n.index[i]=t.InvertedIndex.load(e.index[i]);return n},t.Index.prototype.addField=function(e){return this._fields.push(e),this.index[e]=new t.InvertedIndex,this},t.Index.prototype.setRef=function(e){return this._ref=e,this},t.Index.prototype.saveDocument=function(e){return this.documentStore=new t.DocumentStore(e),this},t.Index.prototype.addDoc=function(e,n){if(e){var n=void 0===n?!0:n,i=e[this._ref];this.documentStore.addDoc(i,e),this._fields.forEach(function(n){var o=this.pipeline.run(t.tokenizer(e[n]));this.documentStore.addFieldLength(i,n,o.length);var r={};o.forEach(function(e){e in r?r[e]+=1:r[e]=1},this);for(var s in r){var u=r[s];u=Math.sqrt(u),this.index[n].addToken(s,{ref:i,tf:u})}},this),n&&this.eventEmitter.emit("add",e,this)}},t.Index.prototype.removeDocByRef=function(e){if(e&&this.documentStore.isDocStored()!==!1&&this.documentStore.hasDoc(e)){var t=this.documentStore.getDoc(e);this.removeDoc(t,!1)}},t.Index.prototype.removeDoc=function(e,n){if(e){var n=void 0===n?!0:n,i=e[this._ref];this.documentStore.hasDoc(i)&&(this.documentStore.removeDoc(i),this._fields.forEach(function(n){var o=this.pipeline.run(t.tokenizer(e[n]));o.forEach(function(e){this.index[n].removeToken(e,i)},this)},this),n&&this.eventEmitter.emit("remove",e,this))}},t.Index.prototype.updateDoc=function(e,t){var t=void 0===t?!0:t;this.removeDocByRef(e[this._ref],!1),this.addDoc(e,!1),t&&this.eventEmitter.emit("update",e,this)},t.Index.prototype.idf=function(e,t){var n="@"+t+"/"+e;if(Object.prototype.hasOwnProperty.call(this._idfCache,n))return this._idfCache[n];var i=this.index[t].getDocFreq(e),o=1+Math.log(this.documentStore.length/(i+1));return this._idfCache[n]=o,o},t.Index.prototype.getFields=function(){return this._fields.slice()},t.Index.prototype.search=function(e,n){if(!e)return[];e="string"==typeof e?{any:e}:JSON.parse(JSON.stringify(e));var i=null;null!=n&&(i=JSON.stringify(n));for(var o=new t.Configuration(i,this.getFields()).get(),r={},s=Object.keys(e),u=0;u185 def take_back(self) -> Any: +186 """Remove and return the item at the back of the deque. +187 +188 Raise `ValueError` if the deque is empty. +189 +190 Complexity: O(1) +191 """ +192 if self.size() == 0: +193 msg = "can't remove a member from an empty deque" +194 raise ValueError(msg) +195 item = self._tail[DATA] +196 self._tail = self._tail[PREV] +197 self._length -= 1 +198 if self.size() == 0: +199 self._head = None +200 else: +201 self._tail[NEXT] = None +202 return item0&&t.push(e);for(var i in n)"docs"!==i&&"df"!==i&&this.expandToken(e+i,t,n[i]);return t},t.InvertedIndex.prototype.toJSON=function(){return{root:this.root}},t.Configuration=function(e,n){var e=e||"";if(void 0==n||null==n)throw new Error("fields should not be null");this.config={};var i;try{i=JSON.parse(e),this.buildUserConfig(i,n)}catch(o){t.utils.warn("user configuration parse failed, will use default configuration"),this.buildDefaultConfig(n)}},t.Configuration.prototype.buildDefaultConfig=function(e){this.reset(),e.forEach(function(e){this.config[e]={boost:1,bool:"OR",expand:!1}},this)},t.Configuration.prototype.buildUserConfig=function(e,n){var i="OR",o=!1;if(this.reset(),"bool"in e&&(i=e.bool||i),"expand"in e&&(o=e.expand||o),"fields"in e)for(var r in e.fields)if(n.indexOf(r)>-1){var s=e.fields[r],u=o;void 0!=s.expand&&(u=s.expand),this.config[r]={boost:s.boost||0===s.boost?s.boost:1,bool:s.bool||i,expand:u}}else t.utils.warn("field name in user configuration not found in index instance fields");else this.addAllFields2UserConfig(i,o,n)},t.Configuration.prototype.addAllFields2UserConfig=function(e,t,n){n.forEach(function(n){this.config[n]={boost:1,bool:e,expand:t}},this)},t.Configuration.prototype.get=function(){return this.config},t.Configuration.prototype.reset=function(){this.config={}},lunr.SortedSet=function(){this.length=0,this.elements=[]},lunr.SortedSet.load=function(e){var t=new this;return t.elements=e,t.length=e.length,t},lunr.SortedSet.prototype.add=function(){var e,t;for(e=0;e 1;){if(r===e)return o;e>r&&(t=o),r>e&&(n=o),i=n-t,o=t+Math.floor(i/2),r=this.elements[o]}return r===e?o:-1},lunr.SortedSet.prototype.locationFor=function(e){for(var t=0,n=this.elements.length,i=n-t,o=t+Math.floor(i/2),r=this.elements[o];i>1;)e>r&&(t=o),r>e&&(n=o),i=n-t,o=t+Math.floor(i/2),r=this.elements[o];return r>e?o:e>r?o+1:void 0},lunr.SortedSet.prototype.intersect=function(e){for(var t=new lunr.SortedSet,n=0,i=0,o=this.length,r=e.length,s=this.elements,u=e.elements;;){if(n>o-1||i>r-1)break;s[n]!==u[i]?s[n]u[i]&&i++:(t.add(s[n]),n++,i++)}return t},lunr.SortedSet.prototype.clone=function(){var e=new lunr.SortedSet;return e.elements=this.toArray(),e.length=e.elements.length,e},lunr.SortedSet.prototype.union=function(e){var t,n,i;this.length>=e.length?(t=this,n=e):(t=e,n=this),i=t.clone();for(var o=0,r=n.toArray();o paddles
is a pedagogical algorithms and data structures library.\n\nIt currently implements the Stack, Queue and Deque abstract data types (ADTs).
\n\nLicence
\n\nThe code and text in this repository are\nCopyright \u00a9 2024 by The Open University, UK.\nThe code is licensed under a BSD-3-clause licence.\nThe text is licensed under a\nCreative Commons Attribution 4.0 International Licence.
\n"}, {"fullname": "paddles.deque", "modulename": "paddles.deque", "kind": "module", "doc": "This module implements the Deque ADT.
\n\nIntuition
\n\nThe Deque ADT models a line of objects that can be accessed, added to and\nremoved from either end of the line\nA deque can be used as a stack or as a queue.
\n\nDefinition
\n\nA deque, pronounced 'deck' and short for 'double-ended queue', is a sequence\nwhere only the members at both ends of the sequence.\n(called the front and the back of the queue) can be accessed and removed.\nNew members can only be added at the front or at the back.
\n\nOperations
\n\nThe Deque ADT provides operations to:
\n\n\n
\n\n- create a new empty deque
\n- add a new member to the front of the deque
\n- add a new member to the back of the deque
\n- remove the member at the front of the deque
\n- remove the member at the back of the deque
\n- access the member at the front of the deque without removing it
\n- access the member at the back of the deque without removing it
\n- compute the size of the deque (number of members).
\nApplications
\n\nConsider using a deque when you need to simulate a line of objects that can be accessed\nfrom both ends, like cars on a ferry.\nOn one shore, cars leave the ferry from the front and new ones board it from the front.\nOn the other shore, cars leave and board the ferry from the back.
\n\nImplementations
\n\nThe Deque ADT can be implemented with circular dynamic arrays or doubly-linked lists.\nIn both cases, the operations listed above take constant time.\nA doubly-linked list uses much more memory than a static array of the same length,\nbut a dynamic array may have wasted capacity and requires resizing.\n
\n"}, {"fullname": "paddles.deque.LinkedListDeque", "modulename": "paddles.deque", "qualname": "LinkedListDeque", "kind": "class", "doc": "paddles
only provides a doubly-linked list implementation for the moment.An implementation of the Deque ADT, using a doubly-linked list.
\n\nBesides the ADT's operations, this class provides two convenience operations:
\n\n\n
\n\n- create a non-empty deque from a given sequence
\n- convert a deque to a string, to see its members listed from front to back.
\n\n\n"}, {"fullname": "paddles.deque.LinkedListDeque.__init__", "modulename": "paddles.deque", "qualname": "LinkedListDeque.__init__", "kind": "function", "doc": "\n>>> from paddles.deque import LinkedListDeque\n>>> deque = LinkedListDeque("abc") # create a non-empty deque\n>>> deque.size() # number of members\n3\n>>> deque.take_front() # remove and return the front member\n'a'\n>>> deque.take_back() # remove and return the back member\n'c'\n>>> deque.front() == deque.back() == 'b' # return the front and back members\nTrue\n>>> deque.add_back("C") # add a new member at the back\n>>> deque.add_front("A") # add a new member at the front\n>>> print(deque) # str(deque) also possible\nLinkedListDeque(['A', 'b', 'C'])\n
Initialize the deque with the members of
\n\nsequence
.The members are added to the deque in the order they are in
\n\nsequence
.\nTo create an empty deque, callLinkedListDeque()
orLinkedListDeque([])
.Complexity: O(len(
\n", "signature": "(sequence: collections.abc.Sequence[typing.Any] = [])"}, {"fullname": "paddles.deque.LinkedListDeque.size", "modulename": "paddles.deque", "qualname": "LinkedListDeque.size", "kind": "function", "doc": "sequence
))Return how many members the deque has.
\n\nComplexity: O(1)
\n", "signature": "(self) -> int:", "funcdef": "def"}, {"fullname": "paddles.deque.LinkedListDeque.front", "modulename": "paddles.deque", "qualname": "LinkedListDeque.front", "kind": "function", "doc": "Return the item at the front of the deque, without removing it.
\n\nRaise
\n\nValueError
if the deque is empty.Complexity: O(1)
\n", "signature": "(self) -> Any:", "funcdef": "def"}, {"fullname": "paddles.deque.LinkedListDeque.back", "modulename": "paddles.deque", "qualname": "LinkedListDeque.back", "kind": "function", "doc": "Return the item at the back of the deque, without removing it.
\n\nRaise
\n\nValueError
if the deque is empty.Complexity: O(1)
\n", "signature": "(self) -> Any:", "funcdef": "def"}, {"fullname": "paddles.deque.LinkedListDeque.add_front", "modulename": "paddles.deque", "qualname": "LinkedListDeque.add_front", "kind": "function", "doc": "Put
\n\nitem
at the front of the deque.Complexity: O(1)
\n", "signature": "(self, item: Any) -> None:", "funcdef": "def"}, {"fullname": "paddles.deque.LinkedListDeque.add_back", "modulename": "paddles.deque", "qualname": "LinkedListDeque.add_back", "kind": "function", "doc": "Put
\n\nitem
at the back of the deque.Complexity: O(1)
\n", "signature": "(self, item: Any) -> None:", "funcdef": "def"}, {"fullname": "paddles.deque.LinkedListDeque.take_front", "modulename": "paddles.deque", "qualname": "LinkedListDeque.take_front", "kind": "function", "doc": "Remove and return the item at the front of the deque.
\n\nRaise
\n\nValueError
if the deque is empty.Complexity: O(1)
\n", "signature": "(self) -> Any:", "funcdef": "def"}, {"fullname": "paddles.deque.LinkedListDeque.take_back", "modulename": "paddles.deque", "qualname": "LinkedListDeque.take_back", "kind": "function", "doc": "Remove and return the item at the back of the deque.
\n\nRaise
\n\nValueError
if the deque is empty.Complexity: O(1)
\n", "signature": "(self) -> Any:", "funcdef": "def"}, {"fullname": "paddles.queue", "modulename": "paddles.queue", "kind": "module", "doc": "This module implements the Queue ADT.
\n\nIntuition
\n\nThe Queue ADT models a line of objects, e.g. cars waiting to board a ferry.\nOnly the object at the front of the line can be accessed and removed.\nThe only way to add an object is to put it at the back of the line.
\n\nDefinition
\n\nA queue is a sequence where members are added to one end of the sequence\n(the back of the queue) and removed from the other end (the front of the queue).
\n\nA queue is a first-in, first-out (FIFO) sequence:\nthe members are removed in the same order they were added.
\n\nA queue is a sequence ordered by age (time of addition).\nThe oldest member is at the front of the queue, and the youngest member is at the back.
\n\nOperations
\n\nThe Queue ADT provides operations to:
\n\n\n
\n\n- create a new empty queue
\n- add a new member, at the back of the existing ones
\n- remove the member at the front of the queue
\n- access the member at the front of the queue without removing it
\n- compute the size of the queue (number of members).
\nApplications
\n\nQueues are used to implement breadth-first search.\nYou should consider using a queue when you need to:
\n\n\n
\n\n- simulate a real-life queue, like travellers at passport control or\ndocuments in a printer queue
\n- process items in the same order they were added, like a to-do list.
\nImplementations
\n\nThe Queue ADT can be implemented with circular dynamic arrays or singly-linked lists.\nIn both cases, the operations listed above take constant time.\nA singly-linked list uses much more memory than a static array of the same length,\nbut a dynamic array may have wasted capacity and requires resizing.\n
\n"}, {"fullname": "paddles.queue.LinkedListQueue", "modulename": "paddles.queue", "qualname": "LinkedListQueue", "kind": "class", "doc": "paddles
only provides a singly-linked list implementation for the moment.An implementation of the Queue ADT, using a singly-linked list.
\n\nBesides the ADT's operations, this class provides two convenience operations:
\n\n\n
\n\n- create a non-empty queue from a given sequence
\n- convert a queue to a string, to see its members listed from front to back.
\n\n\n"}, {"fullname": "paddles.queue.LinkedListQueue.__init__", "modulename": "paddles.queue", "qualname": "LinkedListQueue.__init__", "kind": "function", "doc": "\n>>> from paddles.queue import LinkedListQueue\n>>> q = LinkedListQueue("abc") # create a non-empty queue\n>>> q.size() # number of members\n3\n>>> q.dequeue() # remove and return the front member\n'a'\n>>> q.front() # return but don't remove the front member\n'b'\n>>> q.enqueue("d") # add a new member at the back\n>>> print(q) # str(q) also possible\nLinkedListQueue(['b', 'c', 'd'])\n
Initialize the queue with the members of
\n\nsequence
.The members are added to the queue in the order they are in
\n\nsequence
.\nTo create an empty queue, callLinkedListQueue()
orLinkedListQueue([])
.Complexity: O(len(
\n", "signature": "(sequence: collections.abc.Sequence[typing.Any] = [])"}, {"fullname": "paddles.queue.LinkedListQueue.size", "modulename": "paddles.queue", "qualname": "LinkedListQueue.size", "kind": "function", "doc": "sequence
))Return how many members the queue has.
\n\nComplexity: O(1)
\n", "signature": "(self) -> int:", "funcdef": "def"}, {"fullname": "paddles.queue.LinkedListQueue.front", "modulename": "paddles.queue", "qualname": "LinkedListQueue.front", "kind": "function", "doc": "Return the member at the front of the queue, without removing it.
\n\nRaise
\n\nValueError
if the queue is empty.Complexity: O(1)
\n", "signature": "(self) -> Any:", "funcdef": "def"}, {"fullname": "paddles.queue.LinkedListQueue.enqueue", "modulename": "paddles.queue", "qualname": "LinkedListQueue.enqueue", "kind": "function", "doc": "Put
\n\nitem
at the back of the queue.Complexity: O(1)
\n", "signature": "(self, item: Any) -> None:", "funcdef": "def"}, {"fullname": "paddles.queue.LinkedListQueue.dequeue", "modulename": "paddles.queue", "qualname": "LinkedListQueue.dequeue", "kind": "function", "doc": "Remove and return the item at the front of the queue.
\n\nRaise
\n\nValueError
if the queue is empty.Complexity: O(1)
\n", "signature": "(self) -> Any:", "funcdef": "def"}, {"fullname": "paddles.stack", "modulename": "paddles.stack", "kind": "module", "doc": "This module implements the Stack ADT.
\n\nIntuition
\n\nThe Stack ADT models a pile of objects, e.g. a pile of storage boxes.\nOnly the object at the top of the pile can be accessed and removed.\nThe only way to add an object is to put it on top of the existing pile.
\n\nDefinition
\n\nA stack is a sequence where members are removed from and added to\nthe same end of the sequence, called the top of the stack.
\n\nA stack is a last-in, first-out (LIFO) sequence:\nthe next member to be removed is the one most recently added.
\n\nA stack is a sequence ordered by age (time of addition).\nThe oldest member is at the bottom of the stack, and the youngest member is at the top.
\n\nOperations
\n\nThe Stack ADT provides operations to:
\n\n\n
\n\n- create a new empty stack
\n- add a new member, on top of the existing ones
\n- remove the member at the top of the stack
\n- access the member at the top of the stack without removing it
\n- compute the size of the stack (number of members).
\nApplications
\n\nStacks are used to implement function calls and depth-first search.\nYou should consider using a stack when you need to:
\n\n\n
\n\n- simulate the handling of a pile of objects, like loading and unloading ship containers
\n- process nested structures, like brackets (e.g.
\nprint([1, {2, 3}])
) or\nHTML tags (e.g.<p><b>text</b></p>
)- process items in the reverse order they were added, like undo operations\n(the next command to be undone is the most recently executed one).
\nImplementations
\n\nThe Stack ADT can be implemented with dynamic arrays or singly-linked lists.\nIn both cases, the operations listed above take constant time.\nA singly-linked list uses much more memory than a static array of the same length,\nbut a dynamic array may have wasted capacity and requires resizing.
\n"}, {"fullname": "paddles.stack.DynamicArrayStack", "modulename": "paddles.stack", "qualname": "DynamicArrayStack", "kind": "class", "doc": "An implementation of the Stack ADT, using Python lists.
\n\nBesides the ADT's operations, this class provides two convenience operations:
\n\n\n
\n\n- create a non-empty stack from a given sequence
\n- convert a stack to a string, to see its members listed from bottom to top.
\n\n\n"}, {"fullname": "paddles.stack.DynamicArrayStack.__init__", "modulename": "paddles.stack", "qualname": "DynamicArrayStack.__init__", "kind": "function", "doc": "\n>>> from paddles.stack import DynamicArrayStack\n>>> stack = DynamicArrayStack("abc") # create a non-empty stack\n>>> stack.size() # number of members\n3\n>>> stack.pop() # remove and return the top member\n'c'\n>>> stack.peek() # return but don't remove the top member\n'b'\n>>> stack.push("C") # add a new member on top\n>>> print(stack) # str(stack) also possible\nDynamicArrayStack(['a', 'b', 'C'])\n
Initialize the stack with the members of
\n\nsequence
.The members are added to the stack in the order they are in
\n\nsequence
.\nTo create an empty stack, callDynamicArrayStack()
orDynamicArrayStack([])
.Complexity: O(len(
\n", "signature": "(sequence: collections.abc.Sequence[typing.Any] = [])"}, {"fullname": "paddles.stack.DynamicArrayStack.size", "modulename": "paddles.stack", "qualname": "DynamicArrayStack.size", "kind": "function", "doc": "sequence
))Return how many members the stack has.
\n\nComplexity: O(1)
\n", "signature": "(self) -> int:", "funcdef": "def"}, {"fullname": "paddles.stack.DynamicArrayStack.peek", "modulename": "paddles.stack", "qualname": "DynamicArrayStack.peek", "kind": "function", "doc": "Return the member at the top of the stack, without removing it.
\n\nRaise
\n\nValueError
if the stack is empty.Complexity: O(1)
\n", "signature": "(self) -> Any:", "funcdef": "def"}, {"fullname": "paddles.stack.DynamicArrayStack.push", "modulename": "paddles.stack", "qualname": "DynamicArrayStack.push", "kind": "function", "doc": "Put
\n\nitem
on top of the stack.Complexity: O(1)
\n", "signature": "(self, item: Any) -> None:", "funcdef": "def"}, {"fullname": "paddles.stack.DynamicArrayStack.pop", "modulename": "paddles.stack", "qualname": "DynamicArrayStack.pop", "kind": "function", "doc": "Remove and return the member at the top of the stack.
\n\nRaise
\n\nValueError
if the stack is empty.Complexity: O(1)
\n", "signature": "(self) -> Any:", "funcdef": "def"}, {"fullname": "paddles.stack.LinkedListStack", "modulename": "paddles.stack", "qualname": "LinkedListStack", "kind": "class", "doc": "An implementation of the Stack ADT, using singly-linked lists.
\n\nBesides the ADT's operations, this class provides two convenience operations:
\n\n\n
\n\n- create a non-empty stack from a given sequence
\n- convert a stack to a string, to see its members listed from bottom to top.
\n\n\n"}, {"fullname": "paddles.stack.LinkedListStack.__init__", "modulename": "paddles.stack", "qualname": "LinkedListStack.__init__", "kind": "function", "doc": "\n>>> from paddles.stack import LinkedListStack\n>>> stack = LinkedListStack("abc") # create a non-empty stack\n>>> stack.size() # number of members\n3\n>>> stack.pop() # remove and return the top member\n'c'\n>>> stack.peek() # return but don't remove the top member\n'b'\n>>> stack.push("C") # add a new member on top\n>>> print(stack) # str(stack) also possible\nLinkedListStack(['a', 'b', 'C'])\n
Initialize the stack with the members of
\n\nsequence
.The members are added to the stack in the order they are in
\n\nsequence
.\nTo create an empty stack, callLinkedListStack()
orLinkedListStack([])
.Complexity: O(len(
\n", "signature": "(sequence: collections.abc.Sequence[typing.Any] = [])"}, {"fullname": "paddles.stack.LinkedListStack.size", "modulename": "paddles.stack", "qualname": "LinkedListStack.size", "kind": "function", "doc": "sequence
))Return how many members the stack has.
\n\nComplexity: O(1)
\n", "signature": "(self) -> int:", "funcdef": "def"}, {"fullname": "paddles.stack.LinkedListStack.push", "modulename": "paddles.stack", "qualname": "LinkedListStack.push", "kind": "function", "doc": "Put
\n\nitem
on top of the stack.Complexity: O(1)
\n", "signature": "(self, item: Any) -> None:", "funcdef": "def"}, {"fullname": "paddles.stack.LinkedListStack.pop", "modulename": "paddles.stack", "qualname": "LinkedListStack.pop", "kind": "function", "doc": "Remove and return the member at the top of the stack.
\n\nRaise
\n\nValueError
if the stack is empty.Complexity: O(1)
\n", "signature": "(self) -> Any:", "funcdef": "def"}, {"fullname": "paddles.stack.LinkedListStack.peek", "modulename": "paddles.stack", "qualname": "LinkedListStack.peek", "kind": "function", "doc": "Return the member at the top of the stack.
\n\nRaise
\n\nValueError
if the stack is empty.Complexity: O(1)
\n", "signature": "(self) -> Any:", "funcdef": "def"}]; + /** pdoc search index */const docs = [{"fullname": "paddles", "modulename": "paddles", "kind": "module", "doc": "\n\n
paddles
is a pedagogical algorithms and data structures library.It currently implements the Stack, Queue and Deque abstract data types (ADTs).
\n\nThe code repository is at https://github.com/dsa-ou/paddles.\nThe formatted documentation is at https://dsa-ou.github.io/paddles.
\n\nLicence
\n\n\n"}, {"fullname": "paddles.deque", "modulename": "paddles.deque", "kind": "module", "doc": "
paddles
is Copyright \u00a9 2024 by The Open University, UK.\nThe code is licensed under a BSD-3-clause licence.\nThe documentation is licensed under a\nCreative Commons Attribution 4.0 International Licence.This module implements the Deque ADT.
\n\nIntuition
\n\nThe Deque ADT models a line of objects that can be accessed, added to and\nremoved from either end of the line.\nA deque can be used as a stack or as a queue.
\n\nDefinition
\n\nA deque, pronounced 'deck' and short for 'double-ended queue', is a sequence\nwhere only the members at both ends of the sequence\n(called the front and the back of the queue) can be accessed and removed.\nNew members can only be added at the front or at the back.
\n\nOperations
\n\nThe Deque ADT provides operations to:
\n\n\n
\n\n- create a new empty deque
\n- add a new member to the front of the deque
\n- add a new member to the back of the deque
\n- remove the member at the front of the deque
\n- remove the member at the back of the deque
\n- access the member at the front of the deque without removing it
\n- access the member at the back of the deque without removing it
\n- compute the size of the deque (number of members).
\nApplications
\n\nConsider using a deque when you need to simulate a queue where
\n\n\n
\n\n- objects jump the queue (join at the front) or\nleave it from the back after waiting a certain time
\n- the direction of the queue changes, like cars on a ferry.
\nImplementations
\n\nThe Deque ADT can be implemented with circular dynamic arrays or doubly-linked lists.\nIn both cases, the operations listed above take constant time.\nA doubly-linked list uses much more memory than a static array of the same length,\nbut a dynamic array may have wasted capacity and requires resizing.\n
\n"}, {"fullname": "paddles.deque.LinkedListDeque", "modulename": "paddles.deque", "qualname": "LinkedListDeque", "kind": "class", "doc": "paddles
only provides a doubly-linked list implementation for the moment.An implementation of the Deque ADT, using a doubly-linked list.
\n\nBesides the ADT's operations, this class provides two convenience operations:
\n\n\n
\n\n- create a non-empty deque from a given sequence
\n- convert a deque to a string, to see its members listed from front to back.
\n\n\n"}, {"fullname": "paddles.deque.LinkedListDeque.__init__", "modulename": "paddles.deque", "qualname": "LinkedListDeque.__init__", "kind": "function", "doc": "\n>>> from paddles.deque import LinkedListDeque\n>>> deque = LinkedListDeque("abc") # create a non-empty deque\n>>> deque.size() # number of members\n3\n>>> deque.take_front() # remove and return the front member\n'a'\n>>> deque.take_back() # remove and return the back member\n'c'\n>>> deque.front() == deque.back() == 'b' # return the front and back members\nTrue\n>>> deque.add_back("C") # add a new member at the back\n>>> deque.add_front("A") # add a new member at the front\n>>> print(deque) # str(deque) also possible\nLinkedListDeque(['A', 'b', 'C'])\n
Initialize the deque with the members of
\n\nsequence
.The members are added to the deque in the order they are in
\n\nsequence
.\nTo create an empty deque, callLinkedListDeque()
orLinkedListDeque([])
.Complexity: O(len(
\n", "signature": "(sequence: collections.abc.Sequence[typing.Any] = [])"}, {"fullname": "paddles.deque.LinkedListDeque.size", "modulename": "paddles.deque", "qualname": "LinkedListDeque.size", "kind": "function", "doc": "sequence
))Return how many members the deque has.
\n\nComplexity: O(1)
\n", "signature": "(self) -> int:", "funcdef": "def"}, {"fullname": "paddles.deque.LinkedListDeque.front", "modulename": "paddles.deque", "qualname": "LinkedListDeque.front", "kind": "function", "doc": "Return the item at the front of the deque, without removing it.
\n\nRaise
\n\nValueError
if the deque is empty.Complexity: O(1)
\n", "signature": "(self) -> Any:", "funcdef": "def"}, {"fullname": "paddles.deque.LinkedListDeque.back", "modulename": "paddles.deque", "qualname": "LinkedListDeque.back", "kind": "function", "doc": "Return the item at the back of the deque, without removing it.
\n\nRaise
\n\nValueError
if the deque is empty.Complexity: O(1)
\n", "signature": "(self) -> Any:", "funcdef": "def"}, {"fullname": "paddles.deque.LinkedListDeque.add_front", "modulename": "paddles.deque", "qualname": "LinkedListDeque.add_front", "kind": "function", "doc": "Put
\n\nitem
at the front of the deque.Complexity: O(1)
\n", "signature": "(self, item: Any) -> None:", "funcdef": "def"}, {"fullname": "paddles.deque.LinkedListDeque.add_back", "modulename": "paddles.deque", "qualname": "LinkedListDeque.add_back", "kind": "function", "doc": "Put
\n\nitem
at the back of the deque.Complexity: O(1)
\n", "signature": "(self, item: Any) -> None:", "funcdef": "def"}, {"fullname": "paddles.deque.LinkedListDeque.take_front", "modulename": "paddles.deque", "qualname": "LinkedListDeque.take_front", "kind": "function", "doc": "Remove and return the item at the front of the deque.
\n\nRaise
\n\nValueError
if the deque is empty.Complexity: O(1)
\n", "signature": "(self) -> Any:", "funcdef": "def"}, {"fullname": "paddles.deque.LinkedListDeque.take_back", "modulename": "paddles.deque", "qualname": "LinkedListDeque.take_back", "kind": "function", "doc": "Remove and return the item at the back of the deque.
\n\nRaise
\n\nValueError
if the deque is empty.Complexity: O(1)
\n", "signature": "(self) -> Any:", "funcdef": "def"}, {"fullname": "paddles.queue", "modulename": "paddles.queue", "kind": "module", "doc": "This module implements the Queue ADT.
\n\nIntuition
\n\nThe Queue ADT models a line of objects, e.g. cars waiting to board a ferry.\nOnly the object at the front of the line can be accessed and removed.\nThe only way to add an object is to put it at the back of the line.
\n\nDefinition
\n\nA queue is a sequence where members are added to one end of the sequence\n(the back of the queue) and removed from the other end (the front of the queue).
\n\nA queue is a first-in, first-out (FIFO) sequence:\nthe members are removed in the same order they were added.
\n\nA queue is a sequence ordered by age (time of addition).\nThe oldest member is at the front of the queue, and the youngest member is at the back.
\n\nOperations
\n\nThe Queue ADT provides operations to:
\n\n\n
\n\n- create a new empty queue
\n- add a new member, at the back of the existing ones
\n- remove the member at the front of the queue
\n- access the member at the front of the queue without removing it
\n- compute the size of the queue (number of members).
\nApplications
\n\nQueues are used to implement breadth-first search.\nYou should consider using a queue when you need to:
\n\n\n
\n\n- simulate a real-life queue, like travellers at passport control or\ndocuments in a printer queue
\n- process items in the same order they were added, like a to-do list.
\nImplementations
\n\nThe Queue ADT can be implemented with circular dynamic arrays or singly-linked lists.\nIn both cases, the operations listed above take constant time.\nA singly-linked list uses much more memory than a static array of the same length,\nbut a dynamic array may have wasted capacity and requires resizing.\n
\n"}, {"fullname": "paddles.queue.LinkedListQueue", "modulename": "paddles.queue", "qualname": "LinkedListQueue", "kind": "class", "doc": "paddles
only provides a singly-linked list implementation for the moment.An implementation of the Queue ADT, using a singly-linked list.
\n\nBesides the ADT's operations, this class provides two convenience operations:
\n\n\n
\n\n- create a non-empty queue from a given sequence
\n- convert a queue to a string, to see its members listed from front to back.
\n\n\n"}, {"fullname": "paddles.queue.LinkedListQueue.__init__", "modulename": "paddles.queue", "qualname": "LinkedListQueue.__init__", "kind": "function", "doc": "\n>>> from paddles.queue import LinkedListQueue\n>>> q = LinkedListQueue("abc") # create a non-empty queue\n>>> q.size() # number of members\n3\n>>> q.dequeue() # remove and return the front member\n'a'\n>>> q.front() # return but don't remove the front member\n'b'\n>>> q.enqueue("d") # add a new member at the back\n>>> print(q) # str(q) also possible\nLinkedListQueue(['b', 'c', 'd'])\n
Initialize the queue with the members of
\n\nsequence
.The members are added to the queue in the order they are in
\n\nsequence
.\nTo create an empty queue, callLinkedListQueue()
orLinkedListQueue([])
.Complexity: O(len(
\n", "signature": "(sequence: collections.abc.Sequence[typing.Any] = [])"}, {"fullname": "paddles.queue.LinkedListQueue.size", "modulename": "paddles.queue", "qualname": "LinkedListQueue.size", "kind": "function", "doc": "sequence
))Return how many members the queue has.
\n\nComplexity: O(1)
\n", "signature": "(self) -> int:", "funcdef": "def"}, {"fullname": "paddles.queue.LinkedListQueue.front", "modulename": "paddles.queue", "qualname": "LinkedListQueue.front", "kind": "function", "doc": "Return the member at the front of the queue, without removing it.
\n\nRaise
\n\nValueError
if the queue is empty.Complexity: O(1)
\n", "signature": "(self) -> Any:", "funcdef": "def"}, {"fullname": "paddles.queue.LinkedListQueue.enqueue", "modulename": "paddles.queue", "qualname": "LinkedListQueue.enqueue", "kind": "function", "doc": "Put
\n\nitem
at the back of the queue.Complexity: O(1)
\n", "signature": "(self, item: Any) -> None:", "funcdef": "def"}, {"fullname": "paddles.queue.LinkedListQueue.dequeue", "modulename": "paddles.queue", "qualname": "LinkedListQueue.dequeue", "kind": "function", "doc": "Remove and return the item at the front of the queue.
\n\nRaise
\n\nValueError
if the queue is empty.Complexity: O(1)
\n", "signature": "(self) -> Any:", "funcdef": "def"}, {"fullname": "paddles.stack", "modulename": "paddles.stack", "kind": "module", "doc": "This module implements the Stack ADT.
\n\nIntuition
\n\nThe Stack ADT models a pile of objects, e.g. a pile of storage boxes.\nOnly the object at the top of the pile can be accessed and removed.\nThe only way to add an object is to put it on top of the existing pile.
\n\nDefinition
\n\nA stack is a sequence where members are removed from and added to\nthe same end of the sequence, called the top of the stack.
\n\nA stack is a last-in, first-out (LIFO) sequence:\nthe next member to be removed is the one most recently added.
\n\nA stack is a sequence ordered by age (time of addition).\nThe oldest member is at the bottom of the stack, and the youngest member is at the top.
\n\nOperations
\n\nThe Stack ADT provides operations to:
\n\n\n
\n\n- create a new empty stack
\n- add a new member, on top of the existing ones
\n- remove the member at the top of the stack
\n- access the member at the top of the stack without removing it
\n- compute the size of the stack (number of members).
\nApplications
\n\nStacks are used to implement function calls and depth-first search.\nYou should consider using a stack when you need to:
\n\n\n
\n\n- simulate the handling of a pile of objects, like loading and unloading ship containers
\n- process nested structures, like brackets (e.g.
\nprint([1, {2, 3}])
) or\nHTML tags (e.g.<p><b>text</b></p>
)- process items in the reverse order they were added, like undo operations\n(the next command to be undone is the most recently executed one).
\nImplementations
\n\nThe Stack ADT can be implemented with dynamic arrays or singly-linked lists.\nIn both cases, the operations listed above take constant time.\nA singly-linked list uses much more memory than a static array of the same length,\nbut a dynamic array may have wasted capacity and requires resizing.
\n"}, {"fullname": "paddles.stack.DynamicArrayStack", "modulename": "paddles.stack", "qualname": "DynamicArrayStack", "kind": "class", "doc": "An implementation of the Stack ADT, using Python lists.
\n\nBesides the ADT's operations, this class provides two convenience operations:
\n\n\n
\n\n- create a non-empty stack from a given sequence
\n- convert a stack to a string, to see its members listed from bottom to top.
\n\n\n"}, {"fullname": "paddles.stack.DynamicArrayStack.__init__", "modulename": "paddles.stack", "qualname": "DynamicArrayStack.__init__", "kind": "function", "doc": "\n>>> from paddles.stack import DynamicArrayStack\n>>> stack = DynamicArrayStack("abc") # create a non-empty stack\n>>> stack.size() # number of members\n3\n>>> stack.pop() # remove and return the top member\n'c'\n>>> stack.peek() # return but don't remove the top member\n'b'\n>>> stack.push("C") # add a new member on top\n>>> print(stack) # str(stack) also possible\nDynamicArrayStack(['a', 'b', 'C'])\n
Initialize the stack with the members of
\n\nsequence
.The members are added to the stack in the order they are in
\n\nsequence
.\nTo create an empty stack, callDynamicArrayStack()
orDynamicArrayStack([])
.Complexity: O(len(
\n", "signature": "(sequence: collections.abc.Sequence[typing.Any] = [])"}, {"fullname": "paddles.stack.DynamicArrayStack.size", "modulename": "paddles.stack", "qualname": "DynamicArrayStack.size", "kind": "function", "doc": "sequence
))Return how many members the stack has.
\n\nComplexity: O(1)
\n", "signature": "(self) -> int:", "funcdef": "def"}, {"fullname": "paddles.stack.DynamicArrayStack.peek", "modulename": "paddles.stack", "qualname": "DynamicArrayStack.peek", "kind": "function", "doc": "Return the member at the top of the stack, without removing it.
\n\nRaise
\n\nValueError
if the stack is empty.Complexity: O(1)
\n", "signature": "(self) -> Any:", "funcdef": "def"}, {"fullname": "paddles.stack.DynamicArrayStack.push", "modulename": "paddles.stack", "qualname": "DynamicArrayStack.push", "kind": "function", "doc": "Put
\n\nitem
on top of the stack.Complexity: O(1)
\n", "signature": "(self, item: Any) -> None:", "funcdef": "def"}, {"fullname": "paddles.stack.DynamicArrayStack.pop", "modulename": "paddles.stack", "qualname": "DynamicArrayStack.pop", "kind": "function", "doc": "Remove and return the member at the top of the stack.
\n\nRaise
\n\nValueError
if the stack is empty.Complexity: O(1)
\n", "signature": "(self) -> Any:", "funcdef": "def"}, {"fullname": "paddles.stack.LinkedListStack", "modulename": "paddles.stack", "qualname": "LinkedListStack", "kind": "class", "doc": "An implementation of the Stack ADT, using singly-linked lists.
\n\nBesides the ADT's operations, this class provides two convenience operations:
\n\n\n
\n\n- create a non-empty stack from a given sequence
\n- convert a stack to a string, to see its members listed from bottom to top.
\n\n\n"}, {"fullname": "paddles.stack.LinkedListStack.__init__", "modulename": "paddles.stack", "qualname": "LinkedListStack.__init__", "kind": "function", "doc": "\n>>> from paddles.stack import LinkedListStack\n>>> stack = LinkedListStack("abc") # create a non-empty stack\n>>> stack.size() # number of members\n3\n>>> stack.pop() # remove and return the top member\n'c'\n>>> stack.peek() # return but don't remove the top member\n'b'\n>>> stack.push("C") # add a new member on top\n>>> print(stack) # str(stack) also possible\nLinkedListStack(['a', 'b', 'C'])\n
Initialize the stack with the members of
\n\nsequence
.The members are added to the stack in the order they are in
\n\nsequence
.\nTo create an empty stack, callLinkedListStack()
orLinkedListStack([])
.Complexity: O(len(
\n", "signature": "(sequence: collections.abc.Sequence[typing.Any] = [])"}, {"fullname": "paddles.stack.LinkedListStack.size", "modulename": "paddles.stack", "qualname": "LinkedListStack.size", "kind": "function", "doc": "sequence
))Return how many members the stack has.
\n\nComplexity: O(1)
\n", "signature": "(self) -> int:", "funcdef": "def"}, {"fullname": "paddles.stack.LinkedListStack.push", "modulename": "paddles.stack", "qualname": "LinkedListStack.push", "kind": "function", "doc": "Put
\n\nitem
on top of the stack.Complexity: O(1)
\n", "signature": "(self, item: Any) -> None:", "funcdef": "def"}, {"fullname": "paddles.stack.LinkedListStack.pop", "modulename": "paddles.stack", "qualname": "LinkedListStack.pop", "kind": "function", "doc": "Remove and return the member at the top of the stack.
\n\nRaise
\n\nValueError
if the stack is empty.Complexity: O(1)
\n", "signature": "(self) -> Any:", "funcdef": "def"}, {"fullname": "paddles.stack.LinkedListStack.peek", "modulename": "paddles.stack", "qualname": "LinkedListStack.peek", "kind": "function", "doc": "Return the member at the top of the stack.
\n\nRaise
\n\nValueError
if the stack is empty.Complexity: O(1)
\n", "signature": "(self) -> Any:", "funcdef": "def"}]; // mirrored in build-search-index.js (part 1) // Also split on html tags. this is a cheap heuristic, but good enough. diff --git a/paddles/__init__.py b/paddles/__init__.py index f68b540..2a87b56 100644 --- a/paddles/__init__.py +++ b/paddles/__init__.py @@ -1,12 +1,14 @@ """`paddles` is a pedagogical algorithms and data structures library. -It currently implements the Stack, Queue and Deque **abstract data types (ADTs)**. +It currently implements the Stack, Queue and Deque abstract data types (ADTs). + +The code repository is at https://github.com/dsa-ou/paddles. +The formatted documentation is at https://dsa-ou.github.io/paddles. ## Licence -The code and text in this repository are -Copyright © 2024 by The Open University, UK. -The code is licensed under a [BSD-3-clause licence](../LICENSE.MD). -The text is licensed under a +`paddles` is Copyright © 2024 by The Open University, UK. +The code is licensed under a [BSD-3-clause licence](https://github.com/dsa-ou/paddles/blob/main/LICENSE). +The documentation is licensed under a [Creative Commons Attribution 4.0 International Licence](http://creativecommons.org/licenses/by/4.0). """ diff --git a/paddles/deque.py b/paddles/deque.py index f28c7c4..2f985e6 100644 --- a/paddles/deque.py +++ b/paddles/deque.py @@ -3,13 +3,13 @@ ## Intuition The Deque ADT models a line of objects that can be accessed, added to and -removed from either end of the line +removed from either end of the line. A deque can be used as a [stack](stack.html) or as a [queue](queue.html). ## Definition A **deque**, pronounced 'deck' and short for 'double-ended queue', is a sequence -where only the members at both ends of the sequence. +where only the members at both ends of the sequence (called the **front** and the **back** of the queue) can be accessed and removed. New members can only be added at the front or at the back. @@ -26,10 +26,11 @@ - compute the size of the deque (number of members). ## Applications -Consider using a deque when you need to simulate a line of objects that can be accessed -from both ends, like cars on a ferry. -On one shore, cars leave the ferry from the front and new ones board it from the front. -On the other shore, cars leave and board the ferry from the back. + +Consider using a deque when you need to simulate a queue where +- objects jump the queue (join at the front) or + leave it from the back after waiting a certain time +- the direction of the queue changes, like cars on a ferry. ## Implementations