Data structures: queue explain

Data structures: queue explain

First, the concept:

Advanced, first out, this is the queue.

Think of it as queue up for tickets, first come, first buy, then people can only stand at the end, is not allowed to jump the queue.

Stack queue with very similar support operation is also very limited, basic operation is two-fold:

  • Enqueue the enqueue () , a discharge end of the queue to the data;
  • Dequeue dequeue () , taking an element from the head of the queue;

Therefore, the queue with the same stack, is also a kind 操作受限的线性表数据结构.

Second, the queues and a queue chain:

Like stacks, queues can use arrays to implement, you can also use the list to achieve.

  • Queues implemented by an array called the queue order ;
  • Implemented with queue link list called chain queue ;

1. the queues:

Queue, it requires two 一个head 指针,指向队头;一个tail 指针,指向队尾pointers .

class SqQueue(object):
    """顺序队列"""

    def __init__(self, size):
        """
        size:指定队列的大小
        """
        self.data = list(None for _ in range(size + 1))
        self.max_size = size + 1
        self.head = 0
        self.tail = 0
        self.length = 0

    def get_length(self):
        """获取队列的长度"""
        return self.length

    def is_full(self):
        """判断队列是否满了"""
        if (self.tail + 1) % self.max_size == self.head:
            return True
        return False

    def is_empty(self):
        """判断队列是否为空"""
        if self.head == self.tail:
            return True
        return False

    def en_queue(self, element):
        """进入队列, 从队尾插入"""
        if self.is_full():
            raise IndexError('Queue is full!')
        else:
            self.data[self.tail] = element
            self.tail = (self.tail + 1) % self.max_size
            self.length += 1

    def de_queue(self):
        """出队列, 从对头取出"""
        if self.is_empty():
            raise IndexError('Queue is empty!')
        else:
            del_element = self.data[self.head]
            self.data[self.head] = None
            self.head = (self.head + 1) % self.max_size
            self.length -= 1
            return del_element

    def show_queue(self):
        """显示队列元素, 从队首开始显示"""
        if self.is_empty():
            raise IndexError('Queue is empty!')
        else:
            j = self.head
            while j != self.tail:
                print(self.data[j])
                j = (j + 1) % self.max_size


queue = SqQueue(5)
for i in range(5):
    queue.en_queue(i)

queue.show_queue()
print('----------')
queue.de_queue()
queue.show_queue()

As shown in FIG :

  1. When a, b, c, d successively enqueued, the queue head pointer, pointing at index position 0, the tail pointer to the position labeled 4.

  2. When two calls dequeue operation, the queue head pointer to the next position labeled 2, the tail pointer still point to the position labeled 4.

As the stop enqueue, dequeue operations, head, and tail are continuously moved backward. When the tail move to the right, even if there is space in the array, the data can not continue to add to the queue.

  • If you use the data migration , each time into and out of the team are the equivalent of deleting data array subscript 0, to move data from the entire queue, so a team operation 时间复杂度从原来的O(1) 变为了 O(n).

  • Optimization ideas , when the team, do not move the data, if there is no free space, when the team, starting sequentially moving data set.

2. Chain queue:

Linked list implementation, we also need two pointers: head 指针和 tail 指针. They point to the list 第一个结点和最后一个结点.

class Node(object):
    """节点"""
    def __init__(self, data=None):
        self.data = data
        self.next = None


class LkQueue(object):
    """链式队列"""

    def __init__(self):
        self.front = Node()
        self.rear = Node()
        self.length = 0

    def get_length(self):
        """获取长度"""
        return self.length

    def is_empty(self):
        """判断是否为空"""
        if self.length == 0 :
            return True
        return False

    def en_queue(self, elem):
        """入队操作"""

        tmp = Node(elem)
        if self.is_empty():
            self.front = tmp
            self.rear = tmp
        else:
            self.rear.next = tmp
            self.rear = tmp
        self.length += 1

    def de_queue(self):
        """出队操作"""
        if self.is_empty():
            raise ValueError("LKQueue is empty!")
        else:
            del_elem = self.front.data
            self.front = self.front.next
            self.length -= 1
            return del_elem

    def show_queue(self):
        """显示队列"""
        if self.is_empty():
            raise ValueError("LKQueue is empty!")

        j = self.length
        tmp = self.front
        while j > 0:
            print(tmp.data)
            tmp = tmp.next
            j -= 1


lkq = LkQueue()
for i in range(5):
    lkq.en_queue(i)

lkq.show_queue()
print('------------------')
lkq.de_queue()
lkq.show_queue()

As shown in FIG :

3. circular queue:

我们把首尾相连,扳成一个

如图所示

  1. 队列的大小为8,当前 head = 4,tail = 7;

  2. 当一个新元素 a 入队时,我们放入小标 为 7 的位置;

  3. 这时,我们不把 tail 更新为 8,而是在环中后移一位,到下标 0 的位置;

  4. 在有一个元素 b 入队时, 我们将 b 放入下标为 0 的位置,然后tail 加 1 更新为 1 ;

  5. 在 a,b 依次入队后,循环队列中元素就变成下面这样;

代码实现

class CircularQueue(object):
    """循环队列"""

    def __init__(self, size):
        """设置队列长度为size"""
        
        self.queue = [""] * size
        self.max_size = size
        self.start = -1
        self.end = -1

    def is_full(self):
        """检查循环队列是否已满"""
        if (self.end + 1) % self.max_size == self.start:
            return True
        return False

    def is_empty(self):
        """检查循环队列是否为空"""
        if self.start == -1 and self.end == -1:
            return True
        return False

    def front(self):
        """从队首获取元素, 如果队列为空, 返回 -1"""
        return -1 if self.is_empty() else self.queue[self.start]

    def rear(self):
        """获取队尾元素, 如果队列为空, 返回 -1"""
        return -1 if self.is_empty() else self.queue[self.end]

    def en_queue(self, element):
        """向循环队列插入一个元素, 如果成功插入返回 True"""
        if not self.is_full():
            self.start = 0
            self.end = (self.end + 1) % self.max_size
            self.queue[self.end] = element
            return True
        return False

    def de_queue(self):
        """从循环队列中删除一个元素, 如果成功删除, 返回True"""
        if not self.is_empty():
            if self.start == self.end:
                self.start, self.end = -1, -1
            else:
                self.start = (self.start + 1) % self.max_size
            return True

        return False


queue = CircularQueue(8)
for i in range(8):
    queue.en_queue(i)

4.阻塞队列:

阻塞队列就是在队列基础上增加了阻塞操作

简单理解

  • 就是在队列为的时候,从队头取数据会被阻塞。因为此时还没有数据可取,直到队列中有了数据才能返回;
  • 如果队列已经了,那么插入数据的操作就会被阻塞,直到队列中有空闲位置后再插入数据,然后再返回;

如图所示

也可以想到"生产者" 跟 “消费者” 的个数,来提高数据的处理效率。

如图所示

在多线程的情况下,有多个线程同时操作队列,这个时就会存在线程安全的问题,如何实现一个线程安全队列呢?

5.并发队列:

线程安全的队列,我们叫做并发队列.

最简单方式是直接在 enqueue()、dequeue() 方法上加锁,但是锁粒度大并发度会比较低,同一时刻仅允许一个存或者取操作。实际上,基于数组的循环队列,利用 CAS 原子操作,可以实现非常高效的并发队列。

参考资料:

《数据结构与算法之美》

发布了147 篇原创文章 · 获赞 170 · 访问量 4万+

Guess you like

Origin blog.csdn.net/Fe_cow/article/details/103786538