8、队列

队列是一种线性表,遵循先进先出原则,分为顺序队和链队。顺序队利用环形数组实现,通过求余运算处理队首队尾指针的增减;链队则通过结点插入和删除操作维护队列。队空和队满的判断条件在顺序队和链队中有不同体现。

队列简称队,它是一种操作受限的线性表,仅允许在一端进行插入操作,而在另一端进行删除操作。
  进行插入的一端叫做队尾; 进行删除的一端叫做队首。 插入操作叫做入队或进队;删除操作叫出队或离队。
  与栈的先进后出 不同,元素进出队的次序是先进先出。 队根据数据存储结构的不同也分为顺序队和链队。
在这里插入图片描述

一、顺序队

1.对顺序队操作四个非常重要的要素。

  • 队空的条件:q->front == q->rear。
  • 队满的条件:q->rear == MaxSize-1(data数组的最大下标)。
  • 元素e的进队操作:先将rear增1,然后将元素e放在data数组的rear位置。
  • 出队操作:先将front增1,然后取出data数组中front位置的元素。
    顺序队操作过程示意图
    顺序队操作过程示意图
    2.顺序队核心算法实现
#define MaxSize 50
typedef int ElemType;
typedef struct
{
	ElemType data[MaxSize];
	int front,rear;//队首和队尾指针
}SqQueue;
void InitQueue(SqQueue * &q)
{
	q = (SqQueue*)malloc(sizeof(SqQueue));
	q->front = q->rear = -1;
}
void DestoryQueue(SqQueue * &q)
{
	free(q);
}
bool QueueEmpty(SqQueue * q)
{
	return (q->front == q->rear);
}
//进队
bool enQueue(SqQueue * &q, ElemType e)
{
	if (q->rear == MaxSize - 1)//队满
		return false;
	q->rear++;
	q->data[q->rear] = e;
	return true;
}
//出队
bool deQueue(SqQueue * &q, ElemType &e)
{
	if (q->front == q->rear)//队空
		return false;
	q->front++;
	e = q->data[q->front];
	return true;
}

  把数组data的前端和后端连接起来,形成一个环形数组,即把存储队列元素的数组逻辑上看成一个环,称为环形队列。
  环形队列首尾相连后,当队尾指针 q->rear = MaxSize - 1后,再前进一个位置就到达 0 ,于是就可以使用另一端的空位置存放队列元素了。实际上存储器中的地址总是连续的,为此采用求余运算(%)来实现:

  • 队首指针 front 循环增 1:q->front = (q->front + 1) % MaxSize
  • 队尾指针 rear 循环增 1:q->rear = (q->rear + 1) % MaxSize

环形队操作的几种状态。
在这里插入图片描述
3.环形队列核心算法实现

void InitQueue(SqQueue * &q)
{
	q = (SqQueue*)malloc(sizeof(SqQueue));
	q->front = q->rear = 0;
}
void DestoryQueue(SqQueue * &q)
{
	free(q);
}
bool QueueEmpty(SqQueue * q)
{
	return (q->front == q->rear);
}
//进队
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;
}
//出队
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;
}
一、链队

1.对链队操作四个非常重要的要素。

  • 队空的条件:q->rear == NULL(或q->front == NULL)。
  • 队满的条件:不考虑。
  • 元素e的进队操作:新建一个结点存放元素e(由p指向它),将结点p插入作为队尾结点,让rear指向这个新的尾结。
  • 出队操作:取出队首结点(rear所指向的结点的后继结点)的data值并将其删除。

需要注意的是,在链队进队和出队操作后链
  - 为空
  - 或者为一个不带头节点的由尾结点指针rear唯一标识的循环单链表
不能改变其结构特性。

2.链队核心算法实现

typedef int ElemType;
typedef struct qnode
{
	ElemType data;
	struct qnode * next;
}DataNode;
typedef struct
{
	DataNode * front; //队首
	DataNode * rear; //队尾
}LinkQueue;
void InitQueue(LinkQueue * &q)
{
	q = (LinkQueue*)malloc(sizeof(LinkQueue));
	q->front = q->rear = NULL;
}
void DestoryQueue(LinkQueue * &q)
{
	DataNode * pre = q->front, *p;	//pre指向队首结点
	if (pre != NULL)
	{
		p = p->next;				//p指向结点pre的后继结点
		while (p != NULL)			//p不空循环
		{
			free(pre);				//释放pre结点
			pre = p;
			p = p->next;			//p,pre同步后移
		}
		free(pre);					//释放最后一个结点
	}
	free(q);						//释放链队结点
}
bool QueueEmpty(LinkQueue * q)
{
	return (q->rear == NULL);
}
//进队
void enQueue(LinkQueue * &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;		//将p链到队尾,并将rear指向它
		q->rear = p;
	}
}
//出队
bool deQueue(LinkQueue * &q, ElemType &e)
{
	DataNode * t;
	if (q->rear == NULL)			//队空
		return false;
	t = q->front;					//t指向首结点
	if (q->front == q->rear)		//原来队列只有一个数据结点时
		q->front = q->rear = NULL;
	else							//原来队列只有两个及以上数据结点时
		q->front = q->front->next;
	e = t->data;
	free(t);
	return true;
}
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值