在剛學習完C語言後,我設計了個程序實現10進制向n進制轉換,我發現只能將其最終結果逆序輸出。想正序輸出一直沒有實現。但是當我瞭解到了棧結構的時候豁然開朗。什麼是棧結構?我的理解就是它就像是一個沒蓋子的瓶子,只能從一端進出。所以就有了先進去的後出來,後進去的先出來的說法。
棧 分爲 順序棧 和 鏈棧:
1. 順序棧
和順序表一樣,這個線性結構實質上就是一段線型空間。只不過對這段線性空間進行了限制,而且多了些修飾這段空間的指針。
首先來看一個順序棧應該包含哪些內容
typedef struct SeqStack
{
int top; //記錄棧頂下標
int* base;//指向棧底的指針
int capacity;//當前已經分配的存儲空間
}SeqStack;
順序棧的初始化
void SeqStackInit(SeqStack* pst,int sz)//sz是你要申請空間的大小
{
pst->capacity = sz > SeqStack_Dafult_Size ? sz:SeqStack_Dafult_Size;
pst->base = (int*)malloc(sizeof(SeqStack)*pst->capacity);
pst->top = 0;
}
還有種初始化的方法就是可以減少一個參數
SeqStack* SeqStackCreate(int sz)//創建鏈表方法2
{
SeqStack* pst = (SeqStack*)malloc(sizeof(SeqStack));//先讓pst指向一個順序棧
pst->capacity = sz > SeqStack_Dafult_Size ? sz : SeqStack_Dafult_Size;
pst->base = (int*)malloc(sizeof(pst->capacity)*pst->capacity);
pst->top = 0;
return pst;
這裏面有個問題就是top初始值的問題,在人民郵電版本和清華大學的數據結構教材中top初始值均爲-1,我們這裏採取0;
區別:
在放入元素的時候初始值爲0的情況先放入元素,後指針後移,
top初始值爲-1的情況先指針後移,再放入元素。
出棧,原來的棧頂元素被刪掉,由下一個頂替。 取棧頂元素,只是獲取棧頂元素的值,不刪除該元素
接下來我們來看棧中最常見的操作,取棧頂元素
int SeqStackTop(SeqStack* pst)
{
if (SeqStackIsEmpty(pst))
{
printf("棧爲空,無法取棧頂元素");
return;
}
return pst->base[pst->top - 1];
}
下面再看插入元素
void SeqStackPush(SeqStack *pst, DataType x)
{
if(SeqStackFull(pst))
{
printf("棧已滿,%d 不能入棧.\n", x);
return;
}
pst->base[pst->top++] = x;
}
刪除元素
void SeqStackPop(SeqStack* pst)
{
if (SeqStackIsEmpty(pst))
printf("棧空間已空,不能繼續刪除");
pst->top--;
}
展示
void SeqStackShow(SeqStack* pst)
{
for (int i = pst->top - 1; i > 0; i--)
{
printf("%d ", pst->base[i]);
}
}
銷燬
void SeqStackDestroy(SeqStack* pst)
{
free(pst);
free(pst->base);
}
需要強調的是銷燬棧空間,不但要銷燬這個空間,還要銷燬指向這個空間的指針,這就是爲什麼看到2次free。
這樣,一個完整的順序棧就操作完成
接下來我們來看鏈棧
鏈棧 實際上就是鏈表加了些限定條件,但是少了很多限制(比如說鏈棧不存在棧滿問題)反而比起鏈表還簡單了一些,但是鏈棧也有很多難點,比如說怎麼搭建框架。棧的數據結構操作起來相對鏈表來說比較簡單,但是搭建棧實現棧的思想比較複雜(經常會用到二級指針),我們一起來看。
我們在創建鏈表的時候經常創建指向節點的指針,棧是要用到指向鏈表的指針,即指向節點指針的指針。也就是二級指針。
這裏補充一個小知識點:指針
int a = 5;
int* p;
*p = &a;
通過簡單的代碼監視有無*的區別,
可以看到p是a的地址,而p有自己的地址,p的地址類型就會變成int**類型,但是* p的類型是int 類型。所以,到底加不加 (星號)取決於你要進行的操作,不要混爲一談。
再補充一點 運算符優先級
這幾個運算符優先級別非常高,所以要進行操作時注意什麼時候打括號,否則會出現很多問題。
首先來看棧的初始化
void ListStackInit(ListStack *pst)
{
*pst = NULL;//初始化將棧賦空
}
我們來看鏈棧最複雜的部分 插入
插入的時候由於鏈棧的限制只能是頭插
void ListStackPush(ListStack* pst, int x)
{
StackNode* node = (StackNode*)malloc(sizeof(StackNode));
assert(node);
node->data = x;
node->next = *pst;//結點連接棧
*pst = node;
}
鏈棧刪除棧頂
void ListStackPop(ListStack* pst)
{
ListStack P = (*pst);//
*pst = (*pst)->next;
free(P);
}
鏈棧取棧頂元素
int ListStackTop(ListStack *pst)
{
assert(*pst == NULL);
return false;
return(*pst)->data;
}
鏈棧展示函數
void ListStackShow(ListStack pst)
{
StackNode* p = pst;
while (p != NULL)
{
printf("%d ",p->data);
p = p->next;
}
}
以上就是數據結構中棧的基本操作。雖說結構不復雜,但是牽扯到二級指針問題,什麼時候用一級指針什麼時候用二級指針,所以還是有點苒,所以千萬別混淆概念,否則你就要一步一步調試,超級痛苦的,寫代碼之前先理清楚思路。好了,今天就到這啦,覺得小編寫的還不錯的別忘了點贊哦!