堆栈
抽象数据类型描述
具有一定操作约束的线性表,只在一端(栈顶,Top)做插入,删除
- 插入数据:入栈(Push)
- 删除数据:出栈(Pop)
- 后入先出:Last In First Out(LIFO)
类型名称:堆栈(Stack)
数据对象集:一个 有0个或多个元素的有穷线性表
操作集
- 创建空堆栈
- 判断堆栈是否已满
- 将元素压入堆栈
- 判断堆栈是否为空
- 删除并返回栈顶元素
堆栈的顺序存储实现
通常由一个一维数组和一个记录栈顶元素位置的变量组成
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
class Stack<T:Hashable> {
var data : Array<T> = Array();
var top : Int = -1
func push(_ item:T) -> Void {
data.append(item)
top += 1
}
func pop() -> T? {
if top == -1 {
print("空堆栈")
return nil
}
top -= 1
return data.popLast()
}
}
let stack = Stack<Int>()
stack.push(0)
stack.push(1)
print(stack.pop())
print(stack.top) |
堆栈的链式存储实现
堆栈的链式存储结构实际上是一个单链表,叫做链栈,插入和删除操作只能在链栈的栈顶进行
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 |
class StackNode<T:Hashable> {
var data : T?
var next : StackNode?
}
class Stack<T:Hashable> {
var top = StackNode<T>()// 指向栈顶,本身无意义
func isEmpty() -> Bool {
if top.next == nil {
return true
}
else {
return false
}
}
func push(_ item:T) -> Void {
let node = StackNode<T>();
node.data = item;
node.next = top.next;
top.next = node
}
func pop() -> T? {
if isEmpty() {
print("空堆栈")
return nil
}
let node = top.next
top.next = top.next?.next
return node!.data
}
}
let stack = Stack<String>()
stack.push("aaa")
stack.push("bbb")
print(stack.top.next?.data)
print(stack.pop())
print(stack.pop())
print(stack.isEmpty())
stack.push("cccc")
print(stack.top.next?.data) |
堆栈应用
后缀表达式求值
- 从左向右扫描,逐个处理运算数和运算符号
- 遇到运算数,入栈
- 遇到运算符,出栈两个运算数,做运算
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 |
class ExpressionOperation {
func input(expression:[String]) -> Int {
let stack = Stack<Int>()
for value in expression {
if isInt(string: value) {
stack.push(Int(value)!)
}
else {
let a = stack.pop()!
let b = stack.pop()!
var ret = 0
switch value {
case "+":
ret = a + b;
case "-":
ret = b - a;
case "*":
ret = a * b;
case "/":
ret = b / a;
default:
ret = 0
}
stack.push(ret)
}
}
return stack.top.next!.data!
}
func isInt(string: String) -> Bool {
let scan: Scanner = Scanner(string: string)
var val:Int = 0
return scan.scanInt(&val) && scan.isAtEnd
}
}
let test1 = ["1","1","+","2","*","2","-","1","/"]
let test2 = ["2","9","3","/","+","4","-"]
let exp = ExpressionOperation()
exp.input(expression: test) |
中缀表达式求值
基本策略:将中缀表达式转换为后缀表示式,然后求值
- 从头到尾读取中缀表达式的每个元素
- 运算数:直接输出
- 左括号:入栈
- 右括号:将栈顶的运算符出栈并输出,直到遇到左括号(出栈,不输出)
- 运算符:
- 若优先级大于栈顶运算符时,则入栈
- 若优先级小于栈顶运算符时,将栈顶运算符出栈并输出,再比较新的栈顶运算符,直到该运算符优先级大于栈顶运算符为止,然后该运算符入栈
- 若对各个元素处理完毕,则把堆栈中留存的运算符一并输出
其他应用
- 函数调用及递归实现
- 深度优先搜索
- 回溯算法