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.

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. -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.

@@ -67,16 +69,18 @@

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"""
 
diff --git a/docs/paddles/deque.html b/docs/paddles/deque.html index 0bc5071..83093ce 100644 --- a/docs/paddles/deque.html +++ b/docs/paddles/deque.html @@ -90,13 +90,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 or as a queue.

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.

@@ -117,10 +117,13 @@

Operations

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

+ +

Implementations

@@ -140,13 +143,13 @@

Implementations

3## Intuition 4 5The Deque ADT models a line of objects that can be accessed, added to and - 6removed from either end of the line + 6removed from either end of the line. 7A deque can be used as a [stack](stack.html) or as a [queue](queue.html). 8 9## Definition 10 11A **deque**, pronounced 'deck' and short for 'double-ended queue', is a sequence - 12where only the members at both ends of the sequence. + 12where only the members at both ends of the sequence 13(called the **front** and the **back** of the queue) can be accessed and removed. 14New members can only be added at the front or at the back. 15 @@ -163,178 +166,179 @@

Implementations

26- compute the size of the deque (number of members). 27 28## Applications - 29Consider using a deque when you need to simulate a line of objects that can be accessed - 30from both ends, like cars on a ferry. - 31On one shore, cars leave the ferry from the front and new ones board it from the front. - 32On the other shore, cars leave and board the ferry from the back. - 33 - 34## Implementations - 35 - 36The Deque ADT can be implemented with circular dynamic arrays or doubly-linked lists. - 37In both cases, the operations listed above take constant time. - 38A doubly-linked list uses much more memory than a static array of the same length, - 39but a dynamic array may have wasted capacity and requires resizing. - 40`paddles` only provides a doubly-linked list implementation for the moment. - 41""" - 42 - 43from collections.abc import Sequence - 44from typing import Any - 45 - 46__all__ = ["LinkedListDeque"] - 47 - 48# A doubly-linked list node is a list [previous, item, next]. - 49# These constants make the code more readable. - 50PREV = 0 - 51DATA = 1 - 52NEXT = 2 - 53 + 29 + 30Consider using a deque when you need to simulate a queue where + 31- objects jump the queue (join at the front) or + 32 leave it from the back after waiting a certain time + 33- the direction of the queue changes, like cars on a ferry. + 34 + 35## Implementations + 36 + 37The Deque ADT can be implemented with circular dynamic arrays or doubly-linked lists. + 38In both cases, the operations listed above take constant time. + 39A doubly-linked list uses much more memory than a static array of the same length, + 40but a dynamic array may have wasted capacity and requires resizing. + 41`paddles` only provides a doubly-linked list implementation for the moment. + 42""" + 43 + 44from collections.abc import Sequence + 45from typing import Any + 46 + 47__all__ = ["LinkedListDeque"] + 48 + 49# A doubly-linked list node is a list [previous, item, next]. + 50# These constants make the code more readable. + 51PREV = 0 + 52DATA = 1 + 53NEXT = 2 54 - 55class LinkedListDeque: - 56 """An implementation of the Deque ADT, using a doubly-linked list. - 57 - 58 Besides the ADT's operations, this class provides two convenience operations: - 59 - create a non-empty deque from a given sequence - 60 - convert a deque to a string, to see its members listed from front to back. - 61 - 62 >>> from paddles.deque import LinkedListDeque - 63 >>> deque = LinkedListDeque("abc") # create a non-empty deque - 64 >>> deque.size() # number of members - 65 3 - 66 >>> deque.take_front() # remove and return the front member - 67 'a' - 68 >>> deque.take_back() # remove and return the back member - 69 'c' - 70 >>> deque.front() == deque.back() == 'b' # return the front and back members - 71 True - 72 >>> deque.add_back("C") # add a new member at the back - 73 >>> deque.add_front("A") # add a new member at the front - 74 >>> print(deque) # str(deque) also possible - 75 LinkedListDeque(['A', 'b', 'C']) - 76 """ - 77 - 78 def __init__(self, sequence: Sequence[Any] = []) -> None: - 79 """Initialize the deque with the members of `sequence`. - 80 - 81 The members are added to the deque in the order they are in `sequence`. - 82 To create an empty deque, call `LinkedListDeque()` or `LinkedListDeque([])`. - 83 - 84 Complexity: O(len(`sequence`)) - 85 """ - 86 self._head = None - 87 self._tail = None - 88 self._length = 0 - 89 if sequence: - 90 for item in sequence: - 91 self.add_back(item) - 92 - 93 def __str__(self) -> str: - 94 """Return a string representation of the deque. - 95 - 96 The string is 'LinkedListDeque([front member, ..., back member])'. - 97 - 98 Complexity: O(self.size()) - 99 """ -100 strings = [] -101 current = self._head -102 while current: -103 strings.append(repr(current[DATA])) -104 current = current[NEXT] -105 return f"LinkedListDeque([{', '.join(strings)}])" -106 -107 def size(self) -> int: -108 """Return how many members the deque has. -109 -110 Complexity: O(1) -111 """ -112 return self._length -113 -114 def front(self) -> Any: -115 """Return the item at the front of the deque, without removing it. -116 -117 Raise `ValueError` if the deque is empty. -118 -119 Complexity: O(1) -120 """ -121 if self.size() == 0: -122 msg = "can't access the front of an empty deque" -123 raise ValueError(msg) -124 return self._head[DATA] -125 -126 def back(self) -> Any: -127 """Return the item at the back of the deque, without removing it. -128 -129 Raise `ValueError` if the deque is empty. -130 -131 Complexity: O(1) -132 """ -133 if self.size() == 0: -134 msg = "can't access the back of an empty deque" -135 raise ValueError(msg) -136 return self._tail[DATA] -137 -138 def add_front(self, item: Any) -> None: -139 """Put `item` at the front of the deque. -140 -141 Complexity: O(1) -142 """ -143 node = [None, item, self._head] -144 if self.size() == 0: -145 self._tail = node -146 else: -147 self._head[PREV] = node -148 self._head = node -149 self._length += 1 -150 -151 def add_back(self, item: Any) -> None: -152 """Put `item` at the back of the deque. -153 -154 Complexity: O(1) -155 """ -156 node = [self._tail, item, None] -157 if self.size() == 0: -158 self._head = node -159 else: -160 self._tail[NEXT] = node -161 self._tail = node -162 self._length += 1 -163 -164 def take_front(self) -> Any: -165 """Remove and return the item at the front of the deque. -166 -167 Raise `ValueError` if the deque is empty. -168 -169 Complexity: O(1) -170 """ -171 if self.size() == 0: -172 msg = "can't remove a member from an empty deque" -173 raise ValueError(msg) -174 item = self._head[DATA] -175 self._head = self._head[NEXT] -176 self._length -= 1 -177 if self.size() == 0: -178 self._tail = None -179 else: -180 self._head[PREV] = None -181 return item -182 -183 def take_back(self) -> Any: -184 """Remove and return the item at the back of the deque. -185 -186 Raise `ValueError` if the deque is empty. -187 -188 Complexity: O(1) -189 """ -190 if self.size() == 0: -191 msg = "can't remove a member from an empty deque" -192 raise ValueError(msg) -193 item = self._tail[DATA] -194 self._tail = self._tail[PREV] -195 self._length -= 1 -196 if self.size() == 0: -197 self._head = None -198 else: -199 self._tail[NEXT] = None -200 return item + 55 + 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 @@ -350,152 +354,152 @@

Implementations

-
 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
+            
 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 item
 
@@ -538,20 +542,20 @@

Implementations

-
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)
+            
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)
 
@@ -576,12 +580,12 @@

Implementations

-
108    def size(self) -> int:
-109        """Return how many members the deque has.
-110
-111        Complexity: O(1)
-112        """
-113        return self._length
+            
109    def size(self) -> int:
+110        """Return how many members the deque has.
+111
+112        Complexity: O(1)
+113        """
+114        return self._length
 
@@ -603,17 +607,17 @@

Implementations

-
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]
+            
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]
 
@@ -637,17 +641,17 @@

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]
+            
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]
 
@@ -671,18 +675,18 @@

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
+            
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
 
@@ -704,18 +708,18 @@

Implementations

-
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
+            
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
 
@@ -737,24 +741,24 @@

Implementations

-
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
+            
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
 
@@ -778,24 +782,24 @@

Implementations

-
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
+            
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 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;u0&&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;e1;){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();opaddles is a pedagogical algorithms and data structures library.

\n\n

It currently implements the Stack, Queue and Deque abstract data types (ADTs).

\n\n

Licence

\n\n

The 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\n

Intuition

\n\n

The 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\n

Definition

\n\n

A 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\n

Operations

\n\n

The Deque ADT provides operations to:

\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).
  • \n
\n\n

Applications

\n\n

Consider 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\n

Implementations

\n\n

The 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.\npaddles only provides a doubly-linked list implementation for the moment.

\n"}, {"fullname": "paddles.deque.LinkedListDeque", "modulename": "paddles.deque", "qualname": "LinkedListDeque", "kind": "class", "doc": "

An implementation of the Deque ADT, using a doubly-linked list.

\n\n

Besides the ADT's operations, this class provides two convenience operations:

\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
\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
\n
\n"}, {"fullname": "paddles.deque.LinkedListDeque.__init__", "modulename": "paddles.deque", "qualname": "LinkedListDeque.__init__", "kind": "function", "doc": "

Initialize the deque with the members of sequence.

\n\n

The members are added to the deque in the order they are in sequence.\nTo create an empty deque, call LinkedListDeque() or LinkedListDeque([]).

\n\n

Complexity: O(len(sequence))

\n", "signature": "(sequence: collections.abc.Sequence[typing.Any] = [])"}, {"fullname": "paddles.deque.LinkedListDeque.size", "modulename": "paddles.deque", "qualname": "LinkedListDeque.size", "kind": "function", "doc": "

Return how many members the deque has.

\n\n

Complexity: 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\n

Raise ValueError if the deque is empty.

\n\n

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\n

Raise ValueError if the deque is empty.

\n\n

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 item at the front of the deque.

\n\n

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 item at the back of the deque.

\n\n

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\n

Raise ValueError if the deque is empty.

\n\n

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\n

Raise ValueError if the deque is empty.

\n\n

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\n

Intuition

\n\n

The 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\n

Definition

\n\n

A 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\n

A queue is a first-in, first-out (FIFO) sequence:\nthe members are removed in the same order they were added.

\n\n

A 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\n

Operations

\n\n

The Queue ADT provides operations to:

\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).
  • \n
\n\n

Applications

\n\n

Queues are used to implement breadth-first search.\nYou should consider using a queue when you need to:

\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.
  • \n
\n\n

Implementations

\n\n

The 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.\npaddles only provides a singly-linked list implementation for the moment.

\n"}, {"fullname": "paddles.queue.LinkedListQueue", "modulename": "paddles.queue", "qualname": "LinkedListQueue", "kind": "class", "doc": "

An implementation of the Queue ADT, using a singly-linked list.

\n\n

Besides the ADT's operations, this class provides two convenience operations:

\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
\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
\n
\n"}, {"fullname": "paddles.queue.LinkedListQueue.__init__", "modulename": "paddles.queue", "qualname": "LinkedListQueue.__init__", "kind": "function", "doc": "

Initialize the queue with the members of sequence.

\n\n

The members are added to the queue in the order they are in sequence.\nTo create an empty queue, call LinkedListQueue() or LinkedListQueue([]).

\n\n

Complexity: O(len(sequence))

\n", "signature": "(sequence: collections.abc.Sequence[typing.Any] = [])"}, {"fullname": "paddles.queue.LinkedListQueue.size", "modulename": "paddles.queue", "qualname": "LinkedListQueue.size", "kind": "function", "doc": "

Return how many members the queue has.

\n\n

Complexity: 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\n

Raise ValueError if the queue is empty.

\n\n

Complexity: O(1)

\n", "signature": "(self) -> Any:", "funcdef": "def"}, {"fullname": "paddles.queue.LinkedListQueue.enqueue", "modulename": "paddles.queue", "qualname": "LinkedListQueue.enqueue", "kind": "function", "doc": "

Put item at the back of the queue.

\n\n

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\n

Raise ValueError if the queue is empty.

\n\n

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\n

Intuition

\n\n

The 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\n

Definition

\n\n

A 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\n

A stack is a last-in, first-out (LIFO) sequence:\nthe next member to be removed is the one most recently added.

\n\n

A 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\n

Operations

\n\n

The Stack ADT provides operations to:

\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).
  • \n
\n\n

Applications

\n\n

Stacks are used to implement function calls and depth-first search.\nYou should consider using a stack when you need to:

\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. print([1, {2, 3}])) or\nHTML tags (e.g. <p><b>text</b></p>)
  • \n
  • 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).
  • \n
\n\n

Implementations

\n\n

The 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\n

Besides the ADT's operations, this class provides two convenience operations:

\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
\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
\n
\n"}, {"fullname": "paddles.stack.DynamicArrayStack.__init__", "modulename": "paddles.stack", "qualname": "DynamicArrayStack.__init__", "kind": "function", "doc": "

Initialize the stack with the members of sequence.

\n\n

The members are added to the stack in the order they are in sequence.\nTo create an empty stack, call DynamicArrayStack() or DynamicArrayStack([]).

\n\n

Complexity: O(len(sequence))

\n", "signature": "(sequence: collections.abc.Sequence[typing.Any] = [])"}, {"fullname": "paddles.stack.DynamicArrayStack.size", "modulename": "paddles.stack", "qualname": "DynamicArrayStack.size", "kind": "function", "doc": "

Return how many members the stack has.

\n\n

Complexity: 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\n

Raise ValueError if the stack is empty.

\n\n

Complexity: O(1)

\n", "signature": "(self) -> Any:", "funcdef": "def"}, {"fullname": "paddles.stack.DynamicArrayStack.push", "modulename": "paddles.stack", "qualname": "DynamicArrayStack.push", "kind": "function", "doc": "

Put item on top of the stack.

\n\n

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\n

Raise ValueError if the stack is empty.

\n\n

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\n

Besides the ADT's operations, this class provides two convenience operations:

\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
\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
\n
\n"}, {"fullname": "paddles.stack.LinkedListStack.__init__", "modulename": "paddles.stack", "qualname": "LinkedListStack.__init__", "kind": "function", "doc": "

Initialize the stack with the members of sequence.

\n\n

The members are added to the stack in the order they are in sequence.\nTo create an empty stack, call LinkedListStack() or LinkedListStack([]).

\n\n

Complexity: O(len(sequence))

\n", "signature": "(sequence: collections.abc.Sequence[typing.Any] = [])"}, {"fullname": "paddles.stack.LinkedListStack.size", "modulename": "paddles.stack", "qualname": "LinkedListStack.size", "kind": "function", "doc": "

Return how many members the stack has.

\n\n

Complexity: O(1)

\n", "signature": "(self) -> int:", "funcdef": "def"}, {"fullname": "paddles.stack.LinkedListStack.push", "modulename": "paddles.stack", "qualname": "LinkedListStack.push", "kind": "function", "doc": "

Put item on top of the stack.

\n\n

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\n

Raise ValueError if the stack is empty.

\n\n

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\n

Raise ValueError if the stack is empty.

\n\n

Complexity: O(1)

\n", "signature": "(self) -> Any:", "funcdef": "def"}]; + /** pdoc search index */const docs = [{"fullname": "paddles", "modulename": "paddles", "kind": "module", "doc": "

paddles is a pedagogical algorithms and data structures library.

\n\n

It currently implements the Stack, Queue and Deque abstract data types (ADTs).

\n\n

The code repository is at https://github.com/dsa-ou/paddles.\nThe formatted documentation is at https://dsa-ou.github.io/paddles.

\n\n

Licence

\n\n

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.

\n"}, {"fullname": "paddles.deque", "modulename": "paddles.deque", "kind": "module", "doc": "

This module implements the Deque ADT.

\n\n

Intuition

\n\n

The 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\n

Definition

\n\n

A 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\n

Operations

\n\n

The Deque ADT provides operations to:

\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).
  • \n
\n\n

Applications

\n\n

Consider using a deque when you need to simulate a queue where

\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.
  • \n
\n\n

Implementations

\n\n

The 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.\npaddles only provides a doubly-linked list implementation for the moment.

\n"}, {"fullname": "paddles.deque.LinkedListDeque", "modulename": "paddles.deque", "qualname": "LinkedListDeque", "kind": "class", "doc": "

An implementation of the Deque ADT, using a doubly-linked list.

\n\n

Besides the ADT's operations, this class provides two convenience operations:

\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
\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
\n
\n"}, {"fullname": "paddles.deque.LinkedListDeque.__init__", "modulename": "paddles.deque", "qualname": "LinkedListDeque.__init__", "kind": "function", "doc": "

Initialize the deque with the members of sequence.

\n\n

The members are added to the deque in the order they are in sequence.\nTo create an empty deque, call LinkedListDeque() or LinkedListDeque([]).

\n\n

Complexity: O(len(sequence))

\n", "signature": "(sequence: collections.abc.Sequence[typing.Any] = [])"}, {"fullname": "paddles.deque.LinkedListDeque.size", "modulename": "paddles.deque", "qualname": "LinkedListDeque.size", "kind": "function", "doc": "

Return how many members the deque has.

\n\n

Complexity: 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\n

Raise ValueError if the deque is empty.

\n\n

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\n

Raise ValueError if the deque is empty.

\n\n

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 item at the front of the deque.

\n\n

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 item at the back of the deque.

\n\n

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\n

Raise ValueError if the deque is empty.

\n\n

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\n

Raise ValueError if the deque is empty.

\n\n

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\n

Intuition

\n\n

The 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\n

Definition

\n\n

A 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\n

A queue is a first-in, first-out (FIFO) sequence:\nthe members are removed in the same order they were added.

\n\n

A 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\n

Operations

\n\n

The Queue ADT provides operations to:

\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).
  • \n
\n\n

Applications

\n\n

Queues are used to implement breadth-first search.\nYou should consider using a queue when you need to:

\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.
  • \n
\n\n

Implementations

\n\n

The 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.\npaddles only provides a singly-linked list implementation for the moment.

\n"}, {"fullname": "paddles.queue.LinkedListQueue", "modulename": "paddles.queue", "qualname": "LinkedListQueue", "kind": "class", "doc": "

An implementation of the Queue ADT, using a singly-linked list.

\n\n

Besides the ADT's operations, this class provides two convenience operations:

\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
\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
\n
\n"}, {"fullname": "paddles.queue.LinkedListQueue.__init__", "modulename": "paddles.queue", "qualname": "LinkedListQueue.__init__", "kind": "function", "doc": "

Initialize the queue with the members of sequence.

\n\n

The members are added to the queue in the order they are in sequence.\nTo create an empty queue, call LinkedListQueue() or LinkedListQueue([]).

\n\n

Complexity: O(len(sequence))

\n", "signature": "(sequence: collections.abc.Sequence[typing.Any] = [])"}, {"fullname": "paddles.queue.LinkedListQueue.size", "modulename": "paddles.queue", "qualname": "LinkedListQueue.size", "kind": "function", "doc": "

Return how many members the queue has.

\n\n

Complexity: 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\n

Raise ValueError if the queue is empty.

\n\n

Complexity: O(1)

\n", "signature": "(self) -> Any:", "funcdef": "def"}, {"fullname": "paddles.queue.LinkedListQueue.enqueue", "modulename": "paddles.queue", "qualname": "LinkedListQueue.enqueue", "kind": "function", "doc": "

Put item at the back of the queue.

\n\n

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\n

Raise ValueError if the queue is empty.

\n\n

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\n

Intuition

\n\n

The 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\n

Definition

\n\n

A 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\n

A stack is a last-in, first-out (LIFO) sequence:\nthe next member to be removed is the one most recently added.

\n\n

A 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\n

Operations

\n\n

The Stack ADT provides operations to:

\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).
  • \n
\n\n

Applications

\n\n

Stacks are used to implement function calls and depth-first search.\nYou should consider using a stack when you need to:

\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. print([1, {2, 3}])) or\nHTML tags (e.g. <p><b>text</b></p>)
  • \n
  • 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).
  • \n
\n\n

Implementations

\n\n

The 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\n

Besides the ADT's operations, this class provides two convenience operations:

\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
\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
\n
\n"}, {"fullname": "paddles.stack.DynamicArrayStack.__init__", "modulename": "paddles.stack", "qualname": "DynamicArrayStack.__init__", "kind": "function", "doc": "

Initialize the stack with the members of sequence.

\n\n

The members are added to the stack in the order they are in sequence.\nTo create an empty stack, call DynamicArrayStack() or DynamicArrayStack([]).

\n\n

Complexity: O(len(sequence))

\n", "signature": "(sequence: collections.abc.Sequence[typing.Any] = [])"}, {"fullname": "paddles.stack.DynamicArrayStack.size", "modulename": "paddles.stack", "qualname": "DynamicArrayStack.size", "kind": "function", "doc": "

Return how many members the stack has.

\n\n

Complexity: 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\n

Raise ValueError if the stack is empty.

\n\n

Complexity: O(1)

\n", "signature": "(self) -> Any:", "funcdef": "def"}, {"fullname": "paddles.stack.DynamicArrayStack.push", "modulename": "paddles.stack", "qualname": "DynamicArrayStack.push", "kind": "function", "doc": "

Put item on top of the stack.

\n\n

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\n

Raise ValueError if the stack is empty.

\n\n

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\n

Besides the ADT's operations, this class provides two convenience operations:

\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
\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
\n
\n"}, {"fullname": "paddles.stack.LinkedListStack.__init__", "modulename": "paddles.stack", "qualname": "LinkedListStack.__init__", "kind": "function", "doc": "

Initialize the stack with the members of sequence.

\n\n

The members are added to the stack in the order they are in sequence.\nTo create an empty stack, call LinkedListStack() or LinkedListStack([]).

\n\n

Complexity: O(len(sequence))

\n", "signature": "(sequence: collections.abc.Sequence[typing.Any] = [])"}, {"fullname": "paddles.stack.LinkedListStack.size", "modulename": "paddles.stack", "qualname": "LinkedListStack.size", "kind": "function", "doc": "

Return how many members the stack has.

\n\n

Complexity: O(1)

\n", "signature": "(self) -> int:", "funcdef": "def"}, {"fullname": "paddles.stack.LinkedListStack.push", "modulename": "paddles.stack", "qualname": "LinkedListStack.push", "kind": "function", "doc": "

Put item on top of the stack.

\n\n

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\n

Raise ValueError if the stack is empty.

\n\n

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\n

Raise ValueError if the stack is empty.

\n\n

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