循环队列结构(阵列支持)

时间:2016-06-18 16:52:24

标签: python queue

我需要一些帮助来编写一个python程序,它将实现循环队列数据结构(支持数组)。我已经完成了一些方法但是在添加和删除队列中的东西以及检查其中的值时我有点难过。我相信这是先进先出的结构。这是我到目前为止身体所拥有的东西

class Queue:
    ''' Constructor '''
    def __init__(self, limit):
        self.limit = limit
        self.data = [None] * limit
        self.queue = []
        self.head = -1
        self.tail = -1
        self.count = 0


    def dequeue(self):
        if self.count == 0:
            raise RuntimeError
        else:
            self.head = 0
            x = self.queue.pop(0)
            if self.head == self.tail:
                self.head = -1
                self.tail = -1
            else:
                self.tail -= 1
            self.count -= 1
            #self.head += 1
            return x

    def enqueue(self, item):
        if self.count == self.limit:
            raise RuntimeError
        else:
            self.count += 1
            self.queue.append(item)
            self.tail += 1

    def __str__(self):
        return " ".join([str(v) for v in self.queue])


    def resize(self, new_limit):
        new_q = [None]*self.limit
        old_q = self.queue
        for i in range(len(old_q)):
            new_q[i] = old_q[i]
        self.limit = new_limit
        self.queue = new_q


    def empty(self):
        return 0 == self.count

    def iter(self):
        listt = []
        for v in self.queue:
            listt.append(v)
        return listt

到目前为止我写的内容对我来说最有意义但是如果我用下面的代码块测试它,我会收到一个错误,说10!= 4.这段代码将失败第9行测试,tc.assertEqual(q.data.count(None), 4)我不确定为什么我的代码在此时产生值10。什么允许这个类通过给定的测试?

from unittest import TestCase
tc = TestCase()

q = Queue(10)

for i in range(6):
    q.enqueue(i)

tc.assertEqual(q.data.count(None), 4)

for i in range(5):
    q.dequeue()

tc.assertFalse(q.empty())
tc.assertEqual(q.data.count(None), 9)
tc.assertEqual(q.head, q.tail)
tc.assertEqual(q.head, 5)

for i in range(9):
    q.enqueue(i)

with tc.assertRaises(RuntimeError):
    q.enqueue(10)

for x, y in zip(q, [5] + list(range(9))):
    tc.assertEqual(x, y)

3 个答案:

答案 0 :(得分:2)

我很确定使用self.queue的所有代码都是错误的。根本不需要该属性。 data属性的重点是使用它来存储值。使用索引headtail来确定data放置内容的位置(以及从哪里取出):

class Queue:
    ''' Constructor '''
    def __init__(self, limit):
        self.limit = limit
        self.data = [None] * limit
        self.head = 0
        self.tail = -1
        self.count = 0

    def dequeue(self):
        if self.count == 0:
            raise RuntimeError
        else:
            x = self.data[self.head]
            self.head = (self.head + 1) % self.limit
            self.count -= 1
            return x

    def enqueue(self, item):
        if self.count == self.limit:
            raise RuntimeError
        else:
            self.count += 1
            self.tail = (self.tail + 1) % self.limit
            self.data[self.tail] = item

    def __str__(self):
        return " ".join([str(v) for v in self]) # use __iter__

    def resize(self, new_limit):
        if new_limit < self.count:
            raise RuntimeError
        new_data = [None]*new_limit
        for i, item in enumerate(self):
            new_data[i] = item
        self.data = new_data
        self.head = 0
        self.tail = self.count - 1

    def empty(self):
        return 0 == self.count

    def __bool__(self): # this is better than empty()
        return self.count != 0

    def __iter__(self): # renamed from iter so you can use it in a for loop
        for i in range(self.count):
            return self.data[(self.head + i) % self.limit]

您可能还应该使用__len__方法。

答案 1 :(得分:1)

  

我收到一条错误,指出Queue类没有数据属性

我在您的代码上运行测试时没有提到错误。

答案 2 :(得分:0)

如果由于某些原因您不想使用内置的collections.deque模块,请参见以下示例,了解如何实现自己的循环缓冲区:

"""
Example of circular buffer using regular list
"""


class CircularBuffer:
    def __init__(self, size):
        self.buffer = [None] * size
        self.size = size
        self.count = 0
        self.tail = 0
        self.head = 0

    @property
    def is_empty(self):
        return self.count == 0

    @property
    def is_full(self):
        return self.count == self.size

    def __len__(self):
        return self.count

    def add(self, value):
        # if buffer is full overwrite the value
        if self.is_full:
            self.tail = (self.tail + 1) % self.size
        else:
            self.count += 1
        self.buffer[self.head] = value
        self.head = (self.head + 1) % self.size

    def remove(self):
        if self.count == 0:
            raise Exception("Circular Buffer is empty")
        value = self.buffer[self.tail]
        self.tail = (self.tail + 1) % self.size
        self.count -= 1
        return value

    def __iter__(self):
        index = self.tail
        counter = self.count
        while counter > 0:
            yield self.buffer[index]
            index = (index + 1) % self.size
            counter -= 1

    def __repr__(self):
        return "[]" if self.is_empty else "[" + ",".join(str(i) for i in self) + "]"