avl insertion

This commit is contained in:
Suyono 2023-08-07 13:03:35 +10:00
parent 3c6c1e8df5
commit f31b72c2f7
7 changed files with 241 additions and 1 deletions

1
.gitignore vendored Normal file
View File

@ -0,0 +1 @@
/.idea

1
.tool-versions Normal file
View File

@ -0,0 +1 @@
golang 1.20.6

View File

@ -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
View 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
View 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")
}
}
}

3
go.mod Normal file
View File

@ -0,0 +1,3 @@
module gitea.suyono.dev/suyono/avl
go 1.20

33
tree.go Normal file
View 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
}