数据结构与算法系列7--队列

什么是队列?

1.先进者先出,这就是典型的“队列”结构。
2.支持两个操作:入队enqueue(),放一个数据到队尾;出队dequeue(),从队头取一个元素。所以,和栈一样,队列也是一种操作受限的线性表。
队列的应用也非常广泛,特别是一些具有某些额外特性的队列,比如循环队列、阻塞队列、并发队列。它们在很多偏底层系统、框架、中间件的开发中,起着关键性的作用。

实现队列的两种方式?

顺序队列和链式队列
跟栈一样,队列可以用数组来实现,也可以用链表来实现。用数组实现的栈叫作顺序栈,用链表实现的栈叫作链式栈。同样,用数组实现的队列叫作顺序队列,用链表实现的队列叫作链式队列。
基于数组实现队列:

'''基于数组实现队列'''
class ArrayQueue:
    def __init__(self,n):
        self.items=[]
        self.n=n    #其中n为指定的数组容量
        self.head=0#头指针
        self.tail=0#尾指针

    def enqueue(self,data):
        if self.tail==self.n:
            if self.head==0:
                 #队列已经满了
                return False
            else:
                #需要做数据的搬移处理,因为此时数组前面还有空间
                for i in range(0,self.tail-self.head):
                    self.items[i]=self.items[self.head+i]

                self.tail=self.tail-self.head #重新指定尾指针的 位置
                self.head=0#头指针重新指向首位

        self.items.insert(self.tail,data)
        self.tail=self.tail+1
        return True

    def dequeue(self):
        if self.head!=self.tail:
            data=self.items[self.head]#获取出队的值
            self.head=self.head+1#头指针指向下个位置
            return data
        else:
            return False

    def __repr__(self):
        return " ".join(i for i in self.items[self.head:self.tail])




print("----------")
queue=ArrayQueue(10)
for i in range(5):
    queue.enqueue(str(i))

for i in range(6):
    print(queue.dequeue())
    print(queue)

基于链表实现队列:

'''基于链表实现队列'''
class Node():
    def __init__(self,data,next=None):
        self.data=data
        self.next=next


class LinkedQueue():
    def __init__(self):
        #定义头指针和为指针,分别对应出队口和入队口
        self.head=None
        self.tail=None

    #入队函数
    def enqueue(self,data):
        node= Node(data)
        if self.tail:
            self.tail.next=node #插入链表末尾
        else:
            self.head=node      #如果此时链表为空,头指针指向当前插入节点

        self.tail=node  #让尾指针指向尾节点
        return True

    #出队函数
    def dequeue(self):
        if self.head:
            data=self.head.data
            self.head=self.head.next#头指针向后移动

            if not self.head:
                self.tail=None
            return data #返回出队的值
        else:
            return False


    def __repr__(self):
        data=[]
        current=self.head
        while current:
            data.append(current.data)
            current=current.next

        return "->".join(value for value in data)


if __name__=="__main__":
    queue=LinkedQueue()
    for i in range(5):
        queue.enqueue(str(i))

    print(queue)
    print("----------")
    for i in range(6):
        print(queue.dequeue())
        print(queue)

两者的区别
基于链表的实现方式,可以实现一个支持无限排队的无界队列,但是可能会导致过多的请求排队等待,请求处理的响应时间过长。所以,针对响应时间比较敏感的系统,基于链表实现的无限排队的线程池是不合适的。
而基于数组实现的有界队列,队列的大小有限,所以线程池中排队的请求超过队列大小时,接下来的请求就会被拒绝,这种方式对响应时间敏感的系统来说,就相对更加合理。不过,设置一个合理的队列大小,也是非常有讲究的。队列太大导致等待的请求太多,队列太小会导致无法充分利用系统资源、发挥最大性能。

队列有哪些常见的应用

1.阻塞队列
1)在队列的基础上增加阻塞操作,就成了阻塞队列。
2)阻塞队列就是在队列为空的时候,从队头取数据会被阻塞,因为此时还没有数据可取,直到队列中有了数据才能返回;如果队列已经满了,那么插入数据的操作就会被阻塞,直到队列中有空闲位置后再插入数据,然后在返回。
2.并发队列
1)在多线程的情况下,会有多个线程同时操作队列,这时就会存在线程安全问题。能够有效解决线程安全问题的队列就称为并发队列。
2)并发队列简单的实现就是在enqueue()、dequeue()方法上加锁,但是锁粒度大并发度会比较低,同一时刻仅允许一个存或取操作。
3)实际上,基于数组的循环队列利用CAS原子操作,可以实现非常高效的并发队列。这也是循环队列比链式队列应用更加广泛的原因。
3.线程池资源枯竭时的处理
队列可以应用在任何有限资源池中,用于排队请求,比如数据库连接池等。实际上,对于大部分资源有限的场景,当没有空闲资源时,基本上都可以通过“队列”这种数据结构来实现请求排队。

线程池没有空闲线程时,新的任务请求线程资源时,线程池该如何处理?各种处理策略又是如何实现的呢?

我们一般有两种处理策略。第一种是非阻塞的处理方式,直接拒绝任务请求;另一种是阻塞的处理方式,将请求排队,等到有空闲线程时,取出排队的请求继续处理。

猜你喜欢

转载自blog.csdn.net/qq_34493908/article/details/83115352
今日推荐