avl insertion
This commit is contained in:
parent
3c6c1e8df5
commit
f31b72c2f7
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
||||
/.idea
|
1
.tool-versions
Normal file
1
.tool-versions
Normal file
@ -0,0 +1 @@
|
||||
golang 1.20.6
|
2
LICENSE
2
LICENSE
@ -1,6 +1,6 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) <year> <copyright holders>
|
||||
Copyright (c) 2023 Suyono
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
|
114
avl.go
Normal file
114
avl.go
Normal file
@ -0,0 +1,114 @@
|
||||
package avl
|
||||
|
||||
type Comparable interface {
|
||||
Compare(c Comparable) int
|
||||
}
|
||||
|
||||
type Node struct {
|
||||
key Comparable
|
||||
height int
|
||||
left, right *Node
|
||||
}
|
||||
|
||||
func NewNode(key Comparable) *Node {
|
||||
return &Node{
|
||||
key: key,
|
||||
height: 1,
|
||||
}
|
||||
}
|
||||
|
||||
func Insert(node *Node, key Comparable) *Node {
|
||||
if node == nil {
|
||||
return NewNode(key)
|
||||
}
|
||||
|
||||
if key.Compare(node.key) < 0 {
|
||||
node.left = Insert(node.left, key)
|
||||
} else if key.Compare(node.key) > 0 {
|
||||
node.right = Insert(node.right, key)
|
||||
} else {
|
||||
panic("duplicate key") // duplicate keys not allowed
|
||||
}
|
||||
|
||||
node.height = 1 + max(height(node.left), height(node.right))
|
||||
|
||||
balance := getBalance(node)
|
||||
|
||||
// left-left case
|
||||
if balance > 1 && key.Compare(node.left.key) < 0 {
|
||||
return rightRotate(node)
|
||||
}
|
||||
|
||||
// right-right case
|
||||
if balance < -1 && key.Compare(node.right.key) > 0 {
|
||||
return leftRotate(node)
|
||||
}
|
||||
|
||||
// left-right case
|
||||
if balance > 1 && key.Compare(node.left.key) > 0 {
|
||||
node.left = leftRotate(node.left)
|
||||
return rightRotate(node)
|
||||
}
|
||||
|
||||
// right-left case
|
||||
if balance < -1 && key.Compare(node.right.key) < 0 {
|
||||
node.right = rightRotate(node.right)
|
||||
return leftRotate(node)
|
||||
}
|
||||
|
||||
return node
|
||||
}
|
||||
|
||||
func max(a, b int) int {
|
||||
if a > b {
|
||||
return a
|
||||
} else {
|
||||
return b
|
||||
}
|
||||
}
|
||||
|
||||
func height(node *Node) int {
|
||||
if node == nil {
|
||||
return 0
|
||||
}
|
||||
|
||||
return node.height
|
||||
}
|
||||
|
||||
func getBalance(node *Node) int {
|
||||
if node == nil {
|
||||
return 0
|
||||
}
|
||||
|
||||
return height(node.left) - height(node.right)
|
||||
}
|
||||
|
||||
func rightRotate(y *Node) *Node {
|
||||
var (
|
||||
x *Node = y.left
|
||||
T2 *Node = x.right
|
||||
)
|
||||
|
||||
x.right = y
|
||||
y.left = T2
|
||||
|
||||
y.height = max(height(y.left), height(y.right)) + 1
|
||||
x.height = max(height(x.left), height(x.right)) + 1
|
||||
|
||||
return x
|
||||
}
|
||||
|
||||
func leftRotate(x *Node) *Node {
|
||||
var (
|
||||
y *Node = x.right
|
||||
T2 *Node = y.left
|
||||
)
|
||||
|
||||
y.left = x
|
||||
x.right = T2
|
||||
|
||||
x.height = max(height(x.left), height(x.right)) + 1
|
||||
y.height = max(height(y.left), height(y.right)) + 1
|
||||
|
||||
return y
|
||||
}
|
88
avl_test.go
Normal file
88
avl_test.go
Normal file
@ -0,0 +1,88 @@
|
||||
package avl
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"testing"
|
||||
)
|
||||
|
||||
type testKey int
|
||||
|
||||
func (k testKey) Compare(c Comparable) int {
|
||||
var (
|
||||
ck testKey
|
||||
ok bool
|
||||
)
|
||||
|
||||
if ck, ok = c.(testKey); !ok {
|
||||
panic("unexpected type")
|
||||
}
|
||||
|
||||
return int(k - ck)
|
||||
}
|
||||
|
||||
func (k testKey) String() string {
|
||||
return fmt.Sprintf("%d", int(k))
|
||||
}
|
||||
|
||||
func preOrder(b *bytes.Buffer, node *Node) {
|
||||
if node != nil {
|
||||
_, _ = fmt.Fprint(b, node.key, " ")
|
||||
preOrder(b, node.left)
|
||||
preOrder(b, node.right)
|
||||
}
|
||||
}
|
||||
|
||||
func TestInsert(t *testing.T) {
|
||||
var (
|
||||
root *Node
|
||||
b *bytes.Buffer
|
||||
)
|
||||
|
||||
root = Insert(root, testKey(10))
|
||||
root = Insert(root, testKey(20))
|
||||
root = Insert(root, testKey(30))
|
||||
root = Insert(root, testKey(40))
|
||||
root = Insert(root, testKey(50))
|
||||
root = Insert(root, testKey(25))
|
||||
|
||||
b = bytes.NewBuffer([]byte{})
|
||||
preOrder(b, root)
|
||||
|
||||
//The constructed AVL Tree would be
|
||||
// 30
|
||||
// / \
|
||||
// 20 40
|
||||
// / \ \
|
||||
// 10 25 50
|
||||
|
||||
t.Log("preorder traversal of the tree")
|
||||
t.Log(b)
|
||||
}
|
||||
|
||||
func TestInsert2(t *testing.T) {
|
||||
var (
|
||||
tree *Tree
|
||||
keys = []testKey{10, 20, 25, 30, 40, 50}
|
||||
out []Comparable
|
||||
)
|
||||
|
||||
tree = new(Tree)
|
||||
tree.Insert(keys[0])
|
||||
tree.Insert(keys[1])
|
||||
tree.Insert(keys[3])
|
||||
tree.Insert(keys[4])
|
||||
tree.Insert(keys[5])
|
||||
tree.Insert(keys[2])
|
||||
|
||||
out = tree.Slice()
|
||||
for i, k := range out {
|
||||
if ck, ok := k.(testKey); ok {
|
||||
if ck != keys[i] {
|
||||
t.Fatal("mismatch data")
|
||||
}
|
||||
} else {
|
||||
t.Fatal("invalid data type")
|
||||
}
|
||||
}
|
||||
}
|
33
tree.go
Normal file
33
tree.go
Normal file
@ -0,0 +1,33 @@
|
||||
package avl
|
||||
|
||||
type Tree struct {
|
||||
root *Node
|
||||
num int
|
||||
}
|
||||
|
||||
func (t *Tree) Insert(key Comparable) {
|
||||
t.root = Insert(t.root, key)
|
||||
t.num++
|
||||
}
|
||||
|
||||
func (t *Tree) Slice() []Comparable {
|
||||
retval := make([]Comparable, t.num)
|
||||
t.slice(retval, 0, t.root)
|
||||
|
||||
return retval
|
||||
}
|
||||
|
||||
func (t *Tree) slice(s []Comparable, index int, node *Node) int {
|
||||
if node.left != nil {
|
||||
index = t.slice(s, index, node.left)
|
||||
}
|
||||
|
||||
s[index] = node.key
|
||||
index++
|
||||
|
||||
if node.right != nil {
|
||||
index = t.slice(s, index, node.right)
|
||||
}
|
||||
|
||||
return index
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user