C語言棧與隊列相互實現(xiàn)詳解
一、本章重點
- 用兩個隊列實現(xiàn)棧
- 用兩個棧實現(xiàn)隊列
- 解題思路總結(jié)
二、隊列實現(xiàn)棧

我們有兩個隊列:

入棧數(shù)據(jù)1、 2、 3
可以將數(shù)據(jù)入隊列至隊列一或者隊列二。

如何出棧?
但出棧要先出1,怎么辦?
第一步:
將隊列一出隊n-1個至隊列二。

第二步:
pop隊列一的最后一個元素。

接下來怎么入棧呢?
將元素入隊至不為空的隊列。
怎么判斷????
隊列一和隊列二都為空的情況下,棧就是空的。
如何取棧頂元素?
取不為空的隊列尾部元素。
總的來說就是,入棧時就將數(shù)據(jù)插入不為空的隊列,出棧就將不為空的隊列的前n-1個數(shù)據(jù)導入至另一個隊列,然后pop最后一個元素。
代碼實現(xiàn):
首先我們要構(gòu)造一個棧。
這個棧要包含兩個隊列
typedef struct
{
Queue q1;
Queue q2;
} MyStack;在此之前我們要準備好隊列的一般接口:
我這里的隊列是用單鏈表來構(gòu)建的,具體接口實現(xiàn)可以看我之前的文章。
typedef int QTypeData;
typedef struct QueueNode
{
struct QueueNode* next;
QTypeData val;
}QN;
void QueueInit(Queue* pq)//初始化隊列
size_t QueueSize(Queue* pq)//求隊列元素個數(shù)
int QueueBack(Queue* pq)//取隊列尾部數(shù)據(jù)
void QueuePush(Queue* pq, QTypeData x)//將x入隊
void QueuePop(Queue* pq)//出隊
void QueueDestroy(Queue* pq)//結(jié)束隊列我們要用隊列實現(xiàn)棧的接口:
- 第一個接口:創(chuàng)建并初始化棧
接口一:MyStack* myStackCreate()
這樣做行嗎?
MyStack* myStackCreate()
{
MyStack ms;
QueueInit(&ms.q1);
QueueInit(&ms.q2);
return ms;
}很顯然,返回局部變量的地址是不明智的,因為在函數(shù)返回時,ms開辟的空間會重新交給操作系統(tǒng),再次訪問就是非法操作。
因此我們需要將ms開辟在堆區(qū)。
參考代碼:
- 第二個接口:入棧
接口二:void myStackPush(MyStack* obj, int x)
入棧簡單:只要將數(shù)據(jù)插入到不為空的隊列即可。
入棧之前我們需要判斷隊列滿嗎?
不需要,因為我的隊列是用單鏈表實現(xiàn)的,可以無限鏈接下去。
如果兩個隊列都為空,該插入到哪個隊列呢?
我們可以這樣做,如果隊列1為空,就插入到隊列2,如果不為空,就插入到隊列1.
參考代碼:
- 第三個接口:出棧
接口三:int myStackPop(MyStack* obj) //出棧
再次回顧一下我們是如何出棧的。
首先我們有兩個隊列
初始狀態(tài)它們都是空的
隊列一:空
隊列二:空
入棧1、2、3、4
執(zhí)行后
隊列一:空
隊列二:1、2、3、4
出隊列只能先出1,如何出4呢?
把1、2、3先出給隊列一
執(zhí)行后
隊列一:1、2、3
隊列二:4
然后將4用變量記錄并出隊,最后返回記錄4的變量。
執(zhí)行后
隊列一:1、2、3
隊列二:空。
出隊三板斧
第一步:即將不為空的隊列的前n-1個元素入至為空的隊列。
第二步:將剩下的1個元素用變量記錄,然后將最后一個元素出隊。
第三步:返回用變量記錄的元素。
需要注意的是:如果棧為空,那么就返回false。
參考代碼:
- 第四個接口:取棧頂元素
接口四:int myStackTop(MyStack* obj) //取棧頂元素
取棧頂元素之前我們需要保證棧不為空
如果棧為空,返回false。
取棧頂元素,即取不為空的隊列的隊尾元素。
參考代碼:
- 第五個接口:判斷棧是否為空
接口五:bool myStackEmpty(MyStack* obj) //判斷棧是否為空
如果兩個隊列都是空的那么該棧就是空的。
這里多提一下,棧的元素個數(shù)怎么求?
棧的元素個數(shù)就是那個不為空隊列的元素個數(shù)。
參考代碼:
- 第六個接口:銷毀棧
接口六:void myStackFree(MyStack* obj) //結(jié)束棧
參考代碼:
void myStackFree(MyStack* obj)
{
QueueDestroy(&obj->q1);
QueueDestroy(&obj->q2);
free(obj);
}最后需要注意的是:調(diào)用棧為空的接口時,要先聲明??!
三、棧實現(xiàn)隊列

第一次入隊

將數(shù)據(jù)1出隊操作
將棧1的數(shù)據(jù)全導入棧2

然后棧2進行出棧操作

再次入隊5、6、7
直接將5、6、7入棧至棧1

實際我們的對頭和隊尾是這樣的

總的來說:
用兩個棧實現(xiàn)一個隊列,就得把一個棧專門入隊,另一個棧用作出隊。這里實現(xiàn)的時候我們用棧1做入隊棧,棧2做出隊棧。
也就是說,只要將數(shù)據(jù)入隊,直接放入棧1.
出隊就直接出棧2的數(shù)據(jù),如果棧2為空,這將棧1的數(shù)據(jù)全部導入棧2.
隊列的結(jié)構(gòu)體:
typedef struct
{
ST st1;
ST st2;
} MyQueue;我們需要準備的棧
typedef int STDataType;
typedef struct Stack
{
STDataType* data;
int top;
int capacity;
}ST;這里我用的是動態(tài)數(shù)組實現(xiàn)的棧
需要提前準備棧的接口:
void STInit(ST* p) void STDestroy(ST* p) void STPush(ST* p,STDataType x) void STPop(ST* p) bool STEmpty(ST* p) int STSize(ST* p) STDataType STRear(ST* p)
- 第一個接口:創(chuàng)建并初始化隊列
MyQueue* myQueueCreate()
同樣的,需要把隊列開辟在堆區(qū),同時對棧1和棧2進行初始化。
參考代碼:
MyQueue* myQueueCreate()
{
MyQueue* mq=(MyQueue*)malloc(sizeof(MyQueue));
assert(mq);
STInit(&mq->st1);
STInit(&mq->st2);
return mq;
}- 第二個接口:入隊
void myQueuePush(MyQueue* obj, int x)
我們把棧1做入隊棧,棧2做出隊棧。
也就是說,只要將數(shù)據(jù)入隊,直接放入棧1.
出隊就直接出棧2的數(shù)據(jù),如果棧2為空,這將棧1的數(shù)據(jù)全部導入棧2.
參考代碼:
void myQueuePush(MyQueue* obj, int x)
{
STPush(&obj->st1,x);
}- 第三個接口:出隊
int myQueuePop(MyQueue* obj)
先要判斷隊列是否為空,如果隊列為空則返回false。
其次如果棧2為空,就將棧1的數(shù)據(jù)全導入棧2.
參考代碼:
int myQueuePop(MyQueue* obj)
{
if(myQueueEmpty(obj))
{
return false;
}
if(STEmpty(&obj->st2))
{
int n=STSize(&obj->st1);
while(n--)
{
STPush(&obj->st2,STRear(&obj->st1));
STPop(&obj->st1);
}
}
int ret=STRear(&obj->st2);
STPop(&obj->st2);
return ret;
}第四個接口:取隊頭元素
int myQueuePeek(MyQueue* obj)
取隊頭元素之前,要判斷隊列是否為空,如果為空,則返回false
隊頭元素即棧2的尾部元素。

但如果棧2為空呢?
那隊列的隊頭元素就是棧1的頭部元素。
參考代碼:
int myQueuePeek(MyQueue* obj)
{
if(myQueueEmpty(obj))
{
return false;
}
if(STEmpty(&obj->st2))
{
return STFront(&obj->st1);
}
return STRear(&obj->st2);
}第五個接口:判斷隊列是否為空
bool myQueueEmpty(MyQueue* obj)
隊列為空,需要棧1和棧2都為空。
參考代碼:
bool myQueueEmpty(MyQueue* obj)
{
return STEmpty(&obj->st1) && STEmpty(&obj->st2);
}第六個接口:銷毀隊列
void myQueueFree(MyQueue* obj)
參考代碼:
void myQueueFree(MyQueue* obj)
{
STDestroy(&obj->st1);
STDestroy(&obj->st2);
free(obj);
}注意:當使用判斷隊列是否為空的接口時,注意是否在之前聲明過了。
四、解題思路總結(jié)
1.用隊列實現(xiàn)棧:
我們需要用兩個隊列實現(xiàn)棧
棧類是于尾插尾刪
隊列是尾插頭刪
第一次入棧:兩個隊列都為空,隨便插入一個隊列都可
第一次出棧:出棧要出的是尾部數(shù)據(jù),隊列只能出頭部數(shù)據(jù),這是隊列不能直接實現(xiàn)的。
那么需要將不為空的隊列前n-1個數(shù)據(jù)導入至為空的隊列,再將最后一個元素pop掉。
隊列一:1、2、3、4
隊列二:空
那么導入后
隊列一:4
隊列二:1、2、3
最后pop最后一個元素
隊列一:空
隊列二:1、2、3、4
再次尾插:尾插至不為空的隊列即可。
2.用棧實現(xiàn)隊列
我們有兩個棧要求實現(xiàn)隊列的一般接口
棧一:空
棧二:空
第一次入隊:入棧至棧一或者棧二都可,這里選擇棧一。
假設入隊1、2、3、4
棧一:1、2、3、4
棧二:空
出隊:要先出1
將棧一全部導入棧二
棧一:空
棧二:4、3、2、1
之后入隊就插入至棧一
出隊就pop棧二。

到此這篇關(guān)于C語言棧與隊列相互實現(xiàn)詳解的文章就介紹到這了,更多相關(guān)C語言 棧與隊列內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
C語言數(shù)組實現(xiàn)公交車管理系統(tǒng)
這篇文章主要介紹了C語言數(shù)組實現(xiàn)公交車管理系統(tǒng),文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下2019-12-12
淺談返回函數(shù)內(nèi)部new分配的內(nèi)存的引用
下面小編就為大家?guī)硪黄獪\談返回函數(shù)內(nèi)部new分配的內(nèi)存的引用。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2016-12-12

