1. 程式人生 > >棧及棧的鏈式儲存結構(棧鏈)

棧及棧的鏈式儲存結構(棧鏈)

棧:線性結構,後進先出。棧(Stack)是一種特殊的線性表(順序表,連結串列)只在表尾進行刪除和插入操作。

注意:對於棧來說,表尾稱為棧的棧頂(top),表頭稱為棧底(bottom)。

棧也是線性結構的一種特例。與佇列不同,他只有一個口,只能從這裡讀或者寫資料,這個口稱為棧頂(top)。棧是一種先進後出的資料結構。先進來的元素會放入棧底,而後進來的元素被放在它的上面,最後進來的元素的上面的位置,稱為棧頂。棧所提供的操作比一般的線性表要少很多,只提供:初始化、銷燬、判斷是否為空、求棧的長度、清空棧、將資料壓入棧、將資料彈出棧、得棧頂元素這幾種操作。其中將資料壓入棧、將資料彈出棧、獲得棧頂元素

是最重要的。有人可能覺得,將棧頂元素彈出與獲得棧頂元素是不是有點重複,其實它們主要的目的在於,很多時候你只想知道當前棧頂的元素是誰,而並不想將它彈出。這樣做可以簡單一點。瞭解了棧的基本結構和操作以後,自然而然的想到用陣列來實現棧:因為前面的元素並不發生變化,只能在最後面入棧或者出棧。

因為棧的本質是一個線性表,線性表有兩種儲存形式,那麼棧也有分為棧的順序儲存結構和棧的鏈式儲存結構。

最開始棧中不含有任何資料,叫做空棧,此時棧頂就是棧底。然後資料從棧頂進入,棧頂棧底分離,整個棧的當前容量變大。資料出棧時從棧頂彈出,棧頂下移,整個棧的當前容量變小。

棧頂——地址較高;

棧底——地址較低。

定義一個順序儲存的棧,包含三個元素:base、top、stackSize。

typedef struct{
ElemType *base;//棧底
ElemType *top;//棧頂
int stackSize;//棧的當前可使用的最大容量
}sqStack;

或者:

typedef int ElemType;
 typedef struct{
ElemType data[MAXSIZE];
int top;	// 用於標註棧頂的位置
int stackSize;
}
其中base是指棧底的指標變數,top是指棧頂的指標變數,stackSize指棧的當前可使用的最大容量。

建立一個棧:

#define STACK_INIT_SIZE 100
 
initStack(sqStack *s){
s->base = (ElemType *)malloc( STACK_INIT_SIZE * sizeof(ElemType) );
if( !s->base )
exit(0);
 
s->top = s->base;   // 最開始,棧頂就是棧底
s->stackSize = STACK_INIT_SIZE;
}

入棧操作:

入棧操作又叫壓棧操作,就是向棧中存放資料。

入棧操作要在棧頂進行,每次向棧中壓入一個數據,top指標就要+1,直到棧滿為止。

出棧操作:

出棧操作就是在棧頂取出資料,棧頂指標隨之下移的操作。

每當從棧內彈出一個數據,棧的當前容量就-1。

入棧時,先將值壓入棧中,再改變指標top,即將top指標加1;

出棧時,先將top指標減去1,然後再將top指標指向的值從棧中取出;

注意:top指標在開始時指向的位置其實就是將要存放資料的位置,因此它指向的區域是空的,想要將資料從棧中取出,需要首先將top指標指向該位置。

Pop(sqStack *s, ElemType *e){
if( s->top == s->base )  // 棧為空
return;
*e = *--(s->top);
}

棧的其它操作:清空、銷燬、計算棧的當前容量等。

1、清空:清空一個棧,就是將棧中的元素全部作廢,但棧本身物理空間並不發生改變(不是銷燬)。

因此我們只要將s->top的內容賦值為s->base即可,這樣s->base等於s->top,也就表明這個棧是空的了。

這個原理跟高階格式化只是但單純地清空檔案列表而沒有覆蓋硬碟的原理是一樣的。

ClearStack(sqStack*s){
s->top= s->base;
}
2、銷燬一個棧

銷燬一個棧與清空一個棧不同,銷燬一個棧是要釋放掉該棧所佔據的實體記憶體空間,因此不要把銷燬一個棧與清空一個棧這兩種操作混淆。

DestroyStack(sqStack *s){
int i, len; 
len = s->stackSize;
 
for( i=0; i < len; i++ )
{
free( s->base );
s->base++;
}
 
s->base = s->top = NULL;
s->stackSize = 0;
}
3、計算棧的當前容量

計算棧的當前容量也就是計算棧中元素的個數,因此只要返回s.top-s.base即可。

注意,棧的最大容量是指該棧佔據記憶體空間的大小,其值是s.stackSize,它與棧的當前容量不是一個概念哦。

int StackLen(sqStack s){
return(s.top – s.base);
//兩個地址相減,返回的是存放在該地址的資料的個數
}
(指標的數學計算:++、--、相減,但是指標不能相加!) 

棧的鏈式儲存結構(棧鏈)

棧因為只是棧頂來做插入和刪除操作,所以比較好的方法就是將棧頂放在單鏈表的頭部,棧頂指標和單鏈表的頭指標合二為一。


//棧的鏈式儲存結構(棧鏈)
teypedef struct StackNode
{
	ElemType data;		// 存放棧的資料
	struct StackNode *next;
} StackNode, *LinkStackPtr;

teypedef struct LinkStack
{
	LinkStackPrt top;	// top指標
	int count;	  // 棧元素計數器
}
//對於棧鏈的Push操作,假設元素值為e的新結點是s,top為棧頂指標
Status Push(LinkStack *s, ElemType e){
	LinkStackPtr p = (LinkStackPtr) malloc (sizeof(StackNode));
	p->data = e;
	p->next = s->top;
	s->top = p;
	s->count++;
	return OK;
}
//鏈棧的出棧Pop操作,假設變數p用來儲存要刪除的棧頂結點,將棧頂指標下移一位,最後釋放p即可。
Status Pop(LinkStack *s, ElemType *e){
	LinkStackPtr p;
	if( StackEmpty(*s) )  // 判斷是否為空棧
		return ERROR;
 
	*e = s->top->data;
	p = s->top;
	s->top = s->top->next;
	free(p);
	s->count--; 
	return OK;
}