隊列的分類 隊列一般分為三種:順序隊列、迴圈隊列、鏈式隊列 其中順序隊列和迴圈隊列按照存儲方式又可以分為動態和靜態,鏈式隊列是動態的。 順序隊列 順序隊列存在”假溢出“現象:即隊頭由於出隊操作,還有剩餘空間,但隊尾指針已達到數組的末尾,如果繼續插入元素,隊尾指針就會越出數組的上界,而造成“溢出”,這 ...
隊列的分類
隊列一般分為三種:順序隊列、迴圈隊列、鏈式隊列
其中順序隊列和迴圈隊列按照存儲方式又可以分為動態和靜態,鏈式隊列是動態的。動態表示隊列元素採用動態記憶體分配,靜態表示隊列元素採用數組的方式分配。
順序隊列
順序隊列存在”假溢出“現象:即隊頭由於出隊操作,還有剩餘空間,但隊尾指針已達到數組的末尾,如果繼續插入元素,隊尾指針就會越出數組的上界,而造成“溢出”,這種溢出不是因為存儲空間不夠而產生的溢出,這種溢出不是因為存儲空間不夠而產生的溢出,像這種有存儲空間而不能插入元素的操作稱為“假溢出“。
由於存在順序隊列存在”假溢出“現象,因此一般使用順序隊列。
迴圈隊列
關於判斷隊滿和隊空
當迴圈隊列為空或為滿時,隊尾和隊頭指針都指向同一個元素,可以通過下麵幾種方式判斷隊列空或隊列滿:
(1)、犧牲一個隊列元素用來識別隊列滿和隊列空
(2)、通過計數器來判斷隊列滿和隊列空
(3)、通過一個讀寫標誌來判斷隊列滿和隊列空
靜態迴圈隊列
採用靜態迴圈隊列來展示三種隊列滿和隊列空的判斷方法,舉例如下:
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #define queue_max_length 5 #if 1 //犧牲一個隊列元素用來識別隊列滿和隊列空 typedef struct queue_srt { int front; int rear; int queue_data[queue_max_length]; } queue_srt; int queue_init(queue_srt *q_srt) { q_srt->front = q_srt->rear = 0; memset(q_srt->queue_data, 0, sizeof(q_srt->queue_data)); printf("queue init success\n"); return 0; } int queue_read(queue_srt *q_srt, int *value) { //判斷隊列是否為空 if (q_srt->front == q_srt->rear) { printf("the queue is empty\n"); return 1; } *value = q_srt->queue_data[q_srt->front]; q_srt->front = (q_srt->front + 1) % queue_max_length; return 0; } int queue_write(queue_srt *q_srt, int value) { //犧牲一個隊列元素用來判斷隊列滿 if (((q_srt->rear + 1)%queue_max_length) == q_srt->front) { printf("the queue is full\n"); return 1; } q_srt->queue_data[q_srt->rear] = value; q_srt->rear = (q_srt->rear + 1) % queue_max_length; return 0; } int queue_length(queue_srt *q_srt) { //計算隊列長度 int length = (q_srt->rear - q_srt->front + queue_max_length) % queue_max_length; return length; } #endif #if 0 //通過計數器來判斷隊列滿和隊列空 typedef struct queue_srt { int front; int rear; int queue_data[queue_max_length]; int cnt; //計數器,用來記錄隊列長度 } queue_srt; int queue_init(queue_srt *q_srt) { q_srt->front = q_srt->rear = 0; q_srt->cnt = 0; memset(q_srt->queue_data, 0, sizeof(q_srt->queue_data)); printf("queue init success\n"); return 0; } int queue_read(queue_srt *q_srt, int *value) { //通過判斷計數器來識別隊列是否已經空 if (q_srt->cnt == 0) { printf("the queue is empty\n"); return 1; } *value = q_srt->queue_data[q_srt->front]; q_srt->front = (q_srt->front + 1) % queue_max_length; q_srt->cnt--;//讀完數據,計數器減1 return 0; } int queue_write(queue_srt *q_srt, int value) { //通過判斷計數器來識別隊列是否已經滿 if (q_srt->cnt == queue_max_length) { printf("the queue is full\n"); return 1; } q_srt->queue_data[q_srt->rear] = value; q_srt->rear = (q_srt->rear + 1) % queue_max_length; q_srt->cnt++; //寫完數據,計數器加1 return 0; } int queue_length(queue_srt *q_srt) { //通過計數器獲取隊列長度 int length = q_srt->cnt; return length; } #endif #if 0 //通過一個讀寫標誌來判斷隊列滿和隊列空 typedef struct queue_srt { int front; int rear; int queue_data[queue_max_length]; char rw_flag; //讀寫標誌 w:表示寫完隊列 r:表示讀完隊列 } queue_srt; int queue_init(queue_srt *q_srt) { q_srt->front = q_srt->rear = 0; q_srt->rw_flag = 'r'; //初始為 r ,表示隊列為空 memset(q_srt->queue_data, 0, sizeof(q_srt->queue_data)); printf("queue init success\n"); return 0; } int queue_read(queue_srt *q_srt, int *value) { //通過讀寫標誌判斷隊列是否為空 if ((q_srt->front == q_srt->rear) && (q_srt->rw_flag == 'r')) { printf("the queue is empty\n"); return 1; } *value = q_srt->queue_data[q_srt->front]; q_srt->front = (q_srt->front + 1) % queue_max_length; q_srt->rw_flag = 'r'; //讀完隊列,讀寫標誌設置r return 0; } int queue_write(queue_srt *q_srt, int value) { //通過讀寫標誌判斷隊列是否為空 if ((q_srt->front == q_srt->rear) && (q_srt->rw_flag == 'w')) { printf("the queue is full\n"); return 1; } q_srt->queue_data[q_srt->rear] = value; q_srt->rear = (q_srt->rear + 1) % queue_max_length; q_srt->rw_flag = 'w'; //寫完隊列,讀寫標誌設置w return 0; } int queue_length(queue_srt *q_srt) { int length = 0; if ((q_srt->front == q_srt->rear) && (q_srt->rw_flag == 'w')) //通過讀寫標誌判斷是否隊滿 { length = queue_max_length; } else { length = (q_srt->rear - q_srt->front + queue_max_length) % queue_max_length; } return length; } #endif int main(void) { int action = 0; int value = 0; queue_srt testqueue; queue_init(&testqueue); while (1) { printf("1:write 2:read 3:get length\n"); printf("enter action:"); scanf("%d", &action); switch(action) { case 1: printf("write queue to data:"); scanf("%d", &value); queue_write(&testqueue, value); break; case 2: if (1 == queue_read(&testqueue, &value)) continue; printf("read data from queue: %d\n", value); break; case 3: value = queue_length(&testqueue); printf("the length of queue is: %d\n", value); break; default: printf("no such action\n"); } } return 0; }
動態迴圈隊列
下麵展示一個動態迴圈隊列,隊列元素採用動態記憶體分配,舉例如下:
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #define queue_max_length 5 typedef struct queue_srt { int *front; //指向隊列頭 int *rear; //指向隊列尾 int *queue_data; //指向隊列動態記憶體 int *end; //指向隊列存儲空間之後 } queue_srt; int queue_init(queue_srt *q_srt) { q_srt->queue_data = (int *) (malloc)(sizeof(int) * queue_max_length); if (NULL == q_srt) { printf("malloc mem failed,queue init failed\n"); return 1; } q_srt->front = q_srt->rear = q_srt->queue_data; //指向隊列首部 q_srt->end = q_srt->queue_data + queue_max_length; //指向隊列存儲空間之後 printf("queue init success\n"); return 0; } int queue_read(queue_srt *q_srt, int *value) { if (q_srt->front == q_srt->rear) //判斷隊列是否為空 { printf("the queue is empty\n"); return 1; } *value = *(q_srt->front); if ((q_srt->front + 1) >= q_srt->end) //判斷隊頭指針是否到隊列尾 { q_srt->front = q_srt->queue_data; } else { q_srt->front = q_srt->front + 1; } return 0; } int queue_write(queue_srt *q_srt, int value) { //犧牲一個隊列元素用來識別隊列滿 int *q_tmp = (q_srt->rear + 1 >= q_srt->end)? (q_srt->queue_data) : (q_srt->rear + 1); if (q_tmp == q_srt->front) { printf("the queue is full\n"); return 1; } *(q_srt->rear) = value; q_srt->rear = q_tmp; return 0; } int queue_length(queue_srt *q_srt) { int length = 0; length = (q_srt->rear - q_srt->front + queue_max_length) % queue_max_length;return length; //獲取隊列長度 } int main(void) { int action = 0; int value = 0; queue_srt testqueue; queue_init(&testqueue); while (1) { printf("1:write 2:read 3:get length\n"); printf("enter action:"); scanf("%d", &action); switch(action) { case 1: printf("write queue to data:"); scanf("%d", &value); queue_write(&testqueue, value); break; case 2: if (1 == queue_read(&testqueue, &value)) continue; printf("read data from queue: %d\n", value); break; case 3: value = queue_length(&testqueue); printf("the length of queue is: %d\n", value); break; default: printf("no such action\n"); } } free(testqueue.queue_data); return 0; }
鏈式隊列
鏈式隊列主要有兩個特點:1、隊列是動態的,即隊列元素採用動態記憶體分配 2、隊列採用鏈表的邏輯來組織,因此隊列的長度沒有限制,這是跟迴圈隊列最大的差別
編寫一個帶頭結點的鏈式隊列,舉例如下:
#include <stdio.h> #include <stdlib.h> typedef struct LKNODE { int data; //保存節點數據 struct LKNODE *next; //指向下一個節點 } LKNODE; typedef struct LINKQUEUE //隊列結構體,採用頭尾指針構建鏈式隊列 { LKNODE *front; //頭指針,指向隊列頭結點 LKNODE *rear; //尾指針,指向隊列尾節點 }LINKQUEUE; //初始化鏈式隊列 int InitLinkQueue(LINKQUEUE *lkqueue) { LKNODE *head = (LKNODE*) malloc(sizeof(LKNODE)); //創建頭結點 if (NULL == head) { printf("creat head node failed,init linkqueue failed\n"); return 1; } head->next = NULL; //這裡要head節點的next設置為NULL,避免頭尾指針的next指向未知 //頭尾指針指向頭結點 lkqueue->front = lkqueue->rear = head; return 0; } //節點入隊 int WriteLinkQueue(LINKQUEUE *lkqueue, int value) { //創建新節點 LKNODE *newnode = (LKNODE *)malloc(sizeof(LKNODE)); if (NULL == newnode) { printf("creat newnode failed,write queue failed\n"); return 1; } newnode->data = value; newnode->next = NULL; //這裡要指向空,避免隊列為空後,頭結點的next指針指向未知 //尾指針連接新節點 lkqueue->rear->next = newnode; //尾指針指向新節點 lkqueue->rear = newnode; return 0; } //節點出隊 int ReadLinkQueue(LINKQUEUE *lkqueue, int *value) { //LKNODE *temp = NULL; LKNODE *readnode = NULL; //判斷隊列是否為空隊列 if (lkqueue->front == lkqueue->rear) { printf("link queue is empty\n"); return 1; } //獲取讀取節點值 readnode = lkqueue->front->next; *value = readnode->data;
//頭結點連接讀取節點的下一個節點 lkqueue->front->next = readnode->next; //如果readnode是最後一個節點,則頭結點的next會指向NULL //判斷讀取的節點是不是最後一個節點,防止釋放讀取節點後尾指針指向空 if (readnode == lkqueue->rear) { lkqueue->rear = lkqueue->front; //隊列為空,尾指針指向頭結點 } //釋放讀取節點 free(readnode); return 0; } //獲取隊列長度 int GetLinkQueueLen(LINKQUEUE *lkqueue) { int length = NULL; LKNODE *temp = NULL; //創建臨時節點,因為頭尾指針的位置不能動 temp = lkqueue->front->next; //獲取頭結點的下一個節點 if (NULL == temp) //判斷隊列是否為空 { length = 0; } else { while(temp != lkqueue->rear) //判斷是不是讀到尾節點 { length++; temp = temp->next; } length++; //加上最後一個節點 } return length; } //清空隊列 void ClearLinkQueue(LINKQUEUE *lkqueue) { int value; int ret; while(1) { //讀取隊列元素,釋放動態記憶體,防止記憶體泄漏 ret = ReadLinkQueue(lkqueue, &value); if (1 == ret) //判斷隊列是否讀完 { printf("clear the link queue success\n"); break; } } } //銷毀隊列 void DestroyLinkQueue(LINKQUEUE *lkqueue) { //先清空隊列,釋放隊列的動態記憶體 ClearLinkQueue(lkqueue); //釋放頭結點的動態記憶體 free(lkqueue->front); //頭尾指針指向空 lkqueue->front = lkqueue->rear = NULL; printf("destroy the link queue success\n"); } //遍歷隊列 void TraverseLinkQueue(LINKQUEUE *lkqueue) { int value; int ret = 0; int num = 0; LKNODE *temp = lkqueue->front->next; while(1) { if (NULL != temp) //判斷隊列是否為空 { num++; printf("%d node data is:%d\n", num, temp->data); temp = temp->next; } else { printf("traverse link queue success\n"); break; } } } int main() { int action = 0; int value = 0; int ret = 0; LINKQUEUE testlkqueue = {NULL, NULL}; InitLinkQueue(&testlkqueue); //初始化鏈式隊列 while(1) { printf("**********\n1 write 2 read 3 getlength 4 Traverse 5 Clear link queue 6 destroy link queue\n**********\n"); printf("enter action:"); scanf("%d", &action); switch(action) { case 1: printf("enter the value:"); scanf("%d", &value); WriteLinkQueue(&testlkqueue, value); break; case 2: ret = ReadLinkQueue(&testlkqueue, &value); if (1 != ret) { printf("the readnode data is:%d\n", value); } break; case 3: ret = GetLinkQueueLen(&testlkqueue); printf("the length of link queue is:%d\n", ret); break; case 4: TraverseLinkQueue(&testlkqueue); break; case 5: ClearLinkQueue(&testlkqueue); break; case 6: DestroyLinkQueue(&testlkqueue); return 0; break; default: break; } } return 0; }