資料結構,資料結構與演算法
棧的鏈式儲存
1 棧的鏈式表示
棧的鏈式儲存結構稱為鏈棧,是運算受限的單鏈表。其插入和刪除操作只能在表頭位置上進行。因此,鏈棧沒有必要像單鏈表那樣附加頭結點,棧頂指標top就是鏈表的頭指標。圖3-4是棧的鏈式儲存表示形式。
鏈棧的結點類型說明如下:typedef struct Snode{ ElemType data ;struct Snode *next ;} SNode, *Link_Stack ;
鏈棧基本操作的實現
2 鏈棧基本操作的實現(1) 棧的初始化SNode *Init_Link_Stack(void){ SNode *top ;top=(SNode *)malloc(sizeof(SNode)) ;if(top==NULL) return ERROR;else{ top->next=NULL ; return(top) ;}}
(2) 壓棧(元素進棧)Status push(SNode *top , ElemType e){ SNode *p ;p=(SNode *)malloc(sizeof(SNode)) ; if (!p) return ERROR; /* 申請新結點失敗,返回錯誤標誌 */p->data=e ; p->next=top->next ; top->next=p ; /* 鉤鏈 */return OK;}注意:1、與頭插入法建立鏈表類似 2、此處top結點的資料域不放資料,也可設定成存放資料,程式如何改?
(3) 彈棧(元素出棧)ElemType pop(SNode *top )/* 將棧頂元素出棧 */{ SNode *p ;ElemType e ;if (top->next==NULL )return ERROR ; /* 棧空,返回錯誤標誌 */p=top->next ; e=p->data ; /* 取棧頂元素 */top->next=p->next ; /* 修改棧頂指標 */free(p) ; return OK ;}
輸出棧中元素
void print(SqStack *S){ int c; cout<<"輸出棧中元素"<<endl; for( c=S.top--;c>=0;c--) { cout<<S.bottom[c]<<endl; }}
棧與遞迴調用的實現
棧的另一個重要應用是在程式設計語言中實現遞迴調用。遞迴調用:一個函數(或過程)直接或間接地調用自己本身,簡稱遞迴(Recursive)。遞迴是程式設計中的一個強有力的工具。因為遞迴函式結構清晰,程式易讀,正確性很容易得到證明。為了使遞迴調用不至於無終止地進行下去,實際上有效遞迴調用函數(或過程)應包括兩部分:遞推規則(方法),終止條件。
系統實現遞迴需要一個系統棧 (遞迴工作棧) ,用於在程式運行時處理函數調用。
系統棧是一塊特殊的儲存區。當一個函數被調用時,系統建立一個工作記錄,稱為棧楨(stack frame),並將其置於棧頂。
初始時只包括返回地址和指向上一棧的指標。
當該函數調用另一個函數時,該函數的局部變數、參數將加到它的棧楨中。
一個函數運行結束,將從棧中刪除它的棧楨,程式控制返回原調用函數繼續執行下去。
從被調函數返回調用函數的一般步驟
若棧為空白,則執行正常返回。
否則,從棧頂彈出一個工作記錄,將“工作記錄”中的參數值、局部變數值賦給相應的變數;。
讀取返回地址,將函數值賦給相應的變數。
轉移到返回地址。
遞迴演算法的優缺點
優點
程式非常簡潔而清晰,並且易於分析,可讀性較強。
缺點
費空間:系統實現遞迴需要一個系統棧,用於在程式已耗用時間處理函數調用。
費時:局部變數、形式參數和返回地址的進棧、出棧以及參數的傳遞需要費時,而且遞迴中的重複計算也很浪費時間。