队列结构的简介

1、队列介绍
  • 与栈结构相似的是,也只允许在端口处进行添加、删除操作,但是有两个端口,一个负责添加数据,称为入队 ,该端口称为队尾,另一个端口只负责删除数据,称为出队,该端口称为队头,属于一种先进先出结构,称为FIFO

2、队列所具备的功能
  • 创建队列

  • 销毁队列

  • 判断队空

  • 判断队满 (只有顺序存储时才有)

  • 入队

  • 出队

  • 查看队头元素

  • 查看队尾元素

  • 队列元素数量

3、队列的链式实现
#define TYPE int
​
typedef struct ListNode
{
    TYPE data;
    struct ListNode* next;
}ListNode;
​
ListNode* create_list_node(TYPE data)
{
    ListNode* node = malloc(sizeof(ListNode));
    node->data = data;
    node->next = NULL;
    return node;
}
​
//  设计链式队列结构
typedef struct ListQueue
{
    ListNode* front;    //  队头
    ListNode* rear;     //  队尾
    size_t size;        //  节点数量
}ListQueue;
​
//  创建
ListQueue* create_list_queue(void)
{
    ListQueue* queue = malloc(sizeof(ListQueue));
    queue->front = NULL;
    queue->rear = NULL;
    queue->size = 0;
    return queue;
}
//  队空
bool empty_list_queue(ListQueue* queue)
{
    return 0 == queue->size;
}
//  入队
void push_list_queue(ListQueue* queue,TYPE data)
{
    ListNode* node = create_list_node(data);
    if(empty_list_queue(queue))
    {
        queue->front = node;
                                           }
    else
    {   
        queue->rear->next = node;
        queue->rear = node;
    }
    queue->size++;
}
​
//  出队
bool pop_list_queue(ListQueue* queue)
{
    if(empty_list_queue(queue)) return false;
    
    ListNode* node = queue->front;
    queue->front = node->next;
    free(node);
    queue->size--;
    
    if(0 == queue->size) queue->rear = NULL;
    return true;
}
​
//  队头
TYPE front_list_queue(ListQueue* queue)
{
    return queue->front->data;
}
​
//  队尾
TYPE rear_list_queue(ListQueue* queue)
{
    return queue->rear->data;
}
​
​
//  数量
size_t size_list_queue(ListQueue* queue)
{
    return queue->size;
}
​
//  销毁
void destroy_list_queue(ListQueue* queue)
{
    while(pop_list_queue(queue));
    free(queue);
}
​
​
4、队列的顺序实现
  • 顺序队列的队尾下标rear会随着入队而增大rear+1,队头下标front会随着出队增大front+1,因为是顺序结构,就有随着入队和出队的进行,可能超出有效的下标范围,如果不进行处理,那么队列无法重复使用。

  • 为了避免这种情况,当队尾、队头下标达到存储空间的末尾时,要想办法让它们回到内存的开头位置,相当于把内存想象成一个环形,从而可以循环使用队列,这样的队列称为循环队列

    • 因此当队尾、队头下标增加时,都要对队列的容量求余

    • rear = (rear+1)%cap

    • front = (front+1)%cap

带计数器版本的循环队列
  • 很直接地解决了元素数量的问题

  • 可以直接解决队空、队满的判断矛盾问题

  • 但是在队列结构中会多增加一个数据项,并且每次入队、出队操作都要对其进行修改

typedef struct ArrayQueue
{
    TYPE* ptr;      //  存储元素的内存首地址
    size_t cap;     //  容量
    size_t cnt;     //  元素个数  计数器
    int front;      //  队头下标
    int rear;       //  队尾下标
}ArrayQueue;
​
//  创建
ArrayQueue* create_array_queue(size_t cap)
{
    ArrayQueue* queue = malloc(sizeof(ArrayQueue));
    queue->ptr = malloc(sizeof(TYPE)*cap);
    queue->cap = cap;
    queue->cnt = 0;
    queue->front = 0;
    qeueu->rear = -1;   //  rear指向队尾元素
    return queue;
}
​
//  销毁
void destroy_array_queue(ArrayQueue* queue){}
​
//  队满
bool full_array_queue(ArrayQueue* queue){}
​
//  队空
bool empty_array_queue(ArrayQueue* queue){}
​
//  入队
bool push_array_queue(ArrayQueue* queue,TYPE data){}
​
//  出队
bool pop_array_queue(ArrayQueue* queue){}
​
//  队头
TYPE front_array_queue(ArrayQueue* queue){}
//  队尾
TYPE rear_array_queue(ArrayQueue* queue){}
//  数量
size_t size_array_queue(ArrayQueue* queue){}   
不带计数器的版本
1、如何判断队空、队满状态?

假如把front初值设置0,rear初值设置0,当开始队空状态时front==rear,不停入队rear不停地加1,当队满时,rear==front,导致无法判断队空还是队满

解决方法是:多申请一个存储元素的内存,这样会让存储元素的内存中总有一个元素内存不使用,但是队满的条件就变成了

front == (rear+1)% cap

注意:cap是真实的容量 但是调用者能使用的容量是cap-1

而队空条件依然是:front == rear 这样就可以不同计数器也能判断队空队满

2、计算数量
(rear - front + cap)%cap
3、如何查看队尾元素
ptr [(rear - 1 + cap)% cap ]
5、队列的应用
  • 一般应用于业务处理,例如:银行叫号系统、购票系统等

  • 树的层序遍历

  • 图的广度优先遍历BFS

  • 线程池、数据池

常考题目:使用两个栈,模拟队列的入队、出队操作

用两个栈 s1 s2模拟

注意:当s2非空时,s1不能入栈到s2

当从s1入栈到s2时,必须保证全部入栈,一个不留

class Solution
{
public:
    void push(int node) {
        stack1.push(node);  //  是链式栈
        //  如果stack是顺序栈
        /*
        if(stack1.full())
        {
            //  s1满 s2非空 无法入队
            if(!stack2.empty()) return;
            
            //  s1满 s2是空  把s1全部入s2 再s1入队
            while(!stack1.empty())
            {
                int top = stack1.top();
                stack2.push(top);
                stack1.pop();
            }
        }
        stack1.push(node);
        */
       
    }
​
    int pop() {
        if(stack2.empty())
        {
            while(!stack1.empty())
            {
                stack2.push(stack1.top());
                stack1.pop();
            }
        }
        int top = stack2.top();
        stack2.pop();
        return top;
    }
​
private:
    stack<int> stack1;
    stack<int> stack2;
};

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值