mirror of
https://github.com/wassname/pyrobolearn.git
synced 2026-09-09 11:31:38 +08:00
update utils.data_structures: add queues
This commit is contained in:
@@ -4,5 +4,8 @@
|
||||
# Ordered sets
|
||||
from .orderedset import *
|
||||
|
||||
# Queues
|
||||
from .queues import *
|
||||
|
||||
# Graph
|
||||
from .graph import *
|
||||
from .graph import *
|
||||
|
||||
@@ -1,6 +1,19 @@
|
||||
#!/usr/bin/env python
|
||||
"""Define the OrderedSet data structure class.
|
||||
"""
|
||||
|
||||
import collections
|
||||
|
||||
__author__ = "Brian Delhaisse"
|
||||
__copyright__ = "Copyright 2018, PyRoboLearn"
|
||||
__credits__ = ["Brian Delhaisse"]
|
||||
__license__ = "MIT"
|
||||
__version__ = "1.0.0"
|
||||
__maintainer__ = "Brian Delhaisse"
|
||||
__email__ = "briandelhaisse@gmail.com"
|
||||
__status__ = "Development"
|
||||
|
||||
|
||||
class OrderedSet(collections.MutableSet):
|
||||
r"""Ordered Set
|
||||
|
||||
@@ -59,6 +72,10 @@ class OrderedSet(collections.MutableSet):
|
||||
for item in iterator:
|
||||
self.add(item)
|
||||
|
||||
###########
|
||||
# Methods #
|
||||
###########
|
||||
|
||||
def add(self, item):
|
||||
"""
|
||||
Add/Append an item to the ordered set.
|
||||
@@ -86,15 +103,14 @@ class OrderedSet(collections.MutableSet):
|
||||
Time complexity: O(N)
|
||||
"""
|
||||
# check idx
|
||||
idx = self._checkIndex(idx)
|
||||
idx = self._check_index(idx)
|
||||
if item in self._set:
|
||||
# move the item at the specified location
|
||||
self.move(idx, item) # O(N)
|
||||
self.move(idx, item) # O(N)
|
||||
else:
|
||||
# add it
|
||||
self._list.insert(idx, item) # O(N)
|
||||
self._set.add(item) # O(1)
|
||||
|
||||
self._list.insert(idx, item) # O(N)
|
||||
self._set.add(item) # O(1)
|
||||
|
||||
def move(self, idx, item):
|
||||
"""
|
||||
@@ -102,11 +118,10 @@ class OrderedSet(collections.MutableSet):
|
||||
Time complexity: O(N)
|
||||
"""
|
||||
# remove the item from the list/set
|
||||
self.remove(item) # O(N)
|
||||
self.remove(item) # O(N)
|
||||
|
||||
# insert item
|
||||
self.insert(idx, item) # O(N)
|
||||
|
||||
self.insert(idx, item) # O(N)
|
||||
|
||||
def discard(self, item):
|
||||
"""
|
||||
@@ -115,7 +130,7 @@ class OrderedSet(collections.MutableSet):
|
||||
"""
|
||||
if item in self._set:
|
||||
self._list.remove(item) # O(N)
|
||||
self._set.remove(item) # O(1)
|
||||
self._set.remove(item) # O(1)
|
||||
|
||||
def remove(self, item):
|
||||
"""
|
||||
@@ -134,9 +149,9 @@ class OrderedSet(collections.MutableSet):
|
||||
index: index in the ordered set.
|
||||
"""
|
||||
if index is None: index = len(self._list)
|
||||
index = self._checkIndex(index) # to be sure the index is valid
|
||||
self._set.remove(self._list[index]) # O(1)
|
||||
item = self._list.pop(index) # O(1) if last, O(N) if first
|
||||
index = self._check_index(index) # to be sure the index is valid
|
||||
self._set.remove(self._list[index]) # O(1)
|
||||
item = self._list.pop(index) # O(1) if last, O(N) if first
|
||||
return item
|
||||
|
||||
def copy(self):
|
||||
@@ -146,7 +161,7 @@ class OrderedSet(collections.MutableSet):
|
||||
"""
|
||||
return self.__class__(self)
|
||||
|
||||
def _checkIndex(self, idx):
|
||||
def _check_index(self, idx):
|
||||
"""
|
||||
Check the given index; if it is in the range of the ordered set, and if it is negative return the
|
||||
corresponding positive index.
|
||||
@@ -274,7 +289,12 @@ class OrderedSet(collections.MutableSet):
|
||||
"""
|
||||
return other.issuperset(self, order=order)
|
||||
|
||||
#############
|
||||
# Operators #
|
||||
#############
|
||||
|
||||
def __repr__(self):
|
||||
"""Return a representation string."""
|
||||
return '%s(%r)' % (self.__class__.__name__, list(self))
|
||||
|
||||
def __contains__(self, item):
|
||||
@@ -336,14 +356,14 @@ class OrderedSet(collections.MutableSet):
|
||||
else:
|
||||
self._list[idx] = item
|
||||
self._set.add(item)
|
||||
elif isinstance(idx, slice): # slice
|
||||
elif isinstance(idx, slice): # slice
|
||||
# replace in list
|
||||
items_to_remove = self._list[idx] # O(K)
|
||||
self._list[idx] = item # O(K+N)
|
||||
items_to_remove = self._list[idx] # O(K)
|
||||
self._list[idx] = item # O(K+N)
|
||||
|
||||
# remove previous items from the set
|
||||
for elem in items_to_remove:
|
||||
self._set.remove(elem) # O(1)
|
||||
self._set.remove(elem) # O(1)
|
||||
|
||||
# add new items in the set
|
||||
for elem in item:
|
||||
@@ -455,6 +475,10 @@ class OrderedSet2(collections.MutableSet):
|
||||
for item in iterator:
|
||||
self.add(item)
|
||||
|
||||
###########
|
||||
# Methods #
|
||||
###########
|
||||
|
||||
def add(self, item):
|
||||
"""
|
||||
Add/Append an item to the ordered set.
|
||||
@@ -491,7 +515,7 @@ class OrderedSet2(collections.MutableSet):
|
||||
Time complexity: O(N)
|
||||
"""
|
||||
# check idx
|
||||
idx = self._checkIndex(idx)
|
||||
idx = self._check_index(idx)
|
||||
|
||||
# if the set is initially empty or index is the size of the set, just add the item (at the end)
|
||||
if len(self._map) == 0 or idx == len(self._map):
|
||||
@@ -503,10 +527,10 @@ class OrderedSet2(collections.MutableSet):
|
||||
# get current item at the specified index, update the items nearby, and insert the new item
|
||||
curr = self[idx]
|
||||
prev_item, next_item = self._map[curr]
|
||||
if prev_item == self.NonePtr: # beginning of the ordered set (idx=0)
|
||||
if prev_item == self.NonePtr: # beginning of the ordered set (idx=0)
|
||||
self._map[curr][0] = item
|
||||
self._map[item] = [self.NonePtr, curr]
|
||||
else: # somewhere between the start and the end (not included)
|
||||
else: # somewhere between the start and the end (not included)
|
||||
self._map[item] = [prev_item, next_item]
|
||||
self._map[prev_item][1] = item
|
||||
self._map[next_item][0] = item
|
||||
@@ -525,7 +549,6 @@ class OrderedSet2(collections.MutableSet):
|
||||
# insert item
|
||||
self.insert(idx, item)
|
||||
|
||||
|
||||
def discard(self, item):
|
||||
"""
|
||||
Remove an item from the ordered set if it is a member. If the item is not a member do nothing.
|
||||
@@ -579,7 +602,7 @@ class OrderedSet2(collections.MutableSet):
|
||||
"""
|
||||
return self.__class__(self)
|
||||
|
||||
def _checkIndex(self, idx):
|
||||
def _check_index(self, idx):
|
||||
"""
|
||||
Check the given index; if it is in the range of the ordered set, and if it is negative return the
|
||||
corresponding positive index.
|
||||
@@ -709,7 +732,12 @@ class OrderedSet2(collections.MutableSet):
|
||||
"""
|
||||
return other.issuperset(self, order=order)
|
||||
|
||||
#############
|
||||
# Operators #
|
||||
#############
|
||||
|
||||
def __repr__(self):
|
||||
"""Return a representation string."""
|
||||
return '%s(%r)' % (self.__class__.__name__, list(self))
|
||||
|
||||
def __contains__(self, item):
|
||||
@@ -763,7 +791,7 @@ class OrderedSet2(collections.MutableSet):
|
||||
if isinstance(idx, int): # index is an integer
|
||||
|
||||
# check index
|
||||
idx = self._checkIndex(idx)
|
||||
idx = self._check_index(idx)
|
||||
|
||||
# traverse the set in a specific order based on how close the index is wrt the start/end of the set
|
||||
curr = self.NonePtr
|
||||
@@ -818,7 +846,7 @@ class OrderedSet2(collections.MutableSet):
|
||||
Time complexity: O(N)
|
||||
"""
|
||||
# check idx
|
||||
idx = self._checkIndex(idx)
|
||||
idx = self._check_index(idx)
|
||||
|
||||
# check if item already in the set
|
||||
if item in self._map:
|
||||
@@ -880,7 +908,7 @@ class OrderedSet2(collections.MutableSet):
|
||||
self &= other
|
||||
|
||||
|
||||
#OrderedSet = OrderedSet2
|
||||
# OrderedSet = OrderedSet2
|
||||
|
||||
|
||||
# Tests
|
||||
@@ -954,4 +982,4 @@ if __name__ == '__main__':
|
||||
print("s3 - s1 = {}".format(s3 - s1))
|
||||
print("s3.difference(s1) = {}".format(s3.difference(s1)))
|
||||
print("s1 - s2 = {}".format(s1 - s2))
|
||||
print("s1 - s0 = {}".format(s1 - s0))
|
||||
print("s1 - s0 = {}".format(s1 - s0))
|
||||
|
||||
@@ -0,0 +1,347 @@
|
||||
#!/usr/bin/env python
|
||||
"""Define the queue data structures.
|
||||
|
||||
These inherit from the various queues in the `queue` Python library, to which we provide few more functionalities.
|
||||
"""
|
||||
|
||||
import queue
|
||||
import heapq
|
||||
|
||||
__author__ = "Brian Delhaisse"
|
||||
__copyright__ = "Copyright 2018, PyRoboLearn"
|
||||
__credits__ = ["Brian Delhaisse"]
|
||||
__license__ = "MIT"
|
||||
__version__ = "1.0.0"
|
||||
__maintainer__ = "Brian Delhaisse"
|
||||
__email__ = "briandelhaisse@gmail.com"
|
||||
__status__ = "Development"
|
||||
|
||||
|
||||
# # add functionalities to the original queue.Queue (from which queue.PriorityQueue and LifoQueue inherit from)
|
||||
#
|
||||
# def append(self, item):
|
||||
# """
|
||||
# Append an item in at the end of the FIFO queue. If the queue is already full it will remove the first item.
|
||||
# """
|
||||
# # if full remove the first item
|
||||
# if self.full():
|
||||
# self.get()
|
||||
#
|
||||
# # add the new item
|
||||
# self.put(item)
|
||||
#
|
||||
#
|
||||
# def tolist(self):
|
||||
# """
|
||||
# Return a list of the queue.
|
||||
# """
|
||||
# return list(self.queue)
|
||||
#
|
||||
#
|
||||
# def __repr__(self):
|
||||
# """Return a representation string."""
|
||||
# return str(self.queue)
|
||||
#
|
||||
#
|
||||
# def __len__(self):
|
||||
# """Return the current length of the FIFO queue."""
|
||||
# return self.qsize()
|
||||
#
|
||||
#
|
||||
# def __getitem__(self, idx):
|
||||
# """Return the item corresponding to the given index.
|
||||
#
|
||||
# Args:
|
||||
# idx (int): index.
|
||||
# """
|
||||
# return self.queue[idx]
|
||||
#
|
||||
#
|
||||
# def __setitem__(self, idx, item):
|
||||
# """Set the given item to the given index."""
|
||||
# self.queue[idx] = item
|
||||
#
|
||||
#
|
||||
# def __iter__(self):
|
||||
# """Return an iterator over the queue."""
|
||||
# return iter(self.queue)
|
||||
#
|
||||
#
|
||||
# # add functionalities
|
||||
# queue.Queue.append = append
|
||||
# queue.Queue.tolist = tolist
|
||||
# queue.Queue.__repr__ = __repr__
|
||||
# queue.Queue.__len__ = __len__
|
||||
# queue.Queue.__getitem__ = __getitem__
|
||||
# queue.Queue.__setitem__ = __setitem__
|
||||
# queue.Queue.__iter__ = __iter__
|
||||
#
|
||||
#
|
||||
# # provide aliases
|
||||
# FIFOQueue = queue.Queue
|
||||
# LIFOQueue = queue.LifoQueue
|
||||
|
||||
|
||||
class FIFOQueue(queue.Queue):
|
||||
r"""FIFO Queue
|
||||
|
||||
We provide few more functionalities on top of the original `queue.Queue` class.
|
||||
"""
|
||||
|
||||
def __init__(self, maxsize=0):
|
||||
"""
|
||||
Initialize the FIFO queue.
|
||||
|
||||
Args:
|
||||
maxsize (int): maximum size of the queue.
|
||||
"""
|
||||
queue.Queue.__init__(self, maxsize)
|
||||
|
||||
def append(self, item):
|
||||
"""
|
||||
Append an item in at the end of the FIFO queue. If the queue is already full it will remove the first item.
|
||||
"""
|
||||
# if full remove the first item
|
||||
if self.full():
|
||||
self.get()
|
||||
|
||||
# add the new item
|
||||
self.put(item)
|
||||
|
||||
def tolist(self):
|
||||
"""
|
||||
Return a list of the queue.
|
||||
"""
|
||||
return list(self.queue)
|
||||
|
||||
def __repr__(self):
|
||||
"""Return a representation string."""
|
||||
return str(self.queue)
|
||||
|
||||
def __len__(self):
|
||||
"""Return the current length of the FIFO queue."""
|
||||
return self.qsize()
|
||||
|
||||
def __getitem__(self, idx):
|
||||
"""Return the item corresponding to the given index.
|
||||
|
||||
Args:
|
||||
idx (int): index.
|
||||
"""
|
||||
return self.queue[idx]
|
||||
|
||||
def __setitem__(self, idx, item):
|
||||
"""Set the given item to the given index."""
|
||||
self.queue[idx] = item
|
||||
|
||||
def __iter__(self):
|
||||
"""Return an iterator over the queue."""
|
||||
return iter(self.queue)
|
||||
|
||||
|
||||
class LIFOQueue(queue.LifoQueue):
|
||||
r"""LIFO Queue.
|
||||
|
||||
We provide few more functionalities on top of the original `queue.LifoQueue` class.
|
||||
"""
|
||||
|
||||
def __init__(self, maxsize=0):
|
||||
"""
|
||||
Initialize the FIFO queue.
|
||||
|
||||
Args:
|
||||
maxsize (int): maximum size of the queue.
|
||||
"""
|
||||
queue.Queue.__init__(self, maxsize)
|
||||
|
||||
def append(self, item):
|
||||
"""
|
||||
Append an item in at the end of the FIFO queue. If the queue is already full it will remove the first item.
|
||||
"""
|
||||
# if full remove the first item
|
||||
if self.full():
|
||||
self.get()
|
||||
|
||||
# add the new item
|
||||
self.put(item)
|
||||
|
||||
def tolist(self):
|
||||
"""
|
||||
Return a list of the queue.
|
||||
"""
|
||||
return list(self.queue)
|
||||
|
||||
def __repr__(self):
|
||||
"""Return a representation string."""
|
||||
return str(self.queue)
|
||||
|
||||
def __len__(self):
|
||||
"""Return the current length of the FIFO queue."""
|
||||
return self.qsize()
|
||||
|
||||
def __getitem__(self, idx):
|
||||
"""Return the item corresponding to the given index.
|
||||
|
||||
Args:
|
||||
idx (int): index.
|
||||
"""
|
||||
return self.queue[idx]
|
||||
|
||||
def __setitem__(self, idx, item):
|
||||
"""Set the given item to the given index."""
|
||||
self.queue[idx] = item
|
||||
|
||||
def __iter__(self):
|
||||
"""Return an iterator over the queue."""
|
||||
return reversed(self.queue)
|
||||
|
||||
|
||||
class PriorityQueue(queue.PriorityQueue):
|
||||
r"""Priority Queue.
|
||||
|
||||
We provide few more functionalities on top of the original `queue.PriorityQueue` class.
|
||||
"""
|
||||
|
||||
def __init__(self, maxsize=0, ascending=True):
|
||||
"""
|
||||
Initialize the FIFO queue.
|
||||
|
||||
Args:
|
||||
maxsize (int): maximum size of the queue.
|
||||
ascending (bool): if True, the item with the lowest priority will be the first one to be retrieved.
|
||||
"""
|
||||
queue.Queue.__init__(self, maxsize)
|
||||
self.ascending = bool(ascending)
|
||||
|
||||
def append(self, item):
|
||||
"""
|
||||
Append an item in at the end of the FIFO queue. If the queue is already full it will remove the first item.
|
||||
"""
|
||||
# if full remove the first item
|
||||
if self.full():
|
||||
self.get()
|
||||
|
||||
# add the new item
|
||||
self.put(item)
|
||||
|
||||
def tolist(self):
|
||||
"""
|
||||
Return a list of the queue.
|
||||
"""
|
||||
return list(self.queue)
|
||||
|
||||
def _put(self, item, heappush=heapq.heappush):
|
||||
if not self.ascending:
|
||||
item = (-item[0], item[1])
|
||||
queue.PriorityQueue._put(self, item, heappush=heappush)
|
||||
|
||||
def _get(self, heappop=heapq.heappop):
|
||||
item = queue.PriorityQueue._get(self, heappop=heappop)
|
||||
if not self.ascending:
|
||||
item = (-item[0], item[1])
|
||||
return item
|
||||
|
||||
def get_lowest(self):
|
||||
"""
|
||||
Get the lowest priority item.
|
||||
"""
|
||||
if len(self) == 0:
|
||||
raise ValueError("The priority queue is empty.")
|
||||
|
||||
if self.ascending:
|
||||
return self[0][1]
|
||||
else:
|
||||
return self[-1][1]
|
||||
|
||||
def get_highest(self):
|
||||
"""
|
||||
Get the highest priority item.
|
||||
"""
|
||||
if len(self) == 0:
|
||||
raise ValueError("The priority queue is empty.")
|
||||
if self.ascending:
|
||||
return self[-1][1]
|
||||
else:
|
||||
return self[0][1]
|
||||
|
||||
def __repr__(self):
|
||||
"""Return a representation string."""
|
||||
return str(self.queue)
|
||||
|
||||
def __len__(self):
|
||||
"""Return the current length of the FIFO queue."""
|
||||
return self.qsize()
|
||||
|
||||
def __getitem__(self, idx):
|
||||
"""Return the item corresponding to the given index.
|
||||
|
||||
Args:
|
||||
idx (int): index.
|
||||
"""
|
||||
return self.queue[idx]
|
||||
|
||||
def __setitem__(self, idx, item):
|
||||
"""Set the given item to the given index."""
|
||||
self.queue[idx] = item
|
||||
|
||||
def __iter__(self):
|
||||
"""Return an iterator over the queue."""
|
||||
if self.ascending:
|
||||
return iter(self.queue)
|
||||
else:
|
||||
return reversed(self.queue)
|
||||
|
||||
|
||||
# Tests
|
||||
if __name__ == '__main__':
|
||||
# create queue
|
||||
q = FIFOQueue(2)
|
||||
print("Initial queue (maxsize={}): {}".format(q.maxsize, q))
|
||||
|
||||
# add two elements in the queue
|
||||
q.append(1)
|
||||
q.append(2)
|
||||
print("After adding '1' and '2' in queue: {}".format(q))
|
||||
|
||||
# add third element in the queue
|
||||
q.append(3)
|
||||
print("After adding '3' in queue: {}".format(q))
|
||||
|
||||
# iterate over queue
|
||||
for i, item in enumerate(q):
|
||||
print("Item {}: {}".format(i, item))
|
||||
|
||||
# create stack
|
||||
stack = LIFOQueue(maxsize=2)
|
||||
print("\nInitial stack (maxsize={}): {}".format(stack.maxsize, stack))
|
||||
|
||||
# add two elements in the stack
|
||||
stack.append(1)
|
||||
stack.append(2)
|
||||
print("After adding '1' and '2' in the stack: {}".format(stack))
|
||||
|
||||
# add third element
|
||||
stack.append(3)
|
||||
print("After adding '3' in queue: {}".format(stack))
|
||||
|
||||
# iterate over stack
|
||||
for i, item in enumerate(stack):
|
||||
print("Item {}: {}".format(i, item))
|
||||
|
||||
# create priority queue
|
||||
pq = PriorityQueue(maxsize=2, ascending=True)
|
||||
print("\nInitial priority queue (maxsize={}): {}".format(pq.maxsize, pq))
|
||||
|
||||
# add two elements in the queue
|
||||
pq.append((1, 'hello'))
|
||||
pq.append((2, 'world'))
|
||||
print("After adding (1, 'hello') and (2, 'world') in priority queue: {}".format(pq))
|
||||
print("Lowest priority item: {}".format(pq.get_lowest()))
|
||||
print("Highest priority item: {}".format(pq.get_highest()))
|
||||
|
||||
print("Remove the 1st item: {} --> resulting priority queue: {}".format(pq.get(), pq))
|
||||
|
||||
# add two elements in the queue
|
||||
pq.append((3, 'hello'))
|
||||
pq.append((4, 'sir'))
|
||||
print("After adding (3, 'hello') and (4, 'sir') in priority queue: {}".format(pq))
|
||||
Reference in New Issue
Block a user