408计算机综合数据结构笔记--队列

基本概念

逻辑结构:
只允许在一端(队尾)进行插入,另一端(队头)进行删除的线性表
特点:先进先出,FIFO
基本操作
创销增删查
InitQueue(&Q):初始化队列。构造一个空队列
DestoryQueue(&Q):销毁队列。销毁队列Q并释放其所占的空间

EnQueue(&Q,x):入队。若队列未满,向队列插入元素x,并使其成为新的队尾。
DeQueue(&Q,&x):出队。若队列非空,删除队头元素,并用x返回

GetHead(Q,&x):读取队头元素。若队列非空,用x返回队头元素。

顺序存储

队列的顺序存储就是通过一个数组来存储数据,设置队头指针front和队尾指针rear两个变量。
即:

#define MaxSize 10
typedef struct{
ElemType data[MaxSize];
int front,rear;
} SqQueue;

初始化

根据队列的逻辑结构,数据从队尾进入,队头出去,因此在一开始的时候队头和队尾都指向数组的第一个元素即data[0]。

void InitQuque(SqQueue &Q){
	Q.front = Q.rear = 0;
}

增删查

由于队列的逻辑结构,队列的插入和删除不能顺序表或者链表那样在表中的任意位置进行增删,但同样的是我们都需要在插入前对表进行判满,删除前进行判空。

判空及判满

判空:
在初始化的时候就确定了队头等于队尾,因此判空条件就是队头等于队尾。
判满:
在队列插入或删除元素的时候,每插入或删除一个元素,队尾指针rear和队头指针front都需要加一。那如果我们一边插入一个数据,一边删除一个数据,到最后front会指向数组的最后一个位置,rear指向的位置将会从这个数组溢出,没有办法再增加新的数据,但实际上这个队列还是空的,这样就造成了空间的浪费,为了避免这个问题,我们会让队列的首尾相接,形成一个循环队列。即,在插入或删除一个元素的时候不再让rear或front直接加一,而是让rear或front加一再跟数组的范围大小取余。

Q.rear = (rear+1)%MaxSize
Q.front = (front+1)%MaxSize

这样在队列的倒数第二个元素插入的时候front就会指向队头,即这时候如果没有删除过元素,那么rear也同样会指向队头,此时的判满条件就是rear= =front= =0;但是这样就会导致和判空条件相同,因此这里引出第一种判满方法:舍弃最后一个数组空间来判满
即:
(Q.rear +1)&MaxSize == front
作为判满条件。
示例:若Q.data的长度为10,当存储到Q.data[8]的时候,Q.reae = = 9,这时候若(9+1)&10 = = 0= =front即判满。

第二种判满方法:设置变量size来表示队列长度,

#define MaxSize 10
typedef struct{
ElemType data[MaxSize];
int front,rear;
int size;
} SqQueue;

当插入数据时size++,删除数据时size–;
判满条件:size == MaxSize
这种方法不需要浪费一个数组空间
第二种判满方法:设置变量tag来表示是删除还是插入,

#define MaxSize 10
typedef struct{
ElemType data[MaxSize];
int front,rear;
int tag;
} SqQueue;

当操作为删除时 tag = 0;为插入时tag = 1;
因为只要插入才能够导致队满,所以判满条件可以是:
front = = rear&&tag = =1

插入删除及读取对头元素

插入–入队

bool EnQueue(Queue &Q,x){
	if ((Q.rear+1)%MaxSize==Q.front)
		return false;
	Q.data[rear] = x;
	Q.rear = (Q.rear+1)%MaxSize;
	return true;
}

删除–出队:

bool DeQueue(Queue &Q,&x){
	if (Q.rear == Q.front)
		return true;
	x = Q.data[Q.front];
	Q.front = (Q.front+1)%MaxSize;
	return true;
}

查询–读队头元素:

bool GetHead(Queue &Q,&x){
	if (Q.rear == Q.front)
		return true;
	x = Q.data[Q.front];
	return true;
}

链式存储

列表的链式存储与单链表相比,只能在队尾插入,队头删除。在定义的时候,除了要定义链式队列的节点还有头尾指针。

typedef struct{
ElemType data;
struct LinkNode * next;
}LinkNode;
typedef strcut{
LinkNode *front,*rear;
}LinkQueue;

初始化

和单链表一样队列的链式存储也分带头结点和不带头节点。
带头结点:

void InitQuque(LinkQueue &Q){
	Q.front = Q.rear = (LinkNode*)malloc(sizeof(LinkNode));
	Q.front->next=NULL;
}

不带头节点:

void InitQueue(LinkQueue &Q){
	Q.front = NULL;
	Q.rear = NULL;
}

增删查

从初始化中可以看到Q.front = = Q.rear或者Q.front == NULL都可以作为判空条件,由于是链式存储除非内存不足否则不会出现队满的情况。
增–入队(带头节点):

bool EnQueue(LinkQueue &Q,ElemType x){
 LinkNode *s =(LinkNode*)malloc(sizeof(LinkNode));
 s->data = x;
 s->next = NULL;
 Q.rear->next = s;
 Q.rear = s;

}

增–入队(不带头节点):

bool EnQueue(LinkQueue &Q,ElemType x){
 LinkNode *s =(LinkNode*)malloc(sizeof(LinkNode));
 s->data = x;
 s->next = NULL;
 if(Q.front == NULL){
	Q.front = s;
	Q.rear = s;
}
else{
 Q.rear->next = s;
 Q.rear = s;
 }

}

删–出队(带头节点):

bool DeQueue(LinkQueue &Q,&x){
	if(Q.front == Q.rear)
		return false;
	LinkNode*p = Q.front->next;
	x = p->data;
	Q.front->next = p->next;
	if(Q.rear == p)
		Q.rear = Q.front;
	free(p);
	return true;
}

删–出队(不带头节点):

bool DeQueue(LinkQueue &Q,&x){
	if(Q.front == Q.rear)
		return false;
	LinkNode*p = Q.front->next;
	x = p->data;
	Q.front = p->next;
	if(Q.rear == p)
		Q.rear = NULL;
		Q。front = NULL
	free(p);
	return true;
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值