队列的存储方式除了有顺序队列,还可以有链队列这种形式。链队列是采用链式结构存储的队列,类似单链表,但操作受限制,只允许在表头删除结点和在表尾插入结点。
在链队列中,除了有一个头指针外,还要有一个尾指针。在队头还需要加一个头结点,当队列为空时,头指针与尾指针同时指向头结点。为了与头结点区分开,称队列的第一个结点(头结点后面的第一个结点)为队头结点。
下面的代码就是对链队列的一些操作,其中有个问题还让我纠结了会儿。
#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"); }