队列的存储方式除了有顺序队列,还可以有链队列这种形式。链队列是采用链式结构存储的队列,类似单链表,但操作受限制,只允许在表头删除结点和在表尾插入结点。
在链队列中,除了有一个头指针外,还要有一个尾指针。在队头还需要加一个头结点,当队列为空时,头指针与尾指针同时指向头结点。为了与头结点区分开,称队列的第一个结点(头结点后面的第一个结点)为队头结点。
下面的代码就是对链队列的一些操作,其中有个问题还让我纠结了会儿。
#include <stdio.h>
#include <stdlib.h>
typedef struct list
{
char data;
struct list *next;
}linklist;
typedef struct node
{
linklist *front;
linklist *rear;
}linksequeue; //链队列
linksequeue *Linksequeue_CreateEnd(); //尾插法创建链队列
char Linksequeue_GetFront(linksequeue *q); //取得头结点
void Linksequeue_In(linksequeue *q, char dat); //入队
char Linksequeue_Out(linksequeue *q); //出队
void ShowLinksequeue(linksequeue *q); //输出显示队列
int main(void)
{
linksequeue *q;
int choice;
char ch, ans;
printf("链队列的操作练习:\n");
printf("依次输入队列结点数据('#'号表示结束):\n");
q = Linksequeue_CreateEnd();
getchar();
while(1)
{
printf("链队列操作:\n");
printf("1.取头结点\n");
printf("2.入队\n");
printf("3.出队\n");
printf("4.输出显示队列\n");
printf("5.退出程序\n");
printf("做出选择:\n");
scanf("%d", &choice);
getchar(); //消除回车键带来的影响
switch(choice)
{
//取头结点
case 1:
ch = Linksequeue_GetFront(q);
if(ch)
printf("头结点为%c\n",ch);
else
printf("取头结点失败!\n");
break;
//入队
case 2:
printf("输入想入队的字符数据:");
scanf("%c", &ch);
Linksequeue_In(q, ch);
break;
//出队
case 3:
ans = Linksequeue_Out(q);
if(ans != '\0')
{
printf("出队成功!\n");
printf("出队数据为%c\n", ans);
}
else
printf("出队失败!\n");
break;
//输出显示队列
case 4:
ShowLinksequeue(q);
break;
//退出程序
case 5:
return 0;
break;
default:
printf("选择无效!\n");
break;
}
}
return 1;
}
//链队列置空
void Linksequeue_SetNull(linksequeue *q)
{
q->front = (linklist*)malloc(sizeof(linklist));
q->front->next = NULL; //队头结点为空,尾结点指向头结点
q->rear = q->front;
}
//判断链队列是否为空
int Linksequeue_Empty(linksequeue *q)
{
if(q->front == q->rear) //头结点等于尾结点则为空
return 1;
else
return 0;
}
//创建链队列
linksequeue *Linksequeue_CreateEnd()
{
linksequeue *q;
char ch;
q = (linksequeue*)malloc(sizeof(linksequeue)); //关键啊!!!开始忘了,程序始终有问题- -!!
Linksequeue_SetNull(q);
ch = getchar();
while(ch != '#')
{
Linksequeue_In(q, ch); //入队
ch = getchar();
}
return q;
}
//取得头结点
char Linksequeue_GetFront(linksequeue *q)
{
if(Linksequeue_Empty(q)) //先判断链队列是否为空
return '\0';
else
return q->front->next->data;
}
//入队
void Linksequeue_In(linksequeue *q, char dat)
{
q->rear->next = (linklist*)malloc(sizeof(linklist));
q->rear = q->rear->next; //尾结点移动
q->rear->data = dat;
q->rear->next = NULL; //尾结点为空
}
//出队
char Linksequeue_Out(linksequeue *q)
{
linklist *s;
if(Linksequeue_Empty(q)) //先要判断队列是否为空
return 0;
else
{
s = q->front; //头结点移动到头结点的下一个节点
q->front = s->next;
free(s);
return q->front->data;
}
}
//输出显示队列
void ShowLinksequeue(linksequeue *q)
{
linklist *s;
s = q->front->next;
while(s != NULL)
{
putchar(s->data);
putchar(' ');
s = s->next;
}
printf("\n");
}
其中让我纠结的就是创建链队列中的一句关于空间申请的语句q = (linksequeue*)malloc(sizeof(linksequeue));开始没有这条语句时,程序就不执行while(1)里面的语句了。运行程序输入一串字符后,提示命令结束。开始百思不得其解,不知道为什么,后来灵感莫名以来,感觉是没有申请空间的问题,然后加上这条语句后果然正确。至于其中真正原因,目前还不知道,有知道的高手如果看见这片文章的话,望解答我的疑惑。让我知其所以然。