From c2b7acdf111337632612e26dfdc2b292ac31ddd2 Mon Sep 17 00:00:00 2001
From: Du Yuanchao <shellhub.me@gmail.com>
Date: Sat, 24 Oct 2020 00:16:23 +0800
Subject: [PATCH] Update Linked Stack (#3625)

* update linked_stack

* remove properties

* updating DIRECTORY.md

Co-authored-by: github-actions <${GITHUB_ACTOR}@users.noreply.github.com>
---
 data_structures/stacks/linked_stack.py | 134 +++++++++++++++++++++----
 1 file changed, 112 insertions(+), 22 deletions(-)

diff --git a/data_structures/stacks/linked_stack.py b/data_structures/stacks/linked_stack.py
index 18ba87ddc..1a2d07f20 100644
--- a/data_structures/stacks/linked_stack.py
+++ b/data_structures/stacks/linked_stack.py
@@ -1,11 +1,14 @@
-""" A Stack using a Linked List like structure """
-from typing import Any, Optional
+""" A Stack using a linked list like structure """
+from typing import Any
 
 
 class Node:
-    def __init__(self, data: Any, next: Optional["Node"] = None):
-        self.data: Any = data
-        self.next: Optional["Node"] = next
+    def __init__(self, data):
+        self.data = data
+        self.next = None
+
+    def __str__(self):
+        return f"{self.data}"
 
 
 class LinkedStack:
@@ -19,7 +22,7 @@ class LinkedStack:
     >>> stack.push(5)
     >>> stack.push(9)
     >>> stack.push('python')
-    >>> stack.is_empty();
+    >>> stack.is_empty()
     False
     >>> stack.pop()
     'python'
@@ -39,29 +42,116 @@ class LinkedStack:
     """
 
     def __init__(self) -> None:
-        self.top: Optional[Node] = None
+        self.top = None
+
+    def __iter__(self):
+        node = self.top
+        while node:
+            yield node.data
+            node = node.next
+
+    def __str__(self):
+        """
+        >>> stack = LinkedStack()
+        >>> stack.push("c")
+        >>> stack.push("b")
+        >>> stack.push("a")
+        >>> str(stack)
+        'a->b->c'
+        """
+        return "->".join([str(item) for item in self])
+
+    def __len__(self):
+        """
+        >>> stack = LinkedStack()
+        >>> len(stack) == 0
+        True
+        >>> stack.push("c")
+        >>> stack.push("b")
+        >>> stack.push("a")
+        >>> len(stack) == 3
+        True
+        """
+        return len(tuple(iter(self)))
 
     def is_empty(self) -> bool:
-        """ returns boolean describing if stack is empty """
+        """
+        >>> stack = LinkedStack()
+        >>> stack.is_empty()
+        True
+        >>> stack.push(1)
+        >>> stack.is_empty()
+        False
+        """
         return self.top is None
 
     def push(self, item: Any) -> None:
-        """ append item to top of stack """
-        node: Node = Node(item)
-        if self.is_empty():
-            self.top = node
-        else:
-            # each node points to the item "lower" in the stack
+        """
+        >>> stack = LinkedStack()
+        >>> stack.push("Python")
+        >>> stack.push("Java")
+        >>> stack.push("C")
+        >>> str(stack)
+        'C->Java->Python'
+        """
+        node = Node(item)
+        if not self.is_empty():
             node.next = self.top
-            self.top = node
+        self.top = node
 
     def pop(self) -> Any:
-        """ returns and removes item at top of stack """
+        """
+        >>> stack = LinkedStack()
+        >>> stack.pop()
+        Traceback (most recent call last):
+        ...
+        IndexError: pop from empty stack
+        >>> stack.push("c")
+        >>> stack.push("b")
+        >>> stack.push("a")
+        >>> stack.pop() == 'a'
+        True
+        >>> stack.pop() == 'b'
+        True
+        >>> stack.pop() == 'c'
+        True
+        """
         if self.is_empty():
             raise IndexError("pop from empty stack")
-        else:
-            # "remove" element by having top point to the next one
-            assert isinstance(self.top, Node)
-            node: Node = self.top
-            self.top = node.next
-            return node.data
+        assert isinstance(self.top, Node)
+        pop_node = self.top
+        self.top = self.top.next
+        return pop_node.data
+
+    def peek(self) -> Any:
+        """
+        >>> stack = LinkedStack()
+        >>> stack.push("Java")
+        >>> stack.push("C")
+        >>> stack.push("Python")
+        >>> stack.peek()
+        'Python'
+        """
+        if self.is_empty():
+            raise IndexError("peek from empty stack")
+        return self.top.data
+
+    def clear(self) -> None:
+        """
+        >>> stack = LinkedStack()
+        >>> stack.push("Java")
+        >>> stack.push("C")
+        >>> stack.push("Python")
+        >>> str(stack)
+        'Python->C->Java'
+        >>> stack.clear()
+        >>> len(stack) == 0
+        True
+        """
+        self.top = None
+
+
+if __name__ == "__main__":
+    from doctest import testmod
+
+    testmod()