數據結構中的棧

在剛學習完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;
	}
}

以上就是數據結構中棧的基本操作。雖說結構不復雜,但是牽扯到二級指針問題,什麼時候用一級指針什麼時候用二級指針,所以還是有點苒,所以千萬別混淆概念,否則你就要一步一步調試,超級痛苦的,寫代碼之前先理清楚思路。好了,今天就到這啦,覺得小編寫的還不錯的別忘了點贊哦!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章