손 으로 golang 기본 데이터 구조 와 알고리즘 이 진 트 리 찾기

20847 단어
손 으로 golang 기본 데이터 구조 와 알고리즘 이 진 트 리 찾기
발단
최근 에 < > ([일] 석 다 보 휘, 미 야자 키 수 일) 시 리 즈 를 읽 고 골 랑 으로 연습 할 예정 입 니 다.
두 갈래 찾기 트 리
     (              )       ,
                。

          :
                          ,
                          。

               。
  ,                ,         。
   ,                ,         。

   <> 【 】    ;    

목표.
  • 이 진 트 리 한 그루 를 실현 하고 기본 기능
  • 을 테스트 한다.
    설계 하 다.
  • IComparator: 정의 값 비교 함수. 값 비교 함 수 는 세 가지 상황
  • 보다 작 게 되 돌아 갈 수 있 습 니 다.
  • IBinary SearchTree: 이 진 트 리 의 인 터 페 이 스 를 정의 하고 삭제 와 검 사 를 모두 해 야 합 니 다.
  • Iiterator: 이 진 트 리 의 스 트 리밍 인 터 페 이 스 를 정의 합 니 다.
  • tComparator: 값 비교 함수 의 포장 기 는 IComparator 인 터 페 이 스 를 실현 합 니 다. 구체 적 인 비교 함 수 는 외부 에서 전 달 됩 니 다.
  • tBinary SearchTree: 이 진 트 리 의 예 시 를 찾 아 IBinary SearchTree 인 터 페 이 스 를 실현 합 니 다.
  • tBinary Node: 이 진 트 리 노드 찾기
  • tBSTreeIterator: 이 진 트 리 의 반복 기 를 찾 습 니 다. 내부 에 서 는 넓 은 검색 + 후보 대기 열 을 사용 합 니 다.
  • 유닛 테스트
    bstree_test. go, 이 진 트 리 의 추가 삭제 및 크기 순서 출력 을 테스트 합 니 다.
    package data_structure
    
    import (
        "fmt"
        bstree "learning/gooop/data_structure/binary_search_tree"
        "math/rand"
        "strings"
        "testing"
        "time"
    )
    
    func Test_BinarySearchTree(t *testing.T) {
        fnAssertTrue := func(b bool, msg string) {
            if !b {
                panic(msg)
            }
        }
    
        fnCompare := func(a interface{}, b interface{}) bstree.CompareResult {
            i1 := a.(int)
            i2 := b.(int)
    
            if i1 < i2 {
                return bstree.LESS
            } else if i1 == i2 {
                return bstree.EQUAL
            } else {
                return bstree.GREATER
            }
        }
        comparator := bstree.NewComparator(fnCompare)
    
        // test empty tree
        tree := bstree.NewBinarySearchTree(comparator)
        t.Log(tree)
        fnAssertTrue(tree.String() == "r=nil,s=0,v=0", "expecting r=nil,s=0,v=0")
        fnAssertTrue(tree.Size() == 0, "expecting size == 0")
        fnAssertTrue(tree.IsEmpty(), "expecting empty")
    
        // test one item
        tree.Push(5)
        t.Log(tree)
        fnAssertTrue(tree.String() == "r=5,s=1,v=1 5(n,n)", "expecting r=5,s=1,v=1 5(n,n)")
        fnAssertTrue(tree.Size() == 1, "expecting size == 1")
        fnAssertTrue(tree.IsNotEmpty(), "expecting not empty")
    
        // test min
        ok, v := tree.Min()
        fnAssertTrue(ok, "expecting min() ok")
        fnAssertTrue(v == 5, "expecting 5")
    
        // test max
        ok, v = tree.Max()
        fnAssertTrue(ok, "expecting max() ok")
        fnAssertTrue(v == 5, "expecting 5")
        fnAssertTrue(tree.String() == "r=5,s=1,v=1 5(n,n)", "expecting r=5,s=1,v=1 5(n,n)")
    
        // test pop one
        ok, v = tree.PopMin()
        t.Log(tree)
        fnAssertTrue(tree.String() == "r=nil,s=0,v=2", "expecting r=nil,s=0,v=2")
        fnAssertTrue(ok, "expecting PopMin() ok")
        fnAssertTrue(v == 5, "expecting 5")
        fnAssertTrue(tree.Size() == 0, "expecting size == 0")
        fnAssertTrue(tree.IsEmpty(), "expecting empty")
    
        // test batch push
        samples := []int{ 5,4,8, 2, 7, 9, 1,3,6 }
        for i := 0;i < len(samples);i++ {
            tree.Push(samples[i])
        }
        t.Log(tree)
        fnAssertTrue(tree.Size() == len(samples), "expecting Size() == len(samples)")
        fnAssertTrue(tree.String() == "r=5,s=9,v=11 5(4,8),4(2,n),8(7,9),2(1,3),7(6,n),9(n,n),1(n,n),3(n,n),6(n,n)", "expecting r=5,s=9,v=11 5(4,8),4(2,n),8(7,9),2(1,3),7(6,n),9(n,n),1(n,n),3(n,n),6(n,n)")
    
        for _,it := range samples {
            fnAssertTrue(tree.Has(it), "expecting Has() == true")
        }
    
        // test iterator
        iter := tree.Iterator()
        fnAssertTrue(iter.More(), "expectiong More()")
        iterItems := make([]string, 0)
        for range samples {
            ok,v = iter.Next()
            t.Logf("ok=%v, v=%v", true, v)
            fnAssertTrue(ok, "expectiong Next()")
            iterItems = append(iterItems, fmt.Sprintf("%v", v))
        }
        fnAssertTrue(strings.Join(iterItems, ",") == "5,4,8,2,7,9,1,3,6", "expecting 5,4,8,2,7,9,1,3,6")
        fnAssertTrue(iter.More() == false, "expectiong !iter.More()")
        ok,v = iter.Next()
        fnAssertTrue(!ok, "expecting !iter.Next()")
    
        // test min
        ok,v = tree.Min()
        fnAssertTrue(ok, "expecting ok")
        fnAssertTrue(v == 1, "expection Min() == 1")
    
        // test max
        ok,v = tree.Max()
        fnAssertTrue(ok, "expecting ok")
        fnAssertTrue(v == 9, "expection Max() == 9")
    
        // test batch pop min
        for i := 1;i <= 9;i ++ {
            ok,v = tree.PopMin()
            t.Logf("i=%v v=%v tree=%s", i, v, tree.String())
            fnAssertTrue(ok, "expecting ok")
            fnAssertTrue(v == i, fmt.Sprintf("expecting %v", i))
        }
    
        // test batch pop max
        for i := 0;i < len(samples);i++ {
            tree.Push(samples[i])
        }
        t.Log(tree)
        for i := 1;i <= 9;i ++ {
            ok,v = tree.PopMax()
            t.Logf("i=%v v=%v tree=%s", i, v, tree.String())
            fnAssertTrue(ok, "expecting ok")
            fnAssertTrue(v == 10 - i, fmt.Sprintf("expecting %v", 10 - i))
        }
    
        // test batch push
        samples = []int{ 2,1,3 }
        for i := 0;i < len(samples);i++ {
            tree.Push(samples[i])
        }
        t.Log(tree)
        fnAssertTrue(tree.String() == "r=2,s=3,v=41 2(1,3),1(n,n),3(n,n)", "expecting 2(1,3),1(n,n),3(n,n)")
    
        // test clear
        tree.Clear()
        t.Log(tree)
        fnAssertTrue(tree.String() == "r=nil,s=0,v=42", "expecting empty")
    
        // test batch remove
        rnd := rand.New(rand.NewSource(time.Now().UnixNano()))
        rndItems := make(map[int]bool, 0)
        for i := 0;i < 10000;i++ {
            x := rnd.Intn(50000)
            tree.Push(x)
            rndItems[x] = true
        }
        for k,_ := range rndItems {
            //t.Logf("removing %v", k)
            fnAssertTrue(tree.Remove(k), "expecting Remove() = true")
            //t.Log(tree)
        }
        t.Log(tree)
        fnAssertTrue(tree.IsEmpty(), "expecting empty")
    }

    테스트 출력
    $ go test -v bstree_test.go 
    === RUN   Test_BinarySearchTree
        bstree_test.go:35: r=nil,s=0,v=0
        bstree_test.go:42: r=5,s=1,v=1 5(n,n)
        bstree_test.go:60: r=nil,s=0,v=2
        bstree_test.go:72: r=5,s=9,v=11 5(4,8),4(2,n),8(7,9),2(1,3),7(6,n),9(n,n),1(n,n),3(n,n),6(n,n)
        bstree_test.go:86: ok=true, v=5
        bstree_test.go:86: ok=true, v=4
        bstree_test.go:86: ok=true, v=8
        bstree_test.go:86: ok=true, v=2
        bstree_test.go:86: ok=true, v=7
        bstree_test.go:86: ok=true, v=9
        bstree_test.go:86: ok=true, v=1
        bstree_test.go:86: ok=true, v=3
        bstree_test.go:86: ok=true, v=6
        bstree_test.go:108: i=1 v=1 tree=r=5,s=8,v=12 5(4,8),4(2,n),8(7,9),2(n,3),7(6,n),9(n,n),3(n,n),6(n,n)
        bstree_test.go:108: i=2 v=2 tree=r=5,s=7,v=13 5(4,8),4(3,n),8(7,9),3(n,n),7(6,n),9(n,n),6(n,n)
        bstree_test.go:108: i=3 v=3 tree=r=5,s=6,v=14 5(4,8),4(n,n),8(7,9),7(6,n),9(n,n),6(n,n)
        bstree_test.go:108: i=4 v=4 tree=r=5,s=5,v=15 5(n,8),8(7,9),7(6,n),9(n,n),6(n,n)
        bstree_test.go:108: i=5 v=5 tree=r=8,s=4,v=16 8(7,9),7(6,n),9(n,n),6(n,n)
        bstree_test.go:108: i=6 v=6 tree=r=8,s=3,v=17 8(7,9),7(n,n),9(n,n)
        bstree_test.go:108: i=7 v=7 tree=r=8,s=2,v=18 8(n,9),9(n,n)
        bstree_test.go:108: i=8 v=8 tree=r=9,s=1,v=19 9(n,n)
        bstree_test.go:108: i=9 v=9 tree=r=nil,s=0,v=20
        bstree_test.go:117: r=5,s=9,v=29 5(4,8),4(2,n),8(7,9),2(1,3),7(6,n),9(n,n),1(n,n),3(n,n),6(n,n)
        bstree_test.go:120: i=1 v=9 tree=r=5,s=8,v=30 5(4,8),4(2,n),8(7,n),2(1,3),7(6,n),1(n,n),3(n,n),6(n,n)
        bstree_test.go:120: i=2 v=8 tree=r=5,s=7,v=31 5(4,7),4(2,n),7(6,n),2(1,3),6(n,n),1(n,n),3(n,n)
        bstree_test.go:120: i=3 v=7 tree=r=5,s=6,v=32 5(4,6),4(2,n),6(n,n),2(1,3),1(n,n),3(n,n)
        bstree_test.go:120: i=4 v=6 tree=r=5,s=5,v=33 5(4,n),4(2,n),2(1,3),1(n,n),3(n,n)
        bstree_test.go:120: i=5 v=5 tree=r=4,s=4,v=34 4(2,n),2(1,3),1(n,n),3(n,n)
        bstree_test.go:120: i=6 v=4 tree=r=2,s=3,v=35 2(1,3),1(n,n),3(n,n)
        bstree_test.go:120: i=7 v=3 tree=r=2,s=2,v=36 2(1,n),1(n,n)
        bstree_test.go:120: i=8 v=2 tree=r=1,s=1,v=37 1(n,n)
        bstree_test.go:120: i=9 v=1 tree=r=nil,s=0,v=38
        bstree_test.go:130: r=2,s=3,v=41 2(1,3),1(n,n),3(n,n)
        bstree_test.go:135: r=nil,s=0,v=42
        bstree_test.go:151: r=nil,s=0,v=18146
    --- PASS: Test_BinarySearchTree (0.01s)
    PASS
    ok      command-line-arguments  0.012s

    IComparator.go
    정의 값 비교 함수. 값 비교 함 수 는 세 가지 상황 보다 작 게 되 돌아 갈 수 있 습 니 다.
    package binary_search_tree
    
    type IComparator interface {
        Compare(a interface{}, b interface{}) CompareResult
    }
    
    type CompareResult int
    const LESS CompareResult = -1
    const EQUAL CompareResult = 0
    const GREATER CompareResult = 1

    IBinarySearchTree.go
    이 진 트 리 의 인 터 페 이 스 를 정의 하고 삭제 와 검 사 를 모두 해 야 합 니 다.
    package binary_search_tree
    
    type IBinarySearchTree interface {
        Size() int
        IsEmpty() bool
        IsNotEmpty() bool
    
        Push(value interface{})
        Min() (bool, interface{})
        Max() (bool, interface{})
        Has(value interface{}) bool
        PopMin() (bool, interface{})
        PopMax() (bool, interface{})
        Remove(value interface{}) bool
        Clear()
    
        Iterator() IIterator
        String() string
    }

    IIterator.go
    이 진 트 리 의 스 트 리밍 인 터 페 이 스 를 정의 합 니 다.
    package binary_search_tree
    
    type IIterator interface {
        More() bool
        Next() (bool,interface{})
    }

    tComparator.go
    값 비교 함수 의 포장 기 는 IComparator 인 터 페 이 스 를 실현 합 니 다. 구체 적 인 비교 함 수 는 외부 에서 들 어 옵 니 다.
    package binary_search_tree
    
    import "errors"
    
    type FnCompare func(a interface{}, b interface{}) CompareResult
    
    type tComparator struct {
        fnCompare FnCompare
    }
    
    func NewComparator(fn FnCompare) IComparator {
        if fn == nil {
            panic(gNullArgumentError)
        }
    
        return &tComparator{
            fnCompare: fn,
        }
    }
    
    func (me *tComparator) Compare(a interface{}, b interface{}) CompareResult {
        if a == nil || b == nil {
            panic(gNullArgumentError)
        }
        return me.fnCompare(a, b)
    }
    
    var gNullArgumentError = errors.New("null argument error")

    tBinarySearchTree.go
    이 진 트 리 의 예 시 를 찾 아 IBinary SearchTree 인 터 페 이 스 를 실현 합 니 다.
    package binary_search_tree
    
    import (
        "fmt"
        "strings"
    )
    
    type tBinarySearchTree struct {
        comparator IComparator
        root       *tBinaryNode
        size       int
        version    uint64
    }
    
    func NewBinarySearchTree(comparator IComparator) IBinarySearchTree {
        return &tBinarySearchTree{
            comparator: comparator,
            root:       nil,
            size:       0,
            version:    0,
        }
    }
    
    func (me *tBinarySearchTree) Size() int {
        return me.size
    }
    
    func (me *tBinarySearchTree) IsEmpty() bool {
        return me.size <= 0
    }
    
    func (me *tBinarySearchTree) IsNotEmpty() bool {
        return !me.IsEmpty()
    }
    
    func (me *tBinarySearchTree) Push(value interface{}) {
        if me.IsEmpty() {
            me.root = me.append(value)
            return
        }
    
        for node := me.root; node != nil; {
            r := me.comparator.Compare(value, node.value)
    
            switch r {
            case EQUAL:
                return
    
            case LESS:
                if node.left == nil {
                    node.LChild(me.append(value))
                    return
                } else {
                    node = node.left
                }
                break
    
            case GREATER:
                if node.right == nil {
                    node.RChild(me.append(value))
                    return
                } else {
                    node = node.right
                }
                break
            }
        }
    }
    
    func (me *tBinarySearchTree) append(value interface{}) *tBinaryNode {
        me.size++
        me.version++
        return newBinaryNode(value)
    }
    
    func (me *tBinarySearchTree) Min() (bool, interface{}) {
        ok, node := me.getMinNode(me.root)
        if !ok {
            return false, nil
        }
        return true, node.value
    }
    
    func (me *tBinarySearchTree) Max() (bool, interface{}) {
        ok, node := me.getMaxNode(me.root)
        if !ok {
            return false, nil
        }
        return true, node.value
    }
    
    
    func (me *tBinarySearchTree) Has(value interface{}) bool {
        ok, _ := me.find(value)
        return ok
    }
    
    func (me *tBinarySearchTree) find(value interface{}) (ok bool, node *tBinaryNode) {
        if me.IsEmpty() {
            return false, nil
        }
    
        for node = me.root; node != nil; {
            r := me.comparator.Compare(value, node.value)
    
            switch r {
            case EQUAL:
                return true, node
    
            case LESS:
                if node.left == nil {
                    return false, nil
                } else {
                    node = node.left
                }
                break
    
            case GREATER:
                if node.right == nil {
                    return false, nil
                } else {
                    node = node.right
                }
                break
            }
        }
    
        return false, nil
    }
    
    
    func (me *tBinarySearchTree) getMinNode(from *tBinaryNode) (ok bool, left *tBinaryNode) {
        if from == nil {
            return false, nil
        }
    
        left = from.left
        if left == nil {
            return true, from
        }
    
        for {
            if left.left == nil {
                return true, left
            }
    
            left = left.left
        }
    }
    
    func (me *tBinarySearchTree) getMaxNode(from *tBinaryNode) (ok bool, right *tBinaryNode) {
        if from == nil {
            return false, nil
        }
    
        right = from.right
        if right == nil {
            return true, from
        }
    
        for {
            if right.right == nil {
                return true, right
            }
    
            right = right.right
        }
    }
    
    func (me *tBinarySearchTree) PopMin() (bool, interface{}) {
        ok, node := me.getMinNode(me.root)
        if !ok {
            return false, nil
        }
        value := node.value
    
        me.removeNode(node)
    
        me.size--
        me.version++
    
        return true, value
    }
    
    
    func (me *tBinarySearchTree) removeNode(node *tBinaryNode) {
        //var pv interface{} = "nil"
        //if node.parent != nil {
        //    pv = node.parent.value
        //}
        //fmt.Printf("removeNode %v.%v
    ", pv, node.value) left := node.left right := node.right if node.parent == nil { switch node.childrenCount() { case 0: me.root = nil break case 1: if left != nil { me.root = left left.SetParent(nil) } else if right != nil { me.root = right right.SetParent(nil) } default: _, n := me.getMaxNode(left) if n == left { me.root = n n.SetParent(nil) n.RChild(right) } else { me.root.value = n.value me.removeNode(n) } } } else { parent := node.parent switch node.childrenCount() { case 0: if parent.left == node { parent.left = nil } else { parent.right = nil } break case 1: if left != nil { if parent.left == node { parent.LChild(left) } else { parent.RChild(left) } } else if right != nil { if parent.left == node { parent.LChild(right) } else { parent.RChild(right) } } default: _, n := me.getMaxNode(left) if n == left { if parent.left == node { parent.LChild(n) } else { parent.RChild(n) } n.RChild(right) } else { node.value = n.value me.removeNode(n) } } } } func (me *tBinarySearchTree) PopMax() (bool, interface{}) { ok, node := me.getMaxNode(me.root) if !ok { return false, nil } me.removeNode(node) me.size-- me.version++ return true, node.value } func (me *tBinarySearchTree) Remove(value interface{}) bool { ok, node := me.find(value) if !ok { return false } me.removeNode(node) me.size-- me.version++ return true } func (me *tBinarySearchTree) Clear() { if me.IsEmpty() { return } me.root = nil me.size = 0 me.version++ } func (me *tBinarySearchTree) Iterator() IIterator { return newBSTreeIterator(me) } func (me *tBinarySearchTree) String() string { queue := newVisitQeuue() queue.push(me.root) items := make([]string, 0) for ;queue.more(); { ok, node := queue.poll() if ok { queue.push(node.left) queue.push(node.right) var lv interface{} = "n" if node.left != nil { lv = node.left.value } var rv interface{} = "n" if node.right != nil { rv = node.right.value } items = append(items, fmt.Sprintf("%v(%v,%v)", node.value, lv,rv)) } else { break } } r := "nil" if me.root != nil { r = fmt.Sprintf("%v", me.root.value) } if len(items) > 0 { return fmt.Sprintf("r=%v,s=%v,v=%v %s", r, me.size, me.version, strings.Join(items, ",")) } else { return fmt.Sprintf("r=%v,s=%v,v=%v", r, me.size, me.version) } }

    tBinaryNode.go
    두 갈래 찾기 트 리 노드
    package binary_search_tree
    
    type tBinaryNode struct {
        value interface{}
        parent *tBinaryNode
        left *tBinaryNode
        right *tBinaryNode
    }
    
    func newBinaryNode(value interface{}) *tBinaryNode {
        return &tBinaryNode{
            value: value,
            left: nil,
            right: nil,
        }
    }
    
    func (me *tBinaryNode) childrenCount() int {
        left := me.left
        right := me.right
    
        if left == nil && right == nil {
            return 0
        }
    
        if left == nil || right == nil {
            return 1
        }
    
        return 2
    }
    
    func (me *tBinaryNode) LChild(node *tBinaryNode) {
        me.left = node
        if node != nil {
            node.SetParent(me)
        }
    }
    
    func (me *tBinaryNode) SetParent(parent *tBinaryNode) {
        if me.parent == parent {
            return
        }
    
        if me.parent != nil {
            if me.parent.left == me {
                me.parent.left = nil
            } else if me.parent.right == me {
                me.parent.right = nil
            }
        }
    
        me.parent = parent
    }
    
    func (me *tBinaryNode) RChild(node *tBinaryNode) {
        me.right = node
        if node != nil {
            node.SetParent(me)
        }
    }

    tBSTreeIterator.go
    이 진 트 리 의 반복 기 를 찾 습 니 다. 내부 에 서 는 넓 은 검색 + 후보 대기 열 을 사용 합 니 다.
    package binary_search_tree
    
    type tBSTreeIterator struct {
        tree *tBinarySearchTree
        queue *tVisitQueue
        version uint64
    }
    
    
    type tVisitQueue struct {
        head *tQueuedNode
        tail *tQueuedNode
    }
    
    type tQueuedNode struct {
        node *tBinaryNode
        next *tQueuedNode
    }
    
    func newQueuedNode(node *tBinaryNode) *tQueuedNode {
        return &tQueuedNode{
            node: node,
            next: nil,
        }
    }
    
    func newVisitQeuue() *tVisitQueue {
        return &tVisitQueue{
            nil,
            nil,
        }
    }
    
    func (me *tVisitQueue) push(node *tBinaryNode) {
        if node == nil {
            return
        }
    
        qn := newQueuedNode(node)
        if me.head == nil {
            me.head = qn
            me.tail = qn
        } else {
            me.tail.next = qn
            me.tail = qn
        }
    }
    
    func (me *tVisitQueue) poll() (bool, *tBinaryNode) {
        if me.head == nil {
            return false, nil
    
        } else {
            it := me.head
            if it == me.tail {
                me.tail = nil
            }
            me.head = me.head.next
            return true, it.node
        }
    }
    
    func (me *tVisitQueue) more() bool {
        return me.head != nil
    }
    
    func newBSTreeIterator(tree *tBinarySearchTree) IIterator {
        it := &tBSTreeIterator{
            tree: tree,
            queue: newVisitQeuue(),
            version: tree.version,
        }
        it.queue.push(tree.root)
        return it
    }
    
    func (me *tBSTreeIterator) More() bool {
        if me.version != me.tree.version {
            return false
        } else {
            return me.queue.more()
        }
    }
    
    func (me *tBSTreeIterator) Next() (bool, interface{}) {
        if !me.More() {
            return false, nil
        }
    
        ok, node := me.queue.poll()
        if !ok {
            return false, nil
        }
    
        me.queue.push(node.left)
        me.queue.push(node.right)
        return true, node.value
    }

    (end)

    좋은 웹페이지 즐겨찾기