在写程序之前先说明一下链式队列的一些特点。
1.首先链式队列和数组队列一样遵循FIFO即先进的先出。
2.链式队列和数组队列不同之处在于数组队列在内存中是连续存储的,而链式队列是由指针的指向将相邻两个元素进行连接的,因此在内存中链式队列并不是连续存储的。具体情况如下:
那么开始构建链式队列了!
首先我们定义队列中每个节点的数据类型,因为链式队列节点之间需要指针建立关系,因此每个节点包含数据域和指针域,节点定义如下
struct Node
{
int data; //为了方便这里设置为整型数据,可以是任意类型的数据,包括结构体类型也是可以的
struct Node* next; //指针域,用于指向下一个节点的地址
}
构建好每个节点的结构体后,还要构建队列的结构体,因为队列里面有两个非常重要的成员:头指针和尾指针。
struct Queue
{
struct Node* front; //头指针
struct Node* tail; //尾指针
int sz; //记录队列中节点个数
}
这里我们用到了一个sz,这个数据主要是用来记录队列中节点个数的,定义sz可以简化我们的代码。
头指针指向队列的第一个元素,也就是相对于其他节点来说第一个进入队列的元素,尾指针指向队列的最后一个元素,也就是相对于其他节点来说最后一个进入队列的元素。这里说相对是因为队列有入队和出队的操作,进行一次入队和出队后,就会有一些变化啦,这个后面再说。
将节点和队列的结构体构建好后,就可以开始写构建队列和构建节点的函数了
//构建队列,函数返回指向新建的队列的指针
struct Queue* creatQueue()
{
//在堆区申请一块内存由于保存队列的头尾指针
struct Queue* myqueue = (struct Queue*)malloc(sizeof(struct Queue));
//初始化阶段将头尾指针置为空
myqueue->front = myqueue->tail = NULL;
//节点数为0
myqueue->sz = 0;
return myqueue;
}
//构建节点,函数返回指针新建的节点的指针
struct Node* creatNode(int data)
{
struct Node* newnode = (struct Node*)malloc(sizeof(struct Node));
newnode->data = data;
newnode->next = NULL;
return newnode;
}
运行前面的构建队列的函数之后,我们就得到了一个空的队列了。有了队列之后,就可以进行入队和出队操作了。
因为队列遵循先进先出原则,因此每次入队都是进入队尾,而每次出队都是队头元素弹出。
//入队
void push(struct Queue* myqueue, int data)
{
struct Node* newnode = creatNode(data); //创建要入队的节点
if (myqueue->sz == 0)
{//如果队列为空,则队头指针和队尾指针都指向这个新节点
myqueue->front = myqueue->tail = newnode;
}
else
{//否则队尾指针一开始指向的节点的指针域指向新的节点,然后再让队尾指针指向这个新的节点
//因为我们的队尾指针要遵循指向队列的最后一个节点 这个原则
myqueue->tail->next = newnode;
myqueue->tail = newnode;
}
myqueue->sz++; //别忘了入队操作后,节点数加1,所以sz要加1
}
//出队
void pop(struct Queue* myqueue)
{
if (myqueue->sz == 0)
{//如果队列为空则无法出队,直接结束函数
printf("队列为空,无法出队\n");
return;
}
else
{//队列不为空的情况下,我们定义一个指针指向第二个元素,因为出队后第二个元素就会变成队头了
struct Node* cur = myqueue->front->next;
free(myqueue->front); //free掉队头元素
myqueue->front = cur; //让队头指针指向第二个元素,此时第二个元素相对来说就是第一个元素了
myqueue->sz--; //别忘了出队后,节点数减1,sz也要减1了
}
}
现在最主要的两个函数入队和出队已经写好了,还需要写一些辅助函数来让我们的队列用起来更方便,比如获取队头元素,打印队头元素,判断队列是否为空。
//获取队头元素
int getFront(struct Queue* myqueue)
{
return myqueue->front->data; //直接返回队头节点的数据域
}
//打印队头元素
void print(struct Queue* myqueue)
{
printf("%d ", myqueue->front->data);
}
//判断队列是否为空
int empty(struct Queue* myqueue)
{
if (myqueue->sz == 0)
return 1; // 如果为空则返回1
else
return 0; //不为空则返回0
}
关于我们需要的一些辅助函数已经写好了,那么现在试一下我们写的队列吧!
主函数
int main()
{
struct Queue* myqueue = creatQueue(); //创建队列
//入队
push(myqueue, 1);
push(myqueue, 2);
push(myqueue, 3);
push(myqueue, 4);
push(myqueue, 5);
push(myqueue, 6);
while (!empty(myqueue)) //当队列不为空
{
print(myqueue); //打印队头元素
pop(myqueue); //出队
}
return 0;
}
完整代码
#include<stdio.h>
struct Node
{
int data;
struct Node* next;
};
struct Queue
{
struct Node* front;
struct Node* tail;
int sz;
};
struct Node* creatNode(int data)
{
struct Node* newnode = (struct Node*)malloc(sizeof(struct Node));
newnode->data = data;
newnode->next = NULL;
return newnode;
}
struct Queue* creatQueue()
{
struct Queue* myqueue = (struct Queue*)malloc(sizeof(struct Queue));
myqueue->front = myqueue->tail = NULL;
myqueue->sz = 0;
return myqueue;
}
//入队
void push(struct Queue* myqueue, int data)
{
struct Node* newnode = creatNode(data);
if (myqueue->sz == 0)
{
myqueue->front = myqueue->tail = newnode;
}
else
{
myqueue->tail->next = newnode;
myqueue->tail = newnode;
}
myqueue->sz++;
}
//出队
void pop(struct Queue* myqueue)
{
if (myqueue->sz == 0)
{
printf("队列为空,无法出队\n");
return;
}
else
{
struct Node* cur = myqueue->front->next;
free(myqueue->front);
myqueue->front = cur;
myqueue->sz--;
}
}
//获取队头元素
int getFront(struct Queue* myqueue)
{
return myqueue->front->data;
}
//判断队列是否为空
int empty(struct Queue* myqueue)
{
if (myqueue->sz == 0)
return 1;
else
return 0;
}
//打印队头元素
void print(struct Queue* myqueue)
{
printf("%d ", myqueue->front->data);
}
int main()
{
struct Queue* myqueue = creatQueue();
push(myqueue, 1);
push(myqueue, 2);
push(myqueue, 3);
push(myqueue, 4);
push(myqueue, 5);
push(myqueue, 6);
while (!empty(myqueue))
{
print(myqueue);
pop(myqueue);
}
return 0;
}
输出结果为