数据结构(五):队列——顺序存储(循环队列)与链式存储的定义与基本操作

        队列的顺序实现是指分配一块连续的存储单元存放队列中的元素,并附设两个指针,队头指针 front 指向队头元素,队尾指针 rear 指向队尾元素的下一个位置,如图:

        但这种存储方法容易造成 “假溢出”,即(d)所示,队列判定已满,但还有大量的空闲空间未使用,我们一般使用循环队列,如图:

一、顺序存储(循环队列)

一、定义

typedef struct //循环队列
{
	int data[MaxSize]; //存放队列元素
	int front, rear; //队头指针和队尾指针
} SqQueue;

二、初始化、队判空、入队、出队

//初始化
void InitQueue(SqQueue& Q){Q.rear = Q.front = 0;}

//队判空
bool isEmpty(SqQueue Q){if (Q.rear == Q.front) return true;return false;}

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

//出队
bool DeQueue(SqQueue& Q, int& x)
{
	if (Q.rear == Q.front) return false;
	x = Q.data[Q.front];
	Q.front = (Q.front + 1) % MaxSize;
	return true;
}

说明:

  • 以上采取的方法是:牺牲一个存储单元来区分队空或者队满,入队时少用一个队列单元。
  • 这样,队空仍然为:Q.front == Q.rear
  • 队满的条件为:(Q.rear+1)%MaxSize == Q.front
  • 队列中元素的个数为:(Q.rear-Q.front+MaxSize)%MaxSize

二、链式存储

一、定义

typedef struct LinkLNode //链式队列结点
{
	int data;
	struct LinkLNode* next;
} LinkLNode;

typedef struct //链式队列
{
	LinkLNode *front, *rear; //队列的队头和队尾
} LinkQueue;

二、初始化(带头节点)、判队空、入队、出队

//初始化(带头结点)
void InitQueue(LinkQueue& Q)
{
	Q.front = Q.rear = (LinkLNode*)malloc(sizeof(LinkLNode));
	Q.front->next = NULL;
}

//判队空
bool IsEmpty(LinkQueue Q)
{
	if (Q.front == Q.rear) return true;
	return false;
}

//入队
void EnQueue(LinkQueue& Q, int x)
{
	LinkLNode* s = (LinkLNode*)malloc(sizeof(LinkLNode));
	s->data = x;
	Q.rear->next = s;
	s->next = NULL;
	Q.rear = s;
}

//出队
bool DeQueue(LinkQueue& Q, int& x)
{
	if (Q.front == Q.rear) return false;
	LinkLNode* p = Q.front->next;
	x = p->data;
	Q.front->next = p->next;
	if (Q.rear == p) //若原队列中只有一个结点,删除后变空
		Q.rear = Q.front;
	free(p);
	return true;
}

        用单链表表示的链式队列特别适合于数据元素变动比较大的情形,而且不存在队列满且产生溢出的问题。 

        另外,假如程序中要使用多个队列,与多个栈的情形一样,最好使用链式队列,这样就不会出现存储分配不合理和“溢出”的问题。

猜你喜欢

转载自blog.csdn.net/qq_45832961/article/details/124871747