只是單獨看DeQueue這個函數(shù)不能直觀的了解相關(guān)用途,要知道Q->rear=Q->front 是什么意思,需要了解初始化函數(shù)的實現(xiàn):
//初始化隊列
Status?InitQueue(LinkQueue?&Q){
//初始化的節(jié)點并未給data賦值,相當(dāng)于頭結(jié)點,我們可以用他來存隊列長度
Q.front?=?Q.rear?=?(QueuePtr)malloc(sizeof(Node));?//注意front和rear指針指向的是同一個內(nèi)存地址
if(!Q.rear){
exit(OVERFLOW);
}
Q.front->data?=?0;//長度初始化為0
Q.front->next?=?NULL;
return?OK;
}
上面初始化隊列初始化了一個頭節(jié)點,利用Node這個結(jié)構(gòu)做兩件事,1. 存儲隊列長度。2. front->next指針將來是要指向最早進(jìn)入隊列的一個結(jié)點地址;rear->next是要指向最后進(jìn)入隊列的一個結(jié)點地址。
再看入隊函數(shù):
//入隊
Status?EnQueue(LinkQueue?&Q,ElemType?e){
????????//申請結(jié)點空間,用來存儲新的結(jié)點數(shù)據(jù)
QueuePtr?p?=?(QueuePtr)malloc(sizeof(Node));
if(!p){
exit(OVERFLOW);
}
p->data?=?e;?//將具體數(shù)據(jù)e存儲到data中
p->next??=?NULL;?//新進(jìn)來的結(jié)點下一個肯定是空的,所以這里賦值NULL
Q.rear->next?=?p;//連接p節(jié)點,將上一個結(jié)點的next指針指向到最后進(jìn)來的結(jié)點地址(空的隊列上一個結(jié)點就是首結(jié)點,front和rear都指向這里)
Q.rear?=?p;//移動rear指針始終指向尾部,將指向上一個結(jié)點地址的rear移動指向到最后進(jìn)來的結(jié)點
Q.front->data++;
return?OK;
}
看出隊函數(shù):
//出隊,早進(jìn)早出
Status?DeQueue(LinkQueue?&Q,ElemType?&e){
if(Q.rear?==?Q.front){//隊列為空,初始化隊列時兩個指針指向到同一個地址,所以相同的時候就是空隊列
return?ERROR;
}
QueuePtr?p?=?Q.front->next;//跳過頭結(jié)點,頭結(jié)點是存儲隊列長度的,但next指向了最早進(jìn)入隊列的結(jié)點
e?=?p->data;?//實際數(shù)據(jù)
Q.front->next?=?p->next;?//在注銷p結(jié)點之前,應(yīng)該把頭結(jié)點的next指向到p的下一個結(jié)點
if(p?==?Q.rear){//如果除了頭結(jié)點外只有一個節(jié)點,重點來了,Q.rear因為指向的是最后一個結(jié)點地址,這里意思就是如果p是最后一個結(jié)點
Q.rear?=?Q.front;//將Q.rear復(fù)位會首結(jié)點,如果不執(zhí)行這步,free(p)后Q.rear也將不復(fù)存在并成為野指針
}
free(p);
Q.front->data--;
return?OK;
}