什麼是棧結構
棧結構是從數據的運算來分類的,也就是說棧結構具有特殊的運算規則,即:後進先出。
我們可以把棧理解成一個大倉庫,放在倉庫門口(棧頂)的貨物會優先被取出,然後再取出裏面的貨物。
而從數據的邏輯結構來看,棧結構起始就是一種線性結構。
如果從數據的存儲結構來進一步劃分,棧結構包括兩類:
順序棧結構:
即使用一組地址連續的內存單元依次保存棧中的數據。在程序中,可以定義一個指定大小的結構數組來作爲棧,序號爲0的元素就是棧低,再定義一個變量top保存棧頂的序號即可。
鏈式棧結構:
即使用鏈表的的形式保存棧中各元素的值。鏈表首部(head指針所指向元素)爲棧頂,鏈表尾部(指向地址爲NULL)爲棧底。
在棧結構中只能在一端進行操作,該操作端稱爲棧頂,另一端稱爲棧底。也就是說,保存和取出的數據都只能從棧結構的一端進行。從數據的運算角度來分析,棧結構是按照“後進先出”的原則處理結點數據的。
在棧結構中,只有棧頂元素是可以訪問的,棧結構的數據運算也是非常簡單。一般棧結構的基本操作只有兩個:
入棧(Push):將數據保存到棧頂的操作。進行入棧操作前,先修改棧頂指針,使其向上移一個元素位置,然後將數據保存到棧頂指針所指的位置。
出棧(Pop):將棧頂數據彈出的操作。通過修改棧頂指針,使其指向棧中的下一個元素。
接下來,我們使用C++語言建立順序棧,並完成順序棧結構的基本運算
準備數據
準備在棧操作中需要用到的變量及數據結構等。
#define MAXLEN 50
struct DATA
{
string name;
int age;
};
struct StackType
{
DATA data[MAXLEN+1];
int top;
};
定義棧結構的長度MAXLEN,棧結構的數據元素類型DATA,以及棧結構的數據結構StackType。在數據結構StackType中,data爲數據元素,top爲棧頂的序號。當top=0時,表示棧爲空,當top=MAXLEN時表示棧滿。
數組元素都是充下標0開始的,這裏爲了講述和理解方便,我們從下標1開始記錄數據結點,下標0的位置不用。
初始化棧結構
在使用棧結構之前,首先需要創建一個空的順序棧,也就是初始化順序棧。順序棧的初始化操作如下:
(1)按照符號常量MAXLEN指定大小申請一片內存空間,用來保存棧中的數據
(2)設置棧頂指針的值爲0,表示一個空棧。
示例代碼如下:
StackType *STInit()
{
StackType *p;
if(p=new StackType) //申請棧空間
{
p->top=0; //設置棧頂爲0
return p; //返回棧頂指針
}
return NULL;
}
首先用new申請內存,然後設置棧頂爲0,然後返回申請內存的首地址,申請失敗返回NULL;
判斷空棧
判斷棧結構是否爲空,如果是空棧,則表示該棧結構中沒有數據,此時可以進行入棧操作,但是不可以進行出棧操作。
示例代碼如下:
int STIsEmpty(StackType *s)
{
int t;
t=(s->top==0); //通過棧頂的值進行判斷
return t;
}
輸入參數s爲一個指向操作的棧的指針。根據棧頂指針top判斷是否爲0,判斷棧是否爲空。
判斷滿棧
判斷棧結構是否爲滿。如果是滿棧,則表示該棧結構中沒有多餘的空間來保存額外數據。此時不可以進行入棧操作,但是可以進行進棧操作。
示例代碼如下:
int STIsFull(StackType *s)
{
int t;
t=(s->top==MAXLEN);
return t;
}
輸入參數s爲一個指向操作的棧的指針。根據棧頂指針top判斷是否和MAXLEN相等,判斷棧是否已滿。
清空棧
清空棧就是棧中所有的數據被清除。 示例代碼如下:
void STClear(StackType *s)
{
s->top=0;
}
將棧頂指針top設置爲0,表示執行清空棧操作。(這裏只是邏輯上將棧中數據清空,實際上只是將top設置爲0,以後再添加數據會覆蓋原來的數據)
釋放空間
釋放空間是釋放棧結構所佔用的內存單元,使用delete釋放用new運算符申請的內存空間。
示例代碼如下:
void STFree(StackType *s)
{
delete s;
}
在程序中直接調用delete運算符釋放已分配的內存空間。一般在不需要使用棧結構時調用該函數,特別是在程序結束的時候。
入棧
入棧(Push)是棧結構的基本操作,主要操作是將數據元素保存到棧結構。入棧操作的具體步驟如下:
(1)首先判斷棧頂top,如果top大於等於MAXLEN,則表示溢出,進行出錯處理。否則執行以下操作。
(2)設置top=top+1(棧頂指針加1,指向入棧地址)
(3)將入棧呀U尿素保存到top指向的位置。
示例代碼如下:
int PushST(StackType *s,DATA data)
{
if((s->top+1)>MAXLEN)
{
cout<<"棧溢出"<<endl;
return 0;
}
s->data[++s->top]=data; //將元素壓入棧
return 1;
}
輸入參數s爲一個指向操作的棧的指針,輸入參數data是需要入棧的數據元素。程序首先判斷棧是否溢出,如果溢出就給出警告,不進行入棧操作,否則修改棧頂指針,即top先加1,然後將data放到top現在指向的數據單元。
出棧
出棧(Pop)是佔據誒狗的基本操作,主要操作與入棧相反,它是從棧頂彈出一個數據元素,出棧操作的具體步驟如下:
(1)首先判斷棧頂top,如果top等於0,則表示爲恐慌在哪,進行出錯處理。否則執行下面的操作。
(2)將棧頂指針top所指向的位置的元素返回(實際是返回的指針)
(3)將top的減1,指向棧的下一個元素,原來棧頂的元素被彈出。
DATA * PopST(StackType *s)
{
if(s->top==0)
{
cout<<"棧爲空,不能再輸出!"<<endl;
exit(0);
}
return &(s->data[s->top--]);
}
當棧中有數據時,該函數返回值是一個指向DATA類型數據的指針。
讀取點結構
讀取點結構也就是讀取棧結構中結點的數據。由於棧結構只能在一端進行操作,因此這裏的讀操作其實就是讀站點的數據。
需要注意的是,讀節點數據的操作和出棧操作不同。讀結點操作僅僅是顯示棧頂結點數據的內容,而出棧操作則將棧頂數據彈出。
示例代碼如下:
DATA *PeekST(StackType *s)
{
if(s->top==0)
{
cout<<"棧已空"<<endl;
exit(0);
}
return &(s->data[s->top]);
}
對比出棧的示例代碼,不難發現讀取點結構同樣返回了棧頂結點的地址,但是卻沒有使top減1.
完整示例
下面是棧的基本操作的完整示例:
程序代碼:
#include<iostream>
#include<string>
using namespace std;
#define MAXLEN 50
struct DATA
{
string name;
int age;
};
struct StackType
{
DATA data[MAXLEN+1];
int top;
};
/******************初始化棧結構****************/
StackType *STInit()
{
StackType *p;
if(p=new StackType) //申請棧空間
{
p->top=0; //設置棧頂爲0
return p; //返回棧頂指針
}
return NULL;
}
/****************判斷空棧**********************/
int STIsEmpty(StackType *s)
{
int t;
t=(s->top==0); //通過棧頂的值進行判斷
return t;
}
/**********************判斷滿棧****************/
int STIsFull(StackType *s)
{
int t;
t=(s->top==MAXLEN);
return t;
}
/**********************清空棧**********************/
void STClear(StackType *s)
{
s->top=0;
}
/********************釋放空間********************/
void STFree(StackType *s)
{
delete s;
}
/**********************入棧***********************/
int PushST(StackType *s,DATA data)
{
if((s->top+1)>MAXLEN)
{
cout<<"棧溢出"<<endl;
return 0;
}
s->data[++s->top]=data; //將元素壓入棧
return 1;
}
/************************出棧***********************/
DATA * PopST(StackType *s)
{
if(s->top==0)
{
cout<<"棧爲空,不能再輸出!"<<endl;
exit(0);
}
return &(s->data[s->top--]);
}
/**********************讀取點結構*******************/
DATA *PeekST(StackType *s)
{
if(s->top==0)
{
cout<<"棧已空"<<endl;
exit(0);
}
return &(s->data[s->top]);
}
/*****************進入主函數**********************/
int main()
{
StackType *stack;
DATA data,*p_data;
stack=STInit();
cout<<"===============入棧操作:============="<<endl;
cout<<"輸入姓名 ,年齡進行入棧操作:"<<endl;
//執行入棧操作
while(1)
{
cin>>data.name>>data.age;
if(data.name=="0")
{
break; //當姓名和年齡都是0的時候退出輸入
}else
{
PushST(stack,data);
}
}
p_data=PopST(stack);
cout<<"彈出棧頂元素"<<endl;
cout<<"name:"<<p_data->name<<",age:"<<p_data->age<<endl;
p_data=PeekST(stack);
cout<<"輸出棧頂元素"<<endl;
cout<<"name:"<<p_data->name<<",age:"<<p_data->age<<endl;
cout<<"================將所有的的數據出棧:============="<<endl;
while(1)
{
p_data=PopST(stack);
cout<<"name:"<<p_data->name<<",age:"<<p_data->age<<endl;
}
STFree(stack);
return 0;
}
程序運行界面: