ADT Queue 四种实现

讲四种实现
(普通数组模拟队列实现不讲,很轻便也很实用,不难自己随意写写就行)

循环队列(Circular queue)

队列和栈在使用时,即使操作数很多,但一般实时存储在其中的数据并不多,于是我们采用循环队列的方式来节省空间。
那循环队列其实就是,当队列中申请好的连续空间中已经填满数据时(并不是指队列已满,队列是只夹在front和rear之间的数据,包括front不包括rear)又从这段空间的开头开始覆盖存储。
那要注意的几个点就是

  • 如何判队列空
  • 如何判队列已满
  • 如何计算队长

以上问题有相应公式
https://www.jianshu.com/p/9ba8a65464dd这里有详细图解

#include<iostream>
#include<cstdio>
#include<cstdlib>

using namespace std;

typedef int ElementType;

typedef struct Circular
{
    int Capacity;       //队列容量
    int Front;          //队首
    int Rear;           //队尾
    ElementType *Array;
}*Queue;

Queue CreateQueue(int MaxElements);
bool IsEmpty(Queue Q);
bool IsFull(Queue Q);
int Length(Queue Q);
bool Enqueue(ElementType X, Queue Q);
ElementType Front(Queue Q);
bool FrontAndDequeue(Queue Q, ElementType &E);


int main()
{
    Queue newQ = CreateQueue(5);
    if(IsEmpty)
        cout << "Is empty" << endl;

    for(int i = 0; i < 5; i++)
        if(!Enqueue(i, newQ))
            cout << "IsFull" << endl;
    
    for(int i = 0; i < 5; i++)
    {
        int num = 0;
        FrontAndDequeue(newQ, num);
        cout << num << endl;
    }
    
    cout << endl;

    for(int i = 4; i < 9; i++)
        Enqueue(i, newQ);
    
    for(int i = 0; i < 5; i++)
    {
        int num = 0;
        FrontAndDequeue(newQ, num);
        cout << num << endl;
    }

    if(!IsFull(newQ))
            cout << "IsFull" << endl;


    system("pause");
    return 0;
}
Queue CreateQueue(int MaxElements)
{
    Queue Q = (Queue)malloc(sizeof(Queue));

    Q->Capacity = MaxElements + 1;      //这里留意一下,为什么要加1,如果不加1会咋样(关于判表空以及表满操作)
    Q->Front = Q->Rear = 0;
    Q->Array = new ElementType[MaxElements];

    return Q;
}

bool IsEmpty(Queue Q)
{
    if(Q->Front == Q->Rear)
        return true;
    return false;
}

bool IsFull(Queue Q)
{
    if((Q->Rear + 1) % Q->Capacity == Q->Front)
        return true;
    return false;
}

int Length(Queue Q)
{
    return (Q->Rear - Q->Front + Q->Capacity) % Q->Capacity;
}

bool Enqueue(ElementType X, Queue Q)
{
    if(IsFull(Q))
        return false;
    Q->Array[Q->Rear] = X;
    Q->Rear = (Q->Rear + 1) % Q->Capacity;
    return true;
}

ElementType Front(Queue Q)
{
    if(!IsEmpty(Q))
        return Q->Array[Q->Front];
    return -1;
}

/*
这里有个很有意思的事,这种队列的front直接指向队首,而rear指向队尾的后一格
故这里必须用引用来返回队首值,来完成取队首且出列操作
如果是front指向队首前一格,而rear直接指向队尾
那这里就可以直接使用return来完成操作

ElementType FrontAndDequeue(Queue Q)
{
    if(IsEmpty(Q))
        return NULL;
    
    Q->Front = (Q->Front + 1) % Q->Capacity;
    return Q->Array[Q->Front];
}

其他一些操作也同样需要修改,说实话我是建议这种
front指向队首前一格,而rear直接指向队尾
但我现在懒得改了,道理自己想想就很好修改了
*/
bool FrontAndDequeue(Queue Q, ElementType &E)
{
    if(IsEmpty(Q))
        return false;
    
    E = Q->Array[Q->Front];
    Q->Front = (Q->Front + 1) % Q->Capacity;

    return true;
}

链表队列(Linked queue)

#include<iostream>
#include<cstdio>
#include<cstdlib>

using namespace std;

typedef int ElementType;

//整体使用引用来进行修改操作
typedef struct Node
{
    ElementType Data;
    struct Node *next;
}*QueuePtr;

typedef struct LinkQueue
{
    QueuePtr rear;
    QueuePtr front;
}Queue;

void Initiate(Queue &Q);
bool IsEmpty(Queue Q);
void Enqueue(ElementType X, Queue &Q);
bool DequeueAndFront(Queue &Q, ElementType &e);
void DestoryQueue(Queue &Q);

int main()
{
    Queue newQ;

    Initiate(newQ);

    if(IsEmpty(newQ))
        cout << "Is empty" << endl;

    for(int i = 4; i < 23; i++)
        Enqueue(i, newQ);
    
    for(int i = 0; i < 9; i++)
    {
        int num = 0;
        DequeueAndFront(newQ, num);
        cout << num << endl;
    }

    DestoryQueue(newQ);

    system("pause");
    return 0;
}

void Initiate(Queue &Q)
{
    Q.front = Q.rear = (QueuePtr)malloc(sizeof(Node));
    Q.front->next = NULL;
}

bool IsEmpty(Queue Q)
{
    return Q.front->next == NULL;
}

void Enqueue(ElementType X, Queue &Q)
{
    QueuePtr tmp = (QueuePtr)malloc(sizeof(Node));
    tmp->Data = X;
    tmp->next = NULL;
    Q.rear->next = tmp;
    Q.rear = tmp;
    if(IsEmpty(Q))
        Q.front->next = tmp;
}

bool DequeueAndFront(Queue &Q, ElementType &e)
{
    if(IsEmpty(Q))
        return false;

    QueuePtr tmp = (QueuePtr)malloc(sizeof(Node));
    tmp = Q.front->next;
    e = Q.front->next->Data;
    Q.front->next = tmp->next;
    if(Q.rear == tmp)
        Q.rear = Q.front;
    free(tmp);
    return true;
}

void DestoryQueue(Queue &Q)
{
    while(Q.front)
    {
        Q.rear = Q.front->next;
        free(Q.front);
        Q.front = Q.rear;
    }
}

C++STL < queue >

有兴趣就自己搜搜,反正很简单

用两个栈来实现一个队列

也没啥难度,自己想想,我懒得打了
可以参考:https://www.cnblogs.com/zhuli19901106/p/3788729.html

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
循环队列是一种特殊的队列,它的队尾指针指向最后一个元素的下一个位置,队头指针指向队列中第一个元素。当队列满时,队尾指针和队头指针相等,但此时队列不是空的。 循环队列的实现可以使用数组来存储元素,定义一个结构体来表示队列,其中包含队列的头指针、尾指针和数组元素。下面是循环队列ADT实现: ``` typedef struct { int *base; // 队列的存储空间 int front; // 队头指针 int rear; // 队尾指针 int size; // 队列的最大长度 } Queue; void InitQueue(Queue *q, int size) { q->base = (int *)malloc(size * sizeof(int)); q->front = q->rear = 0; q->size = size; } void EnQueue(Queue *q, int x) { if ((q->rear + 1) % q->size == q->front) { printf("Queue is full.\n"); return; } q->base[q->rear] = x; q->rear = (q->rear + 1) % q->size; } int DeQueue(Queue *q) { if (q->front == q->rear) { printf("Queue is empty.\n"); return -1; } int x = q->base[q->front]; q->front = (q->front + 1) % q->size; return x; } int GetQueueLength(Queue *q) { return (q->rear - q->front + q->size) % q->size; } ``` 使用循环队列可以方便地实现一些算法,如广度优先搜索(BFS)和滑动窗口等。下面是一个使用循环队列实现滑动窗口的例子: ``` void SlidingWindow(int *a, int n, int k) { Queue q; InitQueue(&q, k); int i; for (i = 0; i < k; i++) { while (GetQueueLength(&q) > 0 && a[i] >= a[q.base[q.rear-1]]) { DeQueue(&q); } EnQueue(&q, i); } for (; i < n; i++) { printf("%d ", a[q.base[q.front]]); while (GetQueueLength(&q) > 0 && a[i] >= a[q.base[q.rear-1]]) { DeQueue(&q); } while (GetQueueLength(&q) > 0 && q.base[q.front] <= i - k) { DeQueue(&q); } EnQueue(&q, i); } printf("%d\n", a[q.base[q.front]]); } ``` 该函数可以实现在一个长度为n的数组a中,找出每个长度为k的子数组中的最大值。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值