diff --git a/Writerside/topics/C-Programming.md b/Writerside/topics/C-Programming.md index a86725c..1a6b135 100644 --- a/Writerside/topics/C-Programming.md +++ b/Writerside/topics/C-Programming.md @@ -1045,7 +1045,7 @@ index.

@endmindmap ``` -#### 6.4 Iterators +#### 6.4 Iterators {id="iterators"}

Four iterator operations:

diff --git a/Writerside/topics/Data-Structures-and-Algorithms-1.md b/Writerside/topics/Data-Structures-and-Algorithms-1.md index c29566e..7715c80 100644 --- a/Writerside/topics/Data-Structures-and-Algorithms-1.md +++ b/Writerside/topics/Data-Structures-and-Algorithms-1.md @@ -1302,7 +1302,7 @@ print(len(stack) == 0) #### 4.1.2 Linked-List Implementation - +

Save item to return.

@@ -1346,29 +1346,76 @@ print(len(stack) == 0) -public class LinkedStackOfStrings { - private Node first = null; +import java.util.Iterator; +import java.util.NoSuchElementException; +\/ +public class LinkedStack<Item> implements Iterable<Item> { + private int n; + private Node first; \/ private class Node { - String item; - Node next; + private Item item; + private Node next; + } +\/ + public LinkedStack() { + first = null; + n = 0; } \/ public boolean isEmpty() { return first == null; } \/ - public void push(String item) { - Node oldFirst = first; + public int size() { + return n; + } +\/ + public void push(Item item) { + Node oldfirst = first; first = new Node(); first.item = item; - first.next = oldFirst; + first.next = oldfirst; + n++; } \/ - public String pop() { - String item = first.item; - first = first.next; - return item; + public Item pop() { + if (isEmpty()) throw new NoSuchElementException("Stack underflow"); + Item item = first.item; + first = first.next; + n--; + return item; + } +\/ + public Item peek() { + if (isEmpty()) throw new NoSuchElementException("Stack underflow"); + return first.item; + } +\/ + public String toString() { + StringBuilder s = new StringBuilder(); + for (Item item : this) + s.append(item).append(" "); + return s.toString(); + } +\/ + public Iterator<Item> iterator() { + return new LinkedIterator(); + } +\/ + private class LinkedIterator implements Iterator<Item> { + private Node current = first; +\/ + public boolean hasNext() { + return current != null; + } +\/ + public Item next() { + if (!hasNext()) throw new NoSuchElementException(); + Item item = current.item; + current = current.next; + return item; + } } } @@ -1376,46 +1423,80 @@ public class LinkedStackOfStrings { #include <iostream> +#include <stdexcept> \/ -struct Node { - int data; - Node* next; -}; -\/ -class Stack { +template <typename Item> +class LinkedStack { private: - Node* topNode; + struct Node { + Item item; + Node* next; + }; \/ + int n; + Node* first; +\/ public: - Stack() : topNode(nullptr) {} + LinkedStack() : n(0), first(nullptr) {} \/ - void push(int data) { - Node* newNode = new Node(); - newNode->data = data; - newNode->next = topNode; - topNode = newNode; + [[nodiscard]] bool isEmpty() const { + return first == nullptr; } \/ - void pop() { - if (isEmpty()) { - std::cout << "Stack is empty.\n"; - return; - } - Node* tempNode = topNode; - topNode = topNode->next; - delete tempNode; + [[nodiscard]] int size() const { + return n; } \/ - int top() { - if (isEmpty()) { - std::cout << "Stack is empty.\n"; - return -1; + void push(const Item& item) { + Node* oldfirst = first; + first = new Node(); + first->item = item; + first->next = oldfirst; + n++; + } +\/ + Item pop() { + if (isEmpty()) throw std::runtime_error("Stack underflow"); + Item item = first->item; + const Node* oldfirst = first; + first = first->next; + delete oldfirst; + n--; + return item; + } +\/ + [[nodiscard]] Item peek() const { + if (isEmpty()) throw std::runtime_error("Stack underflow"); + return first->item; + } +\/ + class Iterator { + private: + Node* current; +\/ + public: + explicit Iterator(Node* start) : current(start) {} +\/ + bool operator!=(const Iterator& other) const { + return current != other.current; + } +\/ + Iterator& operator++() { + current = current->next; + return *this; + } +\/ + Item& operator*() { + return current->item; } - return topNode->data; + }; +\/ + [[nodiscard]] Iterator begin() const { + return Iterator(first); } \/ - bool isEmpty() { - return topNode == nullptr; + [[nodiscard]] Iterator end() const { + return Iterator(nullptr); } }; @@ -1423,34 +1504,45 @@ public: class Node: - def __init__(self, data=None): - self.data = data + def __init__(self, item): + self.item = item self.next = None \/ -class Stack: +class LinkedStack: def __init__(self): - self.top = None + self.first = None + self.n = 0 \/ - def push(self, data): - new_node = Node(data) - new_node.next = self.top - self.top = new_node + def is_empty(self): + return self.first is None +\/ + def size(self): + return self.n +\/ + def push(self, item): + oldfirst = self.first + self.first = Node(item) + self.first.next = oldfirst + self.n += 1 \/ def pop(self): if self.is_empty(): - return None - pop_node = self.top - self.top = self.top.next - pop_node.next = None - return pop_node.data + raise Exception("Stack underflow") + item = self.first.item + self.first = self.first.next + self.n -= 1 + return item \/ - def top(self): + def peek(self): if self.is_empty(): - return None - return self.top.data + raise Exception("Stack underflow") + return self.first.item \/ - def is_empty(self): - return self.top is None + def __iter__(self): + current = self.first + while current: + yield current.item + current = current.next @@ -1477,8 +1569,8 @@ represent a stack with N items.

Every operation takes constant time in the worst case. - Every operation takes constant + color="OrangeRed">worst case. + Every operation takes constant amortized time. @@ -1490,94 +1582,166 @@ represent a stack with N items.

-import java.util.ArrayList; -import java.util.EmptyStackException; -import java.util.List; +import java.util.Iterator; +import java.util.NoSuchElementException; \/ -public class ResizingArrayStack<T> { +public class ResizingArrayStack<Item> implements Iterable<Item> { + private static final int INIT_CAPACITY = 8; \/ - private List<T> items; + private Item[] a; + private int n; \/ public ResizingArrayStack() { - items = new ArrayList<>(); + a = (Item[]) new Object[INIT_CAPACITY]; + n = 0; + } +\/ + public boolean isEmpty() { + return n == 0; } \/ - public void push(T item) { - items.add(item); + public int size() { + return n; } \/ - public T pop() { - if (isEmpty()) { - throw new EmptyStackException(); - } - return items.remove(items.size() - 1); + private void resize(int capacity) { + assert capacity >= n; + a = java.util.Arrays.copyOf(a, capacity); + // textbook implementation + // Item[] copy = (Item[]) new Object[capacity]; + // for (int i = 0; i < n; i++) { + // copy[i] = a[i]; + // } + // a = copy; } \/ - public boolean isEmpty() { - return items.isEmpty(); + public void push(Item item) { + if (n == a.length) resize(2*a.length); // double size of array if necessary + a[n++] = item; // add item } \/ - public int size() { - return items.size(); + public Item pop() { + if (isEmpty()) throw new NoSuchElementException("Stack underflow"); + Item item = a[n-1]; + a[n-1] = null; // to avoid loitering + n--; + // shrink size of array if necessary + if (n > 0 && n == a.length/4) resize(a.length/2); + return item; + } +\/ + public Item peek() { + if (isEmpty()) throw new NoSuchElementException("Stack underflow"); + return a[n-1]; + } +\/ + public Iterator<Item> iterator() { + return new ReverseArrayIterator(); + } +\/ + private class ReverseArrayIterator implements Iterator<Item> { + private int i; +\/ + public ReverseArrayIterator() { + i = n-1; + } +\/ + public boolean hasNext() { + return i >= 0; + } +\/ + public Item next() { + if (!hasNext()) throw new NoSuchElementException(); + return a[i--]; + } } } +// no iterator for C++ +#include <iostream> #include <vector> #include <stdexcept> \/ -template <typename T> +template <typename Item> class ResizingArrayStack { private: - std::vector<T> items; + static constexpr int INIT_CAPACITY = 8; + std::vector<Item> a; + int n; \/ public: - ResizingArrayStack() = default; + ResizingArrayStack() : a(INIT_CAPACITY), n(0) {} \/ - void push(const T& item) { - items.push_back(item); + [[nodiscard]] bool isEmpty() const { + return n == 0; } \/ - T pop() { - if (isEmpty()) { - throw std::out_of_range("Stack is empty"); - } - T item = items.back(); - items.pop_back(); + [[nodiscard]] int size() const { + return n; + } +\/ + void push(const Item& item) { + if (n == a.size()) resize(2 * a.size()); + a[n++] = item; + } +\/ + Item pop() { + if (isEmpty()) throw std::runtime_error("Stack underflow"); + Item item = a[n - 1]; + a[n - 1] = Item(); + n--; + if (n > 0 && n == a.size() / 4) resize(a.size() / 2); return item; } \/ - [[nodiscard]] bool isEmpty() const { - return items.empty(); + [[nodiscard]] Item peek() const { + if (isEmpty()) throw std::runtime_error("Stack underflow"); + return a[n - 1]; } \/ - [[nodiscard]] int size() const { - return items.size(); +private: + void resize(int capacity) { + a.resize(capacity); } }; +# Python lists handle resizing automatically class ResizingArrayStack: def __init__(self): - self.items = [] # Using a list (like ArrayList in Java) + self._a = [] + self._n = 0 +\/ + def is_empty(self): + return self._n == 0 +\/ + def size(self): + return self._n \/ def push(self, item): - self.items.append(item) + if self._n == len(self._a): + self._resize(2 * len(self._a)) + self._a.append(item) # Python lists handle resizing automatically + self._n += 1 \/ def pop(self): if self.is_empty(): - raise IndexError("Stack is empty") # Use IndexError for empty stack - return self.items.pop() -\/ - def is_empty(self): - return len(self.items) == 0 + raise Exception("Stack underflow") + self._n -= 1 + item = self._a.pop() + if self._n > 0 and self._n == len(self._a) // 4: + self._resize(len(self._a) // 2) + return item \/ - def size(self): - return len(self.items) + def peek(self): + if self.is_empty(): + raise Exception("Stack underflow") + return self._a[-1] @@ -1678,98 +1842,193 @@ print(q.empty()) -public class LinkedQueueOfStrings { - private Node first, last; +import java.util.Iterator; +import java.util.NoSuchElementException; +\/ +public class LinkedQueue<Item> implements Iterable<Item> { + private int n; + private Node first; + private Node last; \/ private class Node { - String item; - Node next; + private Item item; + private Node next; + } +\/ + public LinkedQueue() { + first = null; + last = null; + n = 0; } \/ public boolean isEmpty() { return first == null; } \/ - public void enqueue(String item) { - Node oldLast = last; + public int size() { + return n; + } +\/ + public Item peek() { + if (isEmpty()) throw new NoSuchElementException("Queue underflow"); + return first.item; + } +\/ + public void enqueue(Item item) { + Node oldlast = last; last = new Node(); last.item = item; last.next = null; - if (isEmpty()) { - first = last; - } else { - oldLast.next = last; - } + if (isEmpty()) first = last; + else oldlast.next = last; + n++; } \/ - public String dequeue() { - String item = first.item; + public Item dequeue() { + if (isEmpty()) throw new NoSuchElementException("Queue underflow"); + Item item = first.item; first = first.next; - if (isEmpty()) { - last = null; - } + n--; + if (isEmpty()) last = null; return item; } +\/ + public String toString() { + StringBuilder s = new StringBuilder(); + for (Item item : this) + s.append(item).append(" "); + return s.toString(); + } +\/ + public Iterator<Item> iterator() { + return new LinkedIterator(); + } +\/ + private class LinkedIterator implements Iterator<Item> { + private Node current = first; +\/ + public boolean hasNext() { + return current != null; + } +\/ + public Item next() { + if (!hasNext()) throw new NoSuchElementException(); + Item item = current.item; + current = current.next; + return item; + } + } } #include <iostream> +#include <stdexcept> \/ -struct Node { - int data; - Node* next; -}; -\/ -class Queue { +template <typename Item> +class LinkedQueue { private: - Node* front; - Node* rear; + struct Node { + Item item; + Node* next; + }; +\/ + int n; + Node* first; + Node* last; \/ public: - Queue() : front(nullptr), rear(nullptr) {} + LinkedQueue() : n(0), first(nullptr), last(nullptr) {} \/ - void enqueue(int data) { - Node* newNode = new Node(); - newNode->data = data; - newNode->next = nullptr; + [[nodiscard]] bool isEmpty() const { + return first == nullptr; + } \/ - if (rear == nullptr) { - front = rear = newNode; - return; - } + [[nodiscard]] int size() const { + return n; + } \/ - rear->next = newNode; - rear = newNode; + [[nodiscard]] Item peek() const { + if (isEmpty()) throw std::runtime_error("Queue underflow"); + return first->item; } \/ - void dequeue() { - if (front == nullptr) { - std::cout << "Queue is empty.\n"; - return; + void enqueue(const Item& item) { + Node* oldlast = last; + last = new Node; + last->item = item; + last->next = nullptr; + if (isEmpty()) first = last; + else oldlast->next = last; + n++; + } +\/ + Item dequeue() { + if (isEmpty()) throw std::runtime_error("Queue underflow"); + Item item = first->item; + const Node* oldfirst = first; + first = first->next; + delete oldfirst; + n--; + if (isEmpty()) last = nullptr; + return item; + } +\/ + friend std::ostream& operator<<(std::ostream& os, const LinkedQueue<Item>& queue) { + for (Node* current = queue.first; current != nullptr; current = current->next) { + os << current->item << " "; + } + return os; + } +\/ + class Iterator { + private: + Node* current; +\/ + public: + explicit Iterator(Node* start) : current(start) {} +\/ + [[nodiscard]] bool hasNext() const { + return current != nullptr; } \/ - Node* tempNode = front; - front = front->next; + Item next() { + if (!hasNext()) throw std::runtime_error("No more elements"); + Item item = current->item; + current = current->next; + return item; + } \/ - if (front == nullptr) { - rear = nullptr; + [[nodiscard]] Node* getCurrent() const { + return current; } \/ - delete tempNode; - } + Iterator& operator++() { + if (current) { + current = current->next; + } + return *this; + } \/ - int peek() { - if (front == nullptr) { - std::cout << "Queue is empty.\n"; - return -1; + Item& operator*() { + if (!current) { + throw std::runtime_error("Dereferencing invalid iterator"); + } + return current->item; } - return front->data; + }; +\/ + friend bool operator!=(const Iterator& lhs, const Iterator& rhs) { + return lhs.getCurrent() != rhs.getCurrent(); + } +\/ + [[nodiscard]] Iterator begin() const { + return Iterator(first); } \/ - bool isEmpty() { - return front == nullptr; + [[nodiscard]] Iterator end() const { + return Iterator(nullptr); } }; @@ -1777,133 +2036,65 @@ public: class Node: - def __init__(self, data=None): - self.data = data + def __init__(self, item): + self.item = item self.next = None \/ -class Queue: +\/ +class LinkedQueue: def __init__(self): - self.front = self.rear = None + self.n = 0 + self.first = None + self.last = None \/ def is_empty(self): - return self.front is None + return self.first is None \/ - def enqueue(self, data): - new_node = Node(data) + def size(self): + return self.n \/ - if self.rear is None: - self.front = self.rear = new_node - return + def peek(self): + if self.is_empty(): + raise Exception("Queue underflow") + return self.first.item \/ - self.rear.next = new_node - self.rear = new_node + def enqueue(self, item): + oldlast = self.last + self.last = Node(item) + if self.is_empty(): + self.first = self.last + else: + oldlast.next = self.last + self.n += 1 \/ def dequeue(self): if self.is_empty(): - return None -\/ - temp = self.front - self.front = temp.next + raise Exception("Queue underflow") + item = self.first.item + self.first = self.first.next + self.n -= 1 + if self.is_empty(): + self.last = None + return item \/ - if self.front is None: - self.rear = None + def __iter__(self): + current = self.first + while current: + yield current.item + current = current.next \/ - return temp.data + def __str__(self): + return " ".join(str(item) for item in self) ### 4.3 Generics - - - -public class Stack<Item> { - private Node first = null; -\/ - private class Node { - Item item; - Node next; - } -\/ - public boolean isEmpty() { - return first == null; - } -\/ - public void push(Item item) { - Node oldFirst = first; - first = new Node(); - first.item = item; - first.next = oldFirst; - } -\/ - public Item pop() { - Item item = first.item; - first = first.next; - return item; - } -} - - - - -#include <vector> -\/ -template<typename T> -class Stack { -private: - std::vector<T> elements; -\/ -public: - void push(T const& element) { - elements.push_back(element); - } -\/ - void pop() { - if (elements.empty()) { - throw std::out_of_range("Stack<>::pop(): empty stack"); - } - elements.pop_back(); - } -\/ - T top() const { - if (elements.empty()) { - throw std::out_of_range("Stack<>::top(): empty stack"); - } - return elements.back(); - } -\/ - bool empty() const { - return elements.empty(); - } -}; - - - - -public class FixedCapacityStack<Item> { - private Item[] s; - private int N = 0; -\/ - public FixedCapacityStack(int capacity) { - s = (Item[]) new Object[capacity]; - } -\/ - public boolean isEmpty() { - return N == 0; - } -\/ - public void push(Item item) { - s[N++] = item; - } -\/ - public Item pop() { - return s[--N]; - } -} - - - +

Use generics for different types of objects!

+ +

The implementation above has already taken generics into account. +

The fixed-capacity-stack code may get a warning about unchecked @@ -1913,111 +2104,23 @@ cast.

### 4.4 Iterators - -

This is the linked-list implementation of stacks with iterators. -

-
+

Iterators allow clients to iterate through the items in a +collection.

- - - -import java.util.Iterator; -\/ -public class Stack<Item> implements Iterable<Item> { - private Node first = null; -\/ - private class Node { - Item item; - Node next; - } -\/ - public boolean isEmpty() { - return first == null; - } -\/ - public void push(Item item) { - Node oldFirst = first; - first = new Node(); - first.item = item; - first.next = oldFirst; - } -\/ - public Item pop() { - Item item = first.item; - first = first.next; - return item; - } -\/ - public Iterator<Item> iterator() { - return new ListIterator(); - } -\/ - private class ListIterator implements Iterator<Item> { - private Node current = first; -\/ - public boolean hasNext() { - return current != null; - } -\/ - public Item next() { - Item item = current.item; - current = current.next; - return item; - } - } +

Using iterator, we can:

+ + +for (Item item : collection) { + // do something with item } - -
-
+ - -

This is the array implementation of stacks with iterators.

-
+

The implementation above has already taken iterators into account. +

- - - -import java.util.Iterator; -\/ -public class Stack<Item> implements Iterable<Item> { - private Item[] s; - private int N = 0; -\/ - public Stack(int capacity) { - s = (Item[]) new Object[capacity]; - } -\/ - public boolean isEmpty() { - return N == 0; - } -\/ - public void push(Item item) { - s[N++] = item; - } -\/ - public Item pop() { - return s[--N]; - } -\/ - public Iterator<Item> iterator() { - return new ReverseArrayIterator(); - } -\/ - private class ReverseArrayIterator implements Iterator<Item> { - private int i = N; -\/ - public boolean hasNext() { - return i > 0; - } -\/ - public Item next() { - return s[--i]; - } - } -} - - - +

For more information on iterators, please visit +Iterators in C++.

### 4.5 Bag (Princeton) diff --git a/Writerside/topics/Python-Programming.md b/Writerside/topics/Python-Programming.md index 5724adf..18eed44 100644 --- a/Writerside/topics/Python-Programming.md +++ b/Writerside/topics/Python-Programming.md @@ -2,6 +2,8 @@ # Python Programming + + ## 1 Basic Python Knowledge ### 1.1 Strings