go语言几种算法(三)

13、Rabin-Karp(Rabin-Karp字符串匹配算法)

package main
 
import (
    "fmt"
)
 
const base = 16777619
 
func Search(txt string, patterns []string) []string {
    in := indices(txt, patterns)
    matches := make([]string, len(in))
    i := 0
    for j, p := range patterns {
        if _, ok := in[j]; ok {
            matches[i] = p
            i++
        }
    }
 
    return matches
}
 
func indices(txt string, patterns []string) map[int]int {
    n, m := len(txt), minLen(patterns)
    matches := make(map[int]int)
 
    if n < m || len(patterns) == 0 {
        return matches
    }
 
    var mult uint32 = 1 // mult = base^(m-1)
    for i := 0; i < m-1; i++ {
        mult = (mult * base)
    }
 
    hp := hashPatterns(patterns, m)
    h := hash(txt[:m])
    for i := 0; i < n-m+1 && len(hp) > 0; i++ {
        if i > 0 {
            h = h - mult*uint32(txt[i-1])
            h = h*base + uint32(txt[i+m-1])
        }
 
        if mps, ok := hp[h]; ok {
            for _, pi := range mps {
                pat := patterns[pi]
                e := i + len(pat)
                if _, ok := matches[pi]; !ok && e <= n && pat == txt[i:e] {
                    matches[pi] = i
                }
            }
        }
    }
    return matches
}
 
func hash(s string) uint32 {
    var h uint32
    for i := 0; i < len(s); i++ {
        h = (h*base + uint32(s[i]))
    }
    return h
}
 
func hashPatterns(patterns []string, l int) map[uint32][]int {
    m := make(map[uint32][]int)
    for i, t := range patterns {
        h := hash(t[:l])
        if _, ok := m[h]; ok {
            m[h] = append(m[h], i)
        } else {
            m[h] = []int{i}
        }
    }
 
    return m
}
 
func minLen(patterns []string) int {
    if len(patterns) == 0 {
        return 0
    }
 
    m := len(patterns[0])
    for i := range patterns {
        if m > len(patterns[i]) {
            m = len(patterns[i])
        }
    }
 
    return m
}
     
func main() {
    txt := "Australia is a country and continent surrounded by the Indian and Pacific oceans."
    patterns := []string{"and", "the", "surround", "Pacific", "Germany"}
    matches := Search(txt, patterns)
    fmt.Println(matches)
}


14、LIFO Stack and FIFO Queue(栈,队列)

package main
  
import (
    "fmt"
)
  
type Node struct {
    Value int
}
  
func (n *Node) String() string {
    return fmt.Sprint(n.Value)
}
  
// NewStack returns a new stack.
func NewStack() *Stack {
    return &Stack{}
}
  
// Stack is a basic LIFO stack that resizes as needed.
type Stack struct {
    nodes []*Node
    count int
}
  
// Push adds a node to the stack.
func (s *Stack) Push(n *Node) {
    s.nodes = append(s.nodes[:s.count], n)
    s.count++
}
  
// Pop removes and returns a node from the stack in last to first order.
func (s *Stack) Pop() *Node {
    if s.count == 0 {
        return nil
    }
    s.count--
    return s.nodes[s.count]
}
  
// NewQueue returns a new queue with the given initial size.
func NewQueue(size int) *Queue {
    return &Queue{
        nodes: make([]*Node, size),
        size:  size,
    }
}
  
// Queue is a basic FIFO queue based on a circular list that resizes as needed.
type Queue struct {
    nodes []*Node
    size  int
    head  int
    tail  int
    count int
}
  
// Push adds a node to the queue.
func (q *Queue) Push(n *Node) {
    if q.head == q.tail && q.count > 0 {
        nodes := make([]*Node, len(q.nodes)+q.size)
        copy(nodes, q.nodes[q.head:])
        copy(nodes[len(q.nodes)-q.head:], q.nodes[:q.head])
        q.head = 0
        q.tail = len(q.nodes)
        q.nodes = nodes
    }
    q.nodes[q.tail] = n
    q.tail = (q.tail + 1) % len(q.nodes)
    q.count++
}
  
// Pop removes and returns a node from the queue in first to last order.
func (q *Queue) Pop() *Node {
    if q.count == 0 {
        return nil
    }
    node := q.nodes[q.head]
    q.head = (q.head + 1) % len(q.nodes)
    q.count--
    return node
}
  
func main() {
    s := NewStack()
    s.Push(&Node{3})
    s.Push(&Node{5})
    s.Push(&Node{7})
    s.Push(&Node{9})
    fmt.Println(s.Pop(), s.Pop(), s.Pop(), s.Pop())
  
    q := NewQueue(1)
    q.Push(&Node{2})
    q.Push(&Node{4})
    q.Push(&Node{6})
    q.Push(&Node{8})
    fmt.Println(q.Pop(), q.Pop(), q.Pop(), q.Pop())
}


15、Median of Medians(中位数的中位数)

package main
 
import "fmt"
 
type Node struct {
    prev *Node
    next *Node
    key  interface{}
}
 
type List struct {
    head *Node
    tail *Node
}
 
func (L *List) Insert(key interface{}) {
    list := &Node{
        next: L.head,
        key:  key,
    }
    if L.head != nil {
        L.head.prev = list
    }
    L.head = list
 
    l := L.head
    for l.next != nil {
        l = l.next
    }
    L.tail = l
}
 
func (l *List) Display() {
    list := l.head
    for list != nil {
        fmt.Printf("%+v ->", list.key)
        list = list.next
    }
    fmt.Println()
}
 
func Display(list *Node) {
    for list != nil {
        fmt.Printf("%v ->", list.key)
        list = list.next
    }
    fmt.Println()
}
 
func ShowBackwards(list *Node) {
    for list != nil {
        fmt.Printf("%v <-", list.key)
        list = list.prev
    }
    fmt.Println()
}
 
func (l *List) Reverse() {
    curr := l.head
    var prev *Node
    l.tail = l.head
 
    for curr != nil {
        next := curr.next
        curr.next = prev
        prev = curr
        curr = next
    }
    l.head = prev
    Display(l.head)
}
 
func main() {
    link := List{}
    link.Insert(5)
    link.Insert(9)
    link.Insert(13)
    link.Insert(22)
    link.Insert(28)
    link.Insert(36)
     
    fmt.Println("\n==============================\n")
    fmt.Printf("Head: %v\n", link.head.key)
    fmt.Printf("Tail: %v\n", link.tail.key)
    link.Display()
    fmt.Println("\n==============================\n")
    fmt.Printf("head: %v\n", link.head.key)
    fmt.Printf("tail: %v\n", link.tail.key)
    link.Reverse()
    fmt.Println("\n==============================\n")
}


16、Longest Common Sub-sequence(最长公共子序列)

package main
 
import "fmt"
 
type Node struct {
    prev *Node
    next *Node
    key  interface{}
}
 
type List struct {
    head *Node
    tail *Node
}
 
func (L *List) Insert(key interface{}) {
    list := &Node{
        next: L.head,
        key:  key,
    }
    if L.head != nil {
        L.head.prev = list
    }
    L.head = list
 
    l := L.head
    for l.next != nil {
        l = l.next
    }
    L.tail = l
}
 
func (l *List) Display() {
    list := l.head
    for list != nil {
        fmt.Printf("%+v ->", list.key)
        list = list.next
    }
    fmt.Println()
}
 
func Display(list *Node) {
    for list != nil {
        fmt.Printf("%v ->", list.key)
        list = list.next
    }
    fmt.Println()
}
 
func ShowBackwards(list *Node) {
    for list != nil {
        fmt.Printf("%v <-", list.key)
        list = list.prev
    }
    fmt.Println()
}
 
func (l *List) Reverse() {
    curr := l.head
    var prev *Node
    l.tail = l.head
 
    for curr != nil {
        next := curr.next
        curr.next = prev
        prev = curr
        curr = next
    }
    l.head = prev
    Display(l.head)
}
 
func main() {
    link := List{}
    link.Insert(5)
    link.Insert(9)
    link.Insert(13)
    link.Insert(22)
    link.Insert(28)
    link.Insert(36)
     
    fmt.Println("\n==============================\n")
    fmt.Printf("Head: %v\n", link.head.key)
    fmt.Printf("Tail: %v\n", link.tail.key)
    link.Display()
    fmt.Println("\n==============================\n")
    fmt.Printf("head: %v\n", link.head.key)
    fmt.Printf("tail: %v\n", link.tail.key)
    link.Reverse()
    fmt.Println("\n==============================\n")
}


17、Levenshtein distance(编辑距离-字符串相似度算法)

package main
import "fmt"
 
func levenshtein(str1, str2 []rune) int {
    s1len := len(str1)
    s2len := len(str2)
    column := make([]int, len(str1)+1)
 
    for y := 1; y <= s1len; y++ {
        column[y] = y
    }
    for x := 1; x <= s2len; x++ {
        column[0] = x
        lastkey := x - 1
        for y := 1; y <= s1len; y++ {
            oldkey := column[y]
            var incr int
            if str1[y-1] != str2[x-1] {
                incr = 1
            }
 
            column[y] = minimum(column[y]+1, column[y-1]+1, lastkey+incr)
            lastkey = oldkey
        }
    }
    return column[s1len]
}
 
func minimum(a, b, c int) int {
    if a < b {
        if a < c {
            return a
        }
    } else {
        if b < c {
            return b
        }
    }
    return c
}
 
func main(){
    var str1 = []rune("Asheville")
    var str2 = []rune("Arizona")
    fmt.Println("Distance between Asheville and Arizona:",levenshtein(str1,str2))
     
    str1 = []rune("Python")
    str2 = []rune("Peithen")
    fmt.Println("Distance between Python and Peithen:",levenshtein(str1,str2))
     
    str1 = []rune("Orange")
    str2 = []rune("Apple")
    fmt.Println("Distance between Orange and Apple:",levenshtein(str1,str2))
}


18、Knuth–Morris–Pratt(KMP-克努斯-莫里斯-普拉特算法-子串匹配算法)

package main
 
import (
    "fmt"
)
 
const ( 
    PatternSize int = 100
)
 
func SearchNext(haystack string, needle string) int {
    retSlice := KMP(haystack, needle)
    if len(retSlice) > 0 {
        return retSlice[len(retSlice)-1]
    }
 
    return -1
}
 
func SearchString(haystack string, needle string) int {
    retSlice := KMP(haystack, needle)
    if len(retSlice) > 0 {
        return retSlice[0]
    }
 
    return -1
}
 
func KMP(haystack string, needle string) []int {
    next := preKMP(needle)
    i := 0
    j := 0
    m := len(needle)
    n := len(haystack)
 
    x := []byte(needle)
    y := []byte(haystack)
    var ret []int
 
    //got zero target or want, just return empty result
    if m == 0 || n == 0 {
        return ret
    }
 
    //want string bigger than target string
    if n < m {
        return ret
    }
 
    for j < n {
        for i > -1 && x[i] != y[j] {
            i = next[i]
        }
        i++
        j++
 
        //fmt.Println(i, j)
        if i >= m {
            ret = append(ret, j-i)
            //fmt.Println("find:", j, i)
            i = next[i]
        }
    }
 
    return ret
}
 
func preMP(x string) [PatternSize]int {
    var i, j int
    length := len(x) - 1
    var mpNext [PatternSize]int
    i = 0
    j = -1
    mpNext[0] = -1
 
    for i < length {
        for j > -1 && x[i] != x[j] {
            j = mpNext[j]
        }
        i++
        j++
        mpNext[i] = j
    }
    return mpNext
}
 
func preKMP(x string) [PatternSize]int {
    var i, j int
    length := len(x) - 1
    var kmpNext [PatternSize]int
    i = 0
    j = -1
    kmpNext[0] = -1
 
    for i < length {
        for j > -1 && x[i] != x[j] {
            j = kmpNext[j]
        }
 
        i++
        j++
 
        if x[i] == x[j] {
            kmpNext[i] = kmpNext[j]
        } else {
            kmpNext[i] = j
        }
    }
    return kmpNext
}
     
func main() {
    fmt.Println("Search First Position String:\n")
    fmt.Println(SearchString("cocacola", "co"))
    fmt.Println(SearchString("Australia", "lia"))   
    fmt.Println(SearchString("cocacola", "cx"))
    fmt.Println(SearchString("AABAACAADAABAABA", "AABA"))
     
    fmt.Println("\nSearch Last Position String:\n")
    fmt.Println(SearchNext("cocacola", "co"))
    fmt.Println(SearchNext("Australia", "lia")) 
    fmt.Println(SearchNext("cocacola", "cx"))
    fmt.Println(SearchNext("AABAACAADAABAABAAABAACAADAABAABA", "AABA"))
}




标签: golang 算法
2017.9.19   /   热度:1238   /   分类: golang

发表评论:

©地球仪的BLOG  |  Powered by Emlog