棧是這樣一種數據結構,越先存入棧中的數據,越後從棧中移除。後進者先出,先進者後出,這就是典型的棧結構。
當某個數據集合只涉及在一段插入和刪除數據,且滿足後進先出、先進後出的特性,應該首選棧這種數據結構。
棧的實現
棧可以用鏈表和數組實現,用數組實現的叫做順序棧,用鏈表實現的叫做鏈式棧。下面是我用數組實現的可以動態擴容的順序棧
/*
* 支持動態擴容的棧
*/
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
@interface Stack : NSObject
- (void)push:(NSString *)value;
- (NSString *)pop;
@end
NS_ASSUME_NONNULL_END
#import "Stack.h"
@interface Stack ()
{
NSMutableArray *_stackArray;
NSInteger _capacity;
}
@end
@implementation Stack
- (instancetype)init {
if (self = [super init]) {
_capacity = 8;
_stackArray = [NSMutableArray arrayWithCapacity:_capacity];
}
return self;
}
- (void)push:(NSString *)value{
if (_stackArray.count >= _capacity) {
_capacity = 2*_capacity;
NSMutableArray *expandArray = [NSMutableArray arrayWithCapacity:_capacity];
[expandArray addObjectsFromArray:_stackArray];
_stackArray = expandArray.mutableCopy;
NSLog(@"expand stack");
}
[_stackArray addObject:value];
}
- (NSString *)pop {
if (_stackArray.count == 0) {
return nil;
}else{
NSString *popStr = _stackArray.lastObject;
[_stackArray removeLastObject];
return popStr;
}
}
@end
棧的應用
棧作爲一個基礎數據結構應用場景很多
-
函數調用棧
操作系統給每個線程分配一塊獨立的內存空間,這塊內存被組織成棧這種結構,用來存儲函數調用的臨時變量。每進入一個函數,就會將臨時變量作爲一個棧幀入棧,函數執行完畢將函數對應的棧幀出棧。
棧在表達式求值中的應用
通過兩個棧實現表達式求值,一個保存操作數的棧,另一個保存運算符的棧。從左向右遍歷表達式,數字壓入操作數棧,遇到運算符,與運算符棧的棧頂元素比較優先級,如果比棧頂元素優先級高,就將當前運算符壓入棧。如果比棧頂元素優先級低或相等,從運算符棧取棧頂運算符,從操作數棧棧頂去連個操作數進行計算,再把計算完的結果壓入棧,繼續比較。如下圖
-
瀏覽器前進後退功能
使用兩個棧X和Y,將首次瀏覽的頁面依次壓入棧X,點擊後退按鈕時,依次從棧X中出棧並將出棧數據依次壓入棧Y。點擊前進按鈕時,依次從棧Y中取出數據壓入棧X中。當棧X沒有數據時,說明頁面可以後退瀏覽了。當棧Y沒有數據,說明沒有頁面可以前進瀏覽了。