数据结构实验二之栈和队列(上)——环形队列和链队

实验题3:实现环形队列的各种基本运算的算法

题目描述

编写一个程序sqqueue.cpp,实现环形队列(假设栈中的元素类型ElemTye为char)的各种基本运算,并在此基础上设计一个程序exp3-3.cpp完成以下功能。

(1)初始化队列q。

(2)判断队列q是否非空。

(3)依次进队元素a、b、c。

(4)出队一个元素,输出该元素。

(5)依次进队元素d、e、f。

(6)输出出队序列。

(7)释放队列。

sqqueue.cpp程序,其中包含如下函数。

· InitQueue(SqQueue *&q):初始化环形队列q。

· DestroyQueue(SqQueue *&q):销毁环形队列q。

·QueueEmpty(SqQueue *q):判断环形队列q是否为空。

· enQueue(SqQueue *&q,ElemType e):环形队列进队一个元素e。

·deQueue(SqQueue *&q,ElemType &e):环形队列出队一个元素e。

运行代码

sqqueue.cpp
#include<iostream>
using namespace std;
#include<stdio.h>
#include<malloc.h>
#define Maxsize 100
typedef char Elemtype;
typedef struct {
	Elemtype data[Maxsize];
	int front,rear;
}SqQueue;
//初始化队列q
void InitQueue(SqQueue*& q) {
    q = (SqQueue*)malloc(sizeof(SqQueue));
    q->front = q->rear = 0;
}
// 销毁队列 q
void DestoryQueue(SqQueue*& q) {
    free(q);
}

// 判断队列 q 是否为空
bool QueueEmpty(SqQueue* q) {
    return(q->front == q->rear);
}

// 进队列 q
bool enQueue(SqQueue*& q, Elemtype e) {
    if ((q->rear + 1) % Maxsize == q->front)
        return false;
    q->rear = (q->rear + 1) % Maxsize;
    q->data[q->rear] = e;
    return true;
}

// 出队列 q
bool deQueue(SqQueue*& q, Elemtype& e) {
    if (q->front == q->rear)
        return false;
    q->front = (q->front + 1) % Maxsize;
    e = q->data[q->front];
    return true;
}
exp3-3.cpp
#include "sqqueue.cpp"
using namespace std;
int main() {
    Elemtype e;
    SqQueue* q;
    cout << "环形队列的基本运算如下:\n";
    cout << "  (1)初始化队列 q\n";
    InitQueue(q);
    cout << "  (2)依次进入队列的元素为 a,b,c\n";
    if (!enQueue(q, 'a')) printf("\t提示:队满,不能进队\n");
    if (!enQueue(q, 'b')) printf("\t提示:队满,不能进队\n");
    if (!enQueue(q, 'c')) printf("\t提示:队满,不能进队\n");
    cout << "  (3)队列为" << (QueueEmpty(q) ? "空" : "非空") << endl;
    if (deQueue(q, e) == 0)
        cout << ("队空,不能出队\n");
    else
        cout << "  (4)出队的第一个元素:" << e << endl;
    cout << "  (5)依次进队列的元素:d,e,f\n";
    if (!enQueue(q, 'd')) printf("\t提示:队满,不能进队\n");
    if (!enQueue(q, 'e')) printf("\t提示:队满,不能进队\n");
    if (!enQueue(q, 'f')) printf("\t提示:队满,不能进队\n");
    cout << "  (6)出队列序列";
    while (!QueueEmpty(q)) {
        deQueue(q, e);
        cout << e << " ";
    }
    cout << endl;
    cout << "  (7)释放队列\n";
    DestoryQueue(q);
    return 1;
}

代码思路

环形队列(也称为循环队列)的基本操作,包括初始化、进队、出队、判断队列是否为空以及销毁队列等功能,并在 main 函数中对这些功能进行了测试。

  1. InitQueue 函数:作用是初始化环形队列。通过动态分配内存为环形队列结构体 SqQueue 分配空间,并将队首指针 front 和队尾指针 rear 初始化为 0,表示队列为空。

  2. DestoryQueue 函数:用于销毁环形队列。释放动态分配给环形队列的内存空间。

  3. QueueEmpty 函数:判断环形队列是否为空。如果队首指针 front 等于队尾指针 rear,则说明队列为空,返回 true;否则返回 false

  4. enQueue 函数:实现进队操作。

    • 首先检查队列是否已满,判断条件是 (q->rear + 1) % Maxsize == q->front,如果满足这个条件则表示队列已满,进队失败,返回 false
    • 如果队列未满,将队尾指针 rear 向后移动一位(q->rear = (q->rear + 1) % Maxsize),并将元素 e 存入队尾位置(q->data[q->rear] = e),然后返回 true
  5. deQueue 函数:执行出队操作。

    • 检查队列是否为空,如果队首指针 front 等于队尾指针 rear,则出队失败,返回 false
    • 如果队列非空,将队首指针 front 向后移动一位(q->front = (q->front + 1) % Maxsize),并将队首元素赋值给变量 e,然后返回 true

实验题4:实现链队的各种基本运算的算法

题目描述

编写一个程序liqueue.cpp,实现链队(假设栈中的元素类型ElemType为char)

的各种基本运算,并在此基础上设计一个程序exp3-4.cpp完成以下功能。

(1)初始化链队q。

(2)判断链队q是否非空。

(3)依次进队元素a、b、c。

(4)出队一个元素,输出该元素。

(5)依次进队元素d、e、f。

(6)输出出队序列。

(7)释放链队。

liqueue.cpp程序,其中包含如下函数。

· InitQueue(LinkQuNode*&q):初始化链队q。

· DestroyQueue(LinkQuNode *&q):销毁链队q。

· QueueEmpty(LinkQuNode*q):判断链队q是否为空。

· enQueue(LinkQuNode*&q,ElemType e):链队进队一个元素e。

· deQueue(LinkQuNode *&q,ElemType &e):链队出队一个元素e。

运行代码

liqueue.cpp
#include<iostream>
using namespace std;
#include<stdio.h>
#include<malloc.h>
#define Maxsize 100
typedef char Elemtype;
typedef struct DataNode {
    Elemtype data;
    struct DataNode* next;
}DataNode;
typedef struct {
    DataNode* front;
    DataNode* rear;
}LinkQuNode;//声明链队类型
//初始化链队q
void InitQueue(LinkQuNode*& q) {
    q = (LinkQuNode*)malloc(sizeof(LinkQuNode));
    q->front = q->rear = NULL;
}
// 销毁链队 q
void DestoryQueue(LinkQuNode*& q) {
    DataNode* p = q->front, * r;
    if (p != NULL) {
        r = p->next;
        while (r != NULL) {
            free(p);
            p = r; r = p->next;
        }
    }
    free(p);
    free(q);
}
// 判断链队 q 是否为空
bool QueueEmpty(LinkQuNode* q) {
    return( q->rear==NULL);
}
// 进队
void enQueue(LinkQuNode*& q, Elemtype e) {
    DataNode* p;
    p = (DataNode*)malloc(sizeof(DataNode));
    p->data = e;
    p->next = NULL;
    if (q->rear == NULL)
        q->front=q->rear = p;
    else {
        q->rear->next = p;
        q->rear = p;
    }
}
// 出链队 q
bool deQueue(LinkQuNode*& q, Elemtype& e) {
    DataNode* t;
    if (q->rear==NULL)
        return false;
    t = q->front;
    if (q->front == q->rear)
        q->front = q->rear = NULL;
    else
        q->front = q->front->next;
    e = t->data;
    free(t);
    return true;
}
exp3-4.cpp
#include "liqueue.cpp"
using namespace std;
int main() {
    Elemtype e;
    LinkQuNode* q;
    cout << "链队的基本运算如下:\n";
    cout << "  (1)初始化链队 q\n";
    InitQueue(q);
    cout << "  (2)依次进入链队的元素为 a,b,c\n";
    enQueue(q, 'a');
    enQueue(q, 'b');
    enQueue(q, 'c');
    cout << "  (3)链队为" << (QueueEmpty(q) ? "空" : "非空") << endl;
    if (deQueue(q, e) == 0)
        cout << ("\t提示:队空,不能出队\n");
    else
        cout << "  (4)出队一个元素:" << e << endl;
    cout << "  (5)依次进链队的元素:d,e,f\n";
    enQueue(q, 'd');
    enQueue(q, 'e');
    enQueue(q, 'f');
    cout << "  (6)出链队序列";
    while (!QueueEmpty(q)) {
        deQueue(q, e);
        cout << e << " ";
    }
    cout << endl;
    cout << "  (7)释放链队\n";
    DestoryQueue(q);
    return 1;
}

代码思路

实现了链队(一种基于链表实现的队列数据结构)的基本操作,包括初始化、进队、出队、判断队列是否为空以及销毁队列等功能,并在 main 函数中对这些功能进行了测试。

  1. InitQueue 函数:作用是初始化链队。通过动态分配内存为链队结构体 LinkQuNode 分配空间,并将队首指针 front 和队尾指针 rear 初始化为 NULL,表示队列为空。

  2. DestoryQueue 函数:用于销毁链队。首先遍历链表,从队首开始,依次释放每个节点的内存空间。使用两个指针 p 和 rp 指向当前节点,r 指向下一个节点。在循环中,先释放 p 指向的节点,然后将 p 指向 rr 指向下一个节点,直到遍历完整个链表。最后释放链队结构体的内存空间。

  3. QueueEmpty 函数:判断链队是否为空。如果队尾指针 rear 为 NULL,则说明队列为空,返回 true;否则返回 false

  4. enQueue 函数:实现进队操作。

    • 首先动态分配一个新节点 p,将待进队元素 e 存入新节点的数据域 data,并将新节点的 next 指针初始化为 NULL
    • 如果队列为空(即队尾指针 rear 为 NULL),则将队首指针 front 和队尾指针 rear 都指向新节点。
    • 如果队列不为空,则将当前队尾节点的 next 指针指向新节点,然后将队尾指针 rear 指向新节点。
  5. deQueue 函数:执行出队操作。

    • 如果队列为空(即队尾指针 rear 为 NULL),则出队失败,返回 false
    • 如果队列非空,将队首节点赋值给临时指针 t。如果队首节点就是队尾节点(即只有一个节点),则将队首指针 front 和队尾指针 rear 都置为 NULL;否则将队首指针 front 指向队首节点的下一个节点。然后将队首节点的数据域 data 赋值给变量 e,释放队首节点的内存空间,并返回 true

环形队列和链队的异同

相同点

  1. 逻辑结构:两者都遵循队列先进先出(FIFO - First In First Out)的原则。在这两种数据结构中,最先进入的数据元素将最先被取出,就像排队一样,先到的人先接受服务。
  2. 基本操作功能:都具备队列的基本操作,包括初始化(创建一个空的队列结构)、判断队列是否为空(确定队列中是否有元素)、入队(将元素添加到队列尾部)、出队(将队列头部的元素移除)等操作。这些操作在概念上是相同的,只是在具体的实现方式上存在差异。

不用点

  1. 存储结构
    • 环形队列:环形队列通常基于数组实现,它利用数组的循环特性来模拟队列的操作。在环形队列中,需要通过取模运算来处理队首和队尾指针的移动,以实现循环利用数组空间的目的。例如,在判断队满和队空条件以及指针的移动操作(如入队时队尾指针 rear=(rear + 1)%Maxsize,出队时队首指针 front=(front+1)%Maxsize)上都体现了这种循环特性。这种存储结构的优点是实现相对简单,并且在空间利用上较为高效(不需要额外的指针域来存储节点间的连接关系),访问元素时可以直接通过数组下标进行,速度较快。但是,它的缺点是需要预先确定数组的大小,如果队列中元素数量超过数组大小,可能会出现问题(如队满判断不准确等)。
    • 链队:链队是通过链表实现的,由节点组成,每个节点包含数据域和指向下一个节点的指针域。链队中的节点在内存中可以不连续存储,通过指针将各个节点连接起来形成队列结构。这种存储方式的优点是可以动态地分配内存,不需要预先确定队列的大小,适合处理元素数量不确定或者变化较大的情况。然而,由于需要额外的指针域来存储节点之间的连接关系,并且访问元素需要通过指针遍历链表,所以在空间和时间效率上相对环形队列可能会稍低一些。
  2. 空间利用效率
    • 环形队列:环形队列预先分配固定大小的数组空间,如果队列中元素较少,会造成一定的空间浪费;但由于不需要额外的指针空间(相比于链队),在元素数量接近数组容量时,空间利用率较高。
    • 链队:链队的空间是根据实际元素数量动态分配的,每个节点除了数据域外还需要额外的指针域,所以在存储少量元素时,由于指针域的存在会占用一定的额外空间。不过,链队不会像环形队列那样存在固定大小导致的空间浪费问题,适合元素数量波动较大的情况。
  3. 操作的实现细节
    • 环形队列:在入队操作时,需要检查队列是否已满,通过特定的队满判断条件(如 (rear + 1)%Maxsize==front)来确定,并且队尾指针的移动通过取模运算实现循环效果。出队操作时同样需要检查队列是否为空(front==rear),队首指针的移动也涉及取模运算。
    • 链队:入队操作需要动态分配新的节点内存,当队列为空时需要特殊处理队首和队尾指针(都指向新节点),非空时只需将新节点连接到队尾并更新队尾指针。出队操作要判断队列是否为空,若队首节点是队尾节点(即只有一个节点)时需要特殊处理队首和队尾指针(都置为 NULL),否则只需更新队首指针并释放出队节点的内存。
编写一个名为`sqqueue.cpp`的程序,用于实现环形队列的基本操作,主要包括: 1. 队列初始化:创建一个固定大小的数组表示队列,同时维护两个指针front和rear,分别指向队首和队尾位置。 ```cpp template <typename ElemType> class CircularQueue { public: // 构造函数,设置队列长度 CircularQueue(size_t size) : capacity(size), front(0), rear(0) {} private: ElemType* data; size_t capacity; size_t front, rear; }; ``` 2. 入队(enqueue):如果队尾不是满的,则将新元素插入队尾,更新rear指针。 3. 出队(dequeue):如果队头不是空的,删除并返回队首元素,更新front指针。 4. 查看队列是否为空(isEmpty):检查front指针是否等于rear,为空则返回true,否则返回false。 5. 查看队列是否已满(isFull):检查队尾之后的位置(即front + capacity)是否超过当前容量,若超过则返回true,否则返回false。 6. 获取队列元素数量(getCount):计算队列中实际包含的元素数,等于rear - front(取模capacity以适应环形队列特性)。 接下来,为了演示如何使用这个环形队列,可以设计一个名为`exp1-2.cpp`的程序,展示上述功能的简单应用,例如打印队列、插入元素、移除元素等操作。示例代码可能会包括: ```cpp #include "sqqueue.h" int main() { CircularQueue<char> queue(5); // 创建一个容量为5的环形队列 // 入队操作 queue.enqueue('A'); queue.enqueue('B'); queue.enqueue('C'); // 输出队列内容 std::cout << "Original queue: "; for (size_t i = 0; i < queue.getCount(); ++i) std::cout << queue.dequeue() << (i != queue.getCount() - 1 ? " " : ""); // 出队操作 queue.enqueue('D'); // 插入新的元素 std::cout << "\nAfter enqueue D: "; for (size_t i = 0; i < queue.getCount(); ++i) std::cout << queue.dequeue() << (i != queue.getCount() - 1 ? " " : ""); return 0; } ``` 运行此程序会输出队列在不同操作前后的状态。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

筱姌

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

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

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

打赏作者

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

抵扣说明:

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

余额充值