avl insertion
This commit is contained in:
parent
3c6c1e8df5
commit
f31b72c2f7
|
@ -0,0 +1 @@
|
|||
/.idea
|
|
@ -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:
|
||||
|
||||
|
|
|
@ -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
|
||||
}
|
|
@ -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")
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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…
Reference in New Issue