# 1. Stack operation

Stack is a linear data structure that stores data in a first in last out or last in first out manner. The insertion and deletion of data in the stack are performed at the top of the stack. Common stack function operations include

- empty() – Return whether the stack is empty – time complexity: O (1)
- size() – Return stack length – time complexity: O (1)
- top() – View stack top element – time complexity: O (1)
- push(g) – Add element to top of stack – time complexity: O (1)
- pop() – Delete stack top element – time complexity: O (1)

The stack in python can be implemented in the following three ways:

１)list

２)collections.deque

３)queue.LifoQueue

1.1 using list to implement stack

python's built-in data structure list can be used to implement the stack, add elements to the top of the stack with append(), and pop() can delete elements in a later in first out order

However, the list itself has some disadvantages. The main problem is that when the list continues to expand, it will encounter a speed bottleneck. The list is a dynamic array, so when adding new elements to it without space to save new elements, it will automatically reallocate the memory block and copy the values in the original memory to the new memory block. This leads to some append() Operation will consume more time

>>> stack = [] >>> #append() fuction to push ... #element in list ... >>> stack.append('hello') >>> stack.append('world') >>> stack.append('!') >>> print('Initial stack') Initial stack >>> print(stack) ['hello', 'world', '!'] >>> #pop() function to pop element ... #from stack in LIFO order ... >>> print('\nElement poped from stack') Element poped from stack >>> print(stack.pop()) ! >>> print(stack.pop()) world >>> print(stack.pop()) hello >>> print('\nStack after all elements are poped') Stack after all elements are poped >>> print(stack) []

1.2 stack implementation using collections.deque

The stack in python can also be implemented with deque class. When we want to implement append and pop operations at both ends of the container more quickly, deque is more appropriate than the list. Deque can provide append and pop operations with O(1) time, while the list needs O(n) time

>>> from collections import deque >>> stack = deque() >>> # append() fuction to push ... #element in list ... >>> stack.append('hello') >>> stack.append('world') >>> stack.append('!') >>> print('Initial stack') Initial stack >>> print(stack) deque(['hello', 'world', '!']) >>> #pop() function to pop element ... #from stack in LIFO order ... >>> print('\nElement poped from stack') Element poped from stack >>> print(stack.pop()) ! >>> print(stack.pop()) world >>> print(stack.pop()) hello >>> print('\nStack after all elements are poped') Stack after all elements are poped >>> print(stack)deque([])

1.3 using queue module to implement stack

The Queue module has LIFO queue, that is, stack structure. Use put() and get() operations to add and obtain data from the Queue

There are several functions available in this module: maxsize - the number of items allowed in the queue. empty() - returns True if the queue is empty, otherwise false. Full() - returns True if there are maxsize items in the queue. If the queue is initialized to maxsize = 0 (the default), full will never return Trueget() -Remove and return items in the queue. If the queue is empty, wait until an item is available. get nowait() - if an item is immediately available, return an item, otherwise raise QueueEmptyput(item) - put an item into the queue. If the queue is full, wait until a free slot is available before adding an item. If no free slots are available, QueueFull is thrown.

>>> from queue import LifoQueue >>> stack = LifoQueue(maxsize = 3) >>> print(stack.qsize()) 0 >>> stack.put('hello') >>> stack.put('world') >>> stack.put('!') >>> print('\nElement poped from stack') Element poped from stack >>> print(stack.get()) ! >>> print(stack.get()) world >>> print(stack.get()) hello >>> print('\nEmpty:', stack.empty()) Empty: True

Using single linked list

# Python program to demonstrate # stack implementation using a linked list. # node class class Node: def __init__(self, value): self.value = value self.next = None class Stack: # Initializing a stack. # Use a dummy node, which is # easier for handling edge cases. def __init__(self): self.head = Node("head") self.size = 0 # String representation of the stack def __str__(self): cur = self.head.next out = "" while cur: out += str(cur.value) + "->" cur = cur.next return out[:-3] # Get the current size of the stack def getSize(self): return self.size # Check if the stack is empty def isEmpty(self): return self.size == 0 # Get the top item of the stack def peek(self): # Sanitary check to see if we # are peeking an empty stack. if self.isEmpty(): raise Exception("Peeking from an empty stack") return self.head.next.value # Push a value into the stack. def push(self, value): node = Node(value) node.next = self.head.next self.head.next = node self.size += 1 # Remove a value from the stack and return. def pop(self): if self.isEmpty(): raise Exception("Popping from an empty stack") remove = self.head.next self.head.next = self.head.next.next self.size -= 1 return remove.value # Driver Code if __name__ == "__main__": stack = Stack() for i in range(1, 11): stack.push(i) print(f"Stack: {stack}") for _ in range(1, 6): remove = stack.pop() print(f"Pop: {remove}") print(f"Stack: {stack}")

# 2. Queue

Like a stack, a queue is a linear data structure that stores items in a first in first out (FIFO) manner. For queues, the most recently added items are deleted first. A good example of a queue is any consumer queue of resources. The first arriving consumer gets the service first.

Enqueue: adds an item to the queue. If the queue is full, it is called an overflow condition - Time Complexity: 0(1) exit the queue: remove an item from the queue. The order of pop-up items is the same as that of push items. If the queue is empty, it is called Underflow condition - Time Complexity: 0(1)Front: get the first item from the queue - Time Complexity: 0(1)Rear: get the last item from the queue - Time Complexity: 0(1)

# Python program to # demonstrate queue implementation # using list # Initializing a queue queue = [] # Adding elements to the queue queue.append('a') queue.append('b') queue.append('c') print("Initial queue") print(queue) # Removing elements from the queue print("\nElements dequeued from queue") print(queue.pop(0)) print(queue.pop(0)) print(queue.pop(0)) print("\nQueue after removing elements") print(queue) # Uncommenting print(queue.pop(0)) # will raise and IndexError # as the queue is now empty

# Python program to # demonstrate queue implementation # using collections.dequeue from collections import deque # Initializing a queue q = deque() # Adding elements to a queue q.append('a') q.append('b') q.append('c') print("Initial queue") print(q) # Removing elements from a queue print("\nElements dequeued from the queue") print(q.popleft()) print(q.popleft()) print(q.popleft()) print("\nQueue after removing elements") print(q) # Uncommenting q.popleft() # will raise an IndexError # as queue is now empty

# Python program to # demonstrate implementation of # queue using queue module from queue import Queue # Initializing a queue q = Queue(maxsize = 3) # qsize() give the maxsize # of the Queue print(q.qsize()) # Adding of element to queue q.put('a') q.put('b') q.put('c') # Return Boolean for Full # Queue print("\nFull: ", q.full()) # Removing element from queue print("\nElements dequeued from the queue") print(q.get()) print(q.get()) print(q.get()) # Return Boolean for Empty # Queue print("\nEmpty: ", q.empty()) q.put(1) print("\nEmpty: ", q.empty()) print("Full: ", q.full()) # This would result into Infinite # Loop as the Queue is empty. # print(q.get())

It is used to execute the program circularly, that is, under certain conditions, execute a certain program circularly to deal with the same tasks that need to be processed repeatedly

# 3. Linked list

A linked list is actually a linked storage structure of a linear list. Unlike an array, it uses a group of arbitrary storage units to store the data in the linear list. The storage units are not necessarily continuous,

And the length of the linked list is not fixed. This feature of the linked list data makes it very convenient to insert and delete nodes

Each element of the linked list is called a node, and each node can be stored in different locations in memory. In order to represent the logical relationship between each element and subsequent elements, so as to form a chain storage structure of "one node is linked to one node",

In addition to storing the information of the element itself, it also stores its direct successor information. Therefore, each node contains two parts. The first part is called the data area of the linked list, which is used to store the data information of the element itself, which is represented by data,

It is not limited to one member data, but also multiple member data. The second part is a structure pointer, called the pointer field of the linked list, which is used to store its direct subsequent node information, which is represented by next,

The value of next is actually the address of the next node. When the current node is the end node, the value of next is set as a null pointer

3.1 reverse linked list

class Solution: def reverseList(self, head: ListNode) -> ListNode: if head==None: return head #If the current header node is 0, the header is output directly old = head.next #The next bit of the header node is 2 new = head #Take the head node as the tail new.next = None #next is empty because it is the tail #Loop to take out the node elements under the body and link them in front of new while old != None: flag = old old = old.next flag.next = new new = flag return new

3.2

three point three Replication of complex linked list

Not applicable to additional space, add node time in the original linked list O(N),Space 0(1) """ # Definition for a Node. class Node: def __init__(self, x: int, next: 'Node' = None, random: 'Node' = None): self.val = int(x) self.next = next self.random = random """ class Solution: def copyRandomList(self, head: 'Node') -> 'Node': if head == None: return None cur = head while cur != None: # Add new node new = Node(cur.val) #The value A of the current node is assigned to the new linked list new.next = cur.next #The next value B of the current node is the next value of the assignment linked list A cur.next = new #Take the next node of the current node as new, that is, A-B, and cur becomes A-A-B cur = new.next #Assign B to cur for the next round cur = head while cur: # Set random cur.next.random = cur.random.next if cur.random else None #Determine whether there is a random cur = cur.next.next new_head = cur = head.next while cur: # Remove new linked list cur.next = cur.next.next if cur.next else None cur = cur.next return new_head