棧的原理與應用
大家學習資料結構的目的是為了更好的處理和儲存資料,對於順序表而言改查比較容易,增刪比較麻煩,對於鏈式表而言,增刪比較簡單,改查比較麻煩,所以每種資料結構都有不同的特點,使用者需要選擇合適的資料結構。
linux記憶體分割槽,棧記憶體自頂向下進行遞增,其實棧和順序表以及鏈式表都一樣,都屬於線性結構,儲存的資料的邏輯關係也是一對一的。
只不過棧是一種特殊的線性表,特殊在棧的一端是封閉的,資料的插入與刪除只能在棧的另一端進行,也就是棧遵循“*後進先出*”的原則。也被成為“LIFO”結構,意思是“last input first output”。
棧(stack),儲存貨物或供旅客住宿的地方,可引申為倉庫、中轉站,所以引入到計算機領域裡,就是指資料暫時儲存的地方,所以才有進棧(PUSH)、出棧(POP)的說法。
棧就像是一摞書,拿到新書時我們會把它放在書堆的最上面,取書時也只能從最上面的新書開始取。
閉合的一端被稱為棧底(Stack Bottom),允許資料的插入與刪除的一端被稱為棧頂(Stack Top),不包含任何元素的棧被稱為空棧。把資料插入到棧空間的動作被稱為入棧或者壓棧
l 從棧空間中刪除資料的動作被稱為出棧或者彈棧
由於棧也是一種線性結構,所以可以以陣列或者連結串列作為基礎,在此基礎上實現棧的操作。
- 以陣列作為基礎實現棧空間(順序棧)
陣列在記憶體中佔用一塊連續的空間,也就是陣列元素的記憶體地址是連續的。為了實現棧,一般是把陣列頭作為棧底,陣列頭部到陣列尾部作為棧的增長方向,也就是使用者只在陣列尾部對資料進行插入和刪除。
//指的是順序棧中的元素的資料型別,使用者可以根據需要進行修改
typedef int DataType_t;
//構造記錄順序棧SequenceStack各項引數(棧底地址+棧容量+棧頂元素的下標)的結構體
typedef struct SequenceStack
{
DataType_t * Bottom; //記錄棧底地址
unsigned int Size; //記錄棧容量
int Top; //記錄棧頂元素的下標
}SeqStack_t;
(1) 建立一個空的順序棧,併為記錄順序棧資訊的結構體申請堆記憶體,並進行初始化即可!
/**
* @function name :SeqStack_Create
* @brief :建立順序表並對順序棧進行初始化
* @param :unsigned int size
* @retval :SeqStack_t結構體指標
* @date :2024/04/25
* @version 1.0 :V1.0
* @note :None
*/
//建立順序表並對順序棧進行初始化 為了方便管理順序棧所以需要構造管理順序棧資訊的結構體型別,用於記錄重要引數
SeqStack_t * SeqStack_Create(unsigned int size)
{
//1.利用calloc為順序棧的管理結構體申請一塊堆記憶體
SeqStack_t *Manager = (SeqStack_t *)calloc(1,sizeof(SeqStack_t));
if(NULL == Manager)
{
perror("calloc memory for manager is failed");
exit(-1); //程式異常終止
}
//2.利用calloc為所有元素申請堆記憶體
Manager->Bottom = (DataType_t *)calloc(size,sizeof(DataType_t));
if (NULL == Manager->Bottom)
{
perror("calloc memory for Stack is failed");
free(Manager);
exit(-1); //程式異常終止
}
//3.對管理順序棧的結構體進行初始化(元素容量 + 最後元素下標)
Manager->Size = size; //對順序棧中的容量進行初始化
Manager->Top = -1; //由於順序棧為空,則棧頂元素的下標初值為-1
return Manager;
}
(2)判斷順序棧是否為已滿
/**
* @function name :SeqStack_IsFull
* @brief :判斷順序棧是否已滿
* @param :SeqStack_t *Manager
* @retval :布林型別
* @date :2024/04/25
* @version 1.0 :V1.0
* @note :None
*/
//判斷順序棧是否已滿
bool SeqStack_IsFull(SeqStack_t *Manager)
{
return (Manager->Top + 1 == Manager->Size) ? true : false;
}
(3)根據棧的特性,把新元素從棧頂入棧,也就是從陣列的尾部進行元素插入
/**
* @function name :SeqStack_Push
* @brief :壓棧(push)
* @param :SeqStack_t *Manager, DataType_t Data
* @retval :布林型別
* @date :2024/04/25
* @version 1.0 :V1.0
* @note :None
*/
//入棧
bool SeqStack_Push(SeqStack_t *Manager, DataType_t Data)
{
//1.判斷順序棧是否已滿
if ( SeqStack_IsFull(Manager) )
{
printf("SeqStack Full is Full!\n");
return false;
}
//2.如果順序棧有空閒空間,則把新元素新增到順序棧的棧頂
Manager->Bottom[++Manager->Top] = Data;
return true;
}
(4)判斷順序棧是否為空
/**
* @function name :SeqStack_IsEmpty
* @brief :判斷順序棧是否為空
* @param :SeqStack_t *Manager
* @retval :布林型別
* @date :2024/04/25
* @version 1.0 :V1.0
* @note :None
*/
//判斷順序棧是否為空
bool SeqStack_IsEmpty(SeqStack_t *Manager)
{
return (-1 == Manager->Top) ? true : false;
}
(5)根據棧的特性,把元素從棧頂出棧,也就是把元素從陣列的尾部把元素刪除
//出棧
DataType_t SeqStack_Pop(SeqStack_t *Manager)
{
DataType_t temp = 0; //用於儲存出棧元素的值
//1.判斷順序棧是否為空
if ( SeqStack_IsEmpty(Manager) )
{
printf("SeqStack is Empty!\n");
return;
}
//2.由於刪除了一個元素,則需要讓順序棧的棧頂元素下標-1
temp = Manager->Bottom[Manager->Top--];
return temp;
}
(6)遍歷順序棧的元素
/**
* @function name SeqStack_Print
* @brief :遍歷順序棧
* @param :SeqStack_t *Manager
* @retval :None
* @date :2024/04/25
* @version 1.0 :V1.0
* @note :None
*/
//遍歷順序棧的元素
void SeqStack_Print(SeqStack_t *Manager)
{
for (int i = 0; i <= Manager->Top; ++i)
{
printf(" Stack Element[%d] = %d\n",i,Manager->Bottom[i]);
}
}