YAZONG 我的开源

(数据结构)第二讲-线性结构(2.3队列-顺序存储与链式存储)

  , ,
0 评论0 浏览

2.3.1 队列及顺序存储实现

堆栈跟队列一样,也是一种受限制的线性表,比如日常排队。

队列最重要的两个操作:入队和出队。

image.png

而一般的线性表可以在任何位置进行插入和删除。

image.png

5将队头元素从队列中删除并返回。一定是位于队列的头。

image.png

#include<stdio.h>
#define MaxSize<储存数据元素的最大个数>
//队列结构
struct QNode{
	//一维数组
	ElementType Data[MaxSize];
	//记录队列头元素位置的变量
	int front;
	//记录队列尾元素位置的变量
	int rear;
};
typedef struct QNode *Queue;

数组工作队列

image.png

当front和rear都指向-1的时候,队列就是空的。

加入一个job,那么rear往右移动一位,rear+1。

删除一个job,那么front往右移动一位,front+1。

此时,如果还想再加入一个元素,那么就加不进去了,已经排到数组的最后了,实际上队列的前头还有空位,后面加不进去,加到前面就好了。

接下来,如果来新元素的时候,那么这就形成了顺环队列。

顺环队列

把数组掰过来形成一个环。

image.png

在此图中,当front和rear相等时候,队列是空的。

初始化时,front指向第一个元素的前一个位置,rear指向最后一个元素的位置。

加入一个job,那么rear往右移动一位,rear+1。

删除一个job,那么front往右移动一位,front+1。

把元素一直从0这个位置开始放,放满了,接下来再回过头来再放到0。

====问题:

现在已经放了7个元素了,如果这个时候再放进去一个元素,会产生:rear=front,按照这样的组织方式,如果rear=front,那么代表队列是空的,此时rear=front=1,队列满了,所以,

(问题一):当rear=front时,队列是满还是空呢?即:堆栈空和满的判别条件是什么呢?

(问题二):为什么会出现空、满无法区分?根本原因是什么呢?

我们判别队列的状态:空、一个元素、多个元素还是满,是根据front和rear的相对关系/它们的距离来判别的,front和rear的取值范围是0到n-1,在此例子中是0到7,所以此队列的状态是有9种情况:

0(空队列)

1(1个元素)

2(2个元素)

3(3个元素)

4(4个元素)

5(5个元素)

6(6个元素)

7(7个元素)

8(满队列)

可知,数组大小如果等于n的话,那么队列装载元素的情况有n+1种。

此时,如果用n来区分实际上存在的n+1种情况,是矛盾的,就像使用一个bit的0或1来表示3种情况是不合适的,这是此问题的根本原因。

====解决方案:

(方案1):使用额外标记size。

size用来记录当前队列元素的个数,当加入一个元素的时候,size+1,删除一个元素的时候,size-1,所以只要根据size是等于0还是等于n,就可以知道是空的还是满的。

(方案2):使用额外标记tag。(个人不推荐,即只用在插入时判断。复杂度也太高了。)

tag表示0和1,当插入一个元素的时候tag=1,当删除一个元素的时候tag=0,那么判断队列空或满,看tag就代表了最后一次操作是插入还是删除。

(方案3):仅使用n-1个数组空间。

到了n-1这个状态就认为是满了,此时,也不会出现front=rear时,不知道空或满的的情况,判断方式是通过求余函数,(小于n的值+1)对n求余,就能判断是front=rear=0还是front+1=rear的情况了。

/*
顺环队列
*/
/*
顺环队列:插入
*/
void addQueue(Queue PtrQ, ElmentType item){
	/*
	front和rear只指针的移动采用"加1取余"办法,
	体现了顺序存储的"循环使用"。
	*/
	if((PtrQ->rear + 1) % MaxSize == PtrQ->front){
		printf("队列满");
		return;
	}
	/*
	front和rear只指针的移动采用"加1取余"办法,
	体现了顺序存储的"循环使用"。
	*/
	PtrQ->rear = (PtrQ->rear + 1) % MaxSize;
	PtrQ->Data[PtrQ->rear] = item;
}
/*
顺环队列:删除
*/
ElementType deleteQueue(Queue PtrQ){
	if(PtrQ->front == PtrQ->rear){
		printf("队列空");
		return ERROR;
	}else{
		/*
		front和rear只指针的移动采用"加1取余"办法,
		体现了顺序存储的"循环使用"。
		*/
		PtrQ->front = (PtrQ->front+1) % MaxSize;
	}
	return PtrQ->Data[PtrQ->front];
}

2.3.2 队列的链式存储实现

image.png

单向链表,链头可做插入和删除操作,而链尾只能做插入操作。

image.png

/*
结点对象
*/
struct Node{
	ElementType Data;
	struct Node *Next;
};
/*
链队列结构
*/
struct QNode{
	/*
	指向队头结点
	*/
	struct Node *rear;
	/*
	指向队尾结点
	*/
	struct Node *front;
};
typedef struct QNode *Queue;
Queue PtrQ;

image.png

/*
不带头结点的链式队列出队操作的示例。
反过来,也能推出来入队操作。
*/
ElementType DeleteQueue(Queue PtrQ){
	struct Node *FrontCell;
	ElementType FrontElem;
	if(PtrQ->front == NULL){
		printf("队列空");
		return ERROR;
	}
	/*
	存储即将被删除头结点的临时对象
	*/
	FrontCell = PtrQ->front;
	/*
	若队列只有一个元素
	*/
	if(PtrQ->front == PtrQ->rear){
		/*
		删除后队列置为空
		*/
		PtrQ->front = PtrQ->rear = NULL;
	}else{
		/*
		如果队列中不止一个元素,那么把头结点front删除之后,尾结点rear是不变的。
		*/
		PtrQ->front = PtrQ->front->Next;
	}
	FrontElem = FrontCell->Data;
	/*
	释放被删除结点空间
	*/
	free(FrontCell);
	return FrontElem;
}

C语言代码 : 队列的定义与操作-顺序存储

#include<stdio.h>
/*
队列的定义与操作-顺序存储
*/
int main(void){
	return 0;
}
typedef int Position;
struct QNode{
	/*
	存储元素的数组
	*/
	ElementType *Data;
	/*
	队列的头尾指针
	*/
	Position Front,Rear;
	/*
	队列最大容量
	*/
	int MaxSize;

}
typedef struct QNode *Queue;
Queue createQueue(int MaxSize){
	Queue Q = (Queue)malloc(sizeof(struct QNode));
	Q->Data = (ElementType *)malloc(MaxSize * sizeof(ElementType));
	Q->Front = Q->Rear = 0;
	Q->MaxSize = MaxSize;
	return Q;
}
bool isFull(Queue Q){
	return ((Q->Rear + 1)%Q->MaxSize == Q->Front);
}
bool addQueue(Queue Q,ElementType X){
	if(isFull(Q)){
		printf("队列满");
		return false;
	}else{
		Q->Rear = (Q->Rear + 1)%Q->MaxSize;
		Q->Data[Q->Rear] = X;
		return true;
	}
}
bool isEmpty(Queue Q){
	return (Q->Front == Q->Rear);
}
ElementType deleteQueue(Queue Q){
	if(isEmpty(Q)){
		printf("队列空");
		return ERROR;
	}else{
		Q->Front = (Q->Front + 1)%Q->MaxSize;
		return Q->Data[Q->Front];
	}
}

C语言代码 : 队列的定义与操作-链式存储

#include<stdio.h>
/*
队列的定义与操作-顺序存储
*/
int main(void){
	return 0;
}
typedef int Position;
struct QNode{
	/*
	存储元素的数组
	*/
	ElementType *Data;
	/*
	队列的头尾指针
	*/
	Position Front,Rear;
	/*
	队列最大容量
	*/
	int MaxSize;

}
typedef struct QNode *Queue;
Queue createQueue(int MaxSize){
	Queue Q = (Queue)malloc(sizeof(struct QNode));
	Q->Data = (ElementType *)malloc(MaxSize * sizeof(ElementType));
	Q->Front = Q->Rear = 0;
	Q->MaxSize = MaxSize;
	return Q;
}
bool isFull(Queue Q){
	return ((Q->Rear + 1)%Q->MaxSize == Q->Front);
}
bool addQueue(Queue Q,ElementType X){
	if(isFull(Q)){
		printf("队列满");
		return false;
	}else{
		Q->Rear = (Q->Rear + 1)%Q->MaxSize;
		Q->Data[Q->Rear] = X;
		return true;
	}
}
bool isEmpty(Queue Q){
	return (Q->Front == Q->Rear);
}
ElementType deleteQueue(Queue Q){
	if(isEmpty(Q)){
		printf("队列空");
		return ERROR;
	}else{
		Q->Front = (Q->Front + 1)%Q->MaxSize;
		return Q->Data[Q->Front];
	}
}

标题:(数据结构)第二讲-线性结构(2.3队列-顺序存储与链式存储)
作者:yazong
地址:https://blog.llyweb.com/articles/2023/08/15/1692030928305.html