有BUG或意见欢迎留言
package main
import (
"fmt"
)
type treeNode struct {
value uint8
lNode *treeNode
rNode *treeNode
}
// 接口定义泛型可以接收的数据类型
type dataType interface {
*treeNode | uint8 | int
}
// 使用泛型定义栈
type stack[T dataType] struct {
data []T
top int
}
// 实现栈的push方法
func (i *stack[T]) push(data T) bool {
if (*i).top < len((*i).data) { //如果没有超出容量则直接赋值
(*i).data[(*i).top] = data
} else {
(*i).data = append((*i).data, data) //否则扩容
}
(*i).top++ //栈顶增长
return true
}
// 获取栈顶元素,不删除
func (i *stack[T]) getTop() T {
return (*i).data[(*i).top-1]
}
// 实现栈的pop方法,获取栈顶元素并删除
func (i *stack[T]) pop() T {
(*i).top--
return (*i).data[(*i).top]
}
// 清空栈
func (i *stack[T]) empty() {
(*i).top = 0
}
// 获取所有数据
func (i *stack[T]) getData() []T {
return (*i).data[0:(*i).top]
}
// 如果需要改变数据结构的内容则接收者为指针,否则接收者为类型
func (i *stack[T]) isEmpty() bool {
return (*i).top == 0
}
// 从另一个栈初始化,复制全部内容
func (i *stack[T]) copyAnotherStack(tempStack stack[T]) {
(*i).data = tempStack.data
(*i).top = tempStack.top
}
var largestState int
var cStack stack[uint8]
var nodeStack stack[*treeNode]
var newStateStack stack[int]
var oldStateStack stack[int]
var alreadyOn []uint8
// map数组,存放转换表
var stateMap map[int]map[uint8][]int = make(map[int]map[uint8][]int)
// 返回指定数量的新状态
func getNewState(num int) []int {
var numArray []int = make([]int, num)
for i := 0; i < num; i++ {
numArray[i] = largestState + i
}
largestState = largestState + num
return numArray
}
// 打印一棵树,采用中序遍历,即中-左-右
func printTree(tempTree *treeNode) {
fmt.Printf("%c\n", (*tempTree).value)
if (*tempTree).lNode != nil {
printTree((*tempTree).lNode)
}
if (*tempTree).rNode != nil {
printTree((*tempTree).rNode)
}
}
// 打印转换表
func printStateMap() {
for key, item := range stateMap { //遍历每个初始状态
fmt.Printf("初始状态state为%d, ", key)
for k, i := range item { //遍历每个状态的转换字符
if k == 0 {
k = '0'
}
fmt.Printf("转换字符为%c,转换后状态为%v\n", k, i)
}
}
}
// 插入单个状态在单个字符下的转换
func makeMapping(state int, c uint8, destState []int) {
//如果map不存在,需要创建后才能使用
if stateMap[state] == nil {
//先初始化map才能使用
stateMap[state] = make(map[uint8][]int)
stateMap[state][c] = destState
} else {
//如果已存在,则将目标状态插在最后
//可能出现状态重复
stateMap[state][c] = append(stateMap[state][c], destState...)
}
}
// 分析一棵树 slice是值传递 数组也是值传递 array *[3]int 指针传递,但使用指针无法append数组
// 返回值开始state 转换字母 接收state
func analyzeTree(tempTree *treeNode) ([]int, []int) {
//处理单个字符
if (*tempTree).lNode == nil && (*tempTree).rNode == nil {
startState := getNewState(1)
receiveState := getNewState(1)
makeMapping(startState[0], (*tempTree).value, receiveState)
return startState, receiveState
}
//处理连接符
if (*tempTree).value == '.' {
lStartState, lReceiveState := analyzeTree((*tempTree).lNode)
rStartState, rReceiveState := analyzeTree((*tempTree).rNode)
//遍历前字符的接收状态集 将前字符的接收状态集和后字符串的开始状态集用空串映射连起来
for _, item := range lReceiveState {
makeMapping(item, 0, rStartState)
}
return lStartState, rReceiveState
} else if (*tempTree).value == '*' {
lStartState, lReceiveState := analyzeTree((*tempTree).lNode)
//新建开始集和接收集
startState := getNewState(1)
receiveState := getNewState(1)
appendStates := append(lStartState, receiveState[0])
//开始集用空串映射到左节点的开始集和结束集
makeMapping(startState[0], 0, appendStates)
//遍历左节点结束集
for _, item := range lReceiveState {
//左节点结束集用空串映射到左节点开始集和结束集
makeMapping(item, 0, appendStates)
}
return startState, receiveState
} else if (*tempTree).value == '+' {
lStartState, lReceiveState := analyzeTree((*tempTree).lNode)
//新建开始集和接收集
startState := getNewState(1)
receiveState := getNewState(1)
//开始集用空串映射到左节点的开始集
makeMapping(startState[0], 0, lStartState)
//遍历左节点结束集
for _, item := range lReceiveState {
//左节点结束集用空串映射到左节点开始集和结束集
makeMapping(item, 0, append(lStartState, receiveState[0]))
}
return startState, receiveState
} else if (*tempTree).value == '|' {
//初始化左右节点各自的开始集和结束集
lStartState, lReceiveState := analyzeTree((*tempTree).lNode)
rStartState, rReceiveState := analyzeTree((*tempTree).rNode)
//初始化开始集和结束集
startState := getNewState(1)
receiveState := getNewState(1)
//开始集用空串映射到左右节点各自的开始集
makeMapping(startState[0], 0, append(lStartState, rStartState...))
//遍历左节点的结束集
for _, item := range lReceiveState {
//左节点结束集用空串映射到结束集
makeMapping(item, 0, receiveState)
}
//遍历右节点的结束集
for _, item := range rReceiveState {
//右节点结束集用空串映射到结束集
makeMapping(item, 0, receiveState)
}
return startState, receiveState
}
return nil, nil
}
// 在数组中查找
func findNumInArray(num int, array []int) int {
for index, item := range array {
if item == num {
return index //成功返回索引
}
}
return -1 //否则返回-1
}
// 空转换和普通转换不同,需要递归,故不能合在一起
func findZeroMapping(startState []int) {
for _, item := range startState {
//将状态插入
if alreadyOn[item] == 0 {
oldStateStack.push(item)
alreadyOn[item] = 1
//只有未被插入才需要继续处理目标状态
//先排除该状态没有转换路线 再排除0转换的目标状态为空切片
if stateMap[item] != nil && len(stateMap[item][0]) != 0 {
//继续处理0转换目标状态
findZeroMapping(stateMap[item][0])
}
}
}
}
// 找出所有空转换的结果
func findMapping(state []int, c uint8) {
//遍历输入的state数组
for _, item := range state {
//先排除该状态没有转换路线 再排除c转换的目标状态为空切片
if stateMap[item] != nil && len(stateMap[item][c]) != 0 {
//将目标状态加入newStateStack
for _, i := range stateMap[item][c] {
if alreadyOn[i] == 0 {
newStateStack.push(i)
alreadyOn[i] = 1
}
}
}
}
}
// 实现match函数
func matchString(str string, startState []int, receiveState []int) string {
//创建alreadyOn数组
alreadyOn = make([]uint8, largestState)
//初始化oldStateStack
findZeroMapping(startState)
var matchPos int
length := len(str)
var state []int
//采用i遍历,方便回退
for i := 0; i < length; i++ {
//重新创建alreadyOn数组
alreadyOn = make([]uint8, largestState)
//获取oldStateStack数据
state = oldStateStack.getData()
//以下为常用调试语句
//fmt.Println(state)
//清空oldStateStack
oldStateStack.empty()
//使用oldStateStack数据初始化newStateStack
findMapping(state, str[i])
//重新创建alreadyOn数组
alreadyOn = make([]uint8, largestState)
//如果转换的目标状态为空,则重置状态
if newStateStack.isEmpty() {
//重置前判断是否已匹配到
for _, item := range state {
if findNumInArray(item, receiveState) != -1 {
return str[matchPos:i]
}
}
//重置匹配开始字符
i = matchPos
//记录新的匹配开始字符
matchPos++
//初始化oldStateStack
findZeroMapping(startState)
} else {
//获取新栈的值
state = newStateStack.getData()
//清空新栈
newStateStack.empty()
//使用新栈初始化旧栈
findZeroMapping(state)
}
}
//匹配完后检查最终状态
state = oldStateStack.getData()
for _, item := range state {
if findNumInArray(item, receiveState) != -1 {
return str[matchPos:] //如果含有接收态,则接收
}
}
return ""
}
func main() {
var str string = "a+b|c"
for _, c := range str {
if (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') { //当遇到字母,与前一部分连接
//如果节点栈非空,且上一运算符是'|'
if !nodeStack.isEmpty() && !cStack.isEmpty() && cStack.getTop() == '|' {
//获取左节点
lNode := nodeStack.pop()
//新建或节点并初始化或节点的左右节点
nodeStack.push(&treeNode{cStack.pop(), lNode, &treeNode{uint8(c), nil, nil}})
} else {
if !nodeStack.isEmpty() {
//连接符采用'.'
cStack.push('.')
}
nodeStack.push(&treeNode{uint8(c), nil, nil})
}
} else if c == '*' {
//理论上'*'的优先级比'+'高 获取左节点
lNode := nodeStack.pop()
//压栈'*'
nodeStack.push(&treeNode{'*', lNode, nil})
} else if c == '|' {
//'|直接压栈'
cStack.push('|')
} else if c == '+' {
//获取左节点
lNode := nodeStack.pop()
//压栈'+' 由于'+'被连接符号占用,需改用
nodeStack.push(&treeNode{'+', lNode, nil})
}
}
//在操作符栈非空的时间内
for !cStack.isEmpty() {
c := cStack.pop()
rNode := nodeStack.pop()
lNode := nodeStack.pop()
nodeStack.push(&treeNode{c, lNode, rNode})
}
tree := nodeStack.pop()
//初始化工作 初始化起始栈
startState, receiveState := analyzeTree(tree)
fmt.Printf("全局初始状态为%v,接收状态为%v\n", startState, receiveState)
printTree(tree)
printStateMap()
//初始化old栈
fmt.Println(matchString("baaaabc", startState, receiveState))
}