栈的特点
- 先进后出
- 栈的相关操作都是通过栈顶位置进行相关操作的
栈的接口抽象
栈可以通过线性表
直接实现(链表、数组
等线性表),由于栈有着先进后出的特点,同时关于栈的操作都集中在栈顶
位置,所以基础的栈接口有这以下几个:
//入栈
func push(element: E)
//出栈
func pop()
//栈容量
func size() -> Int?
//是否为空
func isEmpty() -> Bool
//栈顶元素
func top() -> E?
栈的实现
由于线性表的基本功能已经能够满足栈的基本操作,所以可以对基础的线性表进行 再封装
来实现栈的相关功能。有两种方案可供选择:
-
继承线性表
实现相关的栈的功能 - 通过
对象组合
的形式实现栈的功能
第一种通过继承的方式实现栈的功能是有缺陷的,因为会将栈中不存在的功能通过继承加到了栈中,会造成一定的接口干扰
。由此可见,使用第二种较为合适。
struct Stack<E: Equatable> : CustomStringConvertible {
var description: String {
get {
var mutatingSelf = self
return mutatingSelf.list?.description ?? ""
}
}
var defaultArrayType: E
lazy var list: DynamicArray<E>? = {
DynamicArray<E>(defaultValue: defaultArrayType)
}()
init(arrayDefault: E) {
self.defaultArrayType = arrayDefault
}
mutating func push(element: E) {
list?.add(element: element)
}
mutating func pop() {
if let size = list?.size() {
list?.remove(index: size - 1)
}
}
mutating func size() -> Int? {
list?.size()
}
mutating func isEmpty() -> Bool {
list?.isEmpty() ?? false
}
mutating func top() -> E? {
if let size = list?.size() {
return size > 0 ? list?[size - 1] : nil
}
return nil
}
}
栈的练习
题目:
给定一个只包括'(',')','{','}','[',']'
的字符串 s ,判断字符串是否有效。
有效字符串需满足:
- 左括号必须用相同类型的右括号闭合
- 左括号必须以正确的顺序闭合
思路:如果括号成对出现,在遍历的时候成对括号出现的特点:
- 先拿出成对括号的左边
- 右边的括号一旦出现优先比较第一步中最后的左边括号并比较是否成对匹配
- 全部匹配完成则成立,一旦有一个匹配不对,则不成立
由于有着先进后出比较的操作,这里使用栈进行相关操作比较比较合理。实现如下:
func isVaild(str: String) -> Bool {
var stack: Stack = Stack<Character>(arrayDefault: "c")
//使用字典存储相关的配对括号
let pairDict : Dictionary<Character,Character> = ["(":")","[":"]","{":"}"]
for (_, element) in str.enumerated() {
let character = element
if character == "(" || character == "[" || character == "{" {
stack.push(element: character)
}else {
if character == ")" || character == "]" || character == "}" {
if stack.isEmpty() || character != pairDict[stack.top()!]{
return false
}
if pairDict[stack.top()!] == character {
stack.pop()
}
}
}
}
return stack.isEmpty()
}