1st Implementation: The following stack implementation assumes that the end of the list will hold the top element of the stack. As the stack grows, new items will be added on the end of the list.
class Stack:
def __init__(self):
self.items = []
def isEmpty(self):
return self.items == []
def push(self, item):
self.items.append(item)
def pop(self):
return self.items.pop()
def peek(self):
return self.items[len(self.items)-1]
def size(self):
return len(self.items)
2nd Implementation : The second implementation assumes that the beginning of the list holds the top element of the stack and new items are added at the index 0.
class Stack:
def __init__(self):
self.items = []
def isEmpty(self):
return self.items == []
def push(self, item):
self.items.insert(0,item)
def pop(self):
return self.items.pop(0)
def peek(self):
return self.items[0]
def size(self):
return len(self.items)
Being a beginner to Data Structures, I would like to know:
1. Which implementation is more efficient with respect to time or space, and why ?
2. Is the time complexity of the insert(0) in the 2nd implementation O(n). If yes, how ?
Lists are optimized for appending and popping from the end. Inserting or removing an item from the beginning of a list is much more expensive, because all the items need to be moved.
Python does have a data structure, collections.deque, which is optimized for appending at both ends.
In Python, lists are implemented with resizeable arrays of references to other objects.
See How are lists implemented?
Because of this, pushing/popping elements at the end of the list will be more efficient than pushing/popping at the start of the list.
Adding/removing elements to the start of an array is very expensive because you will have to shift all the other elements over one space. On the other hand, it is relatively cheap to add/remove elements to the end of an array assuming there is sufficient empty space at the end of the array.
When the array is full, Python will dynamically allocate more memory to the end of that array, which is expensive, but the amortized performance is still excellent.
def __init__(self):
self.items=[]
def push(self,item):
self.items.append(item)
def pop(self):
return self.items.pop()
def isEmpty(self):
return self.items==[]
def peek(self):
return self.items[len(self.items)-1]
def size(self):
return len(self.items)
`
Related
I am currently learning python. I am learning about classes, inheritance, and abstract classes. Here is the constructor in question:
def __init__(self, sourceCollection = None):
"""Sets the initial state of self, which includes the
contents of sourceCollection, if it's present."""
self.size = 0
if sourceCollection:
for item in sourceCollection:
self.add(item)
I am getting the following error, and I don't know why:
TypeError: 'int' object is not iterable
In case is helps, here is my add method:
def add(self, item):
"""Adds item to self."""
# Check array memory here and increase it if necessary
self.items[len(self)] = item
self.size += 1
Could anyone assist me with why I am getting this error? I did some research, but to no avail. Thanks so much in advance!!!
list has a method to add all elements from an iterable
Don't use self.size to keep track of the number of elements in self.items, use len(self.items)
def __init__(self, sourceCollection = None):
"""Make a copy of sourceCollection"""
self.items = []
if not sourceCollection: return
self.items.extend(sourceCollection)
def add(self, item):
"""Adds item to self."""
self.items.append(item)
#property
def size(self):
return len(self.items)
Just do (.append()):
def add(self, item):
"""Adds item to self."""
# Check array memory here and increase it if necessary
self.items.append(item)
self.size += 1
I would like to create a very simple class in Python such that, starting from an initial list of elements [3,7,2,7,81], an other list of numbers can be added, in this case a single element 40. Here is my solution:
class Add_elements:
def add(self, elements):
list = [self.list,elements]
return list
add_elements = Add_elements()
add_elements.add([3,7,2,7,81])
add_elements.add([40])
This should return something like:
[[3,7,2,7,81],40]
The issue with this is that the list of elements is reset every time, there is no memory of the previous elements added. Any solution?
You probably need an initialiser to initialise self.list:
class Add_elements:
def __init__(self):
self.list = None
def add(self, elements):
if self.list is None:
self.list = elements
else:
self.list = [self.list,elements]
return self.list
This will make list an attribute of Add_elements - part of its state. And when you call add, it changes that state.
EDIT:
If you want to remove the square brackets when calling add, you can do something like this:
def add(self, *elements):
if self.list is None:
self.list = list(elements)
else:
self.list = [self.list,list(elements)]
return self.list
I scoured the web to come up with this implementation of MinHeap and Maxheap in Python.
import heapq
class MinHeap:
def __init__(self):
self.heap = []
def push(self, item):
heapq.heappush(self.heap, item)
def pop(self):
return heapq.heappop(self.h)
def __getitem__(self, item):
return self.heap[item]
def __len__(self):
return len(self.h)
class MaxHeap(MinHeap):
def push(self, item):
heapq.heappush(self.heap, Comparator(item))
def pop(self):
return heapq.heappop(self.h)
def __getitem__(self, i):
return self.heap[i].val
class Comparator:
def __init__(self, val):
self.val = val
def __lt__(self, other):
return self.val > self.other
def __eq__(self, other):
return self.val == self.other
def __str__(self):
return str(self.val)
Now I need to add a peek method to both these classes. In it's current implementation I could pop and push back. But my question is, is there a better way to do it. Something in O(1) time.
These classes are based on Python's heapq structure, which is built on a standard Python list. The smallest item in the minheap and the largest item in the maxheap is at index zero. So just return
self.heap[0]
If the heap is empty, that will cause an error, but that probably is what you want.
I'm trying to design a Queue data structure with python 3.6
The queue has the aim to keep track node objects with these attributes:
class node(object):
def __init__(self, state, parent):
self.state = state
self.parent = parent
I want avoid to incorporate nodes with the same state in the queue. So I design the following queue:
class queue(object):
def __init__(self):
self.list = []
self.explored = set()
def insert(self, element):
self.list = [element] + self.list
self.explored.add(str(element.state))
return self.list
def pop(self):
oldest_element = self.list.pop()
self.explored.remove(str(oldest_element.state))
return oldest_element
def empty(self):
return len(self.list) == 0
def check_member(self, other):
return other in self.explored
In order to check if a state of a node is in the queue, I use the check_member method with the attribute state as a string type to see if is contained in the set with all the string state of the members. But this is still slowly.
So it is possible to check if an instance has the same attribute of another instance that could differ in other attributes? For example, two nodes, same state attributes but different parents attributes.
How can keep the order of the elements and still checking if some element is in the queue in O(1) without using the additional explored set?
You need a set/dict type object to achieve O(1) contains-check complexity. The easiest would be to use an OrderedDict as your underlying data container. Use state as key and the node as the value. That way, the states are enforced to be unique, and the order is maintained nonetheless:
from collections import OrderedDict
class queue(object):
def __init__(self):
self.q = OrderedDict()
def insert(self, element):
s = str(element.state)
if s not in self.q:
self.q[s] = element # adds to the end
def pop(self):
return self.q.popitem(0)[1] # returns the node from beginning
def empty(self):
return not self.q
def check_member(self, element):
return str(element.state) in self.q
I need to mirror a queue using a function called mirror
I have made the code for the queue class, but i dont know how to create a mirror of it. It needs to print out the original queue and then the same queue reversed
Any help would be appreciated
My Code:
class Queue:
def __init__(self):
self.items = []
def is_empty(self):
return self.items == []
def enqueue(self, item):
self.items.insert(0,item)
def dequeue(self):
return self.items.pop()
def is_empty(self):
return not self.items
def size(self):
return len(self.items)
class Stack:
def __init__(self):
self.items = []
def is_empty(self):
return self.items == []
def push(self, item):
self.items.append(item)
def pop(self):
return self.items.pop()
def peek(self):
return self.items[len(self.items)-1]
def size(self):
return len(self.items)
def mirror(n):
pass
This will work. Your queue is composed of a list, so you can use slice syntax on the list to get a reversed version of the queue.
class Queue:
def __init__(self):
self.items = []
def enqueue(self, item):
self.items.append(item)
def __str__(self):
'''Allow print to be called on the queue object itself'''
return str(self.items)
def __getitem__(self, i):
'''Allow the queue object to be indexable directly'''
return self.items[i]
def mirror(q):
return q[::-1]
q = Queue()
for i in range(10):
q.enqueue(i)
print q
print mirror(q)
Note: A queue appends to the end, not the start. That's the behaviour of a stack.
Maybe you give this one a try: How can I reverse a list in python
You can create a new queue using the reversed self.items list in a member function mirror.
q = ArrayQueue()
def mirror(q):
copy = ArrayQueue()
stack = ArrayStack()
while not q.is_empty():
stack.push(q.first())
copy.enqueue(q.dequeue())
while not stack.is_empty():
copy.enqueue(stack.pop())
for i in range(len(copy)):
print(copy.dequeue(),end=" ")