Queue-实现

本文介绍了一个通用队列数据结构的C++模板实现,包括队列的基本操作如插入、删除等,并提供了一个简单的示例程序展示如何使用这个队列类。
/* Queue.h */
#ifndef __QUEUE_H__
#define __QUEUE_H__
#include <iostream>
using namespace std;
extern "C"
{
    void exit(int);
}
const int nDefaultQueueSize = 50;
template <class T>
class Queue
{
private:
    T *qlist; //存放队列元素的指针(数组)
    int size; //队列大小(容量)
    int front; //队首位置
    int rear; //队尾位置(最后一个元素的下一位置)
    int count; //队列中元素的个数
public:
    //构造函数
    Queue(int initSize=nDefaultQueueSize)
    {
        if (initSize < 1)
            initSize = nDefaultQueueSize;
        qlist = new T[initSize];
        if (!qlist)
        {
            cerr << "存储空间分配失败,应用程序将终止!"<< endl;
            exit(1);
        }
        front = 0;
        rear = 0;
        count = 0;
        size = initSize;
    }
    //析构函数
    ~Queue()
    {
        if (qlist) delete [] qlist;
        front = 0;
        rear = 0;
        count = 0;
        size = 0;
    }
    //判断队列是否为空
    int QEmpty()
    {
        return front == rear;
        //return count == 0;
    }
    //判断队列是否已满
    int QFull()
    {
        return (rear+1) % size == front;
        //return count == size;
    }
    //队列长度
    int QLength()
    {
        return count;
        //return (rear - front + size) % size;
    }
    //队尾插入(追加)元素
    void QInsert(const T &item)
    {
        if (count == size)
        {
            cerr << "队列已满,无法再追加元素。"<< endl;

            return;
        }
        count ++;
        qlist[rear] = item;
        rear = (rear + 1) % size; //rear始终指向最后一个元素的下一个位置
    }
    //队首删除元素

    T QDelete( )
    {
        int pre_front=front;
        if (count > 0)
        {
            count --;
            front = (front + 1) % size; //front移向下一位置
        }
        else
            cerr << "队列已空,无法继续删除。" << endl;
        return qlist[pre_front];
    }
    //读取队首元素
    T QFront(T &data)
    {
        if (count > 0)
            data = qlist[front];
        else
            cerr << "队列为空,无法读取队首元素的值。" << endl;
        return data;
    }
    //清空队列
    void ClearQueue()
    {
        front = 0;
        rear = 0;
        count = 0;
    }
};
#endif __QUEUE_H__

        

// queue.cpp
#include "Queue.h"
#include<stdio.h>
int main()
{
    Queue<int> Q;
    int e,i;
    for(i=0; i<10; i++)
    {
        Q.QInsert(i);

    }
    Q.QInsert(256);
    cout << "Length : " << Q.QLength() << endl;
    cout << "front : " << Q.QFront(e) << endl;
    for(i=0;i<11;i++)
    {
        e=Q.QDelete();
        printf("%d   ",e);
    }



    return 0;
}


<think>我们在讨论C语言中队列的实现,特别是插入元素的操作。用户提供的代码片段是queue->arr[++queue->rear]=item,这可能是循环队列的一部分。根据引用[4],我们了解到循环队列的实现中,通常有一个数组和队头队尾指针(front和rear)。此外,为了避免队空和队满的判断条件冲突,会浪费一个空间,即申请size+1的空间,实际存储size个元素。在循环队列中,插入元素(入队)的操作需要考虑队列是否已满,以及如何更新队尾指针。同时,队尾指针rear的移动需要通过取模运算来实现循环。用户提供的代码片段是:queue->arr[++queue->rear]=item这个操作先增加rear,然后将item放入数组中新的rear位置。但需要注意,在循环队列中,rear的增加应该是循环的,即rear=(rear+1)%(size+1)。此外,在增加之前,需要判断队列是否已满。根据引用[4]的循环队列实现,我们回顾一下相关部分:-初始化时:申请size+1个空间,front和rear都初始化为0。-入队操作:应该先判断队列是否已满(当(rear+1)%(size+1)==front时,队列满),如果不满,则将元素放入rear的位置,然后rear=(rear+1)%(size+1)。用户给出的代码片段没有取模操作,也没有检查队列是否已满,这可能导致错误。正确的入队操作应该是:1.检查队列是否已满,如果满了则不能插入(可以返回错误或扩容,这里假设是定长的)。2.如果不满,将元素放入当前rear位置,然后rear更新为(rear+1)%(size+1)。因此,正确的插入元素代码应该是:if(!isFull(queue)){queue->arr[queue->rear]=item;//先放入当前rear位置queue->rear=(queue->rear+1)%(queue->size+1);//然后更新rear}而用户给出的代码是先增加rear再赋值,且没有取模。这可能会导致错误,因为:-没有取模,当rear到达数组末尾时,无法回到数组开头。-而且先增加rear会使得新元素放在新的位置,但是初始时rear指向的是下一个可以插入的位置,所以这样做可能会跳过一个位置。在循环队列中,我们通常这样定义:-front指向队列的第一个元素的位置。-rear指向队列最后一个元素的下一个位置(即下一个应该插入的位置)。所以,在插入元素时,我们应该将新元素放到当前rear指向的位置,然后移动rear。另外,用户提供的代码中用的是++queue->rear,这个操作会直接改变rear的值,而且是先自增再作为索引。如果队列已满,这样操作会导致rear超出数组范围。因此,我们需要重写一个完整的入队函数。以下是一个标准的循环队列入队操作:```c//入队函数intenqueue(CircleQueue*queue,CQDataTypeitem){//先判断队列是否已满if(isFull(queue)){printf("Queueisfull.\n");return-1;//返回错误码}//将元素放入rear位置queue->arr[queue->rear]=item;//更新rearqueue->rear=(queue->rear+1)%(queue->size+1);return0;//成功返回0}```同时,我们需要实现isFull函数:```cintisFull(CircleQueue*queue){//如果rear的下一个位置是front,就满了(注意取模)return(queue->rear+1)%(queue->size+1)==queue->front;}```注意:这里队列满的条件是:队尾指针的下一个位置等于队头指针(因为循环队列中,我们牺牲了一个空间)。初始化时,队列为空:front=rear。队列满的条件就是:(rear+1)%(size+1)==front。因此,用户给出的代码片段是错误的,我们应该使用上述的正确方法。如果用户使用的不是循环队列,而是普通的顺序队列,那么当rear到达数组末尾时就不能再插入,需要移动元素或者使用循环队列来复用空间。但是,根据引用[4]的内容,用户的问题是关于循环队列的,因为引用了循环队列的初始化等操作。总结:用户提供的插入元素代码有误,正确的做法是先检查队列是否已满,然后将元素放到当前rear位置,再更新rear(使用取模运算)。下面是一个完整的示例,包括循环队列的初始化、入队和出队操作(根据引用[4]的代码结构):</think> 在C语言队列实现中插入元素时,正确方法取决于队列类型。根据您提供的代码片段 `queue->arr[++queue->rear] = item` 和相关引用,以下是关键知识点和可能的错误解决方案: ### 1. 顺序队列插入元素的正确方法(引用[1][2]) ```c // 顺序队列(非循环)的入队操作 void Enqueue(Queue* queue, DataType item) { if(queue->rear >= MAX_SIZE) { // 检查队列是否已满 printf("Queue overflow\n"); return; } queue->data[queue->rear] = item; // 存入元素 queue->rear++; // 队尾后移 } ``` - **错误分析**:您代码中的 `++queue->rear` 会导致: * 首个元素插入位置错误(索引1而非0) * 队列容量浪费一个位置 * 与引用[2]中操作逻辑不符 ### 2. 循环队列的正确实现(引用[4]) 循环队列插入需要特殊处理: ```c // 循环队列入队(参考引用[4]) void Enqueue(CircleQueue* cq, CQDataType item) { if((cq->rear + 1) % (cq->size + 1) == cq->front) { // 判断满队列 printf("Queue full\n"); return; } cq->arr[cq->rear] = item; cq->rear = (cq->rear + 1) % (cq->size + 1); // 循环移动rear } ``` - **关键点**: * 必须对 `size+1` 取模实现循环 * 牺牲一个空间区分空/满状态 * 不可直接用 `++` 运算符(会破坏循环逻辑) ### 3. 常见错误及修复 1. **队列未初始化** ```c // 初始化修复(引用[3]) Queue q; QueueInit(&q); // 必须初始化front/rear ``` 2. **指针越界** ```diff - queue->arr[++queue->rear] = item + queue->arr[queue->rear] = item; + queue->rear++; // 正确操作 ``` 3. **循环队列未取模** ```diff - queue->rear++; + queue->rear = (queue->rear + 1) % (queue->size + 1); ``` ### 完整实现示例 ```c typedef struct { int* arr; int front; int rear; int size; // 最大容量 } CircleQueue; void enqueue(CircleQueue* cq, int item) { if ((cq->rear + 1) % (cq->size + 1) == cq->front) { printf("Queue full\n"); return; } cq->arr[cq->rear] = item; cq->rear = (cq->rear + 1) % (cq->size + 1); } ```
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值