队列

1 队列的基本概念

1.1 定义

  • 队列就是一端允许插入,另一端允许删除的线性表
  • 队头、队尾、空队列
    -队列_第1张图片

1.2 基本操作

  • InitQueue(&Q):初始化队列、构造一个空队列Q
  • DestroyQueue(&Q):销毁队列,销毁并释放队列Q所占用的内存空间
  • EnQueue(&Q,x):入队、若队列未满,则将x插入,使之成为新的队尾
  • DeQueue(&Q,&x):出队、若队列非空、则删除队头元素,并用x返回
  • GetHead(Q,&x):读队头元素、若队列非空,则将队头元素赋值给x
  • QueueEmpty(Q,&x):判断队列是否为空

2 队列的顺序实现

队列_第2张图片

  1. 定义顺序队列
#define MaxSize 10
typedef struct{
	ElemType data[MaxSize];// 用静态数组存放队列元素
	int front,rear;// 队头、队尾指针
}SqQueue;
  1. 初始化操作:
void InitQueue(SqQueue &Q) {
	Q.rear = Q.front = 0;// 初始时,队头】队尾指针都指向0
}
  1. 判空操作
bool QueueEmpty(SqQueue Q) {
	if(Q.rear == Q.front)// 队空条件
		return true;
	else return false;
}
  1. 入队操作
	bool EnQueue(SqQueue &Q,ElemType x) {
		if((Q.rear + 1)%MaxSize == Q.front)// 队满条件
			return false;
		Q.data[rear] = x;
		Q.rear = (Q.rear + 1)%MaxSize;// 队尾指针+1取模
			return true;
}

思考1 队满条件是什么?
队列_第3张图片为什么要空一个位置呢?因为初始化时是Q.rear = Q.front = 0;为了与它区分,我们多空一个位置出来

思考2 Q.rear = (Q.rear + 1) mod MaxSize的原因,为什么不是Q.rear = Q.rear + 1?
队列_第4张图片
如图,思考这个情况,当队尾指针指向MaxSize-1、队头指针指向元素d的位置时,此时想要入队的话,那队尾指针必须要重置回来,不然再Q.rear++的话就跑出数组范围了,那么怎么才能达到这样的效果呢?我们采用对MaxSize取模的操作,只要大于MaxSize了就会重置回来,用模运算将存储空间再逻辑上变成了“环状”

思考3 如何计算队列存在元素个数?
元素个数 = (Q.rear + MaxSize - Q.front)%MaxSize

  1. 出队操作
bool DeQueue(SqQueue &Q,ElemType &x) {
	if(Q.rear == Q.front) {
		return false;
	}
	x = Q.data[Q.front];
	Q.front = (Q.front + 1)%MaxSize;// 队头元素向后移动一位,取模原因如上
	return true
}
  1. 读取队头元素
bool QueueEmpty(SqQueue Q,ElemType &x) {
	if(Q.rear == Q.front) {// 队空
		return false;
	}
	x = Q.data[Q.front];
	return true;
}

2.1 其他的判断队列已满/已空办法

  1. 定义队列时,多添加一个数据表示队列长度
// 定义
typedef struct {
	ElemType data[MaxSize];
	int front,rear;
	int size;// 记录大小长度
}SqQueue;
// 初始化
void InitQueue(SqQueue &Q) {
	Q.rear = Q.front = 0;// 初始时,队头】队尾指针都指向0
	size = 0}
// 入队操作
bool EnQueue(SqQueue &Q,ElemType x) {
		if((Q.rear == Q.front && size == MaxSize)// 队满条件,这样就不浪费空间了
			return false;
		Q.data[rear] = x;
		Q.rear = (Q.rear + 1)%MaxSize;// 队尾指针+1取模
		size++;
			return true;
}
// 出队操作
bool DeQueue(SqQueue &Q,ElemType &x) {
	if(Q.rear == Q.front && size == 0) {// 队空条件
		return false;
	}
	x = Q.data[Q.front];
	Q.front = (Q.front + 1)%MaxSize;// 队头元素向后移动一位,取模原因如上
	size--return true
}
  1. 定义队列时,添加一个数据记录最近进行的是删除还是插入操作

队列_第5张图片

//定义
typedef struct {
	ElemType data[MaxSize];
	int front,rear;
	int tag;// 最近进行的是插入or删除
}SqQueue;

3 队列的链式实现

3.1 用链式存储实现队列

这两个的区别在于front指针指向的是头结点还是第一个元素

  1. 带头结点
    在这里插入图片描述
typedef struct LinkNode {// 链式队列结点
	ElemType data;
	struct LinkNode *next
}LinkNode;
typedef struct {// 链式队列
	LinkNode *front,*rear;// 队列的队头和队尾指针
}LinkQueue;
  1. 不带头结点
    队列_第6张图片
typedef struct LinkNode {// 链式队列结点
	ElemType data;
	struct LinkNode *next
}LinkNode;
typedef struct {// 链式队列
	LinkNode *front,*rear;// 队列的队头和队尾指针
}LinkQueue;

3.2 基本操作

  1. 带头结点
// 初始化
void InitQueue(LinkQueue &Q) {
	// 初始时首尾指针都指向头结点
	Q.rear = Q.front = (LinkNode *)malloc(sizeof(LinkNode));
	Q.front = Null;
}
// 判断空
bool isEmpty(LinkQueue Q) {
	if(Q.rear == Q.front) {
		return true;
	}else {
		return true;
	}
}

// 入队(新节点插入在队尾之后)
void 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 DeQueue(LinkQueue &Q,ElemType &x) {
	if(Q.front == Q.rear) {
		return false;// 空队列
	}else {
		LinkNode *p = Q.front->next;
		x = p->data;
		Q.front = p->next;
		if(Q.rear == p) {// 如果你删除的是最后一个结点的话
			Q.rear = Q.front;// 需要修改队尾指针指向头结点
		}
		free(p);
		return true;
	}
}
  1. 不带
// 初始化
void InitQueue(LinkQueue &Q) {
	// 初始时首尾指针都指向Null
	Q.rear = Q.front = Null;
}
// 判断空
bool isEmpty(LinkQueue Q) {
	if(Q.rear == Null) {
		return true;
	}else {
		return true;
	}
}
// 入队(新节点插入在队尾之后)
void 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,ElemType &x) {
	if(Q.front == Null) {
		return false;// 空队列
	}else {
		LinkNode *p = Q.front;
		x = p->data;
		Q.front = Q.front->next;
		if(Q.rear == p) {// 如果你删除的是最后一个结点的话
			Q.rear = Q.front = Null;// 需要修改队尾指针
		}
		free(p);
		return true;
	}
}

4 双端队列

  1. 双端队列:只允许从双端插入、双端输出的线性表
    队列_第7张图片

  2. 输入受限的双端队列:只允许一端插入、双端删除的线性表
    在这里插入图片描述

  3. 输出首先的双端队列:只允许一端删除、两端插入的线性表
    队列_第8张图片
    在栈中合法的输出序列,在双端队列中必定合法

你可能感兴趣的:(数据结构,数据结构)