数据结构之队列

1. 什么是队列❓

排队买票的队伍,就是一个队列。先来的先买,后来的只能站末尾,不能插队。
特点:先进者先出
同栈一样,是一种操作受限的线性表数据结构

2. 何时使用队列❓

:当我们向一个固定大小的线程池请求一个线程时,此时线程池没有资源,但是我们又不想拒绝掉这次请求,这时候就会用到队列。
具体策略:将请求排队,等到有空闲线程时,取出排队的请求继续处理。

3. 队列的关键操作

  • 入队enqueue():放一个数据到队列尾部
  • 出队dequeue():从队列头部取一个元素

4. 队列的种类

  • 按实现方式分为:顺序队列(用数组实现)和链式队列(用链表实现)
  • 按队列结构分为:一般队列、循环队列、阻塞队列、并发队列等

5. 一般队列的实现

5.1 顺序队列

需要用到两个指针,一个是队头head,一个是队尾tail
关键:数据搬移(为了重新利用起之前申请到的空间)

Java代码:

public class ArrayQueue {
    // 数组:items,数组大小:n
    private String[] items;
    private int n = 0;
    // head表示队头下标,tail表示队尾下标
    private int head = 0;
    private int tail = 0;
    // 申请一个大小为capacity的数组
    public ArrayQueue(int capacity){
        items = new String[capacity];
        n = capacity;
    }
    // 入队
    public boolean enqueue(String item){
        if (tail == n){
            if (head == 0) return false;
            // 数据搬运
            for (int i = head; i < tail; ++ i)
            {
                items[i - head] = items[i];
            }
            tail = tail - head;
            head = 0;
        }
        items[tail] = item;
        ++ tail;
        return true;
    }
    // 出队
    public String dequeue(){
        if (head == tail) return null; // 队头指针与队尾指针相等,表示队列为空
        String ret = items[head];
        ++ head;
        return ret;
    }
}

C++代码:

#include <iostream>
#include <string>
using namespace std;
class ArrayQueue
{
	public:
		ArrayQueue(int capacity); // 申请数组 
		bool enqueue(string item); // 入队 
		string dequeue(); // 出队 
	private:
		int n;
		string* items;
		int head = 0;
		int tail = 0;
}; 
ArrayQueue::ArrayQueue(int capacity){
	items = new string[capacity];
	n = capacity;
}
bool ArrayQueue::enqueue(string item){
	if (tail == n) {
		if (head == 0) return false; // 队满
		for (int i = head; i < tail; ++ i){ // 数据搬运 
			items[i - head] = items[i]; 
		} 
		tail = tail - head;
		head = 0;
	} 
	items[tail] = item;
	++ tail;
	return true;
}
string ArrayQueue::dequeue(){
	if (head == tail) return "This queue is empty!";
	string ret = items[head];
	++ head;
	return ret;
} 
int main(void)
{
	ArrayQueue myQueue(3);
	myQueue.enqueue("zhangsan");
	myQueue.enqueue("lisi");
	myQueue.enqueue("wangwu");
	cout << "插入第四个元素结果:" <<myQueue.enqueue("add") << endl; // 多插一个测试失败结果
	for (int i = 0; i < 4; ++ i){
		cout << myQueue.dequeue() << endl;
	} 
}

Python代码:

from typing import Optional
class ArrayQueue:
    def __init__(self, capacity: int):
        self.__items = [0 for i in range(capacity)]
        self.__n = capacity
        self.__head = 0
        self.__tail = 0
    def enqueue(self, item: str) -> bool:
        if self.__tail == self.__n:
            if self.__head == 0: # 队列已满 
                return False
            # 充分利用空间,进行数据搬运
            for i in range(self.__head, self.__tail):
                self.__items[i - self.__head] = self.__items[i]
            self.__tail = self.__tail - self.__head
            self.__head = 0
        self.__items[self.__tail] = item
        self.__tail = self.__tail + 1
        return True
    def dequeue(self) -> Optional[str]:
        if (self.__head == self.__tail): 
            return None
        item = self.__items[self.__head]
        self.__head = self.__head + 1
        return item

q = ArrayQueue(3)
q.enqueue(3)
q.enqueue(2)
q.enqueue(1)
print(q.enqueue(0)) # 数量上限,故插入失败
print(q.dequeue()) # 将元素3弹出,给元素0腾位置
print(q.enqueue(0))
print(q.dequeue())
print(q.dequeue())
print(q.dequeue())
print(q.dequeue()) # 队列为空情况

5.2 链式队列

两个指针:head指向链表的第一个结点,tail指向链表的最后一个结点
关键:入队时tail->next = new_node, tail = tail->next;出队时head = head->next

Java代码:

public class LinkedListQueue {
    private Node head = null;
    private Node tail = null;
    private int n = 0;
    private int capacity = 0;

    public LinkedListQueue(int capacity){
        this.n = capacity;
    }
    // 入队
    public boolean enqueue(String item){
        if (capacity == n) return false;
        Node node = new Node(item, null);
        if (capacity == 0){
            tail = node;
            head = node;
        }
        else {
            tail.setNext(node);
            tail = tail.getNext();
        }
        ++capacity;
        return true;
    }
    // 出队
    public String dequeue(){
        if (head != null)
        {
            --capacity;
            String ret = head.getData();
            head = head.getNext();
            return ret;
        }else return null;
    }



    private class Node{
        private String data;
        private Node next;
        public Node(String data, Node next){
            this.data = data;
            this.next = next;
        }

        public void setNext(Node next){
            this.next = next;
        }

        public String getData(){
            return data;
        }
        public Node getNext(){
            return next;
        }
    }
}

C++代码:

#include <iostream>
#include <string>
using namespace std;

struct Node
{
	Node* next;
	string data;
	Node(string data){
		this->data = data;
		this->next = NULL;
	}
};

struct LinkedListQueue
{
	Node* head;
	Node* tail;
	int n;
	int capacity;
	LinkedListQueue(int capacity)
	{
		this->n = capacity;
		this->capacity = 0; 
		head = NULL;
		tail = NULL;
	};
	bool enqueue(string item){
		if (capacity == n) return false;
		Node* node = new Node(item);
		if (capacity == 0){
			tail = node;
			head = node;
		}else{
			tail->next = node;
			tail = tail->next;
		}
		++capacity;
		return true;
	}; 
	string dequeue(){
		if (head == NULL)
		{
			return "This queue is empty!"; 
		}
		else
		{
			--capacity;
			string ret = head->data;
			head = head->next;
			return ret;
		}
	}
};


int main(void)
{
	LinkedListQueue* myQueue = new LinkedListQueue(3);
	myQueue->enqueue("zhangsan");
	myQueue->enqueue("lisi");
	myQueue->enqueue("wangwu");
	cout << myQueue->enqueue("add") << endl; // 多加一个 
	for (int i = 0; i < 3; ++ i) cout << myQueue->dequeue() << endl;
	cout << myQueue->dequeue() << endl;
	cout << myQueue->enqueue("add") << endl; 
	cout << myQueue->dequeue() << endl;
	return 0;
}

Python代码:

from typing import Optional
class Node:
    def __init__(self, data: str):
        self.__data = data
        self.__next = None
    def setNext(self, next):
        self.__next = next
    def getNext(self):
        return self.__next
    def setData(self, data: str):
        self.__data = data
    def getData(self) -> str:
        return self.__data

class LinkedListQueue:
    def __init__(self, capacity: int):
        self.__n = capacity
        self.__capacity = 0
        self.__head = None
        self.__tail = None
    def enqueue(self, item: str) -> bool:
        if self.__capacity == self.__n:
            return False
        node = Node(item)
        if self.__capacity == 0: # 队列为空
            self.__tail = node
            self.__head = node
        else:
            self.__tail.setNext(node)
            self.__tail = self.__tail.getNext()
        self.__capacity = self.__capacity + 1
        return True
    def dequeue(self) -> Optional[str]:
        if self.__capacity == 0:
            return None
        else:
            data = self.__head.getData()
            self.__head = self.__head.getNext()
            self.__capacity = self.__capacity - 1
            return data

6. 循环队列

循环队列
图源:王争 数据结构与算法之美

好处:免去了在使用数组实现队列时,当tail==n时的数据搬移操作,提高了入队操作性能
实现难点:队空(head = tail)和队满判断条件((tail+1)%n = head)
小小缺点:当队列满时,tail指向的位置实际上没有存储数据,会浪费一个存储空间

Java代码:

public class CircularQueue {
    private String []items;
    private int n = 0;
    private int head = 0;
    private int tail = 0;
    public CircularQueue(int capacity){
        items = new String[capacity];
        n = capacity;
    }
    // 入队
    public boolean enqueue(String item){
        if ((tail + 1) % n == head) return false;
        items[tail] = item;
        tail = (tail + 1) % n;
        return true;
    }
    // 出队
    public String dequeue(){
        if (head == tail) return null; // 队列为空
        String ret = items[head];
        head = (head + 1) % n;
        return ret;
    }
}

C++代码:

#include <iostream>
#include <string>

using namespace std;
class CircularQueue
{
	public:
		CircularQueue(int capacity);
		bool enqueue(string item);
		string dequeue();
	private:
		int n;
		string* items;
		int head = 0;
		int tail = 0;
}; 
CircularQueue::CircularQueue(int capacity){
	items = new string[capacity];
	n = capacity;
} 
bool CircularQueue::enqueue(string item){ 
	if ((tail + 1) % n == head) return false; // 队满
	items[tail] = item;
	tail = (tail + 1) % n;
	return true; 
}
string CircularQueue::dequeue(){
	if (head == tail) return "This queue is empty!";
	string ret = items[head];
	head = (head + 1) % n;
	return ret;
}



int main(void)
{
	CircularQueue myQueue(3);
 	myQueue.enqueue("zhangsan");
 	myQueue.enqueue("lisi");
 	cout << myQueue.enqueue("wangwu") << endl;
 	for (int i = 0; i < 3; ++ i){
 		cout << myQueue.dequeue() << endl;
 	} 
	cout << myQueue.enqueue("add") << endl;
	cout << myQueue.dequeue() << endl;
	
	return 0;
}

Python代码:

from typing import Optional
class CircularQueue:
    def __init__(self, capacity: int):
        self.__items = [0 for i in range(capacity)]
        self.__n = capacity
        self.__head = 0
        self.__tail = 0
    def enqueue(self, item: str) -> bool:
        if (self.__tail + 1) % self.__n == self.__head:  # 队满
            return False
        self.__items[self.__tail] = item
        self.__tail = (self.__tail + 1) % self.__n
        return True
    def dequeue(self) -> Optional[str]:
        if self.__head == self.__tail:
            return None
        ret = self.__items[self.__head]
        self.__head = (self.__head + 1) % self.__n
        return ret

7. 其他

  • 阻塞队列:队列为空时,取数据的操作会被阻塞,队列满时,插入数据的操作会被阻塞。可以用于实现生产者-消费者模型
  • 并发队列:一种线程安全的队列

8. END

愿我们都有诗和远方 😀

诗和远方

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小陌白

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值