NOTICE: 代碼測試沒問題,直接複製就能跑!
環境:
Visual Stdio Code
鏈式隊列和有頭尾結點的單鏈表:
鏈式隊列可以看成一個有頭尾節點的單鏈表,但是它跟有頭尾節點的單鏈表的唯一區別就是:鏈式隊列只能從一端(rear 端)插入,從另一端(front 端)刪除。
廢話不多說,上代碼:
#include<stdio.h>
#include<stdlib.h>
#define MAXQSIZE 100 // 最大隊列長度
#define ERROR 0
#define OK 1
typedef int QElemType;
typedef int Status;
typedef struct QNode
{
QElemType data;
struct QNode *next;
}QNode, *QueuePtr;
typedef struct
{
QueuePtr front; // 隊頭指針
QueuePtr rear; // 隊尾指針
}LinkQueue;
Status InitQueue(LinkQueue &Q)
{ // 初始化
Q.front = Q.rear = (QueuePtr)malloc(sizeof(QNode)); // 分配兩個空間,一個 data 一個 next
if(!Q.front) return ERROR; // 分配失敗
Q.front->next = NULL;
return OK;
}//InitQueue
Status DestroyQueue(LinkQueue &Q)
{ // 銷燬
while(Q.front) // 如果 front 不爲空
{
Q.rear = Q.front->next; // rear 指向 front 的直接後繼結點
free(Q.front); // 釋放 front 指向的結點
Q.front = Q.rear; // 將 front 後移
}
return OK;
}//DestroyQueue
Status EnQueue(LinkQueue &Q, QElemType e)
{ // 插入新元素 e
QueuePtr p = (QueuePtr)malloc(sizeof(QNode));
if(!p) return ERROR; // 分配失敗
p->data = e;
p->next = NULL;
Q.rear->next = p; // 插入的是隊尾
Q.rear = p; // 隊尾指針後移
return OK;
}//EnQueue
Status DeQueue(LinkQueue &Q, QElemType &e)
{ // 刪除隊頭元素, 用 e 返回
if(Q.front == Q.rear) return ERROR; // 判斷隊列是否爲空
QueuePtr p = Q.front->next;
e = p->data;
Q.front->next = p->next;
if(Q.rear == p) Q.rear = Q.front;
free(p);
return e;
}//DeQueue
Status ClearQueue(LinkQueue &Q)
{ // 清空
QueuePtr p, q;
if(Q.front == Q.rear) return ERROR; // 隊列爲空
Q.rear = Q.front; // 空隊列的 rear 與 front 指向的是同一個結點
p = Q.front->next; // p 指向 front 的直接後繼結點
Q.front->next = NULL; // 將 front 指向的結點的 next 置位空
while(p)
{
q = p; // 逐個刪除
p = p->next;
free(q);
}
return OK;
}//ClearQueue
Status QueueEmpty(LinkQueue &Q)
{ // 判斷隊列是否爲空
return Q.front == Q.rear;
}//QueueEmpty
Status QueueLength(LinkQueue &Q)
{ // 輸出非空隊列的長度
int i = 0;
QueuePtr p;
p = Q.front;
while(p != Q.rear)
{
p = p->next;
i++;
}
return i;
}//QueueLength
Status GetHead(LinkQueue &Q, QElemType e)
{ // 用 e 返回 Q 的隊頭元素
if(Q.front == Q.rear) return ERROR;
e = Q.front->next->data; // 隊頭元素可類比於單鏈表的首元結點
return e;
}//GetHead
Status QueueTraverse(LinkQueue &Q) // 書上還有一個形參: visit() 這個形參可以看成一個打印函數,這裏我們用的是 printf()
{ // 打印隊列元素
QueuePtr p;
if(Q.front == Q.rear) return ERROR; // 隊列爲空
p = Q.front->next; // p 指向隊列的隊頭結點
while(p)
{
printf("%d\t", p->data);
p = p->next;
}
return OK;
}//QueueTraverse
int main()
{
int choice = 1;
LinkQueue Q;
QElemType e;
printf("請輸入序號進行相應的操作:\n");
while(choice)
{
printf("\n1.InitQueue 2.QueueLength 3.QueueTraverse 4.GetHead 5.ClearQueue \n6.EnQueue 7.DeQueue 8.QueueEmpty 9.DestroyQueue 0.exit\n");
scanf("%d", &choice);
switch (choice)
{
case 1:
if(InitQueue(Q))
printf("\n初始化隊列成功!\n");
break;
case 2:
if(QueueEmpty(Q))
printf("\n隊列爲空\n");
else
printf("\n隊列的長度爲:%d\n", QueueLength(Q));
break;
case 3:
if(QueueEmpty(Q))
printf("\n隊列爲空\n");
else
{
printf("\n隊列元素爲:\n");
QueueTraverse(Q);
}
break;
case 4:
if(!QueueEmpty(Q))
printf("\n隊列的隊頭元素爲:%d\n", GetHead(Q, e));
else
printf("\n隊列爲空\n");
break;
case 5:
if(QueueEmpty(Q))
printf("\n隊列爲空!\n");
else if(ClearQueue(Q))
printf("\n成功清空隊列!\n");
break;
case 6:
printf("\n請輸入想要插入的的元素:\n");
scanf("%d", &e);
if(EnQueue(Q, e))
printf("\n插入成功!\n");
else
printf("\n插入失敗!\n");
break;
case 7:
if(QueueEmpty(Q))
printf("\n隊列爲空!\n");
else
printf("\n刪除的隊頭元素爲:%d\n", DeQueue(Q, e));
break;
case 8:
if(QueueEmpty(Q))
printf("\n隊列爲空!\n");
else
printf("\n隊列不爲空!\n");
break;
case 9:
if(DestroyQueue(Q))
printf("\n銷燬成功\n");
else
printf("\n銷燬失敗!\n");
break;
case 0:
choice = 0;
break;
default:
printf("\n程序出錯!\n");
break;
}
}
DestroyQueue(Q);
return 0;
}
運行結果示意圖就不貼出來了,太長了!
THE END!