数据结构之线性表5:队列

395 阅读4分钟

定义

一端插入元素,一端删除元素,删除的一端称为对头,插入的一端称为队尾。

先进先出:FIFO

链队列

队首指针指向头结点,

数据类型

typedef struct Node
{	ElementType data;
	struct Node *next;
}QueueNode;

typedef struct
{	QueueNode *front;
	QueueNode *rear;
}LinkQueue;

链队列由:具有数据域和指针域类型的两个指针:front和rear

初始化操作

int InitQueue(LinkQueue *Q)
{	
	Q->front=(QueueNode*)malloc(sizeof(QueueNode));
	if(Q->front==NULL)
    	return 0;		//申请失败(没地方了)
	else
    {	Q->rear=Q->front;
    	Q->front->next=NULL;
        return 1;
    }
}

入队操作

申请一个新结点接在队尾

int EnterQueue(LinkQueue *Q,ElementType x)
{
	QueueNode *S;	//新结点
	s=(QueueNode*)malloc(sizeof(QueueNode));
    if(s!=NULL)
    {	s->data=x;
    	s->next=NULL;		//尾巴指向空
    	Q->rear->next=s;	//队列Q尾巴连上s
    	Q->rear=s;			//Q尾巴指向新尾巴
        return 1;
     }
     else
     	return 0;			//申请失败
}

出队操作

从队首移出一个结点并将值取出

int DeleteQueue(LinkQueue *Q,ElementType *x)
{
	QueueNode p;			//临时指针
    if(Q->front==Q->rear)
    	return 0;			//空表
    else
    {	
    	p=Q->front->next;			//指向首元
        Q->front->next=p->next;		//越过首元,首元已出列      
    }
    
    if(Q->rear==p)					//定位到的出队结点=原来尾指针所指位置(队列中只有一个元素)
    	Q->rear=Q->front;			
     
     *x=p->data;
     free(p);
     return 1;
}

这里需要重点考虑若队列中仅有一个元素,出队后,头结点指针域不能指向Q->front->next->next,即越过第一元素指向第二个,所以需要单独检测,若出列元素是队列尾元素,则尾结点指向头结点,变成空队列

循环队列

用一维数组存放从队头到队尾的元素,设置两个指针分别存放队头和队尾在数组中的位置。

为了防止假溢出所以采用循环队列,结构基础是取模运算

循环队列判满

当rear==front时可能满,也可能空,如何判断空还是满?

  • 让尾指针指向最后元素的下一个,当rear+1==front时判满 这样的方法下

满:(rear+1)%MAXSIZE=front   空:rear=front

  • 增加一个标志量,保存0或1,区分队列空还是满(习题3.8)

第一种数据类型

#define MAXSIZE 50

typedef struct
{
	QueueElementType element[MAXSIZE];
    int front;
    int rear;
}SeqQueue;

初始化操作

void InitQueue(SeqQueue *Q)
{	Q->front=Q->rear=0;		//头尾都存0
}

入队操作

将x放入尾指针指向的位置(尾元素后的空缺),尾指针后移

int EnterQueue(SeqQueue *Q,QueueElementType x)
{
	if((Q->rear+1)%MAXSIZE==Q->front)
    	return 0;						//若尾指针下一位就是头指针,则不能入队
    else
    {	
    	Q->element[Q->rear]=x;			//将x放入队尾指针指向的位置
        Q->rear=(Q->rear+1)%MAXSIZE;	//队尾后移并通过取模循环
        return 1;
    }
}

出队操作

将头指针指向元素赋值给x,头指针后移

{
	if(Q->rear==Q->front)
    	return 0;				//队列为空
    else
    {
    	x=Q->element[Q->front];
        Q->front=(Q->front+1)%MAXSIZE;
        return 1;
    }
}

队列应用:杨辉三角

本函数输入行数N,输出N行杨辉三角,InitQueue,EnterQueue,DelQueue,GetHead,作用分别为初始化,入队,出队,获取队首元素

void YangHuiTriangle(int N)
{
	int n, i, x, temp;
	SeqQueue Q;
	InitQueue(&Q);
	EnterQueue(&Q, 1);//第一行元素入队
	for (n = 2; n <= N; n++)
	{
		EnterQueue(&Q, 1);//入队
		for (i = 1; i <= n - 2; i++)
		{
			DelQueue(&Q, &temp);//出队的数赋给temp
			printf("%d ", temp);
			GetHead(&Q, &x);
			temp = temp + x;
			EnterQueue(&Q, temp);
		}
		DelQueue(&Q, &x);//出队
		printf("%d ", x);
		EnterQueue(&Q, 1);
		printf("\n");
	}
	while (!IsEmpty(&Q))
	{
		DelQueue(&Q, &x);
		printf("%d ", x);
 
	}
}

由于杨辉三角两侧都是1,所以第一行的1需要手动添加。从第二行开始进入for循环,每次循环是一行的操作,每行操作中都对队尾添加一次1,(实际上是下一行的最左边的1)。除了上面的循环,内部还有一个循环,完成这行元素挨个出队,求和并将和进入队列。


例如:当n等于4:输出1 2 1,队列中存着1 3 3 1 。

外层循环n=4,先将1入队;

进入第一次循环,先将1 2 1 1 的队首1出队并保存在temp中,这时队列为2 1 1,然后获取队首元素2,将2+temp存入新的temp=3(就是杨辉三角的头上俩求和等于下面),将这个temp入队,这时队列为2 1 1 3;

进入第二次循环,先将2 1 1 3的队首2出队并保存在temp中,这时队列1 1 3,然后获取队首元素1,将1+temp存入新的temp=3,将temp=3入队,这时队列为1 1 3 3,退出循环

最后再将队首1出队,这时队列为1 3 3,然后手动添加1入队,队列变成1 3 3 1。


代码来源:blog.csdn.net/duan1992010…