mirror of
https://github.com/golang/go
synced 2024-09-15 22:20:06 +00:00
bytes: use Rabin-Karp algorithm for LastIndex
Implement LastIndex using the Rabin-Karp algorithm akin to strings.LastIndex name old time/op new time/op delta LastIndexHard1-8 3.16ms ± 1% 1.44ms ± 0% -54.35% (p=0.008 n=5+5) LastIndexHard2-8 3.17ms ± 1% 1.45ms ± 0% -54.27% (p=0.008 n=5+5) LastIndexHard3-8 3.05ms ± 1% 1.44ms ± 1% -52.58% (p=0.008 n=5+5) Change-Id: Ie8ddd179cd84dfa00e3e4e2327ef932975c88670 Reviewed-on: https://go-review.googlesource.com/c/go/+/166258 Run-TryBot: Tobias Klauser <tobias.klauser@gmail.com> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Ian Lance Taylor <iant@golang.org>
This commit is contained in:
parent
b4baa8dd1d
commit
ce7534ff06
|
@ -114,12 +114,34 @@ func indexBytePortable(s []byte, c byte) int {
|
|||
// LastIndex returns the index of the last instance of sep in s, or -1 if sep is not present in s.
|
||||
func LastIndex(s, sep []byte) int {
|
||||
n := len(sep)
|
||||
if n == 0 {
|
||||
switch {
|
||||
case n == 0:
|
||||
return len(s)
|
||||
case n == 1:
|
||||
return LastIndexByte(s, sep[0])
|
||||
case n == len(s):
|
||||
if Equal(s, sep) {
|
||||
return 0
|
||||
}
|
||||
return -1
|
||||
case n > len(s):
|
||||
return -1
|
||||
}
|
||||
c := sep[0]
|
||||
for i := len(s) - n; i >= 0; i-- {
|
||||
if s[i] == c && (n == 1 || Equal(s[i:i+n], sep)) {
|
||||
// Rabin-Karp search from the end of the string
|
||||
hashss, pow := hashStrRev(sep)
|
||||
last := len(s) - n
|
||||
var h uint32
|
||||
for i := len(s) - 1; i >= last; i-- {
|
||||
h = h*primeRK + uint32(s[i])
|
||||
}
|
||||
if h == hashss && Equal(s[last:], sep) {
|
||||
return last
|
||||
}
|
||||
for i := last - 1; i >= 0; i-- {
|
||||
h *= primeRK
|
||||
h += uint32(s[i])
|
||||
h -= pow * uint32(s[i+n])
|
||||
if h == hashss && Equal(s[i:i+n], sep) {
|
||||
return i
|
||||
}
|
||||
}
|
||||
|
@ -987,3 +1009,20 @@ func hashStr(sep []byte) (uint32, uint32) {
|
|||
}
|
||||
return hash, pow
|
||||
}
|
||||
|
||||
// hashStrRev returns the hash of the reverse of sep and the
|
||||
// appropriate multiplicative factor for use in Rabin-Karp algorithm.
|
||||
func hashStrRev(sep []byte) (uint32, uint32) {
|
||||
hash := uint32(0)
|
||||
for i := len(sep) - 1; i >= 0; i-- {
|
||||
hash = hash*primeRK + uint32(sep[i])
|
||||
}
|
||||
var pow, sq uint32 = 1, primeRK
|
||||
for i := len(sep); i > 0; i >>= 1 {
|
||||
if i&1 != 0 {
|
||||
pow *= sq
|
||||
}
|
||||
sq *= sq
|
||||
}
|
||||
return hash, pow
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue