From dc5d924a2c99a29c479523b1ae0fe34653ba26dc Mon Sep 17 00:00:00 2001 From: Huangzj Date: Tue, 2 Mar 2021 13:33:07 +0800 Subject: [PATCH] =?UTF-8?q?feat(Go-Tool)=EF=BC=9A=20=20=20=20=20=20=20=20?= =?UTF-8?q?=20=20=20=20=202021/03/02:=20=E6=96=B0=E5=A2=9E=E5=AD=97?= =?UTF-8?q?=E7=AC=A6=E4=B8=B2=E5=8C=B9=E9=85=8D=20=E6=9A=B4=E5=8A=9B?= =?UTF-8?q?=E5=8C=B9=E9=85=8D=E3=80=81KMP=E5=8C=B9=E9=85=8D=E3=80=81SunDay?= =?UTF-8?q?=E5=8C=B9=E9=85=8D=E7=AE=97=E6=B3=95=20=20=20=20=20=20=20=20=20?= =?UTF-8?q?=20=20=20=202021/03/02:=20=E4=BF=AE=E5=A4=8DRand=E5=8C=85?= =?UTF-8?q?=E9=9A=8F=E6=9C=BA=E8=8E=B7=E5=8F=96=E6=96=B9=E6=B3=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- readme.md | 12 +++-- util/rand/AwardWeight.go | 12 +++++ util/rand/Rand.go | 4 +- util/rand/RandByWeight.go | 2 +- util/rand/RandObjectByWeight.go | 62 ++++++++++++++++++++++++++ util/rand/RandObjectByWeight_test.go | 46 +++++++++++++++++++ util/stringMatch/HorspoolMatch_test.go | 2 + util/stringMatch/KMPMatch.go | 55 +++++++++++++++++++++++ util/stringMatch/KMPMatch_test.go | 54 ++++++++++++++++++++++ util/stringMatch/SundayMatch.go | 45 +++++++++++++++++++ util/stringMatch/SundayMatch_test.go | 33 ++++++++++++++ util/stringMatch/ViolentMatch.go | 32 +++++++++++++ util/stringMatch/ViolentMatch_test.go | 33 ++++++++++++++ 13 files changed, 385 insertions(+), 7 deletions(-) create mode 100644 util/rand/AwardWeight.go create mode 100644 util/rand/RandObjectByWeight.go create mode 100644 util/rand/RandObjectByWeight_test.go create mode 100644 util/stringMatch/KMPMatch.go create mode 100644 util/stringMatch/KMPMatch_test.go create mode 100644 util/stringMatch/SundayMatch.go create mode 100644 util/stringMatch/SundayMatch_test.go create mode 100644 util/stringMatch/ViolentMatch.go create mode 100644 util/stringMatch/ViolentMatch_test.go diff --git a/readme.md b/readme.md index 83e0ec2..d22f4c6 100644 --- a/readme.md +++ b/readme.md @@ -60,7 +60,7 @@ 2020/11/25:完善linq包使用示例 -2020/12/7 :更新bit位操作工作 BitTool +2020/12/7 : 更新bit位操作工作 BitTool 2020/12/15:添加前缀树工具,实现前缀搜索和字符串搜索功能 @@ -68,7 +68,9 @@ 2020/12/31:新增项目案例(角色技能树) -2021/2/5: 新增二分查找区间内数值方法 +2021/02/05: 新增二分查找区间内数值方法 + +2021/03/02: 新增字符串匹配 暴力匹配、KMP匹配、SunDay匹配算法 # 修复日志 2020/11/23:修改项目案例(按照一定规则对一组数据进行排序分组) @@ -79,11 +81,13 @@ 2020/12/31:删除源码学习部分,挪到Go-Study工程 -2021/1/4 :reflectM包添加indirect处理指针和非指针,获取type、value +2021/01/04:reflectM包添加indirect处理指针和非指针,获取type、value 2021/02/18:bitStore新增特殊档位获取方法,修改档位数目的参数标识 -2021/02/23:删除linq包使用示例,修改二进制工具与单测类,修改lomuto划分,修改前缀树与单测类,修改时间比较工具 +2021/02/23: 删除linq包使用示例,修改二进制工具与单测类,修改lomuto划分,修改前缀树与单测类,修改时间比较工具 + +2021/03/02: 修复Rand包随机获取方法 # mod vendor模式加载包 通过go mod的方式加载的github上面的包会有报红的问题,但是包本身是可以运行的,这样就是会有一个问题,如果你想要点击去看方法的内容,没办法做到 diff --git a/util/rand/AwardWeight.go b/util/rand/AwardWeight.go new file mode 100644 index 0000000..88013f0 --- /dev/null +++ b/util/rand/AwardWeight.go @@ -0,0 +1,12 @@ +/* + * @Author : huangzj + * @Time : 2021/2/23 20:52 + * @Description: + */ + +package rand + +type AwardWeight struct { + Award interface{} //奖励数据 + Weight int //权重 +} diff --git a/util/rand/Rand.go b/util/rand/Rand.go index 5e8f7d3..88257b6 100644 --- a/util/rand/Rand.go +++ b/util/rand/Rand.go @@ -1,7 +1,7 @@ /* * @Author : huangzj * @Time : 2020/6/29 10:48 - * @Description:这边的随机获取没有加锁,对于一些需要加锁的场景可以在外面再包装一层 + * @Description: */ package rand @@ -47,7 +47,7 @@ func GetRandIntNoRepeat(count, min, max int) []int { return randAttr } -//从一个数组中获取到X个不重复随机数 +//从一个数组中获取到X个不重复下标的随机数 func GetDiffNum(data []int, count int) []int { if count > len(data) { panic("获取随机数数量有误") diff --git a/util/rand/RandByWeight.go b/util/rand/RandByWeight.go index 0517b81..14926c0 100644 --- a/util/rand/RandByWeight.go +++ b/util/rand/RandByWeight.go @@ -1,7 +1,7 @@ /* * @Author : huangzj * @Time : 2020/6/29 10:23 - * @Description:这边的随机获取没有加锁,对于一些需要加锁的场景可以在外面再包装一层 + * @Description: */ package rand diff --git a/util/rand/RandObjectByWeight.go b/util/rand/RandObjectByWeight.go new file mode 100644 index 0000000..23c21dc --- /dev/null +++ b/util/rand/RandObjectByWeight.go @@ -0,0 +1,62 @@ +/* + * @Author : huangzj + * @Time : 2021/2/23 20:50 + * @Description: + */ + +package rand + +func GetAwardWeightByWeight(awardWeight []*AwardWeight) *AwardWeight { + //求总权重 + weight := 0 + for _, award := range awardWeight { + weight += award.Weight + } + randNum := GetRandInt(1, weight) + sum := 0 + for _, award := range awardWeight { + sum += award.Weight + if sum >= randNum { + return award + } + } + return nil +} + +//根据权重不放回的抽取,出参是:抽到的道具、剩余没有抽的道具 +func GetByWeightWithLeftAward(awardWeight []*AwardWeight) (*AwardWeight, []*AwardWeight) { + weight := 0 + leftAwards := make([]*AwardWeight, 0) + for _, award := range awardWeight { + weight += award.Weight + } + randNum := GetRandInt(1, weight) + sum := 0 + for index, award := range awardWeight { + sum += award.Weight + if sum >= randNum { + //如果获取到奖励则将当前获取的奖励扣除 + leftAwards = append(awardWeight[0:index], awardWeight[index+1:]...) + return award, leftAwards + } + } + return nil, leftAwards +} + +// 根据权重不放回的抽取X个元素,直接返回这些元素 +// 入参:奖池、抽取数量,出参:获得的所有道具,剩余的其他道具 +func GetSomeAwardsFromPool(srcAwardPool []*AwardWeight, count int) ([]*AwardWeight, []*AwardWeight) { + if count > len(srcAwardPool) { + panic("抽取数量不对") + } + var finalAwardList []*AwardWeight + var award *AwardWeight + var leftAward = make([]*AwardWeight, len(srcAwardPool)) + copy(leftAward, srcAwardPool) + + for i := 0; i < count; i++ { + award, leftAward = GetByWeightWithLeftAward(leftAward) + finalAwardList = append(finalAwardList, award) + } + return finalAwardList, leftAward +} diff --git a/util/rand/RandObjectByWeight_test.go b/util/rand/RandObjectByWeight_test.go new file mode 100644 index 0000000..9337e15 --- /dev/null +++ b/util/rand/RandObjectByWeight_test.go @@ -0,0 +1,46 @@ +/* + * @Author : huangzj + * @Time : 2021/2/23 22:08 + * @Description: + */ + +package rand + +import ( + "fmt" + "testing" +) + +func TestRandByAwardWeight(t *testing.T) { + awardList := make([]*AwardWeight, 0) + awardList = append(awardList, &AwardWeight{ + Award: []int{1, 2}, + Weight: 10, + }) + awardList = append(awardList, &AwardWeight{ + Award: []int{2, 2}, + Weight: 20, + }) + awardList = append(awardList, &AwardWeight{ + Award: []int{3, 2}, + Weight: 30, + }) + + award := GetAwardWeightByWeight(awardList) + fmt.Println(award.Award) + + award1, list3 := GetByWeightWithLeftAward(awardList) + fmt.Println(award1.Award) + for _, award := range list3 { + fmt.Println(award.Award) + } + + list4, left := GetSomeAwardsFromPool(awardList, 2) + for _, award := range list4 { + fmt.Println(award.Award) + } + for _, award := range left { + fmt.Println(award.Award) + } + +} diff --git a/util/stringMatch/HorspoolMatch_test.go b/util/stringMatch/HorspoolMatch_test.go index b40994c..e4cfe8a 100644 --- a/util/stringMatch/HorspoolMatch_test.go +++ b/util/stringMatch/HorspoolMatch_test.go @@ -23,4 +23,6 @@ func TestHorspool(t *testing.T) { fmt.Println("该子串的位置为:", Horspool("abcdefghijk", "kdasdsad")) //输出-1 fmt.Println("该子串的位置为:", Horspool("abcdefghijk", "dsadsa")) //输出-1 + fmt.Println(shiTable("abdabe")) + } diff --git a/util/stringMatch/KMPMatch.go b/util/stringMatch/KMPMatch.go new file mode 100644 index 0000000..3b5b5b7 --- /dev/null +++ b/util/stringMatch/KMPMatch.go @@ -0,0 +1,55 @@ +/* + * @Author : huangzj + * @Time : 2021/2/24 13:19 + * @Description:KMP字符串匹配算法,参考地址:https://www.cnblogs.com/en-heng/p/5091365.html + * http://www.ruanyifeng.com/blog/2013/05/Knuth%E2%80%93Morris%E2%80%93Pratt_algorithm.html + */ + +package stringMatch + +func KmpMatch(allString string, match string) int { + next := getNext(match) + i := 0 //被匹配的字符串下标 + j := 0 //模式匹配字符串下标 + sLength := len(allString) - 1 + mLength := len(match) - 1 + for i <= sLength && j <= mLength { + if j == -1 || allString[i] == match[j] { + j++ + i++ + } else { + j = next[j] + } + } + + if j == len(match) { + return i - j + } + return -1 +} + +//失配表函数构建(部分匹配函数) +func getNext(match string) []int { + next := make([]int, len(match)) + next[0] = -1 + i := 0 + j := -1 + + mLength := len(match) - 1 + + for i < mLength { + //处理两种情况: 1.数组第一个数是-1 2. match对应位置字符相等的情况 + if j == -1 || match[i] == match[j] { + //如果这里是数组第一个数的时候,下标要往后移动 + //如果这里是数组相等的情况,要比较下一个相应的字符,所以下标需要往后移动,而next需要在上一个的基础上去做+1操作 + i++ + j++ + next[i] = j + } else { + //如果匹配过程中,出现对应不上的情况,也就是说 match[i] != match[j], + j = next[j] + } + } + + return next +} diff --git a/util/stringMatch/KMPMatch_test.go b/util/stringMatch/KMPMatch_test.go new file mode 100644 index 0000000..31bc5c8 --- /dev/null +++ b/util/stringMatch/KMPMatch_test.go @@ -0,0 +1,54 @@ +/* + * @Author : huangzj + * @Time : 2021/2/24 17:52 + * @Description: + */ + +package stringMatch + +import ( + "fmt" + "testing" +) + +func TestKmpMatch(t *testing.T) { + s := "abcbvxs" + m := "bcb" + showResult(s, m) + s = "abcbvxs" + m = "bx" + showResult(s, m) + s = "abcbvxssdaadsad" + m = "cbvxssdaa" + showResult(s, m) +} + +func TestMatchNum(t *testing.T) { + s := "ababababca" + m := "abababca" + showResult(s, m) +} + +func showResult(s, m string) { + i := KmpMatch(s, m) + if i == -1 { + fmt.Println("未找到对应字符串") + } else { + fmt.Println(fmt.Sprintf("匹配到的字符串是:%v", s[i:len(m)+i])) + } +} + +func TestGetNext(t *testing.T) { + next := getNext("abababca") + fmt.Println(next) + next1 := getNext("abababc") + fmt.Println(next1) + next2 := getNext("abababcxy") + fmt.Println(next2) + next3 := getNext("abababcxyxyy") + fmt.Println(next3) + next4 := getNext("abcdabd") + fmt.Println(next4) + next5 := getNext("abcxabcxabcyabcz") + fmt.Println(next5) +} diff --git a/util/stringMatch/SundayMatch.go b/util/stringMatch/SundayMatch.go new file mode 100644 index 0000000..1cacbcb --- /dev/null +++ b/util/stringMatch/SundayMatch.go @@ -0,0 +1,45 @@ +/* + * @Author : huangzj + * @Time : 2021/3/2 11:21 + * @Description: + */ + +package stringMatch + +func ShiftTable(modeString string) []int { + shiftTable := make([]int, 256) + + //一开始设置所有的字符匹配不上向右移动大小为:模式字符串长度 + 1(因为要移动到下一个字符的后一位) + for i := range shiftTable { + shiftTable[i] = len(modeString) + 1 + } + + //设置模式字符串中每一个字符的移动长度. + for i := range modeString { + shiftTable[modeString[i]-'a'] = len(modeString) - i + } + + return shiftTable +} + +func SundayMatch(allString, modeString string) int { + table := ShiftTable(modeString) + aLength := len(allString) + mLength := len(modeString) + i := 0 //这个参数记录的是移动过程中,,模式字符串对应原始字符串的第一个位置. + + for i < aLength-mLength { + j := 0 + for allString[i+j] == modeString[j] { + j++ + if j >= len(modeString) { + return i + } + } + //找到移动后模式字符串对应原始字符串的第一个位置 + move := allString[i+mLength] + i = i + table[move-'a'] + } + + return -1 +} diff --git a/util/stringMatch/SundayMatch_test.go b/util/stringMatch/SundayMatch_test.go new file mode 100644 index 0000000..8f21b43 --- /dev/null +++ b/util/stringMatch/SundayMatch_test.go @@ -0,0 +1,33 @@ +/* + * @Author : huangzj + * @Time : 2021/3/2 11:21 + * @Description: + */ + +package stringMatch + +import ( + "fmt" + "testing" +) + +func TestSundayMatch(t *testing.T) { + s := "abcbvxs" + m := "bcb" + showResult2(s, m) + s = "abcbvxs" + m = "bx" + showResult2(s, m) + s = "abcbvxssdaadsad" + m = "cbvxssdaa" + showResult2(s, m) +} + +func showResult2(s, m string) { + i := SundayMatch(s, m) + if i == -1 { + fmt.Println("未找到对应字符串") + } else { + fmt.Println(fmt.Sprintf("匹配到的字符串是:%v", s[i:len(m)+i])) + } +} diff --git a/util/stringMatch/ViolentMatch.go b/util/stringMatch/ViolentMatch.go new file mode 100644 index 0000000..f940a97 --- /dev/null +++ b/util/stringMatch/ViolentMatch.go @@ -0,0 +1,32 @@ +/* + * @Author : huangzj + * @Time : 2021/2/25 11:11 + * @Description: + */ + +package stringMatch + +func ViolentMatch(allString, match string) int { + i := 0 + j := 0 + sLength := len(allString) + mLenght := len(match) + + for i < sLength && j < mLenght { + //当前字符如果匹配,继续匹配下一个字符,坐标移动 + if allString[i] == match[j] { + j++ + i++ + } else { + //如果字符不匹配,match从头开始,被匹配的字符串从之前匹配的下一个字符开始,坐标修改 + i = i - j + 1 + j = 0 + } + } + + if j == len(match) { + return i - j + } + + return -1 +} diff --git a/util/stringMatch/ViolentMatch_test.go b/util/stringMatch/ViolentMatch_test.go new file mode 100644 index 0000000..aed0b77 --- /dev/null +++ b/util/stringMatch/ViolentMatch_test.go @@ -0,0 +1,33 @@ +/* + * @Author : huangzj + * @Time : 2021/2/25 11:11 + * @Description: + */ + +package stringMatch + +import ( + "fmt" + "testing" +) + +func TestViolentMatch(t *testing.T) { + s := "abcbvxs" + m := "bcb" + showResult1(s, m) + s = "abcbvxs" + m = "bx" + showResult1(s, m) + s = "abcbvxssdaadsad" + m = "cbvxssdaa" + showResult1(s, m) +} + +func showResult1(s, m string) { + i := ViolentMatch(s, m) + if i == -1 { + fmt.Println("未找到对应字符串") + } else { + fmt.Println(fmt.Sprintf("匹配到的字符串是:%v", s[i:len(m)+i])) + } +}