元素码农
基础
UML建模
数据结构
算法
设计模式
网络
TCP/IP协议
HTTPS安全机制
WebSocket实时通信
数据库
sqlite
postgresql
clickhouse
后端
rust
go
java
php
mysql
redis
mongodb
etcd
nats
zincsearch
前端
浏览器
javascript
typescript
vue3
react
游戏
unity
unreal
C++
C#
Lua
App
android
ios
flutter
react-native
安全
Web安全
测试
软件测试
自动化测试 - Playwright
人工智能
Python
langChain
langGraph
运维
linux
docker
工具
git
svn
🌞
🌙
目录
▶
算法基础
▶
复杂度分析
时间复杂度
空间复杂度
渐进符号
▶
算法思想
分治法
贪心算法
回溯法
概率算法
枚举算法
递推算法
递归算法
动态规划
分支限界法
模拟算法
▶
算法分析
正确性证明
性能优化
算法比较
▶
搜索算法
▶
基本搜索
顺序搜索
二分搜索
插值搜索
▶
图搜索
深度优先搜索
广度优先搜索
启发式搜索
▶
高级搜索
双向搜索
A*算法
模式匹配
▶
排序算法
▶
比较类排序
冒泡排序
快速排序
归并排序
插入排序
选择排序
▶
非比较类排序
计数排序
基数排序
桶排序
▶
高级排序
堆排序
希尔排序
外部排序
拓扑排序
▶
图论算法
▶
图的表示
邻接矩阵
邻接表
边集数组
▶
最短路径
Dijkstra算法
Floyd算法
Bellman-Ford算法
最短路径概述
▶
生成树
Prim算法
Kruskal算法
并查集
最小生成树
▶
图的连通性
强连通分量
割点与桥
双连通分量
欧拉路径
▶
动态规划
▶
基础概念
最优子结构
重叠子问题
状态转移方程
▶
经典问题
背包问题
最长公共子序列
编辑距离
▶
优化技巧
空间优化
状态压缩
区间动态规划
▶
字符串算法
▶
字符串匹配
KMP算法
Boyer-Moore算法
Sunday算法
▶
字符串处理
字典树
后缀数组
字符串哈希
▶
压缩算法
游程编码
Huffman编码
LZ77算法
发布时间:
2025-03-21 20:09
↑
☰
# Sunday字符串匹配算法 Sunday算法是一种高效的字符串匹配算法,由Daniel M. Sunday在1990年提出。它是对Boyer-Moore算法的改进,具有实现简单且性能优秀的特点。 ## 基本概念 ### 匹配原理 Sunday算法的核心思想是: - 从左向右对齐文本串和模式串进行比较 - 当出现不匹配时,关注文本串中参与下一次匹配的第一个字符 - 根据这个字符在模式串中最右边出现的位置来确定移动距离 ### 移动规则 当匹配失败时: 1. 查看文本串中位于模式串后面的第一个字符(即跳跃字符) 2. 如果该字符不在模式串中,则直接跳过,移动距离为模式串长度+1 3. 如果该字符在模式串中,则移动模式串,使该字符与模式串中最右边的相同字符对齐 ## 实现原理 ### 预处理 ```go // 构建移动表 func buildShiftTable(pattern string) map[byte]int { shift := make(map[byte]int) length := len(pattern) // 默认移动距离为模式串长度+1 for i := 0; i < 256; i++ { shift[byte(i)] = length + 1 } // 根据模式串中字符出现的最右位置更新移动距离 for i := 0; i < length; i++ { shift[pattern[i]] = length - i } return shift } ``` ### 基本实现 ```go // Sunday算法实现 func Sunday(text, pattern string) int { if len(pattern) == 0 { return 0 } if len(text) < len(pattern) { return -1 } // 构建移动表 shift := buildShiftTable(pattern) textLen := len(text) patternLen := len(pattern) pos := 0 for pos <= textLen - patternLen { matched := true // 比较当前位置 for i := 0; i < patternLen; i++ { if text[pos+i] != pattern[i] { matched = false break } } // 找到匹配 if matched { return pos } // 计算下一次移动位置 nextPos := pos + patternLen if nextPos >= textLen { break } // 根据移动表确定跳转距离 pos += shift[text[nextPos]] } return -1 } ``` ### 优化实现 ```go // 优化的Sunday算法 type SundayMatcher struct { pattern string shift map[byte]int patternLen int } // 创建匹配器 func NewSundayMatcher(pattern string) *SundayMatcher { return &SundayMatcher{ pattern: pattern, shift: buildShiftTable(pattern), patternLen: len(pattern), } } // 查找所有匹配位置 func (sm *SundayMatcher) FindAll(text string) []int { result := make([]int, 0) textLen := len(text) pos := 0 for pos <= textLen - sm.patternLen { matched := true // 比较当前位置 for i := 0; i < sm.patternLen; i++ { if text[pos+i] != sm.pattern[i] { matched = false break } } // 记录匹配位置 if matched { result = append(result, pos) pos++ continue } // 计算下一次移动位置 nextPos := pos + sm.patternLen if nextPos >= textLen { break } // 根据移动表确定跳转距离 pos += sm.shift[text[nextPos]] } return result } ``` ## 应用场景 ### 文本编辑器 ```go // 文本编辑器中的查找功能 type TextEditor struct { content string matcher *SundayMatcher } // 查找并高亮显示 func (te *TextEditor) FindAndHighlight(pattern string) []string { te.matcher = NewSundayMatcher(pattern) positions := te.matcher.FindAll(te.content) results := make([]string, 0) // 生成带有高亮标记的文本片段 for _, pos := range positions { start := max(0, pos-10) end := min(len(te.content), pos+len(pattern)+10) // 添加上下文 context := te.content[start:end] if start > 0 { context = "..." + context } if end < len(te.content) { context = context + "..." } results = append(results, context) } return results } ``` ### 日志分析 ```go // 日志分析器 type LogAnalyzer struct { matcher *SundayMatcher buffer []string } // 流式处理日志 func (la *LogAnalyzer) ProcessLog(logLine string) bool { // 使用Sunday算法查找特定模式 if la.matcher.FindAll(logLine) != nil { // 匹配成功,保存到缓冲区 la.buffer = append(la.buffer, logLine) return true } return false } // 批量处理日志文件 func (la *LogAnalyzer) AnalyzeFile(filename string) error { file, err := os.Open(filename) if err != nil { return err } defer file.Close() scanner := bufio.NewScanner(file) for scanner.Scan() { la.ProcessLog(scanner.Text()) } return scanner.Err() } ``` ## 性能分析 ### 时间复杂度 1. 预处理阶段 - 构建移动表:O(m + k),m为模式串长度,k为字符集大小 2. 匹配阶段 - 最好情况:O(n/m),n为文本串长度 - 平均情况:O(n) - 最坏情况:O(n*m) ### 空间复杂度 1. 基本实现 - 移动表:O(k),k为字符集大小 - 临时变量:O(1) 2. 优化实现 - 移动表:O(k) - 结果数组:O(n),用于存储所有匹配位置 ### 性能对比 1. 与其他算法比较 - 比朴素算法更快 - 通常比KMP算法简单且效率相近 - 在实际应用中常优于Boyer-Moore算法 2. 优势 - 实现简单 - 预处理开销小 - 移动距离大 ## 实践建议 ### 使用场景选择 1. 适合场景 - 文本编辑器的查找功能 - 日志分析和过滤 - 需要多次重复使用同一模式串的场景 2. 不适合场景 - 模式串经常变化 - 文本串较短 - 对空间要求极其严格 ### 优化技巧 1. 实现优化 - 使用缓存优化移动表访问 - 特殊情况快速返回 - 并行处理大文本 2. 应用优化 - 预编译常用模式 - 批量处理 - 结合其他算法 ## 总结 1. 优点 - 实现简单直观 - 性能优秀 - 预处理开销小 2. 缺点 - 最坏情况性能不佳 - 需要额外空间存储移动表 - 对模式串变化敏感 3. 使用建议 - 优先用于中等规模文本处理 - 结合具体场景选择实现方式 - 注意边界条件处理