数据结构-队列详解(类C语言版)
目錄
隊列的相關概念
定義
邏輯結構
存儲結構
運算規則
實現方式
隊列的基本操作
循環隊列——隊列的順序表示和實現
隊列的順序存儲結構
假溢出-引出循環隊列
判斷循環隊列隊空隊滿
?循環隊列的操作
隊列的初始化
求循環隊列長度
循環隊列入隊
循環隊列出隊
取循環隊列隊頭元素
隊列-鏈式隊列
?隊列的鏈式存儲結構
鏈隊列的類型定義
鏈式隊列的操作
鏈隊的初始化
鏈隊的入隊
?鏈隊的出隊
取鏈隊的隊頭元素
銷毀鏈隊列
隊列的相關概念
定義
只能在表的一端進行插入運算,在表的另一端進行刪除運算的線性表(頭刪尾插)。
邏輯結構
與線性表相同,仍為一對一關系。
存儲結構
順序隊或鏈隊,以循環順序隊列更常見。
隊列的物理存儲可以用順序存儲結構,也可用鏈式存儲結構。相應地,隊列的存儲方式也分兩種,即順序隊列和鏈式隊列。
運算規則
只能在隊首和隊尾運算,且訪問節點時依照先進先出(FIFO)的原則。
實現方式
關鍵是掌握入隊和出隊操作,具體實現依順序隊或鏈隊的不同而不同。
隊列的基本操作
ADT?Queue{
? ? ? ? 數據對象:D={ai | ai?∈ElemSet, i = 1,2,...,n,n≥0 }
? ? ? ? 數據關系:R={<ai-1,ai>|ai-1,ai∈D,i=2,...,n}?約定其中a1端為隊列頭,an端為隊列尾。
}ADT?Queue
InitQueue(&Q) 操作結果:構造空隊列Q
DestroyQueue(&Q)? ? ? ? 條件:隊列Q已存在;操作結果:隊列Q被銷毀
ClearQueue(&Q)? ? ? ? 條件:隊列Q已存在;操作結果:將Q清空
QueueLength(Q)????????條件:隊列Q已存在;操作結果:返回Q的元素個數,即隊長
GetHead(Q, &e)????????條件:Q為非空隊列;操作結果:用e返回Q的隊頭元素
EnQueue(&Q, e)?????????條件:隊列Q已存在;操作結果:插入元素e為Q的隊尾元素
DeQueue(&Q, &e)? ? ? ??條件:Q為非空隊列;操作結果:刪除Q的隊頭元素,用e返回值
……還有將對列置空、遍歷隊列等操作……
循環隊列——隊列的順序表示和實現
隊列的順序存儲結構
用一維數組base[MAXQSIZE]
#define MAXQSIZE 100 // 最大隊列長度 Typedef struct {QElemType *base; // 初始化的動態分配存儲空間int front; // 頭指針int rear; // 尾指針 }SqQueue;假溢出-引出循環隊列
假設當前隊列分配的最大空間為 6, 則當隊列處于圖(d) 所示的狀態時不可再繼續插入新的隊尾元素,否則會出現溢出現象, 即因數組越界而導致程序的非法操作錯誤。 事實上,此時隊列的實際可用空間并未占滿,所以這種現象稱為 “假溢出"。這是由 "隊尾入隊,隊頭出隊” 這種受限制的操作造成的。?
怎樣解決這種 “假溢出” 問題呢? 一個較巧妙的辦法是將順序隊列變為一個環狀的空間,如圖所示,稱之為循環隊列。
base[0]接在hase[MAXQSIZE -1]之后,若rear+1==M,則令rear=0;
實現方法:利用模(mod,C語言中:%)運算。
插入元素:Q.base[Q.rear]=x;
? ? ? ? ? ? ? ? ? Q.rear=(Q.rear+1)%MAXQSIZE;
刪除元素:x=Q.base[s.front]
? ? ? ? ? ? ? ? ? Q.front=(Q.front+1)%MAXQSIZE
循環隊列:循環使用為隊列分配的存儲空間。
?
判斷循環隊列隊空隊滿
?少用一個元素空間
?隊空:front==rear
隊滿:(rear+1)%MAXQSIZE==front
?循環隊列的操作
隊列的初始化
Status InitQueue(SqQueue &Q){Q.base = new QElemType[MAXQSIZE] // 分配數組空間// Q.base = (QElemType*)malloc(MAXQSIZE*sizeof(QElemType));if(!Q.base) exit(OVERFLOW); // 存儲分配失敗Q.front=Q.rear=0; // 頭指針尾指針置為0,隊列為空return OK; }求循環隊列長度
對于非循環隊列,尾指針和頭指針的差值便是隊列長度,而對于循環隊列,差值可能為負數,所以需要將差值加上MAXQSIZE,然后與MAXQSIZE求余。
int QueueLength(SqQueue Q){// 返回Q的元素個數,即隊列的長度return(Q.rear-Q.front+MAXQSIZE) % MAXQSIZE; }循環隊列入隊
入隊操作是指在隊尾插入一個新的元素。
Status EnQueue(SqQueue &Q, QElemType e) {// 插入元素e為Q的新的隊尾元素if((Q.rear+1) % MAXQSIZE == Q.front) // 尾指針在循環意義上加1后等于頭指針,表明隊滿return ERROR;Q.base[Q.rear] = e; // 新元素插入隊尾Q.rear = (Q.rear + 1) % MAXQSIZE; // 隊尾指針加1return OK; }循環隊列出隊
出隊操作是將隊頭元素刪除。
Status DeQueue(SqQueue &Q, QElemType &e) {// 刪除Q的隊頭元素,用e返回其值if(Q.front==Q.rear) return ERROR; // 隊空e = Q.base[Q.front]; // 保存隊頭元素Q.front = (Q.front + 1) % MAXQSIZE; // 隊頭指針加1return OK; }取循環隊列隊頭元素
當隊列非空時, 此操作返回當前隊頭元素的值, 隊頭指針保持不變。
SElemType GetHead(SqQueue Q) {// 返回Q的隊頭元素,不修改隊頭指針if(Q.front != Q.rear) // 隊列非空return Q.base[Q.front]; // 返回隊頭元素的值,隊頭指針不變 }隊列-鏈式隊列
若用戶無法估計所用隊列的長度,則宜采用鏈隊列。
?隊列的鏈式存儲結構
鏈隊列的類型定義
#define MAXQSIZE 100 // 最大隊列長度 typedef struct Qnode {QElemType data;stuct Qnode *next; }QNode, *QueuePtr;typedef struct {QueuePtr front; // 隊頭指針Queueptr rear; // 隊尾指針 }LinkQueue;鏈式隊列的操作
鏈隊的初始化
Status InitQueue(LinkQueue &Q) {// 構造一個空隊列QQ.front = Q.rear = new QNode; // 生成新結點作為頭結點,隊頭和隊尾指針指向此結點Q.front -> next = NULL; // 頭結點的指針域置空return OK; }鏈隊的入隊
Status EnQueue(LinkQueue &Q, QElemType e) {// 插入元素e為Q的新的隊尾元素p = new QNode; // 為入隊元素分配結點空間,用指針p指向p -> data = e; // 將新結點數據域置為ep -> next = NULL; Q.rear -> next = p; // 將新結點插入到隊尾Q.rear = p; // 修改隊尾指針return OK; }?鏈隊的出隊
Status DeQueue(LinkQueue &Q, QElemType &e) {// 刪除Q的隊頭元素,用e返回其值if(Q.front == Q.rear) return ERROR; // 若隊列空,則返回ERRORp = Q.front -> next; // p指向隊頭元素e = p -> data; // e保存隊頭元素的值Q.front -> next = p -> next; // 修改頭指針if(Q.rear == p) Q.rear = Q.front; // 最后一個元素被刪,隊尾指針指向頭結點delete p; // 釋放原隊頭元素的空間return OK; }需要注意的是,在鏈隊出隊操作時還要考慮當隊列中最后一個元素被刪后,隊列尾指針也丟失了,因此需對隊尾指針重新賦值(指向頭結點)。
取鏈隊的隊頭元素
SElemType GetHead(LinkQueue Q) {// 返回Q的隊頭元素,不修改隊頭指針if(Q.front != Q.rear){ // 隊列非空return Q.front -> next -> data; // 返回隊頭元素的值,隊頭指針不變} }銷毀鏈隊列
Status DestroyQueue(LinkQueue &Q) {while(Q.front) {p= Q.front -> next; free(Q.front);Q.front = p;} // Q.rear = Q.front -> next; free(Q.front); Q.front = Q.rear;return OK; }總結
以上是生活随笔為你收集整理的数据结构-队列详解(类C语言版)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 数据结构-栈详解(类C语言版)
- 下一篇: spring框架注解多?注解到底是个什么