[数据结构]第三章-栈和队列(读书笔记3)

第三章-栈和队列


□3.4 队列
和栈相反,队列(queue)是一种先进先出(first in first out)的线性表,它只允许在表的一端进行插入,而在另一端删除元素。在队列中,允许插入的一端叫做队尾(rear),允许删除的一端则称为队头(front)。队列在程序涉及中也经常出现。一个最经典的例子就是操作系统中的作业排队。
双端队列(deque):除了栈和队列之外,还有一种限定性数据结构是双端队列。它是限定插入和删除操作在表的两端进行的线性表。

□3.4.2 链队列-队列的链式表示和实现
用链表示的队列简称为链队列。一个链队列显然需要两个分别指示队头和队尾的指针才能唯一确定。链队列的操作即为单链表的插入和删除操作的特殊情况,只是尚需修改尾指针或头指针。

typedef int QElemType;
/*----------------------------------------
    链队列
------------------------------------------*/
typedef struct QNode{/*结点类型*/
	QElemType data;
	struct QNode *next;
}QNode,*QueuePtr;

typedef struct{
	/*分别指向线性表中的头结点和最后一个结点*/
	QueuePtr front,rear; /* 队头、队尾指针 */
}LinkQueue;

Status InitQueue(LinkQueue *Q)
{ /* 构造一个空队列Q */
	(*Q).front = (*Q).rear = (QueuePtr)malloc(sizeof(QNode));
	if(!(*Q).front){
		exit(OVERFLOW);
	}
	(*Q).front->next = NULL;
	return OK;
}
Status DestroyQueue(LinkQueue *Q)
{ /* 销毁队列Q(无论空否均可) */
	QueuePtr p = NULL;
	while((*Q).front){
		p = (*Q).front->next;
		free((*Q).front);
		(*Q).front = p;
	}
	return OK;
}
Status ClearQueue(LinkQueue *Q)
{ /* 将Q清为空队列 */
	QueuePtr p = NULL;
	QueuePtr q = NULL;
	(*Q).rear = (*Q).front;
	p = (*Q).front->next;
	(*Q).front->next = NULL;
	while (p){
		q = p;
		p = p->next;
		free(q);
	}
	return OK;
}
Status QueueEmpty(LinkQueue Q)
{ /* 若Q为空队列,则返回TRUE,否则返回FALSE */
	if(Q.front == Q.rear){
		return TRUE;
	}
	else{
		return FALSE;
	}
}
int QueueLength(LinkQueue Q)
{ /* 求队列的长度 */
	int count = 0;
	QueuePtr p = Q.front;
	while (Q.rear != p){
		p = p->next;
		count++;;
	}
	return count;
}
Status EnQueue(LinkQueue *Q, QElemType e)
{ /* 插入元素e为Q的新的队尾元素 */
	QueuePtr p = NULL;
	p = (QueuePtr)malloc(sizeof(QNode));
	p->data = e;
	p->next = NULL;
	(*Q).rear->next = p;
	(*Q).rear = p;
	return OK;
}

Status DeQueue(LinkQueue *Q, QElemType *e)
{ /* 若队列不空,删除Q的队头元素,用e返回其值,并返回OK,否则返回ERROR */
	QueuePtr p = NULL;
	if ((*Q).front == (*Q).rear){
		return ERROR;
	}
	p = (*Q).front->next;
	*e = p->data;
	(*Q).front->next = p->next;
	if ((*Q).rear == p){
		(*Q).rear = (*Q).front;
	}
	free(p);
	p = NULL;
	return OK;
}
Status QueueTraverse(LinkQueue Q,void(*vi)(QElemType))
{ /* 从队头到队尾依次对队列Q中每个元素调用函数vi()。一旦vi失败,则操作失败 */
	QueuePtr p = NULL;
	p = Q.front->next;
	while(p){
		vi(p->data);
		p = p->next;
	}
	printf("\n");
	return OK;
}
Status GetHead_Q(LinkQueue Q, QElemType *e) /* 避免与bo2-6.c重名 */
{ /* 若队列不空,则用e返回Q的队头元素,并返回OK,否则返回ERROR */
	QueuePtr p = NULL;
	if (Q.front == Q.rear){
		return ERROR;
	}
	p = Q.front->next;
	*e = p->data;
	return OK;
}
void visit(QElemType i)
{
	printf("%d ",i);
}
int _tmain(int argc, _TCHAR* argv[])
{
	int i;
	QElemType d;
	LinkQueue q;
	i=InitQueue(&q);
	if(i){
		printf("成功地构造了一个空队列!\n");
	}
	printf("是否空队列?%d(1:空 0:否)  ",QueueEmpty(q));
	printf("队列的长度为%d\n",QueueLength(q));
	EnQueue(&q,-5);
	EnQueue(&q,5);
	EnQueue(&q,10);
	printf("插入3个元素(-5,5,10)后,队列的长度为%d\n",QueueLength(q));
	printf("是否空队列?%d(1:空 0:否)  ",QueueEmpty(q));
	printf("队列的元素依次为:");
	QueueTraverse(q,visit);
	i = GetHead_Q(q,&d);
	if(i == OK){
		printf("队头元素是:%d\n",d);
	}
	DeQueue(&q,&d);
	printf("删除了队头元素%d\n",d);
	i = GetHead_Q(q,&d);
	if(i == OK){
		printf("新的队头元素是:%d\n",d);
	}
	ClearQueue(&q);
	printf("清空队列后,q.front=%u q.rear=%u q.front->next=%u\n",q.front,q.rear,q.front->next);
	DestroyQueue(&q);
	printf("销毁队列后,q.front=%u q.rear=%u\n",q.front, q.rear);
	return 0;
}

□3.4.3 循环队列--队列的顺序表示和实现
在队列的顺序存储结构中,除了用一组地址连续的存储单元依次存放从队头到队尾的元素之外,尚需附设两个指针front和rear分别指示队列头元素及队列尾元素的位置。约定以队列头指针在队列尾指针的下一位置(指环上的下一位置)上作为队列呈满状态的标志。在C语言中不能用动态分配的一维数组来实现循环队列。如果用户的应用程序中设有循环队列,则必须为它设定一个最大队列长度;若用户无法预估所用队列的最大长度,则宜采用链队列。

/*---------------------------------------------
循环队列
---------------------------------------------*/
typedef int QElemType;
/* 最大队列长度(对于循环队列,最大队列长度要减1) */
#define MAXSIZE 5
typedef struct {
	QElemType *base;	/* 初始化的动态分配存储空间 */
	int rear;			/* 头指针,若队列不空,指向队列头元素 */
	int front;			/* 尾指针,若队列不空,指向队列尾元素的下一个位置 */
}SqQueue;

/* bo3-3.c 循环队列(存储结构由c3-3.h定义)的基本操作(9个) */
Status InitQueue(SqQueue *Q)
{ /* 构造一个空队列Q */
	(*Q).base = (QElemType *)malloc(MAXSIZE * sizeof(QElemType) );
	if(!(*Q).base){ /* 存储分配失败 */
		exit(OVERFLOW);
	}
	(*Q).front = (*Q).rear = 0;
	return OK;
}
Status DestroyQueue(SqQueue *Q)
{ /* 销毁队列Q,Q不再存在 */
	if((*Q).base){ 
		free((*Q).base);
	}
	(*Q).base = NULL;
	(*Q).front = (*Q).rear = 0;
	return OK;
}
Status ClearQueue(SqQueue *Q)
{ /* 将Q清为空队列 */
	(*Q).front = (*Q).rear = 0;
	return OK;
}
Status QueueEmpty(SqQueue Q)
{ /* 若队列Q为空队列,则返回TRUE,否则返回FALSE */
	if(Q.front==Q.rear){ /* 队列空的标志 */
		return TRUE;
	}
	else{
		return FALSE;
	}
}
int QueueLength(SqQueue Q)
{ /* 返回Q的元素个数,即队列的长度 */
	return ( Q.rear - Q.front + MAXSIZE) % MAXSIZE;
}
Status GetHead(SqQueue Q,QElemType *e)
{ /* 若队列不空,则用e返回Q的队头元素,并返回OK,否则返回ERROR */
	if(Q.front == Q.rear){
		return ERROR;
	}
	*e = *(Q.base + Q.front);
	return OK;
}
Status EnQueue(SqQueue *Q,QElemType e)
{ /* 插入元素e为Q的新的队尾元素 */
	/*队列满的情况*/
	if (((*Q).rear + 1) % MAXSIZE == (*Q).front ){
		return ERROR;
	}
	(*Q).base[(*Q).rear] = e;
	(*Q).rear = ((*Q).rear + 1) % MAXSIZE;
	return OK;
}
Status DeQueue(SqQueue *Q,QElemType *e)
{ /* 若队列不空,则删除Q的队头元素,用e返回其值,并返回OK;否则返回ERROR */
	if ((*Q).rear == (*Q).front){/*队列空的情况*/
		return ERROR;
	}
	*e = (*Q).base[(*Q).front];
	(*Q).front = ((*Q).front + 1) % MAXSIZE;
	return OK;
}
Status QueueTraverse(SqQueue Q,void(*vi)(QElemType))
{ /* 从队头到队尾依次对队列Q中每个元素调用函数vi().一旦vi失败,则操作失败 */
	int pos = Q.front;
	while (pos != Q.rear){
		vi(Q.base[pos]);
		pos = (pos + 1) % MAXSIZE;
	}
	printf("\n");
	return OK;
}

void visit(QElemType i)
{
	printf("%d ",i);
}

int _tmain(int argc, _TCHAR* argv[])
{
   Status j;
   int i=0,l;
   QElemType d;
   SqQueue Q;
   InitQueue(&Q);
   printf("初始化队列后,队列空否?%u(1:空 0:否)\n",QueueEmpty(Q));
   printf("请输入整型队列元素(不超过%d个),-1为提前结束符: ",MAXSIZE-1);
   do
   {
     scanf("%d",&d);
     if(d==-1)
       break;
     i++;
     EnQueue(&Q,d);
   }while(i<MAXSIZE-1);
   printf("队列长度为: %d\n",QueueLength(Q));
   printf("现在队列空否?%u(1:空 0:否)\n",QueueEmpty(Q));
   printf("连续%d次由队头删除元素,队尾插入元素:\n",MAXSIZE);
   for(l=1;l<=MAXSIZE;l++)
   {
     DeQueue(&Q,&d);
     printf("删除的元素是%d,请输入待插入的元素: ",d);
     scanf("%d",&d);
     EnQueue(&Q,d);
   }
   l=QueueLength(Q);
   printf("现在队列中的元素为: \n");
   QueueTraverse(Q,visit);
   printf("共向队尾插入了%d个元素\n",i+MAXSIZE);
   if(l-2>0)
     printf("现在由队头删除%d个元素:\n",l-2);
   while(QueueLength(Q)>2)
   {
     DeQueue(&Q,&d);
     printf("删除的元素值为%d\n",d);
   }
   j=GetHead(Q,&d);
   if(j)
     printf("现在队头元素为: %d\n",d);
   ClearQueue(&Q);
   printf("清空队列后, 队列空否?%u(1:空 0:否)\n",QueueEmpty(Q));
   DestroyQueue(&Q);
	return 0;
}

你可能感兴趣的:([数据结构]第三章-栈和队列(读书笔记3))