C++抽象数据类型(ADT)表示和实现--链队列(Queue)

目录

单链队列的表示与实现

 完整代码实现


先放上ADT的解释和预定义常量。

  抽象数据类型(ADT)是指一个数学模型以及定义在该模型上的一组操作。抽象数据类型的定义仅取决于它的一组逻辑特性,而与其在计算机内部如何表示和实现无关,即不论其内部结构如何变化,只要它的数学特性不变,都不影响其外部的使用。

//预定义常量和类型:

#define TRUE 1 
#define FALSE 0
#define OK 1
#define ERROR 0
#define INFEASIBLE -1 //INFEASIBLE意为不可行
#define OVERFLOW -2

typedef int Status;
typedef int QElemType;

  以下是队列的抽象数据类型定义

ADT Queue{
//此处省略了数据对象和数据关系的定义

基本操作:
    InitQueue(&Q)//构造队列
    DestoryQueue(&Q)//销毁队列
    ClearQueue(&Q)//清空队列
    QueueEmpty(Q)//判断队列为空
    QueueLength(Q)//队列长度
    GetHead(Q,&e)//队首元素
    EnQueue(&Q,e)//入队操作
    DeQueue(&Q,&e)//退队操作
    QueueTraverse(Q,visit())//遍历队列

}ADT Queue

单链队列的表示与实现

  首先是链队列的数据成员,既然是和链有关那自然少不了指针。此处用的是C语言中的结构来表示。

  对于队列先进先出的特点,允许删除的一端称为队头(front),允许插入的一端称为队尾(rear)。

typedef struct QNode{
    QEleType data;
    struct QNode *next;
}QNode,* QueuePtr;

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

  接下来开始逐步实现链队列的各个函数。

  Status InitQueue(LinkQueue &Q) 

  //构造一个空队列

  分配内存这块其实就是QueuePtr Q.front = new QNode(); 

Status InitQueue(LinkQueue &Q){
    Q.front = Q.rear = (QueuePtr)malloc(sizeof(QNode));
    if(!Q.front)
        exit(OVERFLOW);//分配失败代表溢出
    Q.front->next=NULL;
    return ok;
}

 Status DestroyQueue(LinkQueue& Q)

//销毁队列

销毁意味着将队列从内存中释放,直接free即可

Status DestroyQueue(LinkQueue& Q)
{
	while (Q.front) {
		Q.rear = Q.front->next;
		free(Q.front);
		Q.front = Q.rear;
	}
	return OK;
}

 Status ClearQueue(LinkQueue& Q)

//清空队列

和销毁不同的时清空队列时可能出现队列为空的情况,所以要先判断是否为空。同时清空队列时要保留了队列的头指针,相当于pop出了队列的所有元素但仍保留队列本身,以后还可以对队列进行插入元素的操作;而销毁队列就不能再插入元素了。

Status ClearQueue(LinkQueue& Q)
{
	if (Q.front == Q.rear)return ERROR;
	Q.rear = Q.front->next;
	while (Q.front->next)
	{
		Q.rear = Q.rear->next;
		free(Q.front->next);
		Q.front->next = Q.rear;
	}
	Q.rear = Q.front;
	return OK;
}

 Status QueueEmpty(LinkQueue& Q)

//判断队列为空

头尾指针相等时就为空了,比较简单

Status QueueEmpty(LinkQueue& Q)
{
	//判断是否为空
	if (Q.front == Q.rear)
	{
		return TRUE;//为空
	}
	return FALSE;
}

 Status QueueLength(LinkQueue& Q)

//求队列长度

相当于queue.length(),遍历队列最后返回长度即可

Status QueueLength(LinkQueue& Q)
{
	int len = 0;
	if (Q.front == Q.rear)return 0;
	Q.rear = Q.front->next;
	while (Q.rear)
	{
		Q.rear = Q.rear->next;
		len++;
	}
	return len;
}

 Status GetHead(LinkQueue& Q, QElemType& e)

//获取队列的队列开头的元素,并保存到e中

相当于queue.front(),记住头指针不保存数据,头指针的下一个即front->next才保存着队首的数据

Status GetHead(LinkQueue& Q, QElemType& e)
{
	if (Q.front == Q.rear) return ERROR;
	e = Q.front->next->data;
	return OK;
}

 Status QueueTraverse(LinkQueue& Q/*,visit()*/)

//遍历队列并对每个成员通过visit函数进行访问

这里因为队列元素都是int类型所以省略了visit函数,但如果是结构,类或者STL之类的就要好好写visit函数了。

遍历方式参照链表的遍历,比STL里队列的优点就是遍历的时候不用pop出队列元素。

Status QueueTraverse(LinkQueue& Q/*,visit()*/)
{
	if (Q.front == Q.rear)
	{
		cout << "Queue is Empty." << endl;
		return ERROR;
	}
	QueuePtr p = Q.front->next;
	while (p)
	{
		cout << p->data << " ";
		p = p->next;
	}
	cout << endl;
	return OK;
}

 Status EnQueue(LinkQueue &Q, QElemType e)

//队队列进行入队操作,e进入队尾

Status DeQueue(LinkQueue &Q, QElemType& e)

//对队列进行退队操作,退出队首元素,并保存到e中

这两个函数一起讲。入队的时候需要新建一个节点p(p->next=NULL)来接到队列尾部,由于rear就是队列尾部所以直接Q.rear->next=p,并把新的队尾更新为p(即Q.rear=p)

退队时记得看看队列是不是为空先。要注意的是如果队列只剩一个元素再退队时,此时队列为空,需要更新头尾指针使头尾指针相等。

Status EnQueue(LinkQueue &Q, QElemType e)
{
	QueuePtr p = (QueuePtr)malloc(sizeof(QNode));
	if (!p)
		exit(OVERFLOW);
	p->data = e;p->next = NULL;
	Q.rear->next = p;
	Q.rear = p;
	return OK;
}
Status DeQueue(LinkQueue &Q, QElemType& e)
{
	if (Q.front == Q.rear)return ERROR;
	QueuePtr p = Q.front->next;
	e = p->data;
	Q.front->next = p->next;
	if (Q.rear == p)
		Q.rear = Q.front;
	free(p);
	return OK;
}

 以下是完整代码实现

#include <stdio.h>
#include <iostream>
#include <stdlib.h>

#define TRUE 1
#define FALSE 0
#define OK 1
#define ERROR 0
#define INFEASIBLE -1
#define OVERFLOW -2

typedef int Status;
typedef int QElemType;

using namespace std;

typedef struct QNode {
	QElemType data;
	struct QNode* next;
}QNode, * QueuePtr;
typedef struct {
	QueuePtr front;
	QueuePtr rear;
}LinkQueue;


Status InitQueue(LinkQueue& Q) {
	Q.front = Q.rear = (QueuePtr)malloc(sizeof(QNode));
	if (!Q.front)
		exit(OVERFLOW);
	Q.front->next = NULL;
	return OK;
}
Status DestroyQueue(LinkQueue& Q)
{
	while (Q.front) {
		Q.rear = Q.front->next;
		free(Q.front);
		Q.front = Q.rear;
	}
	return OK;
}
Status ClearQueue(LinkQueue& Q)
{
	if (Q.front == Q.rear)return ERROR;
	Q.rear = Q.front->next;
	while (Q.front->next)
	{
		Q.rear = Q.rear->next;
		free(Q.front->next);
		Q.front->next = Q.rear;
	}
	Q.rear = Q.front;
	return OK;
}
Status QueueEmpty(LinkQueue& Q)
{
	//判断是否为空
	if (Q.front == Q.rear)
	{
		return TRUE;//为空
	}
	return FALSE;
}
Status QueueLength(LinkQueue& Q)
{
	int len = 0;
	if (Q.front == Q.rear)return 0;
	Q.rear = Q.front->next;
	while (Q.rear)
	{
		Q.rear = Q.rear->next;
		len++;
	}
	return len;
}
Status GetHead(LinkQueue& Q, QElemType& e)
{
	if (Q.front == Q.rear) return ERROR;
	e = Q.front->next->data;
	return OK;
}

Status QueueTraverse(LinkQueue& Q/*,visit()*/)
{
	if (Q.front == Q.rear)
	{
		cout << "Queue is Empty." << endl;
		return ERROR;
	}
	QueuePtr p = Q.front->next;
	while (p)
	{
		cout << p->data << " ";
		p = p->next;
	}
	cout << endl;
	return OK;
}
Status EnQueue(LinkQueue &Q, QElemType e)
{
	QueuePtr p = (QueuePtr)malloc(sizeof(QNode));
	if (!p)
		exit(OVERFLOW);
	p->data = e;p->next = NULL;
	Q.rear->next = p;
	Q.rear = p;
	return OK;
}
Status DeQueue(LinkQueue &Q, QElemType& e)
{
	if (Q.front == Q.rear)return ERROR;
	QueuePtr p = Q.front->next;
	e = p->data;
	Q.front->next = p->next;
	if (Q.rear == p)
		Q.rear = Q.front;
	free(p);
	return OK;
}

    为了方便测试这里写了主函数,各位可以根据需要自行改进。(Show函数为遍历队列+打印输出,和上面的QueueTraverse是同样的功能)

Status Show(LinkQueue& Q)
{
	if (Q.front == Q.rear)
	{
		cout << "Queue is Empty." << endl;
		return ERROR;
	}
	QueuePtr p = Q.front->next;
	while (p)
	{
		cout << p->data << " ";
		p = p->next;
	}
	cout << endl;
	return OK;
}
int main()
{
	LinkQueue Q;
	InitQueue(Q);
	int n;
	cin >> n;
	for (int i = 0;i < n;i++)
	{
		EnQueue(Q, i);
	}
	int tmp = 0;
	cout << "len: " << QueueLength(Q) << endl;

	Show(Q);

	GetHead(Q, tmp);
	cout << "head is " << tmp << endl;

	DeQueue(Q, tmp);
	Show(Q);

	ClearQueue(Q);
	Show(Q);

	EnQueue(Q,827);
	Show(Q);

	if (QueueEmpty(Q) == TRUE)
	{
		cout << "Is empty." << endl;
	}
	else
	{
		cout << "Not empty." << endl;
	}

	EnQueue(Q, 106);
	Show(Q);

	DestroyQueue(Q);
	Show(Q);
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值