Data commit
This commit is contained in:
parent
7387c8f97b
commit
cb5bb5e222
199093 changed files with 3378972 additions and 0 deletions
4
Task/AVL-tree/00-META.yaml
Normal file
4
Task/AVL-tree/00-META.yaml
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
---
|
||||
category:
|
||||
- Data Structures
|
||||
from: http://rosettacode.org/wiki/AVL_tree
|
||||
12
Task/AVL-tree/00-TASK.txt
Normal file
12
Task/AVL-tree/00-TASK.txt
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
<br>
|
||||
In computer science, an '''AVL tree''' is a self-balancing binary search tree. In an AVL tree, the heights of the two child subtrees of any node differ by at most one; at no time do they differ by more than one because rebalancing is done ensure this is the case. Lookup, insertion, and deletion all take O(log ''n'') time in both the average and worst cases, where n is the number of nodes in the tree prior to the operation. Insertions and deletions may require the tree to be rebalanced by one or more tree rotations. Note the tree of nodes comprise a set, so duplicate node keys are not allowed.
|
||||
|
||||
AVL trees are often compared with [[Red_black_trees|red-black trees]] because they support the same set of operations and because red-black trees also take O(log ''n'') time for the basic operations. Because AVL trees are more rigidly balanced, they are faster than red-black trees for lookup-intensive applications. Similar to red-black trees, AVL trees are height-balanced, but in general not weight-balanced nor μ-balanced; that is, sibling nodes can have hugely differing numbers of descendants.
|
||||
|
||||
|
||||
;Task:
|
||||
Implement an AVL tree in the language of choice, and provide at least basic operations.
|
||||
<br><br>
|
||||
;Related task
|
||||
[[Red_black_tree_sort]]
|
||||
<br><br>
|
||||
861
Task/AVL-tree/AArch64-Assembly/avl-tree.aarch64
Normal file
861
Task/AVL-tree/AArch64-Assembly/avl-tree.aarch64
Normal file
|
|
@ -0,0 +1,861 @@
|
|||
/* ARM assembly AARCH64 Raspberry PI 3B */
|
||||
/* program avltree64.s */
|
||||
|
||||
/*******************************************/
|
||||
/* Constantes file */
|
||||
/*******************************************/
|
||||
/* for this file see task include a file in language AArch64 assembly*/
|
||||
.include "../includeConstantesARM64.inc"
|
||||
|
||||
.equ NBVAL, 12
|
||||
|
||||
/*******************************************/
|
||||
/* Structures */
|
||||
/********************************************/
|
||||
/* structure tree */
|
||||
.struct 0
|
||||
tree_root: // root pointer (or node right)
|
||||
.struct tree_root + 8
|
||||
tree_size: // number of element of tree
|
||||
.struct tree_size + 8
|
||||
tree_suite:
|
||||
.struct tree_suite + 24 // for alignement to node
|
||||
tree_fin:
|
||||
/* structure node tree */
|
||||
.struct 0
|
||||
node_right: // right pointer
|
||||
.struct node_right + 8
|
||||
node_left: // left pointer
|
||||
.struct node_left + 8
|
||||
node_value: // element value
|
||||
.struct node_value + 8
|
||||
node_height: // element value
|
||||
.struct node_height + 8
|
||||
node_parent: // element value
|
||||
.struct node_parent + 8
|
||||
node_fin:
|
||||
|
||||
/*******************************************/
|
||||
/* Initialized data */
|
||||
/*******************************************/
|
||||
.data
|
||||
szMessPreOrder: .asciz "PreOrder :\n"
|
||||
szCarriageReturn: .asciz "\n"
|
||||
/* datas error display */
|
||||
szMessErreur: .asciz "Error detected.\n"
|
||||
szMessKeyDbl: .asciz "Key exists in tree.\n"
|
||||
szMessInsInv: .asciz "Insertion in inverse order.\n"
|
||||
/* datas message display */
|
||||
szMessResult: .asciz "Ele: @ G: @ D: @ val @ h @ \npere @\n"
|
||||
|
||||
/*******************************************/
|
||||
/* UnInitialized data */
|
||||
/*******************************************/
|
||||
.bss
|
||||
sZoneConv: .skip 24
|
||||
stTree: .skip tree_fin // place to structure tree
|
||||
stTree1: .skip tree_fin // place to structure tree
|
||||
/*******************************************/
|
||||
/* code section */
|
||||
/*******************************************/
|
||||
.text
|
||||
.global main
|
||||
main:
|
||||
mov x20,#1 // node tree value
|
||||
1: // loop insertion in order
|
||||
ldr x0,qAdrstTree // structure tree address
|
||||
mov x1,x20
|
||||
bl insertElement // add element value x1
|
||||
cmp x0,-1
|
||||
beq 99f
|
||||
add x20,x20,1 // increment value
|
||||
cmp x20,NBVAL // end ?
|
||||
ble 1b // no -> loop
|
||||
|
||||
ldr x0,qAdrstTree // structure tree address
|
||||
mov x1,11 // verif key dobble
|
||||
bl insertElement // add element value x1
|
||||
cmp x0,-1
|
||||
bne 2f
|
||||
ldr x0,qAdrszMessErreur
|
||||
bl affichageMess
|
||||
2:
|
||||
ldr x0,qAdrszMessPreOrder // load verification
|
||||
bl affichageMess
|
||||
ldr x3,qAdrstTree // tree root address (begin structure)
|
||||
ldr x0,[x3,tree_root]
|
||||
ldr x1,qAdrdisplayElement // function to execute
|
||||
bl preOrder
|
||||
|
||||
|
||||
ldr x0,qAdrszMessInsInv
|
||||
bl affichageMess
|
||||
mov x20,NBVAL // node tree value
|
||||
3: // loop insertion inverse order
|
||||
ldr x0,qAdrstTree1 // structure tree address
|
||||
mov x1,x20
|
||||
bl insertElement // add element value x1
|
||||
cmp x0,-1
|
||||
beq 99f
|
||||
sub x20,x20,1 // increment value
|
||||
cmp x20,0 // end ?
|
||||
bgt 3b // no -> loop
|
||||
|
||||
ldr x0,qAdrszMessPreOrder // load verification
|
||||
bl affichageMess
|
||||
ldr x3,qAdrstTree1 // tree root address (begin structure)
|
||||
ldr x0,[x3,tree_root]
|
||||
ldr x1,qAdrdisplayElement // function to execute
|
||||
bl preOrder
|
||||
|
||||
// search value
|
||||
ldr x0,qAdrstTree1 // tree root address (begin structure)
|
||||
mov x1,11 // value to search
|
||||
bl searchTree
|
||||
cmp x0,-1
|
||||
beq 100f
|
||||
mov x2,x0
|
||||
ldr x0,qAdrszMessKeyDbl // key exists
|
||||
bl affichageMess
|
||||
// suppresssion previous value
|
||||
mov x0,x2
|
||||
ldr x1,qAdrstTree1
|
||||
bl supprimer
|
||||
|
||||
ldr x0,qAdrszMessPreOrder // verification
|
||||
bl affichageMess
|
||||
ldr x3,qAdrstTree1 // tree root address (begin structure)
|
||||
ldr x0,[x3,tree_root]
|
||||
ldr x1,qAdrdisplayElement // function to execute
|
||||
bl preOrder
|
||||
|
||||
b 100f
|
||||
99: // display error
|
||||
ldr x0,qAdrszMessErreur
|
||||
bl affichageMess
|
||||
100: // standard end of the program
|
||||
mov x8, #EXIT // request to exit program
|
||||
svc 0 // perform system call
|
||||
qAdrszMessPreOrder: .quad szMessPreOrder
|
||||
qAdrszMessErreur: .quad szMessErreur
|
||||
qAdrszCarriageReturn: .quad szCarriageReturn
|
||||
qAdrstTree: .quad stTree
|
||||
qAdrstTree1: .quad stTree1
|
||||
qAdrdisplayElement: .quad displayElement
|
||||
qAdrszMessInsInv: .quad szMessInsInv
|
||||
/******************************************************************/
|
||||
/* insert element in the tree */
|
||||
/******************************************************************/
|
||||
/* x0 contains the address of the tree structure */
|
||||
/* x1 contains the value of element */
|
||||
/* x0 returns address of element or - 1 if error */
|
||||
insertElement: // INFO: insertElement
|
||||
stp x1,lr,[sp,-16]! // save registers
|
||||
mov x6,x0 // save head
|
||||
mov x0,#node_fin // reservation place one element
|
||||
bl allocHeap
|
||||
cmp x0,#-1 // allocation error
|
||||
beq 100f
|
||||
mov x5,x0
|
||||
str x1,[x5,#node_value] // store value in address heap
|
||||
mov x3,#0
|
||||
str x3,[x5,#node_left] // init left pointer with zero
|
||||
str x3,[x5,#node_right] // init right pointer with zero
|
||||
str x3,[x5,#node_height] // init balance with zero
|
||||
ldr x2,[x6,#tree_size] // load tree size
|
||||
cmp x2,#0 // 0 element ?
|
||||
bne 1f
|
||||
str x5,[x6,#tree_root] // yes -> store in root
|
||||
b 4f
|
||||
1: // else search free address in tree
|
||||
ldr x3,[x6,#tree_root] // start with address root
|
||||
2: // begin loop to insertion
|
||||
ldr x4,[x3,#node_value] // load key
|
||||
cmp x1,x4
|
||||
beq 6f // key equal
|
||||
blt 3f // key <
|
||||
// key > insertion right
|
||||
ldr x8,[x3,#node_right] // node empty ?
|
||||
cmp x8,#0
|
||||
csel x3,x8,x3,ne // current = right node if not
|
||||
//movne x3,x8 // no -> next node
|
||||
bne 2b // and loop
|
||||
str x5,[x3,#node_right] // store node address in right pointer
|
||||
b 4f
|
||||
3: // left
|
||||
ldr x8,[x3,#node_left] // left pointer empty ?
|
||||
cmp x8,#0
|
||||
csel x3,x8,x3,ne // current = left node if not
|
||||
//movne x3,x8 //
|
||||
bne 2b // no -> loop
|
||||
str x5,[x3,#node_left] // store node address in left pointer
|
||||
4:
|
||||
str x3,[x5,#node_parent] // store parent
|
||||
mov x4,#1
|
||||
str x4,[x5,#node_height] // store height = 1
|
||||
mov x0,x5 // begin node to requilbrate
|
||||
mov x1,x6 // head address
|
||||
bl equilibrer
|
||||
|
||||
5:
|
||||
add x2,x2,#1 // increment tree size
|
||||
str x2,[x6,#tree_size]
|
||||
mov x0,#0
|
||||
b 100f
|
||||
6: // key equal ?
|
||||
ldr x0,qAdrszMessKeyDbl
|
||||
bl affichageMess
|
||||
mov x0,#-1
|
||||
b 100f
|
||||
100:
|
||||
ldp x1,lr,[sp],16 // restaur 2 registers
|
||||
ret // return to address lr x30
|
||||
qAdrszMessKeyDbl: .quad szMessKeyDbl
|
||||
/******************************************************************/
|
||||
/* equilibrer after insertion */
|
||||
/******************************************************************/
|
||||
/* x0 contains the address of the node */
|
||||
/* x1 contains the address of head */
|
||||
equilibrer: // INFO: equilibrer
|
||||
stp x1,lr,[sp,-16]! // save registers
|
||||
stp x2,x3,[sp,-16]! // save registers
|
||||
stp x4,x5,[sp,-16]! // save registers
|
||||
stp x6,x7,[sp,-16]! // save registers
|
||||
mov x3,#0 // balance factor
|
||||
1: // begin loop
|
||||
ldr x5,[x0,#node_parent] // load father
|
||||
cmp x5,#0 // end ?
|
||||
beq 8f
|
||||
cmp x3,#2 // right tree too long
|
||||
beq 8f
|
||||
cmp x3,#-2 // left tree too long
|
||||
beq 8f
|
||||
mov x6,x0 // s = current
|
||||
ldr x0,[x6,#node_parent] // current = father
|
||||
ldr x7,[x0,#node_left]
|
||||
mov x4,#0
|
||||
cmp x7,#0
|
||||
beq 2f
|
||||
ldr x4,[x7,#node_height] // height left tree
|
||||
2:
|
||||
ldr x7,[x0,#node_right]
|
||||
mov x2,#0
|
||||
cmp x7,#0
|
||||
beq 3f
|
||||
ldr x2,[x7,#node_height] // height right tree
|
||||
3:
|
||||
cmp x4,x2
|
||||
ble 4f
|
||||
add x4,x4,#1
|
||||
str x4,[x0,#node_height]
|
||||
b 5f
|
||||
4:
|
||||
add x2,x2,#1
|
||||
str x2,[x0,#node_height]
|
||||
5:
|
||||
ldr x7,[x0,#node_right]
|
||||
mov x4,0
|
||||
cmp x7,#0
|
||||
beq 6f
|
||||
ldr x4,[x7,#node_height]
|
||||
6:
|
||||
ldr x7,[x0,#node_left]
|
||||
mov x2,0
|
||||
cmp x7,#0
|
||||
beq 7f
|
||||
ldr x2,[x7,#node_height]
|
||||
7:
|
||||
sub x3,x4,x2 // compute balance factor
|
||||
b 1b
|
||||
8:
|
||||
cmp x3,#2
|
||||
beq 9f
|
||||
cmp x3,#-2
|
||||
beq 9f
|
||||
b 100f
|
||||
9:
|
||||
mov x3,x1
|
||||
mov x4,x0
|
||||
mov x1,x6
|
||||
bl equiUnSommet
|
||||
// change head address ?
|
||||
ldr x2,[x3,#tree_root]
|
||||
cmp x2,x4
|
||||
bne 100f
|
||||
str x6,[x3,#tree_root]
|
||||
100:
|
||||
ldp x6,x7,[sp],16 // restaur 2 registers
|
||||
ldp x4,x5,[sp],16 // restaur 2 registers
|
||||
ldp x2,x3,[sp],16 // restaur 2 registers
|
||||
ldp x1,lr,[sp],16 // restaur 2 registers
|
||||
ret // return to address lr x30
|
||||
/******************************************************************/
|
||||
/* equilibre 1 sommet */
|
||||
/******************************************************************/
|
||||
/* x0 contains the address of the node */
|
||||
/* x1 contains the address of the node */
|
||||
equiUnSommet: // INFO: equiUnSommet
|
||||
stp x1,lr,[sp,-16]! // save registers
|
||||
stp x2,x3,[sp,-16]! // save registers
|
||||
stp x4,x5,[sp,-16]! // save registers
|
||||
stp x6,x7,[sp,-16]! // save registers
|
||||
mov x5,x0 // save p
|
||||
mov x6,x1 // s
|
||||
ldr x2,[x5,#node_left]
|
||||
cmp x2,x6
|
||||
bne 6f
|
||||
ldr x7,[x5,#node_right]
|
||||
mov x4,#0
|
||||
cmp x7,#0
|
||||
beq 1f
|
||||
ldr x4,[x7,#node_height]
|
||||
1:
|
||||
ldr x7,[x5,#node_left]
|
||||
mov x2,0
|
||||
cmp x7,#0
|
||||
beq 2f
|
||||
ldr x2,[x7,#node_height]
|
||||
2:
|
||||
sub x3,x4,x2
|
||||
cmp x3,#-2
|
||||
bne 100f
|
||||
ldr x7,[x6,#node_right]
|
||||
mov x4,0
|
||||
cmp x7,#0
|
||||
beq 3f
|
||||
ldr x4,[x7,#node_height]
|
||||
3:
|
||||
ldr x7,[x6,#node_left]
|
||||
mov x2,0
|
||||
cmp x7,#0
|
||||
beq 4f
|
||||
ldr x2,[x7,#node_height]
|
||||
4:
|
||||
sub x3,x4,x2
|
||||
cmp x3,#1
|
||||
bge 5f
|
||||
mov x0,x5
|
||||
bl rotRight
|
||||
b 100f
|
||||
5:
|
||||
mov x0,x6
|
||||
bl rotLeft
|
||||
mov x0,x5
|
||||
bl rotRight
|
||||
b 100f
|
||||
|
||||
6:
|
||||
ldr x7,[x5,#node_right]
|
||||
mov x4,0
|
||||
cmp x7,#0
|
||||
beq 7f
|
||||
ldr x4,[x7,#node_height]
|
||||
7:
|
||||
ldr x7,[x5,#node_left]
|
||||
mov x2,0
|
||||
cmp x7,#0
|
||||
beq 8f
|
||||
ldr x2,[x7,#node_height]
|
||||
8:
|
||||
sub x3,x4,x2
|
||||
cmp x3,2
|
||||
bne 100f
|
||||
ldr x7,[x6,#node_right]
|
||||
mov x4,0
|
||||
cmp x7,#0
|
||||
beq 9f
|
||||
ldr x4,[x7,#node_height]
|
||||
9:
|
||||
ldr x7,[x6,#node_left]
|
||||
mov x2,0
|
||||
cmp x7,#0
|
||||
beq 10f
|
||||
ldr x2,[x7,#node_height]
|
||||
10:
|
||||
sub x3,x4,x2
|
||||
cmp x3,#-1
|
||||
ble 11f
|
||||
mov x0,x5
|
||||
bl rotLeft
|
||||
b 100f
|
||||
11:
|
||||
mov x0,x6
|
||||
bl rotRight
|
||||
mov x0,x5
|
||||
bl rotLeft
|
||||
|
||||
100:
|
||||
ldp x6,x7,[sp],16 // restaur 2 registers
|
||||
ldp x4,x5,[sp],16 // restaur 2 registers
|
||||
ldp x2,x3,[sp],16 // restaur 2 registers
|
||||
ldp x1,lr,[sp],16 // restaur 2 registers
|
||||
ret // return to address lr x30
|
||||
/******************************************************************/
|
||||
/* right rotation */
|
||||
/******************************************************************/
|
||||
/* x0 contains the address of the node */
|
||||
rotRight: // INFO: rotRight
|
||||
stp x1,lr,[sp,-16]! // save registers
|
||||
stp x2,x3,[sp,-16]! // save registers
|
||||
stp x4,x5,[sp,-16]! // save registers
|
||||
// x2 x2
|
||||
// x0 x1
|
||||
// x1 x0
|
||||
// x3 x3
|
||||
ldr x1,[x0,#node_left] // load left children
|
||||
ldr x2,[x0,#node_parent] // load father
|
||||
cmp x2,#0 // no father ???
|
||||
beq 2f
|
||||
ldr x3,[x2,#node_left] // load left node father
|
||||
cmp x3,x0 // equal current node ?
|
||||
bne 1f
|
||||
str x1,[x2,#node_left] // yes store left children
|
||||
b 2f
|
||||
1:
|
||||
str x1,[x2,#node_right] // no store right
|
||||
2:
|
||||
str x2,[x1,#node_parent] // change parent
|
||||
str x1,[x0,#node_parent]
|
||||
ldr x3,[x1,#node_right]
|
||||
str x3,[x0,#node_left]
|
||||
cmp x3,#0
|
||||
beq 3f
|
||||
str x0,[x3,#node_parent] // change parent node left
|
||||
3:
|
||||
str x0,[x1,#node_right]
|
||||
|
||||
ldr x3,[x0,#node_left] // compute newbalance factor
|
||||
mov x4,0
|
||||
cmp x3,#0
|
||||
beq 4f
|
||||
ldr x4,[x3,#node_height]
|
||||
4:
|
||||
ldr x3,[x0,#node_right]
|
||||
mov x5,0
|
||||
cmp x3,#0
|
||||
beq 5f
|
||||
ldr x5,[x3,#node_height]
|
||||
5:
|
||||
cmp x4,x5
|
||||
ble 6f
|
||||
add x4,x4,#1
|
||||
str x4,[x0,#node_height]
|
||||
b 7f
|
||||
6:
|
||||
add x5,x5,#1
|
||||
str x5,[x0,#node_height]
|
||||
7:
|
||||
//
|
||||
ldr x3,[x1,#node_left] // compute new balance factor
|
||||
mov x4,0
|
||||
cmp x3,#0
|
||||
beq 8f
|
||||
ldr x4,[x3,#node_height]
|
||||
8:
|
||||
ldr x3,[x1,#node_right]
|
||||
mov x5,0
|
||||
cmp x3,#0
|
||||
beq 9f
|
||||
ldr x5,[x3,#node_height]
|
||||
9:
|
||||
cmp x4,x5
|
||||
ble 10f
|
||||
add x4,x4,#1
|
||||
str x4,[x1,#node_height]
|
||||
b 100f
|
||||
10:
|
||||
add x5,x5,#1
|
||||
str x5,[x1,#node_height]
|
||||
100:
|
||||
ldp x4,x5,[sp],16 // restaur 2 registers
|
||||
ldp x2,x3,[sp],16 // restaur 2 registers
|
||||
ldp x1,lr,[sp],16 // restaur 2 registers
|
||||
ret // return to address lr x30
|
||||
/******************************************************************/
|
||||
/* left rotation */
|
||||
/******************************************************************/
|
||||
/* x0 contains the address of the node sommet */
|
||||
rotLeft: // INFO: rotLeft
|
||||
stp x1,lr,[sp,-16]! // save registers
|
||||
stp x2,x3,[sp,-16]! // save registers
|
||||
stp x4,x5,[sp,-16]! // save registers
|
||||
// x2 x2
|
||||
// x0 x1
|
||||
// x1 x0
|
||||
// x3 x3
|
||||
ldr x1,[x0,#node_right] // load right children
|
||||
ldr x2,[x0,#node_parent] // load father (racine)
|
||||
cmp x2,#0 // no father ???
|
||||
beq 2f
|
||||
ldr x3,[x2,#node_left] // load left node father
|
||||
cmp x3,x0 // equal current node ?
|
||||
bne 1f
|
||||
str x1,[x2,#node_left] // yes store left children
|
||||
b 2f
|
||||
1:
|
||||
str x1,[x2,#node_right] // no store to right
|
||||
2:
|
||||
str x2,[x1,#node_parent] // change parent of right children
|
||||
str x1,[x0,#node_parent] // change parent of sommet
|
||||
ldr x3,[x1,#node_left] // left children
|
||||
str x3,[x0,#node_right] // left children pivot exists ?
|
||||
cmp x3,#0
|
||||
beq 3f
|
||||
str x0,[x3,#node_parent] // yes store in
|
||||
3:
|
||||
str x0,[x1,#node_left]
|
||||
//
|
||||
ldr x3,[x0,#node_left] // compute new height for old summit
|
||||
mov x4,0
|
||||
cmp x3,#0
|
||||
beq 4f
|
||||
ldr x4,[x3,#node_height] // left height
|
||||
4:
|
||||
ldr x3,[x0,#node_right]
|
||||
mov x5,0
|
||||
cmp x3,#0
|
||||
beq 5f
|
||||
ldr x5,[x3,#node_height] // right height
|
||||
5:
|
||||
cmp x4,x5
|
||||
ble 6f
|
||||
add x4,x4,#1
|
||||
str x4,[x0,#node_height] // if right > left
|
||||
b 7f
|
||||
6:
|
||||
add x5,x5,#1
|
||||
str x5,[x0,#node_height] // if left > right
|
||||
7:
|
||||
//
|
||||
ldr x3,[x1,#node_left] // compute new height for new
|
||||
mov x4,0
|
||||
cmp x3,#0
|
||||
beq 8f
|
||||
ldr x4,[x3,#node_height]
|
||||
8:
|
||||
ldr x3,[x1,#node_right]
|
||||
mov x5,0
|
||||
cmp x3,#0
|
||||
beq 9f
|
||||
ldr x5,[x3,#node_height]
|
||||
9:
|
||||
cmp x4,x5
|
||||
ble 10f
|
||||
add x4,x4,#1
|
||||
str x4,[x1,#node_height]
|
||||
b 100f
|
||||
10:
|
||||
add x5,x5,#1
|
||||
str x5,[x1,#node_height]
|
||||
100:
|
||||
ldp x4,x5,[sp],16 // restaur 2 registers
|
||||
ldp x2,x3,[sp],16 // restaur 2 registers
|
||||
ldp x1,lr,[sp],16 // restaur 2 registers
|
||||
ret // return to address lr x30
|
||||
/******************************************************************/
|
||||
/* search value in tree */
|
||||
/******************************************************************/
|
||||
/* x0 contains the address of structure of tree */
|
||||
/* x1 contains the value to search */
|
||||
searchTree: // INFO: searchTree
|
||||
stp x2,lr,[sp,-16]! // save registers
|
||||
stp x3,x4,[sp,-16]! // save registers
|
||||
ldr x2,[x0,#tree_root]
|
||||
|
||||
1: // begin loop
|
||||
ldr x4,[x2,#node_value] // load key
|
||||
cmp x1,x4
|
||||
beq 3f // key equal
|
||||
blt 2f // key <
|
||||
// key > insertion right
|
||||
ldr x3,[x2,#node_right] // node empty ?
|
||||
cmp x3,#0
|
||||
csel x2,x3,x2,ne
|
||||
//movne x2,x3 // no -> next node
|
||||
bne 1b // and loop
|
||||
mov x0,#-1 // not find
|
||||
b 100f
|
||||
2: // left
|
||||
ldr x3,[x2,#node_left] // left pointer empty ?
|
||||
cmp x3,#0
|
||||
csel x2,x3,x2,ne
|
||||
bne 1b // no -> loop
|
||||
mov x0,#-1 // not find
|
||||
b 100f
|
||||
3:
|
||||
mov x0,x2 // return node address
|
||||
100:
|
||||
ldp x3,x4,[sp],16 // restaur 2 registers
|
||||
ldp x2,lr,[sp],16 // restaur 2 registers
|
||||
ret // return to address lr x30
|
||||
/******************************************************************/
|
||||
/* suppression node */
|
||||
/******************************************************************/
|
||||
/* x0 contains the address of the node */
|
||||
/* x1 contains structure tree address */
|
||||
supprimer: // INFO: supprimer
|
||||
stp x1,lr,[sp,-16]! // save registers
|
||||
stp x2,x3,[sp,-16]! // save registers
|
||||
stp x4,x5,[sp,-16]! // save registers
|
||||
stp x6,x7,[sp,-16]! // save registers
|
||||
ldr x1,[x0,#node_left]
|
||||
cmp x1,#0
|
||||
bne 5f
|
||||
ldr x1,[x0,#node_right]
|
||||
cmp x1,#0
|
||||
bne 5f
|
||||
// is a leaf
|
||||
mov x4,#0
|
||||
ldr x3,[x0,#node_parent] // father
|
||||
cmp x3,#0
|
||||
bne 11f
|
||||
str x4,[x1,#tree_root]
|
||||
b 100f
|
||||
11:
|
||||
ldr x1,[x3,#node_left]
|
||||
cmp x1,x0
|
||||
bne 2f
|
||||
str x4,[x3,#node_left] // suppression left children
|
||||
ldr x5,[x3,#node_right]
|
||||
mov x6,#0
|
||||
cmp x5,#0
|
||||
beq 12f
|
||||
ldr x6,[x5,#node_height]
|
||||
12:
|
||||
add x6,x6,#1
|
||||
str x6,[x3,#node_height]
|
||||
b 3f
|
||||
2: // suppression right children
|
||||
str x4,[x3,#node_right]
|
||||
ldr x5,[x3,#node_left]
|
||||
mov x6,#0
|
||||
cmp x5,#0
|
||||
beq 21f
|
||||
ldr x6,[x5,#node_height]
|
||||
21:
|
||||
add x6,x6,#1
|
||||
str x6,[x3,#node_height]
|
||||
3: // new balance
|
||||
mov x0,x3
|
||||
bl equilibrerSupp
|
||||
b 100f
|
||||
5: // is not à leaf
|
||||
ldr x7,[x0,#node_right]
|
||||
cmp x7,#0
|
||||
beq 7f
|
||||
mov x2,x0
|
||||
mov x0,x7
|
||||
6:
|
||||
ldr x6,[x0,#node_left] // search the litle element
|
||||
cmp x6,#0
|
||||
beq 9f
|
||||
mov x0,x6
|
||||
b 6b
|
||||
7:
|
||||
ldr x7,[x0,#node_left]
|
||||
cmp x7,#0
|
||||
beq 9f
|
||||
mov x2,x0
|
||||
mov x0,x7
|
||||
8:
|
||||
ldr x6,[x0,#node_right] // search the great element
|
||||
cmp x6,#0
|
||||
beq 9f
|
||||
mov x0,x6
|
||||
b 8b
|
||||
9:
|
||||
ldr x5,[x0,#node_value] // copy value
|
||||
str x5,[x2,#node_value]
|
||||
bl supprimer // suppression node x0
|
||||
100:
|
||||
ldp x6,x7,[sp],16 // restaur 2 registers
|
||||
ldp x4,x5,[sp],16 // restaur 2 registers
|
||||
ldp x2,x3,[sp],16 // restaur 2 registers
|
||||
ldp x1,lr,[sp],16 // restaur 2 registers
|
||||
ret // return to address lr x30
|
||||
|
||||
/******************************************************************/
|
||||
/* equilibrer after suppression */
|
||||
/******************************************************************/
|
||||
/* x0 contains the address of the node */
|
||||
/* x1 contains the address of head */
|
||||
equilibrerSupp: // INFO: equilibrerSupp
|
||||
stp x1,lr,[sp,-16]! // save registers
|
||||
stp x2,x3,[sp,-16]! // save registers
|
||||
stp x4,x5,[sp,-16]! // save registers
|
||||
stp x6,x7,[sp,-16]! // save registers
|
||||
mov x3,#1 // balance factor
|
||||
ldr x2,[x1,#tree_root]
|
||||
1:
|
||||
ldr x5,[x0,#node_parent] // load father
|
||||
cmp x5,#0 // no father
|
||||
beq 100f
|
||||
cmp x3,#0 // balance equilibred
|
||||
beq 100f
|
||||
mov x6,x0 // save entry node
|
||||
ldr x0,[x6,#node_parent] // current = father
|
||||
ldr x7,[x0,#node_left]
|
||||
mov x4,#0
|
||||
cmp x7,#0
|
||||
b 11f
|
||||
ldr x4,[x7,#node_height] // height left tree
|
||||
11:
|
||||
ldr x7,[x0,#node_right]
|
||||
mov x5,#0
|
||||
cmp x7,#0
|
||||
beq 12f
|
||||
ldr x5,[x7,#node_height] // height right tree
|
||||
12:
|
||||
cmp x4,x5
|
||||
ble 13f
|
||||
add x4,x4,1
|
||||
str x4,[x0,#node_height]
|
||||
b 14f
|
||||
13:
|
||||
add x5,x5,1
|
||||
str x5,[x0,#node_height]
|
||||
14:
|
||||
ldr x7,[x0,#node_right]
|
||||
mov x4,#0
|
||||
cmp x7,#0
|
||||
beq 15f
|
||||
ldr x4,[x7,#node_height]
|
||||
15:
|
||||
ldr x7,[x0,#node_left]
|
||||
mov x5,0
|
||||
cmp x7,#0
|
||||
beq 16f
|
||||
ldr x5,[x7,#node_height]
|
||||
16:
|
||||
sub x3,x4,x5 // compute balance factor
|
||||
mov x2,x1
|
||||
mov x7,x0 // save current
|
||||
mov x1,x6
|
||||
bl equiUnSommet
|
||||
// change head address ?
|
||||
cmp x2,x7
|
||||
bne 17f
|
||||
str x6,[x3,#tree_root]
|
||||
17:
|
||||
mov x0,x7 // restaur current
|
||||
b 1b
|
||||
|
||||
100:
|
||||
ldp x6,x7,[sp],16 // restaur 2 registers
|
||||
ldp x4,x5,[sp],16 // restaur 2 registers
|
||||
ldp x2,x3,[sp],16 // restaur 2 registers
|
||||
ldp x1,lr,[sp],16 // restaur 2 registers
|
||||
ret // return to address lr x30
|
||||
/******************************************************************/
|
||||
/* preOrder */
|
||||
/******************************************************************/
|
||||
/* x0 contains the address of the node */
|
||||
/* x1 function address */
|
||||
preOrder: // INFO: preOrder
|
||||
stp x2,lr,[sp,-16]! // save registers
|
||||
cmp x0,#0
|
||||
beq 100f
|
||||
mov x2,x0
|
||||
blr x1 // call function
|
||||
ldr x0,[x2,#node_left]
|
||||
bl preOrder
|
||||
ldr x0,[x2,#node_right]
|
||||
bl preOrder
|
||||
100:
|
||||
ldp x2,lr,[sp],16 // restaur 2 registers
|
||||
ret // return to address lr x30
|
||||
|
||||
/******************************************************************/
|
||||
/* display node */
|
||||
/******************************************************************/
|
||||
/* x0 contains node address */
|
||||
displayElement: // INFO: displayElement
|
||||
stp x1,lr,[sp,-16]! // save registers
|
||||
stp x2,x3,[sp,-16]! // save registers
|
||||
stp x4,x5,[sp,-16]! // save registers
|
||||
mov x2,x0
|
||||
ldr x1,qAdrsZoneConv
|
||||
bl conversion16
|
||||
//strb wzr,[x1,x0]
|
||||
ldr x0,qAdrszMessResult
|
||||
ldr x1,qAdrsZoneConv
|
||||
bl strInsertAtCharInc
|
||||
mov x3,x0
|
||||
ldr x0,[x2,#node_left]
|
||||
ldr x1,qAdrsZoneConv
|
||||
bl conversion16
|
||||
//strb wzr,[x1,x0]
|
||||
mov x0,x3
|
||||
ldr x1,qAdrsZoneConv
|
||||
bl strInsertAtCharInc
|
||||
mov x3,x0
|
||||
ldr x0,[x2,#node_right]
|
||||
ldr x1,qAdrsZoneConv
|
||||
bl conversion16
|
||||
//strb wzr,[x1,x0]
|
||||
mov x0,x3
|
||||
ldr x1,qAdrsZoneConv
|
||||
bl strInsertAtCharInc
|
||||
mov x3,x0
|
||||
ldr x0,[x2,#node_value]
|
||||
ldr x1,qAdrsZoneConv
|
||||
bl conversion10
|
||||
//strb wzr,[x1,x0]
|
||||
mov x0,x3
|
||||
ldr x1,qAdrsZoneConv
|
||||
bl strInsertAtCharInc
|
||||
mov x3,x0
|
||||
ldr x0,[x2,#node_height]
|
||||
ldr x1,qAdrsZoneConv
|
||||
bl conversion10
|
||||
//strb wzr,[x1,x0]
|
||||
mov x0,x3
|
||||
ldr x1,qAdrsZoneConv
|
||||
bl strInsertAtCharInc
|
||||
mov x3,x0
|
||||
ldr x0,[x2,#node_parent]
|
||||
ldr x1,qAdrsZoneConv
|
||||
bl conversion16
|
||||
//strb wzr,[x1,x0]
|
||||
mov x0,x3
|
||||
ldr x1,qAdrsZoneConv
|
||||
bl strInsertAtCharInc
|
||||
bl affichageMess
|
||||
100:
|
||||
ldp x4,x5,[sp],16 // restaur 2 registers
|
||||
ldp x2,x3,[sp],16 // restaur 2 registers
|
||||
ldp x1,lr,[sp],16 // restaur 2 registers
|
||||
ret // return to address lr x30
|
||||
qAdrszMessResult: .quad szMessResult
|
||||
qAdrsZoneConv: .quad sZoneConv
|
||||
|
||||
/******************************************************************/
|
||||
/* memory allocation on the heap */
|
||||
/******************************************************************/
|
||||
/* x0 contains the size to allocate */
|
||||
/* x0 returns address of memory heap or - 1 if error */
|
||||
/* CAUTION : The size of the allowance must be a multiple of 4 */
|
||||
allocHeap:
|
||||
stp x1,lr,[sp,-16]! // save registers
|
||||
stp x2,x8,[sp,-16]! // save registers
|
||||
// allocation
|
||||
mov x1,x0 // save size
|
||||
mov x0,0 // read address start heap
|
||||
mov x8,BRK // call system 'brk'
|
||||
svc 0
|
||||
mov x2,x0 // save address heap for return
|
||||
add x0,x0,x1 // reservation place for size
|
||||
mov x8,BRK // call system 'brk'
|
||||
svc 0
|
||||
cmp x0,-1 // allocation error
|
||||
beq 100f
|
||||
mov x0,x2 // return address memory heap
|
||||
100:
|
||||
ldp x2,x8,[sp],16 // restaur 2 registers
|
||||
ldp x1,lr,[sp],16 // restaur 2 registers
|
||||
ret // return to address lr x30
|
||||
/********************************************************/
|
||||
/* File Include fonctions */
|
||||
/********************************************************/
|
||||
/* for this file see task include a file in language AArch64 assembly */
|
||||
.include "../includeARM64.inc"
|
||||
764
Task/AVL-tree/ARM-Assembly/avl-tree.arm
Normal file
764
Task/AVL-tree/ARM-Assembly/avl-tree.arm
Normal file
|
|
@ -0,0 +1,764 @@
|
|||
/* ARM assembly Raspberry PI */
|
||||
/* program avltree2.s */
|
||||
|
||||
/* REMARK 1 : this program use routines in a include file
|
||||
see task Include a file language arm assembly
|
||||
for the routine affichageMess conversion10
|
||||
see at end of this program the instruction include */
|
||||
|
||||
/*******************************************/
|
||||
/* Constantes */
|
||||
/*******************************************/
|
||||
.equ STDOUT, 1 @ Linux output console
|
||||
.equ EXIT, 1 @ Linux syscall
|
||||
.equ WRITE, 4 @ Linux syscall
|
||||
.equ BRK, 0x2d @ Linux syscall
|
||||
.equ CHARPOS, '@'
|
||||
|
||||
.equ NBVAL, 12
|
||||
|
||||
/*******************************************/
|
||||
/* Structures */
|
||||
/********************************************/
|
||||
/* structure tree */
|
||||
.struct 0
|
||||
tree_root: @ root pointer (or node right)
|
||||
.struct tree_root + 4
|
||||
tree_size: @ number of element of tree
|
||||
.struct tree_size + 4
|
||||
tree_suite:
|
||||
.struct tree_suite + 12 @ for alignement to node
|
||||
tree_fin:
|
||||
/* structure node tree */
|
||||
.struct 0
|
||||
node_right: @ right pointer
|
||||
.struct node_right + 4
|
||||
node_left: @ left pointer
|
||||
.struct node_left + 4
|
||||
node_value: @ element value
|
||||
.struct node_value + 4
|
||||
node_height: @ element value
|
||||
.struct node_height + 4
|
||||
node_parent: @ element value
|
||||
.struct node_parent + 4
|
||||
node_fin:
|
||||
/* structure queue*/
|
||||
.struct 0
|
||||
queue_begin: @ next pointer
|
||||
.struct queue_begin + 4
|
||||
queue_end: @ element value
|
||||
.struct queue_end + 4
|
||||
queue_fin:
|
||||
/* structure node queue */
|
||||
.struct 0
|
||||
queue_node_next: @ next pointer
|
||||
.struct queue_node_next + 4
|
||||
queue_node_value: @ element value
|
||||
.struct queue_node_value + 4
|
||||
queue_node_fin:
|
||||
/*******************************************/
|
||||
/* Initialized data */
|
||||
/*******************************************/
|
||||
.data
|
||||
szMessPreOrder: .asciz "PreOrder :\n"
|
||||
szCarriageReturn: .asciz "\n"
|
||||
/* datas error display */
|
||||
szMessErreur: .asciz "Error detected.\n"
|
||||
szMessKeyDbl: .asciz "Key exists in tree.\n"
|
||||
szMessInsInv: .asciz "Insertion in inverse order.\n"
|
||||
/* datas message display */
|
||||
szMessResult: .asciz "Ele: @ G: @ D: @ val @ h @ pere @\n"
|
||||
sValue: .space 12,' '
|
||||
.asciz "\n"
|
||||
/*******************************************/
|
||||
/* UnInitialized data */
|
||||
/*******************************************/
|
||||
.bss
|
||||
sZoneConv: .skip 24
|
||||
stTree: .skip tree_fin @ place to structure tree
|
||||
stTree1: .skip tree_fin @ place to structure tree
|
||||
stQueue: .skip queue_fin @ place to structure queue
|
||||
/*******************************************/
|
||||
/* code section */
|
||||
/*******************************************/
|
||||
.text
|
||||
.global main
|
||||
main:
|
||||
mov r8,#1 @ node tree value
|
||||
1: @ loop insertion in order
|
||||
ldr r0,iAdrstTree @ structure tree address
|
||||
mov r1,r8
|
||||
bl insertElement @ add element value r1
|
||||
cmp r0,#-1
|
||||
beq 99f
|
||||
//ldr r3,iAdrstTree @ tree root address (begin structure)
|
||||
//ldr r0,[r3,#tree_root]
|
||||
//ldr r1,iAdrdisplayElement @ function to execute
|
||||
//bl preOrder
|
||||
add r8,#1 @ increment value
|
||||
cmp r8,#NBVAL @ end ?
|
||||
ble 1b @ no -> loop
|
||||
|
||||
ldr r0,iAdrstTree @ structure tree address
|
||||
mov r1,#11 @ verif key dobble
|
||||
bl insertElement @ add element value r1
|
||||
cmp r0,#-1
|
||||
bne 2f
|
||||
ldr r0,iAdrszMessErreur
|
||||
bl affichageMess
|
||||
2:
|
||||
ldr r0,iAdrszMessPreOrder @ load verification
|
||||
bl affichageMess
|
||||
ldr r3,iAdrstTree @ tree root address (begin structure)
|
||||
ldr r0,[r3,#tree_root]
|
||||
ldr r1,iAdrdisplayElement @ function to execute
|
||||
bl preOrder
|
||||
|
||||
|
||||
ldr r0,iAdrszMessInsInv
|
||||
bl affichageMess
|
||||
mov r8,#NBVAL @ node tree value
|
||||
3: @ loop insertion inverse order
|
||||
ldr r0,iAdrstTree1 @ structure tree address
|
||||
mov r1,r8
|
||||
bl insertElement @ add element value r1
|
||||
cmp r0,#-1
|
||||
beq 99f
|
||||
sub r8,#1 @ increment value
|
||||
cmp r8,#0 @ end ?
|
||||
bgt 3b @ no -> loop
|
||||
|
||||
ldr r0,iAdrszMessPreOrder @ load verification
|
||||
bl affichageMess
|
||||
ldr r3,iAdrstTree1 @ tree root address (begin structure)
|
||||
ldr r0,[r3,#tree_root]
|
||||
ldr r1,iAdrdisplayElement @ function to execute
|
||||
bl preOrder
|
||||
|
||||
@ search value
|
||||
ldr r0,iAdrstTree1 @ tree root address (begin structure)
|
||||
mov r1,#11 @ value to search
|
||||
bl searchTree
|
||||
cmp r0,#-1
|
||||
beq 100f
|
||||
mov r2,r0
|
||||
ldr r0,iAdrszMessKeyDbl @ key exists
|
||||
bl affichageMess
|
||||
@ suppresssion previous value
|
||||
mov r0,r2
|
||||
ldr r1,iAdrstTree1
|
||||
bl supprimer
|
||||
|
||||
ldr r0,iAdrszMessPreOrder @ verification
|
||||
bl affichageMess
|
||||
ldr r3,iAdrstTree1 @ tree root address (begin structure)
|
||||
ldr r0,[r3,#tree_root]
|
||||
ldr r1,iAdrdisplayElement @ function to execute
|
||||
bl preOrder
|
||||
|
||||
b 100f
|
||||
99: @ display error
|
||||
ldr r0,iAdrszMessErreur
|
||||
bl affichageMess
|
||||
100: @ standard end of the program
|
||||
mov r7, #EXIT @ request to exit program
|
||||
svc 0 @ perform system call
|
||||
iAdrszMessPreOrder: .int szMessPreOrder
|
||||
iAdrszMessErreur: .int szMessErreur
|
||||
iAdrszCarriageReturn: .int szCarriageReturn
|
||||
iAdrstTree: .int stTree
|
||||
iAdrstTree1: .int stTree1
|
||||
iAdrstQueue: .int stQueue
|
||||
iAdrdisplayElement: .int displayElement
|
||||
iAdrszMessInsInv: .int szMessInsInv
|
||||
/******************************************************************/
|
||||
/* insert element in the tree */
|
||||
/******************************************************************/
|
||||
/* r0 contains the address of the tree structure */
|
||||
/* r1 contains the value of element */
|
||||
/* r0 returns address of element or - 1 if error */
|
||||
insertElement: @ INFO: insertElement
|
||||
push {r1-r8,lr} @ save registers
|
||||
mov r7,r0 @ save head
|
||||
mov r0,#node_fin @ reservation place one element
|
||||
bl allocHeap
|
||||
cmp r0,#-1 @ allocation error
|
||||
beq 100f
|
||||
mov r5,r0
|
||||
str r1,[r5,#node_value] @ store value in address heap
|
||||
mov r3,#0
|
||||
str r3,[r5,#node_left] @ init left pointer with zero
|
||||
str r3,[r5,#node_right] @ init right pointer with zero
|
||||
str r3,[r5,#node_height] @ init balance with zero
|
||||
ldr r2,[r7,#tree_size] @ load tree size
|
||||
cmp r2,#0 @ 0 element ?
|
||||
bne 1f
|
||||
str r5,[r7,#tree_root] @ yes -> store in root
|
||||
b 4f
|
||||
1: @ else search free address in tree
|
||||
ldr r3,[r7,#tree_root] @ start with address root
|
||||
2: @ begin loop to insertion
|
||||
ldr r4,[r3,#node_value] @ load key
|
||||
cmp r1,r4
|
||||
beq 6f @ key equal
|
||||
blt 3f @ key <
|
||||
@ key > insertion right
|
||||
ldr r8,[r3,#node_right] @ node empty ?
|
||||
cmp r8,#0
|
||||
movne r3,r8 @ no -> next node
|
||||
bne 2b @ and loop
|
||||
str r5,[r3,#node_right] @ store node address in right pointer
|
||||
b 4f
|
||||
3: @ left
|
||||
ldr r8,[r3,#node_left] @ left pointer empty ?
|
||||
cmp r8,#0
|
||||
movne r3,r8 @
|
||||
bne 2b @ no -> loop
|
||||
str r5,[r3,#node_left] @ store node address in left pointer
|
||||
4:
|
||||
str r3,[r5,#node_parent] @ store parent
|
||||
mov r4,#1
|
||||
str r4,[r5,#node_height] @ store height = 1
|
||||
mov r0,r5 @ begin node to requilbrate
|
||||
mov r1,r7 @ head address
|
||||
bl equilibrer
|
||||
|
||||
5:
|
||||
add r2,#1 @ increment tree size
|
||||
str r2,[r7,#tree_size]
|
||||
mov r0,#0
|
||||
b 100f
|
||||
6: @ key equal ?
|
||||
ldr r0,iAdrszMessKeyDbl
|
||||
bl affichageMess
|
||||
mov r0,#-1
|
||||
b 100f
|
||||
100:
|
||||
pop {r1-r8,lr} @ restaur registers
|
||||
bx lr @ return
|
||||
iAdrszMessKeyDbl: .int szMessKeyDbl
|
||||
/******************************************************************/
|
||||
/* equilibrer after insertion */
|
||||
/******************************************************************/
|
||||
/* r0 contains the address of the node */
|
||||
/* r1 contains the address of head */
|
||||
equilibrer: @ INFO: equilibrer
|
||||
push {r1-r8,lr} @ save registers
|
||||
mov r3,#0 @ balance factor
|
||||
1: @ begin loop
|
||||
ldr r5,[r0,#node_parent] @ load father
|
||||
cmp r5,#0 @ end ?
|
||||
beq 5f
|
||||
cmp r3,#2 @ right tree too long
|
||||
beq 5f
|
||||
cmp r3,#-2 @ left tree too long
|
||||
beq 5f
|
||||
mov r6,r0 @ s = current
|
||||
ldr r0,[r6,#node_parent] @ current = father
|
||||
ldr r7,[r0,#node_left]
|
||||
cmp r7,#0
|
||||
ldrne r8,[r7,#node_height] @ height left tree
|
||||
moveq r8,#0
|
||||
ldr r7,[r0,#node_right]
|
||||
cmp r7,#0
|
||||
ldrne r9,[r7,#node_height] @ height right tree
|
||||
moveq r9,#0
|
||||
cmp r8,r9
|
||||
addgt r8,#1
|
||||
strgt r8,[r0,#node_height]
|
||||
addle r9,#1
|
||||
strle r9,[r0,#node_height]
|
||||
//
|
||||
ldr r7,[r0,#node_right]
|
||||
cmp r7,#0
|
||||
ldrne r8,[r7,#node_height]
|
||||
moveq r8,#0
|
||||
ldr r7,[r0,#node_left]
|
||||
cmp r7,#0
|
||||
ldrne r9,[r7,#node_height]
|
||||
moveq r9,#0
|
||||
sub r3,r8,r9 @ compute balance factor
|
||||
b 1b
|
||||
5:
|
||||
cmp r3,#2
|
||||
beq 6f
|
||||
cmp r3,#-2
|
||||
beq 6f
|
||||
b 100f
|
||||
6:
|
||||
mov r3,r1
|
||||
mov r4,r0
|
||||
mov r1,r6
|
||||
bl equiUnSommet
|
||||
@ change head address ?
|
||||
ldr r2,[r3,#tree_root]
|
||||
cmp r2,r4
|
||||
streq r6,[r3,#tree_root]
|
||||
100:
|
||||
pop {r1-r8,lr} @ restaur registers
|
||||
bx lr @ return
|
||||
/******************************************************************/
|
||||
/* equilibre 1 sommet */
|
||||
/******************************************************************/
|
||||
/* r0 contains the address of the node */
|
||||
/* r1 contains the address of the node */
|
||||
equiUnSommet: @ INFO: equiUnSommet
|
||||
push {r1-r9,lr} @ save registers
|
||||
mov r5,r0 @ save p
|
||||
mov r6,r1 // s
|
||||
ldr r2,[r5,#node_left]
|
||||
cmp r2,r6
|
||||
bne 5f
|
||||
ldr r7,[r5,#node_right]
|
||||
cmp r7,#0
|
||||
moveq r8,#0
|
||||
ldrne r8,[r7,#node_height]
|
||||
ldr r7,[r5,#node_left]
|
||||
cmp r7,#0
|
||||
moveq r9,#0
|
||||
ldrne r9,[r7,#node_height]
|
||||
sub r3,r8,r9
|
||||
cmp r3,#-2
|
||||
bne 100f
|
||||
ldr r7,[r6,#node_right]
|
||||
cmp r7,#0
|
||||
moveq r8,#0
|
||||
ldrne r8,[r7,#node_height]
|
||||
ldr r7,[r6,#node_left]
|
||||
cmp r7,#0
|
||||
moveq r9,#0
|
||||
ldrne r9,[r7,#node_height]
|
||||
sub r3,r8,r9
|
||||
cmp r3,#1
|
||||
bge 2f
|
||||
mov r0,r5
|
||||
bl rotRight
|
||||
b 100f
|
||||
2:
|
||||
mov r0,r6
|
||||
bl rotLeft
|
||||
mov r0,r5
|
||||
bl rotRight
|
||||
b 100f
|
||||
|
||||
5:
|
||||
ldr r7,[r5,#node_right]
|
||||
cmp r7,#0
|
||||
moveq r8,#0
|
||||
ldrne r8,[r7,#node_height]
|
||||
ldr r7,[r5,#node_left]
|
||||
cmp r7,#0
|
||||
moveq r9,#0
|
||||
ldrne r9,[r7,#node_height]
|
||||
sub r3,r8,r9
|
||||
cmp r3,#2
|
||||
bne 100f
|
||||
ldr r7,[r6,#node_right]
|
||||
cmp r7,#0
|
||||
moveq r8,#0
|
||||
ldrne r8,[r7,#node_height]
|
||||
ldr r7,[r6,#node_left]
|
||||
cmp r7,#0
|
||||
moveq r9,#0
|
||||
ldrne r9,[r7,#node_height]
|
||||
sub r3,r8,r9
|
||||
cmp r3,#-1
|
||||
ble 2f
|
||||
mov r0,r5
|
||||
bl rotLeft
|
||||
b 100f
|
||||
2:
|
||||
mov r0,r6
|
||||
bl rotRight
|
||||
mov r0,r5
|
||||
bl rotLeft
|
||||
b 100f
|
||||
|
||||
100:
|
||||
pop {r1-r9,lr} @ restaur registers
|
||||
bx lr @ return
|
||||
/******************************************************************/
|
||||
/* right rotation */
|
||||
/******************************************************************/
|
||||
/* r0 contains the address of the node */
|
||||
rotRight: @ INFO: rotRight
|
||||
push {r1-r5,lr} @ save registers
|
||||
// r2 r2
|
||||
// r0 r1
|
||||
// r1 r0
|
||||
// r3 r3
|
||||
ldr r1,[r0,#node_left] @ load left children
|
||||
ldr r2,[r0,#node_parent] @ load father
|
||||
cmp r2,#0 @ no father ???
|
||||
beq 2f
|
||||
ldr r3,[r2,#node_left] @ load left node father
|
||||
cmp r3,r0 @ equal current node ?
|
||||
streq r1,[r2,#node_left] @ yes store left children
|
||||
strne r1,[r2,#node_right] @ no store right
|
||||
2:
|
||||
str r2,[r1,#node_parent] @ change parent
|
||||
str r1,[r0,#node_parent]
|
||||
ldr r3,[r1,#node_right]
|
||||
str r3,[r0,#node_left]
|
||||
cmp r3,#0
|
||||
strne r0,[r3,#node_parent] @ change parent node left
|
||||
str r0,[r1,#node_right]
|
||||
|
||||
ldr r3,[r0,#node_left] @ compute newbalance factor
|
||||
cmp r3,#0
|
||||
moveq r4,#0
|
||||
ldrne r4,[r3,#node_height]
|
||||
ldr r3,[r0,#node_right]
|
||||
cmp r3,#0
|
||||
moveq r5,#0
|
||||
ldrne r5,[r3,#node_height]
|
||||
cmp r4,r5
|
||||
addgt r4,#1
|
||||
strgt r4,[r0,#node_height]
|
||||
addle r5,#1
|
||||
strle r5,[r0,#node_height]
|
||||
//
|
||||
ldr r3,[r1,#node_left] @ compute new balance factor
|
||||
cmp r3,#0
|
||||
moveq r4,#0
|
||||
ldrne r4,[r3,#node_height]
|
||||
ldr r3,[r1,#node_right]
|
||||
cmp r3,#0
|
||||
moveq r5,#0
|
||||
ldrne r5,[r3,#node_height]
|
||||
cmp r4,r5
|
||||
addgt r4,#1
|
||||
strgt r4,[r1,#node_height]
|
||||
addle r5,#1
|
||||
strle r5,[r1,#node_height]
|
||||
100:
|
||||
pop {r1-r5,lr} @ restaur registers
|
||||
bx lr
|
||||
/******************************************************************/
|
||||
/* left rotation */
|
||||
/******************************************************************/
|
||||
/* r0 contains the address of the node sommet */
|
||||
rotLeft: @ INFO: rotLeft
|
||||
push {r1-r5,lr} @ save registers
|
||||
// r2 r2
|
||||
// r0 r1
|
||||
// r1 r0
|
||||
// r3 r3
|
||||
ldr r1,[r0,#node_right] @ load right children
|
||||
ldr r2,[r0,#node_parent] @ load father (racine)
|
||||
cmp r2,#0 @ no father ???
|
||||
beq 2f
|
||||
ldr r3,[r2,#node_left] @ load left node father
|
||||
cmp r3,r0 @ equal current node ?
|
||||
streq r1,[r2,#node_left] @ yes store left children
|
||||
strne r1,[r2,#node_right] @ no store to right
|
||||
2:
|
||||
str r2,[r1,#node_parent] @ change parent of right children
|
||||
str r1,[r0,#node_parent] @ change parent of sommet
|
||||
ldr r3,[r1,#node_left] @ left children
|
||||
str r3,[r0,#node_right] @ left children pivot exists ?
|
||||
cmp r3,#0
|
||||
strne r0,[r3,#node_parent] @ yes store in
|
||||
str r0,[r1,#node_left]
|
||||
//
|
||||
ldr r3,[r0,#node_left] @ compute new height for old summit
|
||||
cmp r3,#0
|
||||
moveq r4,#0
|
||||
ldrne r4,[r3,#node_height] @ left height
|
||||
ldr r3,[r0,#node_right]
|
||||
cmp r3,#0
|
||||
moveq r5,#0
|
||||
ldrne r5,[r3,#node_height] @ right height
|
||||
cmp r4,r5
|
||||
addgt r4,#1
|
||||
strgt r4,[r0,#node_height] @ if right > left
|
||||
addle r5,#1
|
||||
strle r5,[r0,#node_height] @ if left > right
|
||||
//
|
||||
ldr r3,[r1,#node_left] @ compute new height for new
|
||||
cmp r3,#0
|
||||
moveq r4,#0
|
||||
ldrne r4,[r3,#node_height]
|
||||
ldr r3,[r1,#node_right]
|
||||
cmp r3,#0
|
||||
moveq r5,#0
|
||||
ldrne r5,[r3,#node_height]
|
||||
cmp r4,r5
|
||||
addgt r4,#1
|
||||
strgt r4,[r1,#node_height]
|
||||
addle r5,#1
|
||||
strle r5,[r1,#node_height]
|
||||
100:
|
||||
pop {r1-r5,lr} @ restaur registers
|
||||
bx lr
|
||||
/******************************************************************/
|
||||
/* search value in tree */
|
||||
/******************************************************************/
|
||||
/* r0 contains the address of structure of tree */
|
||||
/* r1 contains the value to search */
|
||||
searchTree: @ INFO: searchTree
|
||||
push {r1-r4,lr} @ save registers
|
||||
ldr r2,[r0,#tree_root]
|
||||
|
||||
1: @ begin loop
|
||||
ldr r4,[r2,#node_value] @ load key
|
||||
cmp r1,r4
|
||||
beq 3f @ key equal
|
||||
blt 2f @ key <
|
||||
@ key > insertion right
|
||||
ldr r3,[r2,#node_right] @ node empty ?
|
||||
cmp r3,#0
|
||||
movne r2,r3 @ no -> next node
|
||||
bne 1b @ and loop
|
||||
mov r0,#-1 @ not find
|
||||
b 100f
|
||||
2: @ left
|
||||
ldr r3,[r2,#node_left] @ left pointer empty ?
|
||||
cmp r3,#0
|
||||
movne r2,r3 @
|
||||
bne 1b @ no -> loop
|
||||
mov r0,#-1 @ not find
|
||||
b 100f
|
||||
3:
|
||||
mov r0,r2 @ return node address
|
||||
100:
|
||||
pop {r1-r4,lr} @ restaur registers
|
||||
bx lr
|
||||
/******************************************************************/
|
||||
/* suppression node */
|
||||
/******************************************************************/
|
||||
/* r0 contains the address of the node */
|
||||
/* r1 contains structure tree address */
|
||||
supprimer: @ INFO: supprimer
|
||||
push {r1-r8,lr} @ save registers
|
||||
ldr r1,[r0,#node_left]
|
||||
cmp r1,#0
|
||||
bne 5f
|
||||
ldr r1,[r0,#node_right]
|
||||
cmp r1,#0
|
||||
bne 5f
|
||||
@ is a leaf
|
||||
mov r4,#0
|
||||
ldr r3,[r0,#node_parent] @ father
|
||||
cmp r3,#0
|
||||
streq r4,[r1,#tree_root]
|
||||
beq 100f
|
||||
ldr r1,[r3,#node_left]
|
||||
cmp r1,r0
|
||||
bne 2f
|
||||
str r4,[r3,#node_left] @ suppression left children
|
||||
ldr r5,[r3,#node_right]
|
||||
cmp r5,#0
|
||||
moveq r6,#0
|
||||
ldrne r6,[r5,#node_height]
|
||||
add r6,#1
|
||||
str r6,[r3,#node_height]
|
||||
b 3f
|
||||
2: @ suppression right children
|
||||
str r4,[r3,#node_right]
|
||||
ldr r5,[r3,#node_left]
|
||||
cmp r5,#0
|
||||
moveq r6,#0
|
||||
ldrne r6,[r5,#node_height]
|
||||
add r6,#1
|
||||
str r6,[r3,#node_height]
|
||||
3: @ new balance
|
||||
mov r0,r3
|
||||
bl equilibrerSupp
|
||||
b 100f
|
||||
5: @ is not à leaf
|
||||
ldr r7,[r0,#node_right]
|
||||
cmp r7,#0
|
||||
beq 7f
|
||||
mov r8,r0
|
||||
mov r0,r7
|
||||
6:
|
||||
ldr r6,[r0,#node_left]
|
||||
cmp r6,#0
|
||||
movne r0,r6
|
||||
bne 6b
|
||||
b 9f
|
||||
7:
|
||||
ldr r7,[r0,#node_left] @ search the litle element
|
||||
cmp r7,#0
|
||||
beq 9f
|
||||
mov r8,r0
|
||||
mov r0,r7
|
||||
8:
|
||||
ldr r6,[r0,#node_right] @ search the great element
|
||||
cmp r6,#0
|
||||
movne r0,r6
|
||||
bne 8b
|
||||
9:
|
||||
ldr r5,[r0,#node_value] @ copy value
|
||||
str r5,[r8,#node_value]
|
||||
bl supprimer @ suppression node r0
|
||||
100:
|
||||
pop {r1-r8,lr} @ restaur registers
|
||||
bx lr
|
||||
|
||||
/******************************************************************/
|
||||
/* equilibrer after suppression */
|
||||
/******************************************************************/
|
||||
/* r0 contains the address of the node */
|
||||
/* r1 contains the address of head */
|
||||
equilibrerSupp: @ INFO: equilibrerSupp
|
||||
push {r1-r8,lr} @ save registers
|
||||
mov r3,#1 @ balance factor
|
||||
ldr r2,[r1,#tree_root]
|
||||
1:
|
||||
ldr r5,[r0,#node_parent] @ load father
|
||||
cmp r5,#0 @ no father
|
||||
beq 100f
|
||||
cmp r3,#0 @ balance equilibred
|
||||
beq 100f
|
||||
mov r6,r0 @ save entry node
|
||||
ldr r0,[r6,#node_parent] @ current = father
|
||||
ldr r7,[r0,#node_left]
|
||||
cmp r7,#0
|
||||
ldrne r8,[r7,#node_height] @ height left tree
|
||||
moveq r8,#0
|
||||
ldr r7,[r0,#node_right]
|
||||
cmp r7,#0
|
||||
ldrne r9,[r7,#node_height] @ height right tree
|
||||
moveq r9,#0
|
||||
cmp r8,r9
|
||||
addgt r8,#1
|
||||
strgt r8,[r0,#node_height]
|
||||
addle r9,#1
|
||||
strle r9,[r0,#node_height]
|
||||
//
|
||||
ldr r7,[r0,#node_right]
|
||||
cmp r7,#0
|
||||
ldrne r8,[r7,#node_height]
|
||||
moveq r8,#0
|
||||
ldr r7,[r0,#node_left]
|
||||
cmp r7,#0
|
||||
ldrne r9,[r7,#node_height]
|
||||
moveq r9,#0
|
||||
sub r3,r8,r9 @ compute balance factor
|
||||
mov r2,r1
|
||||
mov r4,r0 @ save current
|
||||
mov r1,r6
|
||||
bl equiUnSommet
|
||||
@ change head address ?
|
||||
cmp r2,r4
|
||||
streq r6,[r3,#tree_root]
|
||||
mov r0,r4 @ restaur current
|
||||
b 1b
|
||||
|
||||
100:
|
||||
pop {r1-r8,lr} @ restaur registers
|
||||
bx lr @ return
|
||||
/******************************************************************/
|
||||
/* preOrder */
|
||||
/******************************************************************/
|
||||
/* r0 contains the address of the node */
|
||||
/* r1 function address */
|
||||
preOrder: @ INFO: preOrder
|
||||
push {r1-r2,lr} @ save registers
|
||||
cmp r0,#0
|
||||
beq 100f
|
||||
mov r2,r0
|
||||
blx r1 @ call function
|
||||
|
||||
ldr r0,[r2,#node_left]
|
||||
bl preOrder
|
||||
ldr r0,[r2,#node_right]
|
||||
bl preOrder
|
||||
100:
|
||||
pop {r1-r2,lr} @ restaur registers
|
||||
bx lr
|
||||
|
||||
/******************************************************************/
|
||||
/* display node */
|
||||
/******************************************************************/
|
||||
/* r0 contains node address */
|
||||
displayElement: @ INFO: displayElement
|
||||
push {r1,r2,r3,lr} @ save registers
|
||||
mov r2,r0
|
||||
ldr r1,iAdrsZoneConv
|
||||
bl conversion16
|
||||
mov r4,#0
|
||||
strb r4,[r1,r0]
|
||||
ldr r0,iAdrszMessResult
|
||||
ldr r1,iAdrsZoneConv
|
||||
bl strInsertAtCharInc
|
||||
mov r3,r0
|
||||
ldr r0,[r2,#node_left]
|
||||
ldr r1,iAdrsZoneConv
|
||||
bl conversion16
|
||||
mov r4,#0
|
||||
strb r4,[r1,r0]
|
||||
mov r0,r3
|
||||
ldr r1,iAdrsZoneConv
|
||||
bl strInsertAtCharInc
|
||||
mov r3,r0
|
||||
ldr r0,[r2,#node_right]
|
||||
ldr r1,iAdrsZoneConv
|
||||
bl conversion16
|
||||
mov r4,#0
|
||||
strb r4,[r1,r0]
|
||||
mov r0,r3
|
||||
ldr r1,iAdrsZoneConv
|
||||
bl strInsertAtCharInc
|
||||
mov r3,r0
|
||||
ldr r0,[r2,#node_value]
|
||||
ldr r1,iAdrsZoneConv
|
||||
bl conversion10
|
||||
mov r4,#0
|
||||
strb r4,[r1,r0]
|
||||
mov r0,r3
|
||||
ldr r1,iAdrsZoneConv
|
||||
bl strInsertAtCharInc
|
||||
mov r3,r0
|
||||
ldr r0,[r2,#node_height]
|
||||
ldr r1,iAdrsZoneConv
|
||||
bl conversion10
|
||||
mov r4,#0
|
||||
strb r4,[r1,r0]
|
||||
mov r0,r3
|
||||
ldr r1,iAdrsZoneConv
|
||||
bl strInsertAtCharInc
|
||||
mov r3,r0
|
||||
ldr r0,[r2,#node_parent]
|
||||
ldr r1,iAdrsZoneConv
|
||||
bl conversion16
|
||||
mov r4,#0
|
||||
strb r4,[r1,r0]
|
||||
mov r0,r3
|
||||
ldr r1,iAdrsZoneConv
|
||||
bl strInsertAtCharInc
|
||||
bl affichageMess
|
||||
100:
|
||||
pop {r1,r2,r3,lr} @ restaur registers
|
||||
bx lr @ return
|
||||
iAdrszMessResult: .int szMessResult
|
||||
iAdrsZoneConv: .int sZoneConv
|
||||
iAdrsValue: .int sValue
|
||||
|
||||
/******************************************************************/
|
||||
/* memory allocation on the heap */
|
||||
/******************************************************************/
|
||||
/* r0 contains the size to allocate */
|
||||
/* r0 returns address of memory heap or - 1 if error */
|
||||
/* CAUTION : The size of the allowance must be a multiple of 4 */
|
||||
allocHeap:
|
||||
push {r5-r7,lr} @ save registers
|
||||
@ allocation
|
||||
mov r6,r0 @ save size
|
||||
mov r0,#0 @ read address start heap
|
||||
mov r7,#0x2D @ call system 'brk'
|
||||
svc #0
|
||||
mov r5,r0 @ save address heap for return
|
||||
add r0,r6 @ reservation place for size
|
||||
mov r7,#0x2D @ call system 'brk'
|
||||
svc #0
|
||||
cmp r0,#-1 @ allocation error
|
||||
movne r0,r5 @ return address memory heap
|
||||
pop {r5-r7,lr} @ restaur registers
|
||||
bx lr @ return
|
||||
/***************************************************/
|
||||
/* ROUTINES INCLUDE */
|
||||
/***************************************************/
|
||||
.include "../affichage.inc"
|
||||
1661
Task/AVL-tree/ATS/avl-tree.ats
Normal file
1661
Task/AVL-tree/ATS/avl-tree.ats
Normal file
File diff suppressed because it is too large
Load diff
241
Task/AVL-tree/Ada/avl-tree.ada
Normal file
241
Task/AVL-tree/Ada/avl-tree.ada
Normal file
|
|
@ -0,0 +1,241 @@
|
|||
with Ada.Text_IO, Ada.Finalization, Ada.Unchecked_Deallocation;
|
||||
|
||||
procedure Main is
|
||||
|
||||
generic
|
||||
type Key_Type is private;
|
||||
with function "<"(a, b : Key_Type) return Boolean is <>;
|
||||
with function "="(a, b : Key_Type) return Boolean is <>;
|
||||
with function "<="(a, b : Key_Type) return Boolean is <>;
|
||||
package AVL_Tree is
|
||||
type Tree is tagged limited private;
|
||||
function insert(self : in out Tree; key : Key_Type) return Boolean;
|
||||
procedure delete(self : in out Tree; key : Key_Type);
|
||||
procedure print_balance(self : in out Tree);
|
||||
|
||||
private
|
||||
type Height_Amt is range -1 .. Integer'Last;
|
||||
|
||||
-- Since only one key is inserted before each rebalance, the balance of
|
||||
-- all trees/subtrees will stay in range -2 .. 2
|
||||
type Balance_Amt is range -2 .. 2;
|
||||
|
||||
type Node;
|
||||
type Node_Ptr is access Node;
|
||||
type Node is new Ada.Finalization.Limited_Controlled with record
|
||||
left, right, parent : Node_Ptr := null;
|
||||
key : Key_Type;
|
||||
balance : Balance_Amt := 0;
|
||||
end record;
|
||||
overriding procedure Finalize(self : in out Node);
|
||||
subtype Node_Parent is Ada.Finalization.Limited_Controlled;
|
||||
|
||||
type Tree is new Ada.Finalization.Limited_Controlled with record
|
||||
root : Node_Ptr := null;
|
||||
end record;
|
||||
overriding procedure Finalize(self : in out Tree);
|
||||
|
||||
end AVL_Tree;
|
||||
|
||||
package body AVL_Tree is
|
||||
|
||||
procedure Free_Node is new Ada.Unchecked_Deallocation(Node, Node_Ptr);
|
||||
|
||||
overriding procedure Finalize(self : in out Node) is
|
||||
begin
|
||||
Free_Node(self.left);
|
||||
Free_Node(self.right);
|
||||
end Finalize;
|
||||
|
||||
overriding procedure Finalize(self : in out Tree) is
|
||||
begin
|
||||
Free_Node(self.root);
|
||||
end Finalize;
|
||||
|
||||
|
||||
function height(n : Node_Ptr) return Height_Amt is
|
||||
begin
|
||||
if n = null then
|
||||
return -1;
|
||||
else
|
||||
return 1 + Height_Amt'Max(height(n.left), height(n.right));
|
||||
end if;
|
||||
end height;
|
||||
|
||||
procedure set_balance(n : not null Node_Ptr) is
|
||||
begin
|
||||
n.balance := Balance_Amt(height(n.right) - height(n.left));
|
||||
end set_balance;
|
||||
|
||||
procedure update_parent(parent : Node_Ptr; new_child : Node_Ptr; old_child : Node_Ptr) is
|
||||
begin
|
||||
if parent /= null then
|
||||
if parent.right = old_child then
|
||||
parent.right := new_child;
|
||||
else
|
||||
parent.left := new_child;
|
||||
end if;
|
||||
end if;
|
||||
end update_parent;
|
||||
|
||||
function rotate_left(a : not null Node_Ptr) return Node_Ptr is
|
||||
b : Node_Ptr := a.right;
|
||||
begin
|
||||
b.parent := a.parent;
|
||||
a.right := b.left;
|
||||
if a.right /= null then
|
||||
a.right.parent := a;
|
||||
end if;
|
||||
b.left := a;
|
||||
a.parent := b;
|
||||
update_parent(parent => b.parent, new_child => b, old_child => a);
|
||||
|
||||
set_balance(a);
|
||||
set_balance(b);
|
||||
return b;
|
||||
end rotate_left;
|
||||
|
||||
function rotate_right(a : not null Node_Ptr) return Node_Ptr is
|
||||
b : Node_Ptr := a.left;
|
||||
begin
|
||||
b.parent := a.parent;
|
||||
a.left := b.right;
|
||||
if a.left /= null then
|
||||
a.left.parent := a;
|
||||
end if;
|
||||
b.right := a;
|
||||
a.parent := b;
|
||||
update_parent(parent => b.parent, new_child => b, old_child => a);
|
||||
|
||||
set_balance(a);
|
||||
set_balance(b);
|
||||
return b;
|
||||
end rotate_right;
|
||||
|
||||
function rotate_left_right(n : not null Node_Ptr) return Node_Ptr is
|
||||
begin
|
||||
n.left := rotate_left(n.left);
|
||||
return rotate_right(n);
|
||||
end rotate_left_right;
|
||||
|
||||
function rotate_right_left(n : not null Node_Ptr) return Node_Ptr is
|
||||
begin
|
||||
n.right := rotate_right(n.right);
|
||||
return rotate_left(n);
|
||||
end rotate_right_left;
|
||||
|
||||
procedure rebalance(self : in out Tree; n : not null Node_Ptr) is
|
||||
new_n : Node_Ptr := n;
|
||||
begin
|
||||
set_balance(new_n);
|
||||
if new_n.balance = -2 then
|
||||
if height(new_n.left.left) >= height(new_n.left.right) then
|
||||
new_n := rotate_right(new_n);
|
||||
else
|
||||
new_n := rotate_left_right(new_n);
|
||||
end if;
|
||||
elsif new_n.balance = 2 then
|
||||
if height(new_n.right.right) >= height(new_n.right.left) then
|
||||
new_n := rotate_left(new_n);
|
||||
else
|
||||
new_n := rotate_right_left(new_n);
|
||||
end if;
|
||||
end if;
|
||||
|
||||
if new_n.parent /= null then
|
||||
rebalance(self, new_n.parent);
|
||||
else
|
||||
self.root := new_n;
|
||||
end if;
|
||||
end rebalance;
|
||||
|
||||
function new_node(key : Key_Type) return Node_Ptr is
|
||||
(new Node'(Node_Parent with key => key, others => <>));
|
||||
|
||||
function insert(self : in out Tree; key : Key_Type) return Boolean is
|
||||
curr, parent : Node_Ptr;
|
||||
go_left : Boolean;
|
||||
begin
|
||||
if self.root = null then
|
||||
self.root := new_node(key);
|
||||
return True;
|
||||
end if;
|
||||
|
||||
curr := self.root;
|
||||
while curr.key /= key loop
|
||||
parent := curr;
|
||||
go_left := key < curr.key;
|
||||
curr := (if go_left then curr.left else curr.right);
|
||||
if curr = null then
|
||||
if go_left then
|
||||
parent.left := new_node(key);
|
||||
parent.left.parent := parent;
|
||||
else
|
||||
parent.right := new_node(key);
|
||||
parent.right.parent := parent;
|
||||
end if;
|
||||
rebalance(self, parent);
|
||||
return True;
|
||||
end if;
|
||||
end loop;
|
||||
return False;
|
||||
end insert;
|
||||
|
||||
procedure delete(self : in out Tree; key : Key_Type) is
|
||||
successor, parent, child : Node_Ptr := self.root;
|
||||
to_delete : Node_Ptr := null;
|
||||
begin
|
||||
if self.root = null then
|
||||
return;
|
||||
end if;
|
||||
|
||||
while child /= null loop
|
||||
parent := successor;
|
||||
successor := child;
|
||||
child := (if successor.key <= key then successor.right else successor.left);
|
||||
if successor.key = key then
|
||||
to_delete := successor;
|
||||
end if;
|
||||
end loop;
|
||||
|
||||
if to_delete = null then
|
||||
return;
|
||||
end if;
|
||||
to_delete.key := successor.key;
|
||||
child := (if successor.left = null then successor.right else successor.left);
|
||||
if self.root.key = key then
|
||||
self.root := child;
|
||||
else
|
||||
update_parent(parent => parent, new_child => child, old_child => successor);
|
||||
rebalance(self, parent);
|
||||
end if;
|
||||
Free_Node(successor);
|
||||
end delete;
|
||||
|
||||
procedure print_balance(n : Node_Ptr) is
|
||||
begin
|
||||
if n /= null then
|
||||
print_balance(n.left);
|
||||
Ada.Text_IO.Put(n.balance'Image);
|
||||
print_balance(n.right);
|
||||
end if;
|
||||
end print_balance;
|
||||
|
||||
procedure print_balance(self : in out Tree) is
|
||||
begin
|
||||
print_balance(self.root);
|
||||
end print_balance;
|
||||
end AVL_Tree;
|
||||
|
||||
package Int_AVL_Tree is new AVL_Tree(Integer);
|
||||
|
||||
tree : Int_AVL_Tree.Tree;
|
||||
success : Boolean;
|
||||
begin
|
||||
for i in 1 .. 10 loop
|
||||
success := tree.insert(i);
|
||||
end loop;
|
||||
Ada.Text_IO.Put("Printing balance: ");
|
||||
tree.print_balance;
|
||||
Ada.Text_IO.New_Line;
|
||||
end Main;
|
||||
103
Task/AVL-tree/Agda/avl-tree.agda
Normal file
103
Task/AVL-tree/Agda/avl-tree.agda
Normal file
|
|
@ -0,0 +1,103 @@
|
|||
module Avl where
|
||||
|
||||
-- The Peano naturals
|
||||
data Nat : Set where
|
||||
z : Nat
|
||||
s : Nat -> Nat
|
||||
|
||||
-- An AVL tree's type is indexed by a natural.
|
||||
-- Avl N is the type of AVL trees of depth N. There arj 3 different
|
||||
-- node constructors:
|
||||
-- Left: The left subtree is one level deeper than the right
|
||||
-- Balanced: The subtrees have the same depth
|
||||
-- Right: The right Subtree is one level deeper than the left
|
||||
-- Since the AVL invariant is that the depths of a node's subtrees
|
||||
-- always differ by at most 1, this perfectly encodes the AVL depth invariant.
|
||||
data Avl : Nat -> Set where
|
||||
Empty : Avl z
|
||||
Left : {X : Nat} -> Nat -> Avl (s X) -> Avl X -> Avl (s (s X))
|
||||
Balanced : {X : Nat} -> Nat -> Avl X -> Avl X -> Avl (s X)
|
||||
Right : {X : Nat} -> Nat -> Avl X -> Avl (s X) -> Avl (s (s X))
|
||||
|
||||
-- A wrapper type that hides the AVL tree invariant. This is the interface
|
||||
-- exposed to the user.
|
||||
data Tree : Set where
|
||||
avl : {N : Nat} -> Avl N -> Tree
|
||||
|
||||
-- Comparison result
|
||||
data Ord : Set where
|
||||
Less : Ord
|
||||
Equal : Ord
|
||||
Greater : Ord
|
||||
|
||||
-- Comparison function
|
||||
cmp : Nat -> Nat -> Ord
|
||||
cmp z (s X) = Less
|
||||
cmp z z = Equal
|
||||
cmp (s X) z = Greater
|
||||
cmp (s X) (s Y) = cmp X Y
|
||||
|
||||
-- Insertions can either leave the depth the same or
|
||||
-- increase it by one. Encode this in the type.
|
||||
data InsertResult : Nat -> Set where
|
||||
Same : {X : Nat} -> Avl X -> InsertResult X
|
||||
Bigger : {X : Nat} -> Avl (s X) -> InsertResult X
|
||||
|
||||
-- If the left subtree is 2 levels deeper than the right, rotate to the right.
|
||||
-- balance-left X L R means X is the root, L is the left subtree and R is the right.
|
||||
balance-left : {N : Nat} -> Nat -> Avl (s (s N)) -> Avl N -> InsertResult (s (s N))
|
||||
balance-left X (Right Y A (Balanced Z B C)) D = Same (Balanced Z (Balanced X A B) (Balanced Y C D))
|
||||
balance-left X (Right Y A (Left Z B C)) D = Same (Balanced Z (Balanced X A B) (Right Y C D))
|
||||
balance-left X (Right Y A (Right Z B C)) D = Same (Balanced Z (Left X A B) (Balanced Y C D))
|
||||
balance-left X (Left Y (Balanced Z A B) C) D = Same (Balanced Z (Balanced X A B) (Balanced Y C D))
|
||||
balance-left X (Left Y (Left Z A B) C) D = Same (Balanced Z (Left X A B) (Balanced Y C D))
|
||||
balance-left X (Left Y (Right Z A B) C) D = Same (Balanced Z (Right X A B) (Balanced Y C D))
|
||||
balance-left X (Balanced Y (Balanced Z A B) C) D = Bigger (Right Z (Balanced X A B) (Left Y C D))
|
||||
balance-left X (Balanced Y (Left Z A B) C) D = Bigger (Right Z (Left X A B) (Left Y C D))
|
||||
balance-left X (Balanced Y (Right Z A B) C) D = Bigger (Right Z (Right X A B) (Left Y C D))
|
||||
|
||||
-- Symmetric with balance-left
|
||||
balance-right : {N : Nat} -> Nat -> Avl N -> Avl (s (s N)) -> InsertResult (s (s N))
|
||||
balance-right X A (Left Y (Left Z B C) D) = Same (Balanced Z (Balanced X A B) (Right Y C D))
|
||||
balance-right X A (Left Y (Balanced Z B C) D) = Same(Balanced Z (Balanced X A B) (Balanced Y C D))
|
||||
balance-right X A (Left Y (Right Z B C) D) = Same(Balanced Z (Left X A B) (Balanced Y C D))
|
||||
balance-right X A (Balanced Z B (Left Y C D)) = Bigger(Left Z (Right X A B) (Left Y C D))
|
||||
balance-right X A (Balanced Z B (Balanced Y C D)) = Bigger (Left Z (Right X A B) (Balanced Y C D))
|
||||
balance-right X A (Balanced Z B (Right Y C D)) = Bigger (Left Z (Right X A B) (Right Y C D))
|
||||
balance-right X A (Right Z B (Left Y C D)) = Same (Balanced Z (Balanced X A B) (Left Y C D))
|
||||
balance-right X A (Right Z B (Balanced Y C D)) = Same (Balanced Z (Balanced X A B) (Balanced Y C D))
|
||||
balance-right X A (Right Z B (Right Y C D)) = Same (Balanced Z (Balanced X A B) (Right Y C D))
|
||||
|
||||
-- insert' T N does all the work of inserting the element N into the tree T.
|
||||
insert' : {N : Nat} -> Avl N -> Nat -> InsertResult N
|
||||
insert' Empty N = Bigger (Balanced N Empty Empty)
|
||||
insert' (Left Y L R) X with cmp X Y
|
||||
insert' (Left Y L R) X | Less with insert' L X
|
||||
insert' (Left Y L R) X | Less | Same L' = Same (Left Y L' R)
|
||||
insert' (Left Y L R) X | Less | Bigger L' = balance-left Y L' R
|
||||
insert' (Left Y L R) X | Equal = Same (Left Y L R)
|
||||
insert' (Left Y L R) X | Greater with insert' R X
|
||||
insert' (Left Y L R) X | Greater | Same R' = Same (Left Y L R')
|
||||
insert' (Left Y L R) X | Greater | Bigger R' = Same (Balanced Y L R')
|
||||
insert' (Balanced Y L R) X with cmp X Y
|
||||
insert' (Balanced Y L R) X | Less with insert' L X
|
||||
insert' (Balanced Y L R) X | Less | Same L' = Same (Balanced Y L' R)
|
||||
insert' (Balanced Y L R) X | Less | Bigger L' = Bigger (Left Y L' R)
|
||||
insert' (Balanced Y L R) X | Equal = Same (Balanced Y L R)
|
||||
insert' (Balanced Y L R) X | Greater with insert' R X
|
||||
insert' (Balanced Y L R) X | Greater | Same R' = Same (Balanced Y L R')
|
||||
insert' (Balanced Y L R) X | Greater | Bigger R' = Bigger (Right Y L R')
|
||||
insert' (Right Y L R) X with cmp X Y
|
||||
insert' (Right Y L R) X | Less with insert' L X
|
||||
insert' (Right Y L R) X | Less | Same L' = Same (Right Y L' R)
|
||||
insert' (Right Y L R) X | Less | Bigger L' = Same (Balanced Y L' R)
|
||||
insert' (Right Y L R) X | Equal = Same (Right Y L R)
|
||||
insert' (Right Y L R) X | Greater with insert' R X
|
||||
insert' (Right Y L R) X | Greater | Same R' = Same (Right Y L R')
|
||||
insert' (Right Y L R) X | Greater | Bigger R' = balance-right Y L R'
|
||||
|
||||
-- Wrapper around insert' to use the depth-agnostic type Tree.
|
||||
insert : Tree -> Nat -> Tree
|
||||
insert (avl T) X with insert' T X
|
||||
... | Same T' = avl T'
|
||||
... | Bigger T' = avl T'
|
||||
255
Task/AVL-tree/C++/avl-tree.cpp
Normal file
255
Task/AVL-tree/C++/avl-tree.cpp
Normal file
|
|
@ -0,0 +1,255 @@
|
|||
#include <algorithm>
|
||||
#include <iostream>
|
||||
|
||||
/* AVL node */
|
||||
template <class T>
|
||||
class AVLnode {
|
||||
public:
|
||||
T key;
|
||||
int balance;
|
||||
AVLnode *left, *right, *parent;
|
||||
|
||||
AVLnode(T k, AVLnode *p) : key(k), balance(0), parent(p),
|
||||
left(NULL), right(NULL) {}
|
||||
|
||||
~AVLnode() {
|
||||
delete left;
|
||||
delete right;
|
||||
}
|
||||
};
|
||||
|
||||
/* AVL tree */
|
||||
template <class T>
|
||||
class AVLtree {
|
||||
public:
|
||||
AVLtree(void);
|
||||
~AVLtree(void);
|
||||
bool insert(T key);
|
||||
void deleteKey(const T key);
|
||||
void printBalance();
|
||||
|
||||
private:
|
||||
AVLnode<T> *root;
|
||||
|
||||
AVLnode<T>* rotateLeft ( AVLnode<T> *a );
|
||||
AVLnode<T>* rotateRight ( AVLnode<T> *a );
|
||||
AVLnode<T>* rotateLeftThenRight ( AVLnode<T> *n );
|
||||
AVLnode<T>* rotateRightThenLeft ( AVLnode<T> *n );
|
||||
void rebalance ( AVLnode<T> *n );
|
||||
int height ( AVLnode<T> *n );
|
||||
void setBalance ( AVLnode<T> *n );
|
||||
void printBalance ( AVLnode<T> *n );
|
||||
};
|
||||
|
||||
/* AVL class definition */
|
||||
template <class T>
|
||||
void AVLtree<T>::rebalance(AVLnode<T> *n) {
|
||||
setBalance(n);
|
||||
|
||||
if (n->balance == -2) {
|
||||
if (height(n->left->left) >= height(n->left->right))
|
||||
n = rotateRight(n);
|
||||
else
|
||||
n = rotateLeftThenRight(n);
|
||||
}
|
||||
else if (n->balance == 2) {
|
||||
if (height(n->right->right) >= height(n->right->left))
|
||||
n = rotateLeft(n);
|
||||
else
|
||||
n = rotateRightThenLeft(n);
|
||||
}
|
||||
|
||||
if (n->parent != NULL) {
|
||||
rebalance(n->parent);
|
||||
}
|
||||
else {
|
||||
root = n;
|
||||
}
|
||||
}
|
||||
|
||||
template <class T>
|
||||
AVLnode<T>* AVLtree<T>::rotateLeft(AVLnode<T> *a) {
|
||||
AVLnode<T> *b = a->right;
|
||||
b->parent = a->parent;
|
||||
a->right = b->left;
|
||||
|
||||
if (a->right != NULL)
|
||||
a->right->parent = a;
|
||||
|
||||
b->left = a;
|
||||
a->parent = b;
|
||||
|
||||
if (b->parent != NULL) {
|
||||
if (b->parent->right == a) {
|
||||
b->parent->right = b;
|
||||
}
|
||||
else {
|
||||
b->parent->left = b;
|
||||
}
|
||||
}
|
||||
|
||||
setBalance(a);
|
||||
setBalance(b);
|
||||
return b;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
AVLnode<T>* AVLtree<T>::rotateRight(AVLnode<T> *a) {
|
||||
AVLnode<T> *b = a->left;
|
||||
b->parent = a->parent;
|
||||
a->left = b->right;
|
||||
|
||||
if (a->left != NULL)
|
||||
a->left->parent = a;
|
||||
|
||||
b->right = a;
|
||||
a->parent = b;
|
||||
|
||||
if (b->parent != NULL) {
|
||||
if (b->parent->right == a) {
|
||||
b->parent->right = b;
|
||||
}
|
||||
else {
|
||||
b->parent->left = b;
|
||||
}
|
||||
}
|
||||
|
||||
setBalance(a);
|
||||
setBalance(b);
|
||||
return b;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
AVLnode<T>* AVLtree<T>::rotateLeftThenRight(AVLnode<T> *n) {
|
||||
n->left = rotateLeft(n->left);
|
||||
return rotateRight(n);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
AVLnode<T>* AVLtree<T>::rotateRightThenLeft(AVLnode<T> *n) {
|
||||
n->right = rotateRight(n->right);
|
||||
return rotateLeft(n);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
int AVLtree<T>::height(AVLnode<T> *n) {
|
||||
if (n == NULL)
|
||||
return -1;
|
||||
return 1 + std::max(height(n->left), height(n->right));
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void AVLtree<T>::setBalance(AVLnode<T> *n) {
|
||||
n->balance = height(n->right) - height(n->left);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void AVLtree<T>::printBalance(AVLnode<T> *n) {
|
||||
if (n != NULL) {
|
||||
printBalance(n->left);
|
||||
std::cout << n->balance << " ";
|
||||
printBalance(n->right);
|
||||
}
|
||||
}
|
||||
|
||||
template <class T>
|
||||
AVLtree<T>::AVLtree(void) : root(NULL) {}
|
||||
|
||||
template <class T>
|
||||
AVLtree<T>::~AVLtree(void) {
|
||||
delete root;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
bool AVLtree<T>::insert(T key) {
|
||||
if (root == NULL) {
|
||||
root = new AVLnode<T>(key, NULL);
|
||||
}
|
||||
else {
|
||||
AVLnode<T>
|
||||
*n = root,
|
||||
*parent;
|
||||
|
||||
while (true) {
|
||||
if (n->key == key)
|
||||
return false;
|
||||
|
||||
parent = n;
|
||||
|
||||
bool goLeft = n->key > key;
|
||||
n = goLeft ? n->left : n->right;
|
||||
|
||||
if (n == NULL) {
|
||||
if (goLeft) {
|
||||
parent->left = new AVLnode<T>(key, parent);
|
||||
}
|
||||
else {
|
||||
parent->right = new AVLnode<T>(key, parent);
|
||||
}
|
||||
|
||||
rebalance(parent);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void AVLtree<T>::deleteKey(const T delKey) {
|
||||
if (root == NULL)
|
||||
return;
|
||||
|
||||
AVLnode<T>
|
||||
*n = root,
|
||||
*parent = root,
|
||||
*delNode = NULL,
|
||||
*child = root;
|
||||
|
||||
while (child != NULL) {
|
||||
parent = n;
|
||||
n = child;
|
||||
child = delKey >= n->key ? n->right : n->left;
|
||||
if (delKey == n->key)
|
||||
delNode = n;
|
||||
}
|
||||
|
||||
if (delNode != NULL) {
|
||||
delNode->key = n->key;
|
||||
|
||||
child = n->left != NULL ? n->left : n->right;
|
||||
|
||||
if (root->key == delKey) {
|
||||
root = child;
|
||||
}
|
||||
else {
|
||||
if (parent->left == n) {
|
||||
parent->left = child;
|
||||
}
|
||||
else {
|
||||
parent->right = child;
|
||||
}
|
||||
|
||||
rebalance(parent);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void AVLtree<T>::printBalance() {
|
||||
printBalance(root);
|
||||
std::cout << std::endl;
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
AVLtree<int> t;
|
||||
|
||||
std::cout << "Inserting integer values 1 to 10" << std::endl;
|
||||
for (int i = 1; i <= 10; ++i)
|
||||
t.insert(i);
|
||||
|
||||
std::cout << "Printing balance: ";
|
||||
t.printBalance();
|
||||
}
|
||||
287
Task/AVL-tree/Common-Lisp/avl-tree.lisp
Normal file
287
Task/AVL-tree/Common-Lisp/avl-tree.lisp
Normal file
|
|
@ -0,0 +1,287 @@
|
|||
(defpackage :avl-tree
|
||||
(:use :cl)
|
||||
(:export
|
||||
:avl-tree
|
||||
:make-avl-tree
|
||||
:avl-tree-count
|
||||
:avl-tree-p
|
||||
:avl-tree-key<=
|
||||
:gettree
|
||||
:remtree
|
||||
:clrtree
|
||||
:dfs-maptree
|
||||
:bfs-maptree))
|
||||
|
||||
(in-package :avl-tree)
|
||||
|
||||
(defstruct %tree
|
||||
key
|
||||
value
|
||||
(height 0 :type fixnum)
|
||||
left
|
||||
right)
|
||||
|
||||
(defstruct (avl-tree (:constructor %make-avl-tree))
|
||||
key<=
|
||||
tree
|
||||
(count 0 :type fixnum))
|
||||
|
||||
(defun make-avl-tree (key<=)
|
||||
"Create a new AVL tree using the given comparison function KEY<=
|
||||
for emplacing keys into the tree."
|
||||
(%make-avl-tree :key<= key<=))
|
||||
|
||||
(declaim (inline
|
||||
recalc-height
|
||||
height balance
|
||||
swap-kv
|
||||
right-right-rotate
|
||||
right-left-rotate
|
||||
left-right-rotate
|
||||
left-left-rotate
|
||||
rotate))
|
||||
|
||||
(defun recalc-height (tree)
|
||||
"Calculate the new height of the tree from the heights of the children."
|
||||
(when tree
|
||||
(setf (%tree-height tree)
|
||||
(1+ (the fixnum (max (height (%tree-right tree))
|
||||
(height (%tree-left tree))))))))
|
||||
|
||||
(declaim (ftype (function (t) fixnum) height balance))
|
||||
(defun height (tree)
|
||||
(if tree (%tree-height tree) 0))
|
||||
|
||||
(defun balance (tree)
|
||||
(if tree
|
||||
(- (height (%tree-right tree))
|
||||
(height (%tree-left tree)))
|
||||
0))
|
||||
|
||||
(defmacro swap (place-a place-b)
|
||||
"Swap the values of two places."
|
||||
(let ((tmp (gensym)))
|
||||
`(let ((,tmp ,place-a))
|
||||
(setf ,place-a ,place-b)
|
||||
(setf ,place-b ,tmp))))
|
||||
|
||||
(defun swap-kv (tree-a tree-b)
|
||||
"Swap the keys and values of two trees."
|
||||
(swap (%tree-value tree-a) (%tree-value tree-b))
|
||||
(swap (%tree-key tree-a) (%tree-key tree-b)))
|
||||
|
||||
;; We should really use gensyms for the variables in here.
|
||||
(defmacro slash-rotate (tree right left)
|
||||
"Rotate nodes in a slash `/` imbalance."
|
||||
`(let* ((a ,tree)
|
||||
(b (,right a))
|
||||
(c (,right b))
|
||||
(a-left (,left a))
|
||||
(b-left (,left b)))
|
||||
(setf (,right a) c)
|
||||
(setf (,left a) b)
|
||||
(setf (,left b) a-left)
|
||||
(setf (,right b) b-left)
|
||||
(swap-kv a b)
|
||||
(recalc-height b)
|
||||
(recalc-height a)))
|
||||
|
||||
(defmacro angle-rotate (tree right left)
|
||||
"Rotate nodes in an angle bracket `<` imbalance."
|
||||
`(let* ((a ,tree)
|
||||
(b (,right a))
|
||||
(c (,left b))
|
||||
(a-left (,left a))
|
||||
(c-left (,left c))
|
||||
(c-right (,right c)))
|
||||
(setf (,left a) c)
|
||||
(setf (,left c) a-left)
|
||||
(setf (,right c) c-left)
|
||||
(setf (,left b) c-right)
|
||||
(swap-kv a c)
|
||||
(recalc-height c)
|
||||
(recalc-height b)
|
||||
(recalc-height a)))
|
||||
|
||||
(defun right-right-rotate (tree)
|
||||
(slash-rotate tree %tree-right %tree-left))
|
||||
|
||||
(defun left-left-rotate (tree)
|
||||
(slash-rotate tree %tree-left %tree-right))
|
||||
|
||||
(defun right-left-rotate (tree)
|
||||
(angle-rotate tree %tree-right %tree-left))
|
||||
|
||||
(defun left-right-rotate (tree)
|
||||
(angle-rotate tree %tree-left %tree-right))
|
||||
|
||||
(defun rotate (tree)
|
||||
(declare (type %tree tree))
|
||||
"Perform a rotation on the given TREE if it is imbalanced."
|
||||
(recalc-height tree)
|
||||
(with-slots (left right) tree
|
||||
(let ((balance (balance tree)))
|
||||
(cond ((< 1 balance) ;; Right imbalanced tree
|
||||
(if (<= 0 (balance right))
|
||||
(right-right-rotate tree)
|
||||
(right-left-rotate tree)))
|
||||
((> -1 balance) ;; Left imbalanced tree
|
||||
(if (<= 0 (balance left))
|
||||
(left-right-rotate tree)
|
||||
(left-left-rotate tree)))))))
|
||||
|
||||
(defun gettree (key avl-tree &optional default)
|
||||
"Finds an entry in AVL-TREE whos key is KEY and returns the
|
||||
associated value and T as multiple values, or returns DEFAULT and NIL
|
||||
if there was no such entry. Entries can be added using SETF."
|
||||
(with-slots (key<= tree) avl-tree
|
||||
(labels
|
||||
((rec (tree)
|
||||
(if tree
|
||||
(with-slots ((t-key key) left right value) tree
|
||||
(if (funcall key<= t-key key)
|
||||
(if (funcall key<= key t-key)
|
||||
(values value t)
|
||||
(rec right))
|
||||
(rec left)))
|
||||
(values default nil))))
|
||||
(rec tree))))
|
||||
|
||||
(defun puttree (value key avl-tree)
|
||||
;;(declare (optimize speed))
|
||||
(declare (type avl-tree avl-tree))
|
||||
"Emplace the the VALUE with the given KEY into the AVL-TREE, or
|
||||
overwrite the value if the given key already exists."
|
||||
(let ((node (make-%tree :key key :value value)))
|
||||
(with-slots (key<= tree count) avl-tree
|
||||
(cond (tree
|
||||
(labels
|
||||
((rec (tree)
|
||||
(with-slots ((t-key key) left right) tree
|
||||
(if (funcall key<= t-key key)
|
||||
(if (funcall key<= key t-key)
|
||||
(setf (%tree-value tree) value)
|
||||
(cond (right (rec right))
|
||||
(t (setf right node)
|
||||
(incf count))))
|
||||
(cond (left (rec left))
|
||||
(t (setf left node)
|
||||
(incf count))))
|
||||
(rotate tree))))
|
||||
(rec tree)))
|
||||
(t (setf tree node)
|
||||
(incf count))))
|
||||
value))
|
||||
|
||||
(defun (setf gettree) (value key avl-tree &optional default)
|
||||
(declare (ignore default))
|
||||
(puttree value key avl-tree))
|
||||
|
||||
(defun remtree (key avl-tree)
|
||||
(declare (type avl-tree avl-tree))
|
||||
"Remove the entry in AVL-TREE associated with KEY. Return T if
|
||||
there was such an entry, or NIL if not."
|
||||
(with-slots (key<= tree count) avl-tree
|
||||
(labels
|
||||
((find-left (tree)
|
||||
(with-slots ((t-key key) left right) tree
|
||||
(if left
|
||||
(find-left left)
|
||||
tree)))
|
||||
(rec (tree &optional parent type)
|
||||
(when tree
|
||||
(prog1
|
||||
(with-slots ((t-key key) left right) tree
|
||||
(if (funcall key<= t-key key)
|
||||
(cond
|
||||
((funcall key<= key t-key)
|
||||
(cond
|
||||
((and left right)
|
||||
(let ((sub-left (find-left right)))
|
||||
(swap-kv sub-left tree)
|
||||
(rec right tree :right)))
|
||||
(t
|
||||
(let ((sub (or left right)))
|
||||
(case type
|
||||
(:right (setf (%tree-right parent) sub))
|
||||
(:left (setf (%tree-left parent) sub))
|
||||
(nil (setf (avl-tree-tree avl-tree) sub))))
|
||||
(decf count)))
|
||||
t)
|
||||
(t (rec right tree :right)))
|
||||
(rec left tree :left)))
|
||||
(when parent (rotate parent))))))
|
||||
(rec tree))))
|
||||
|
||||
(defun clrtree (avl-tree)
|
||||
"This removes all the entries from AVL-TREE and returns the tree itself."
|
||||
(setf (avl-tree-tree avl-tree) nil)
|
||||
(setf (avl-tree-count avl-tree) 0)
|
||||
avl-tree)
|
||||
|
||||
(defun dfs-maptree (function avl-tree)
|
||||
"For each entry in AVL-TREE call the two-argument FUNCTION on
|
||||
the key and value of each entry in depth-first order from left to right.
|
||||
Consequences are undefined if AVL-TREE is modified during this call."
|
||||
(with-slots (key<= tree) avl-tree
|
||||
(labels
|
||||
((rec (tree)
|
||||
(when tree
|
||||
(with-slots ((t-key key) left right key value) tree
|
||||
(rec left)
|
||||
(funcall function key value)
|
||||
(rec right)))))
|
||||
(rec tree))))
|
||||
|
||||
(defun bfs-maptree (function avl-tree)
|
||||
"For each entry in AVL-TREE call the two-argument FUNCTION on
|
||||
the key and value of each entry in breadth-first order from left to right.
|
||||
Consequences are undefined if AVL-TREE is modified during this call."
|
||||
(with-slots (key<= tree) avl-tree
|
||||
(let* ((queue (cons nil nil))
|
||||
(end queue))
|
||||
(labels ((pushend (value)
|
||||
(when value
|
||||
(setf (cdr end) (cons value nil))
|
||||
(setf end (cdr end))))
|
||||
(empty-p () (eq nil (cdr queue)))
|
||||
(popfront ()
|
||||
(prog1 (pop (cdr queue))
|
||||
(when (empty-p) (setf end queue)))))
|
||||
(when tree
|
||||
(pushend tree)
|
||||
(loop until (empty-p)
|
||||
do (let ((current (popfront)))
|
||||
(with-slots (key value left right) current
|
||||
(funcall function key value)
|
||||
(pushend left)
|
||||
(pushend right)))))))))
|
||||
|
||||
(defun test ()
|
||||
(let ((tree (make-avl-tree #'<=))
|
||||
(printer (lambda (k v) (print (list k v)))))
|
||||
(loop for key in '(0 8 6 4 2 3 7 9 1 5 5)
|
||||
for value in '(a b c d e f g h i j k)
|
||||
do (setf (gettree key tree) value))
|
||||
(loop for key in '(0 1 2 3 4 10)
|
||||
do (print (multiple-value-list (gettree key tree))))
|
||||
(terpri)
|
||||
(print tree)
|
||||
(terpri)
|
||||
(dfs-maptree printer tree)
|
||||
(terpri)
|
||||
(bfs-maptree printer tree)
|
||||
(terpri)
|
||||
(loop for key in '(0 1 2 3 10 7)
|
||||
do (print (remtree key tree)))
|
||||
(terpri)
|
||||
(print tree)
|
||||
(terpri)
|
||||
(clrtree tree)
|
||||
(print tree))
|
||||
(values))
|
||||
|
||||
(defun profile-test ()
|
||||
(let ((tree (make-avl-tree #'<=))
|
||||
(randoms (loop repeat 1000000 collect (random 100.0))))
|
||||
(loop for key in randoms do (setf (gettree key tree) key))))
|
||||
196
Task/AVL-tree/Component-Pascal/avl-tree-1.pas
Normal file
196
Task/AVL-tree/Component-Pascal/avl-tree-1.pas
Normal file
|
|
@ -0,0 +1,196 @@
|
|||
MODULE RosettaAVLTrees;
|
||||
|
||||
(* An implementation of persistent AVL Trees *)
|
||||
|
||||
TYPE
|
||||
Order = ABSTRACT RECORD END;
|
||||
Tree* = POINTER TO Node;
|
||||
Node* = ABSTRACT RECORD (Order)
|
||||
left, right: Tree;
|
||||
height: INTEGER
|
||||
END; (* Contains the left and right child nodes and the height of the node *)
|
||||
|
||||
Out* = ABSTRACT RECORD END; (* Used for output by the `Draw` procedure *)
|
||||
|
||||
Void = RECORD (Order) END; (* Used by the `Ordered` procedure *)
|
||||
|
||||
(* The following abstract procedures must be implemented by a user of `Node` *)
|
||||
(* They must be implemented correctly for the AVL tree to work *)
|
||||
|
||||
(* Compares one node with another and returns a boolean value based on which is less *)
|
||||
PROCEDURE (IN n: Order) Less- (IN m: Node): BOOLEAN, NEW, ABSTRACT;
|
||||
(* Compares one node with another and returns a boolean value based on which is more *)
|
||||
PROCEDURE (IN n: Order) More- (IN m: Node): BOOLEAN, NEW, ABSTRACT;
|
||||
(* Creates a new root node *)
|
||||
PROCEDURE (IN n: Node) Alloc- (): Tree, NEW, ABSTRACT;
|
||||
|
||||
(* Returns TRUE if n is in the tree t, FALSE otherwise *)
|
||||
PROCEDURE (IN n: Node) Lookup* (t: Tree): BOOLEAN, NEW;
|
||||
BEGIN
|
||||
IF t = NIL THEN RETURN FALSE END;
|
||||
IF n.Less(t) THEN RETURN n.Lookup(t.left) END;
|
||||
IF n.More(t) THEN RETURN n.Lookup(t.right) END;
|
||||
RETURN TRUE
|
||||
END Lookup;
|
||||
|
||||
(* Returns the height of the AVL tree t *)
|
||||
PROCEDURE Height (t: Tree): INTEGER;
|
||||
BEGIN
|
||||
IF t = NIL THEN RETURN 0 END;
|
||||
RETURN t.height
|
||||
END Height;
|
||||
|
||||
(* Creates and returns a new Node with the given children *)
|
||||
PROCEDURE (IN n: Node) New (left, right: Tree): Tree, NEW;
|
||||
VAR t: Tree;
|
||||
BEGIN
|
||||
t := n.Alloc(); (* Create a new root node *)
|
||||
t.left := left; t.right := right; (* set the children *)
|
||||
(* set the height of the node based on its children *)
|
||||
t.height := MAX(Height(left), Height(right)) + 1;
|
||||
RETURN t
|
||||
END New;
|
||||
|
||||
(* Returns the difference in height between the left and right children of a node *)
|
||||
PROCEDURE Slope (l, r: Tree): INTEGER;
|
||||
BEGIN RETURN Height(l) - Height(r) END Slope;
|
||||
|
||||
(* Returns an AVL tree if it is right-heavy *)
|
||||
PROCEDURE (IN n: Node) BalL (l, r: Tree): Tree, NEW;
|
||||
BEGIN
|
||||
IF Slope(l, r) = - 2 THEN
|
||||
IF Slope(r.left, r.right) = 1 THEN
|
||||
RETURN r.left.New(n.New(l, r.left.left),
|
||||
r.New(r.left.right, r.right))
|
||||
END;
|
||||
RETURN r.New(n.New(l, r.left), r.right)
|
||||
END;
|
||||
RETURN n.New(l, r)
|
||||
END BalL;
|
||||
|
||||
(* Returns an AVL tree if it is left-heavy *)
|
||||
PROCEDURE (IN n: Node) BalR (l, r: Tree): Tree, NEW;
|
||||
BEGIN
|
||||
IF Slope(l, r) = 2 THEN
|
||||
IF Slope(l.left, l.right) = - 1 THEN
|
||||
RETURN l.right.New(l.New(l.left, l.right.left),
|
||||
n.New(l.right.right, r))
|
||||
END;
|
||||
RETURN l.New(l.left, n.New(l.right, r))
|
||||
END;
|
||||
RETURN n.New(l, r)
|
||||
END BalR;
|
||||
|
||||
(* Returns the AVL tree t with the node n *)
|
||||
PROCEDURE (IN n: Node) Insert* (t: Tree): Tree, NEW;
|
||||
BEGIN
|
||||
IF t = NIL THEN RETURN n.New(NIL, NIL) END;
|
||||
IF n.Less(t) THEN RETURN t.BalR(n.Insert(t.left), t.right) END;
|
||||
IF n.More(t) THEN RETURN t.BalL(t.left, n.Insert(t.right)) END;
|
||||
RETURN t
|
||||
END Insert;
|
||||
|
||||
(* Returns the leftmost node of the non-empty tree t *)
|
||||
PROCEDURE (t: Tree) Head (): Tree, NEW;
|
||||
BEGIN
|
||||
IF t.left = NIL THEN RETURN t END;
|
||||
RETURN t.left.Head()
|
||||
END Head;
|
||||
|
||||
(* Returns the rightmost node of the non-empty tree t *)
|
||||
PROCEDURE (t: Tree) Last (): Tree, NEW;
|
||||
BEGIN
|
||||
IF t.right = NIL THEN RETURN t END;
|
||||
RETURN t.right.Last()
|
||||
END Last;
|
||||
|
||||
(* Returns the AVL tree t without the leftmost node *)
|
||||
PROCEDURE (IN t: Node) Tail* (): Tree, NEW;
|
||||
BEGIN
|
||||
IF t.left = NIL THEN RETURN t.right END;
|
||||
RETURN t.BalL(t.left.Tail(), t.right)
|
||||
END Tail;
|
||||
|
||||
(* Returns the AVL tree t without the rightmost node *)
|
||||
PROCEDURE (IN t: Node) Init* (): Tree, NEW;
|
||||
BEGIN
|
||||
IF t.right = NIL THEN RETURN t.left END;
|
||||
RETURN t.BalR(t.left, t.right.Init())
|
||||
END Init;
|
||||
|
||||
(* Returns the AVL tree t without node n *)
|
||||
PROCEDURE (IN n: Node) Delete* (t: Tree): Tree, NEW;
|
||||
BEGIN
|
||||
IF t = NIL THEN RETURN NIL END;
|
||||
IF n.Less(t) THEN RETURN t.BalL(n.Delete(t.left), t.right) END;
|
||||
IF n.More(t) THEN RETURN t.BalR(t.left, n.Delete(t.right)) END;
|
||||
IF Slope(t.left, t.right) = 1 THEN
|
||||
RETURN t.left.Last().BalL(t.left.Init(), t.right)
|
||||
END;
|
||||
IF t.right = NIL THEN RETURN t.left END;
|
||||
RETURN t.right.Head().BalR(t.left, t.right.Tail())
|
||||
END Delete;
|
||||
|
||||
(* The following procedures are used for debugging *)
|
||||
|
||||
PROCEDURE (IN n: Void) Less- (IN m: Node): BOOLEAN;
|
||||
BEGIN RETURN TRUE END Less;
|
||||
|
||||
PROCEDURE (IN n: Void) More- (IN m: Node): BOOLEAN;
|
||||
BEGIN RETURN TRUE END More;
|
||||
|
||||
(* Returns TRUE if the AVL tree t is ordered, FALSE otherwise *)
|
||||
PROCEDURE Ordered* (t: Tree): BOOLEAN;
|
||||
VAR void: Void;
|
||||
|
||||
PROCEDURE Bounded (IN lo, hi: Order; t: Tree): BOOLEAN;
|
||||
BEGIN
|
||||
IF t = NIL THEN RETURN TRUE END;
|
||||
RETURN lo.Less(t) & hi.More(t) &
|
||||
Bounded(lo, t, t.left) & Bounded(t, hi, t.right)
|
||||
END Bounded;
|
||||
|
||||
BEGIN RETURN Bounded(void, void, t) END Ordered;
|
||||
|
||||
(* The following abstract procedures must be implemented by a user of `Out` *)
|
||||
|
||||
(* Writes a string *)
|
||||
PROCEDURE (IN o: Out) Str- (s: ARRAY OF CHAR), NEW, ABSTRACT;
|
||||
(* Writes an integer *)
|
||||
PROCEDURE (IN o: Out) Int- (i: INTEGER), NEW, ABSTRACT;
|
||||
(* Writes a new-line *)
|
||||
PROCEDURE (IN o: Out) Ln-, NEW, ABSTRACT;
|
||||
(* Writes a node *)
|
||||
PROCEDURE (IN o: Out) Node- (IN n: Node), NEW, ABSTRACT;
|
||||
|
||||
(* Writes a tree (rotated) *)
|
||||
PROCEDURE (IN o: Out) Draw* (t: Tree), NEW;
|
||||
|
||||
PROCEDURE Bars (bars, bar: ARRAY OF CHAR);
|
||||
BEGIN
|
||||
IF LEN(bars + bar) # 0 THEN o.Str(bars + "+--") END
|
||||
END Bars;
|
||||
|
||||
PROCEDURE Do (lBar, rBar, bars: ARRAY OF CHAR; t: Tree);
|
||||
BEGIN
|
||||
IF t = NIL THEN Bars(bars, lBar); o.Str("|"); o.Ln
|
||||
ELSIF (t.left = NIL) & (t.right = NIL) THEN
|
||||
Bars(bars, lBar); o.Node(t); o.Ln
|
||||
ELSE
|
||||
Do("| ", " ", bars + rBar, t.right);
|
||||
o.Str(bars + rBar + "|"); o.Ln;
|
||||
Bars(bars, lBar); o.Node(t);
|
||||
IF Slope(t.left, t.right) # 0 THEN
|
||||
o.Str(" ["); o.Int(Slope(t.left, t.right)); o.Str("]")
|
||||
END;
|
||||
o.Ln;
|
||||
o.Str(bars + lBar + "|"); o.Ln;
|
||||
Do(" ", "| ", bars + lBar, t.left)
|
||||
END
|
||||
END Do;
|
||||
|
||||
BEGIN
|
||||
Do("", "", "", t)
|
||||
END Draw;
|
||||
|
||||
END RosettaAVLTrees.
|
||||
24
Task/AVL-tree/Component-Pascal/avl-tree-2.pas
Normal file
24
Task/AVL-tree/Component-Pascal/avl-tree-2.pas
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
DEFINITION RosettaAVLTrees;
|
||||
|
||||
TYPE
|
||||
Tree = POINTER TO Node;
|
||||
Node = ABSTRACT RECORD (Order)
|
||||
(IN n: Node) Alloc- (): Tree, NEW, ABSTRACT;
|
||||
(IN n: Node) Delete (t: Tree): Tree, NEW;
|
||||
(IN t: Node) Init (): Tree, NEW;
|
||||
(IN n: Node) Insert (t: Tree): Tree, NEW;
|
||||
(IN n: Node) Lookup (t: Tree): BOOLEAN, NEW;
|
||||
(IN t: Node) Tail (): Tree, NEW
|
||||
END;
|
||||
|
||||
Out = ABSTRACT RECORD
|
||||
(IN o: Out) Draw (t: Tree), NEW;
|
||||
(IN o: Out) Int- (i: INTEGER), NEW, ABSTRACT;
|
||||
(IN o: Out) Ln-, NEW, ABSTRACT;
|
||||
(IN o: Out) Node- (IN n: Node), NEW, ABSTRACT;
|
||||
(IN o: Out) Str- (s: ARRAY OF CHAR), NEW, ABSTRACT
|
||||
END;
|
||||
|
||||
PROCEDURE Ordered (t: Tree): BOOLEAN;
|
||||
|
||||
END RosettaAVLTrees.
|
||||
63
Task/AVL-tree/Component-Pascal/avl-tree-3.pas
Normal file
63
Task/AVL-tree/Component-Pascal/avl-tree-3.pas
Normal file
|
|
@ -0,0 +1,63 @@
|
|||
MODULE RosettaAVLTreesUse;
|
||||
|
||||
IMPORT Set := RosettaAVLTrees, Log := StdLog;
|
||||
|
||||
TYPE
|
||||
Height = RECORD (Set.Node) height: INTEGER END;
|
||||
(* Note that Set.Node already contains an integer field `height`. *)
|
||||
(* It does not cause a duplicate field error as it is hidden from this module *)
|
||||
|
||||
Out = RECORD (Set.Out) END; (* Used for output by the `Draw` procedure *)
|
||||
|
||||
(* The following three procedures are implemented here for use by Set.Node *)
|
||||
|
||||
(* Compares one node with another and returns a boolean value based on which is less *)
|
||||
PROCEDURE (IN h: Height) Less- (IN n: Set.Node): BOOLEAN;
|
||||
BEGIN RETURN h.height < n(Height).height END Less;
|
||||
|
||||
(* Compares one node with another and returns a boolean value based on which is more *)
|
||||
PROCEDURE (IN h: Height) More- (IN n: Set.Node): BOOLEAN;
|
||||
BEGIN RETURN h.height > n(Height).height END More;
|
||||
|
||||
(* Creates a new root node *)
|
||||
PROCEDURE (IN h: Height) Alloc- (): Set.Tree;
|
||||
VAR r: POINTER TO Height;
|
||||
BEGIN NEW(r); r.height := h.height; RETURN r END Alloc;
|
||||
|
||||
(* The following four procedures are implemented here for use by Set.Out *)
|
||||
|
||||
(* Writes a string *)
|
||||
PROCEDURE (IN o: Out) Str- (s: ARRAY OF CHAR);
|
||||
BEGIN Log.String(s) END Str;
|
||||
|
||||
(* Writes an integer *)
|
||||
PROCEDURE (IN o: Out) Int- (i: INTEGER);
|
||||
BEGIN Log.IntForm(i, Log.decimal, 0, ' ', Log.hideBase) END Int;
|
||||
|
||||
(* Writes a new-line *)
|
||||
PROCEDURE (IN o: Out) Ln-; BEGIN Log.Ln END Ln;
|
||||
|
||||
(* Writes a node *)
|
||||
PROCEDURE (IN o: Out) Node- (IN n: Set.Node);
|
||||
BEGIN
|
||||
Log.IntForm(n(Height).height, Log.decimal, 0, ' ', Log.hideBase)
|
||||
END Node;
|
||||
|
||||
PROCEDURE Use*;
|
||||
TYPE BAD = POINTER TO Height;
|
||||
VAR h: Height; hs, save: Set.Tree; i: INTEGER; o: Out;
|
||||
BEGIN
|
||||
h.height := 10; hs := h.Insert(hs);
|
||||
FOR i := 0 TO 9 DO h.height := i; hs := h.Insert(hs) END;
|
||||
o.Draw(hs); Log.Ln; Log.Ln;
|
||||
save := hs;
|
||||
FOR i := 0 TO 9 DO h.height := i; hs := h.Delete(hs) END;
|
||||
o.Draw(hs); Log.Ln; Log.Ln;
|
||||
o.Draw(save); Log.Ln; Log.Ln; (* Tree demonstrates persistence *)
|
||||
ASSERT(Set.Ordered(save)); (* This ASSERT succeeds *)
|
||||
save(BAD).height := 11; (* UNSAFE STATEMENT *)
|
||||
o.Draw(save);
|
||||
ASSERT(Set.Ordered(save)) (* This ASSERT fails *)
|
||||
END Use;
|
||||
|
||||
END RosettaAVLTreesUse.
|
||||
195
Task/AVL-tree/D/avl-tree.d
Normal file
195
Task/AVL-tree/D/avl-tree.d
Normal file
|
|
@ -0,0 +1,195 @@
|
|||
import std.stdio, std.algorithm;
|
||||
|
||||
class AVLtree {
|
||||
private Node* root;
|
||||
|
||||
private static struct Node {
|
||||
private int key, balance;
|
||||
private Node* left, right, parent;
|
||||
|
||||
this(in int k, Node* p) pure nothrow @safe @nogc {
|
||||
key = k;
|
||||
parent = p;
|
||||
}
|
||||
}
|
||||
|
||||
public bool insert(in int key) pure nothrow @safe {
|
||||
if (root is null)
|
||||
root = new Node(key, null);
|
||||
else {
|
||||
Node* n = root;
|
||||
Node* parent;
|
||||
while (true) {
|
||||
if (n.key == key)
|
||||
return false;
|
||||
|
||||
parent = n;
|
||||
|
||||
bool goLeft = n.key > key;
|
||||
n = goLeft ? n.left : n.right;
|
||||
|
||||
if (n is null) {
|
||||
if (goLeft) {
|
||||
parent.left = new Node(key, parent);
|
||||
} else {
|
||||
parent.right = new Node(key, parent);
|
||||
}
|
||||
rebalance(parent);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public void deleteKey(in int delKey) pure nothrow @safe @nogc {
|
||||
if (root is null)
|
||||
return;
|
||||
Node* n = root;
|
||||
Node* parent = root;
|
||||
Node* delNode = null;
|
||||
Node* child = root;
|
||||
|
||||
while (child !is null) {
|
||||
parent = n;
|
||||
n = child;
|
||||
child = delKey >= n.key ? n.right : n.left;
|
||||
if (delKey == n.key)
|
||||
delNode = n;
|
||||
}
|
||||
|
||||
if (delNode !is null) {
|
||||
delNode.key = n.key;
|
||||
|
||||
child = n.left !is null ? n.left : n.right;
|
||||
|
||||
if (root.key == delKey) {
|
||||
root = child;
|
||||
} else {
|
||||
if (parent.left is n) {
|
||||
parent.left = child;
|
||||
} else {
|
||||
parent.right = child;
|
||||
}
|
||||
rebalance(parent);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void rebalance(Node* n) pure nothrow @safe @nogc {
|
||||
setBalance(n);
|
||||
|
||||
if (n.balance == -2) {
|
||||
if (height(n.left.left) >= height(n.left.right))
|
||||
n = rotateRight(n);
|
||||
else
|
||||
n = rotateLeftThenRight(n);
|
||||
|
||||
} else if (n.balance == 2) {
|
||||
if (height(n.right.right) >= height(n.right.left))
|
||||
n = rotateLeft(n);
|
||||
else
|
||||
n = rotateRightThenLeft(n);
|
||||
}
|
||||
|
||||
if (n.parent !is null) {
|
||||
rebalance(n.parent);
|
||||
} else {
|
||||
root = n;
|
||||
}
|
||||
}
|
||||
|
||||
private Node* rotateLeft(Node* a) pure nothrow @safe @nogc {
|
||||
Node* b = a.right;
|
||||
b.parent = a.parent;
|
||||
|
||||
a.right = b.left;
|
||||
|
||||
if (a.right !is null)
|
||||
a.right.parent = a;
|
||||
|
||||
b.left = a;
|
||||
a.parent = b;
|
||||
|
||||
if (b.parent !is null) {
|
||||
if (b.parent.right is a) {
|
||||
b.parent.right = b;
|
||||
} else {
|
||||
b.parent.left = b;
|
||||
}
|
||||
}
|
||||
|
||||
setBalance(a, b);
|
||||
|
||||
return b;
|
||||
}
|
||||
|
||||
private Node* rotateRight(Node* a) pure nothrow @safe @nogc {
|
||||
Node* b = a.left;
|
||||
b.parent = a.parent;
|
||||
|
||||
a.left = b.right;
|
||||
|
||||
if (a.left !is null)
|
||||
a.left.parent = a;
|
||||
|
||||
b.right = a;
|
||||
a.parent = b;
|
||||
|
||||
if (b.parent !is null) {
|
||||
if (b.parent.right is a) {
|
||||
b.parent.right = b;
|
||||
} else {
|
||||
b.parent.left = b;
|
||||
}
|
||||
}
|
||||
|
||||
setBalance(a, b);
|
||||
|
||||
return b;
|
||||
}
|
||||
|
||||
private Node* rotateLeftThenRight(Node* n) pure nothrow @safe @nogc {
|
||||
n.left = rotateLeft(n.left);
|
||||
return rotateRight(n);
|
||||
}
|
||||
|
||||
private Node* rotateRightThenLeft(Node* n) pure nothrow @safe @nogc {
|
||||
n.right = rotateRight(n.right);
|
||||
return rotateLeft(n);
|
||||
}
|
||||
|
||||
private int height(in Node* n) const pure nothrow @safe @nogc {
|
||||
if (n is null)
|
||||
return -1;
|
||||
return 1 + max(height(n.left), height(n.right));
|
||||
}
|
||||
|
||||
private void setBalance(Node*[] nodes...) pure nothrow @safe @nogc {
|
||||
foreach (n; nodes)
|
||||
n.balance = height(n.right) - height(n.left);
|
||||
}
|
||||
|
||||
public void printBalance() const @safe {
|
||||
printBalance(root);
|
||||
}
|
||||
|
||||
private void printBalance(in Node* n) const @safe {
|
||||
if (n !is null) {
|
||||
printBalance(n.left);
|
||||
write(n.balance, ' ');
|
||||
printBalance(n.right);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void main() @safe {
|
||||
auto tree = new AVLtree();
|
||||
|
||||
writeln("Inserting values 1 to 10");
|
||||
foreach (immutable i; 1 .. 11)
|
||||
tree.insert(i);
|
||||
|
||||
write("Printing balance: ");
|
||||
tree.printBalance;
|
||||
}
|
||||
854
Task/AVL-tree/Fortran/avl-tree.f
Normal file
854
Task/AVL-tree/Fortran/avl-tree.f
Normal file
|
|
@ -0,0 +1,854 @@
|
|||
module avl_trees
|
||||
!
|
||||
! References:
|
||||
!
|
||||
! * Niklaus Wirth, 1976. Algorithms + Data Structures =
|
||||
! Programs. Prentice-Hall, Englewood Cliffs, New Jersey.
|
||||
!
|
||||
! * Niklaus Wirth, 2004. Algorithms and Data Structures. Updated
|
||||
! by Fyodor Tkachov, 2014.
|
||||
!
|
||||
|
||||
implicit none
|
||||
private
|
||||
|
||||
! The type for an AVL tree.
|
||||
public :: avl_tree_t
|
||||
|
||||
! The type for a pair of pointers to key and data within the tree.
|
||||
! (Be careful with these!)
|
||||
public :: avl_pointer_pair_t
|
||||
|
||||
! Insertion, replacement, modification, etc.
|
||||
public :: avl_insert_or_modify
|
||||
|
||||
! Insert or replace.
|
||||
public :: avl_insert
|
||||
|
||||
! Is the key in the tree?
|
||||
public :: avl_contains
|
||||
|
||||
! Retrieve data from a tree.
|
||||
public :: avl_retrieve
|
||||
|
||||
! Delete data from a tree. This is a generic function.
|
||||
public :: avl_delete
|
||||
|
||||
! Implementations of avl_delete.
|
||||
public :: avl_delete_with_found
|
||||
public :: avl_delete_without_found
|
||||
|
||||
! How many nodes are there in the tree?
|
||||
public :: avl_size
|
||||
|
||||
! Return a list of avl_pointer_pair_t for the elements in the
|
||||
! tree. The list will be in order.
|
||||
public :: avl_pointer_pairs
|
||||
|
||||
! Print a representation of the tree to an output unit.
|
||||
public :: avl_write
|
||||
|
||||
! Check the AVL condition (that the heights of the two branches from
|
||||
! a node should differ by zero or one). ERROR STOP if the condition
|
||||
! is not met.
|
||||
public :: avl_check
|
||||
|
||||
! Procedure types.
|
||||
public :: avl_less_than_t
|
||||
public :: avl_insertion_t
|
||||
public :: avl_key_data_writer_t
|
||||
|
||||
type :: avl_node_t
|
||||
class(*), allocatable :: key, data
|
||||
type(avl_node_t), pointer :: left
|
||||
type(avl_node_t), pointer :: right
|
||||
integer :: bal ! bal == -1, 0, 1
|
||||
end type avl_node_t
|
||||
|
||||
type :: avl_tree_t
|
||||
type(avl_node_t), pointer :: p => null ()
|
||||
contains
|
||||
final :: avl_tree_t_final
|
||||
end type avl_tree_t
|
||||
|
||||
type :: avl_pointer_pair_t
|
||||
class(*), pointer :: p_key, p_data
|
||||
class(avl_pointer_pair_t), pointer :: next => null ()
|
||||
contains
|
||||
final :: avl_pointer_pair_t_final
|
||||
end type avl_pointer_pair_t
|
||||
|
||||
interface avl_delete
|
||||
module procedure avl_delete_with_found
|
||||
module procedure avl_delete_without_found
|
||||
end interface avl_delete
|
||||
|
||||
interface
|
||||
function avl_less_than_t (key1, key2) result (key1_lt_key2)
|
||||
!
|
||||
! The ordering predicate (‘<’).
|
||||
!
|
||||
! Two keys a,b are considered equivalent if neither a<b nor
|
||||
! b<a.
|
||||
!
|
||||
class(*), intent(in) :: key1, key2
|
||||
logical key1_lt_key2
|
||||
end function avl_less_than_t
|
||||
|
||||
subroutine avl_insertion_t (key, data, p_is_new, p)
|
||||
!
|
||||
! Insertion or modification of a found node.
|
||||
!
|
||||
import avl_node_t
|
||||
class(*), intent(in) :: key, data
|
||||
logical, intent(in) :: p_is_new
|
||||
type(avl_node_t), pointer, intent(inout) :: p
|
||||
end subroutine avl_insertion_t
|
||||
|
||||
subroutine avl_key_data_writer_t (unit, key, data)
|
||||
!
|
||||
! Printing the key and data of a node.
|
||||
!
|
||||
integer, intent(in) :: unit
|
||||
class(*), intent(in) :: key, data
|
||||
end subroutine avl_key_data_writer_t
|
||||
end interface
|
||||
|
||||
contains
|
||||
|
||||
subroutine avl_tree_t_final (tree)
|
||||
type(avl_tree_t), intent(inout) :: tree
|
||||
|
||||
type(avl_node_t), pointer :: p
|
||||
|
||||
p => tree%p
|
||||
call free_the_nodes (p)
|
||||
|
||||
contains
|
||||
|
||||
recursive subroutine free_the_nodes (p)
|
||||
type(avl_node_t), pointer, intent(inout) :: p
|
||||
|
||||
if (associated (p)) then
|
||||
call free_the_nodes (p%left)
|
||||
call free_the_nodes (p%right)
|
||||
deallocate (p)
|
||||
end if
|
||||
end subroutine free_the_nodes
|
||||
|
||||
end subroutine avl_tree_t_final
|
||||
|
||||
recursive subroutine avl_pointer_pair_t_final (node)
|
||||
type(avl_pointer_pair_t), intent(inout) :: node
|
||||
|
||||
if (associated (node%next)) deallocate (node%next)
|
||||
end subroutine avl_pointer_pair_t_final
|
||||
|
||||
function avl_contains (less_than, key, tree) result (found)
|
||||
procedure(avl_less_than_t) :: less_than
|
||||
class(*), intent(in) :: key
|
||||
class(avl_tree_t), intent(in) :: tree
|
||||
logical :: found
|
||||
|
||||
found = avl_contains_recursion (less_than, key, tree%p)
|
||||
end function avl_contains
|
||||
|
||||
recursive function avl_contains_recursion (less_than, key, p) result (found)
|
||||
procedure(avl_less_than_t) :: less_than
|
||||
class(*), intent(in) :: key
|
||||
type(avl_node_t), pointer, intent(in) :: p
|
||||
logical :: found
|
||||
|
||||
if (.not. associated (p)) then
|
||||
found = .false.
|
||||
else if (less_than (key, p%key)) then
|
||||
found = avl_contains_recursion (less_than, key, p%left)
|
||||
else if (less_than (p%key, key)) then
|
||||
found = avl_contains_recursion (less_than, key, p%right)
|
||||
else
|
||||
found = .true.
|
||||
end if
|
||||
end function avl_contains_recursion
|
||||
|
||||
subroutine avl_retrieve (less_than, key, tree, found, data)
|
||||
procedure(avl_less_than_t) :: less_than
|
||||
class(*), intent(in) :: key
|
||||
class(avl_tree_t), intent(in) :: tree
|
||||
logical, intent(out) :: found
|
||||
class(*), allocatable, intent(inout) :: data
|
||||
|
||||
call avl_retrieve_recursion (less_than, key, tree%p, found, data)
|
||||
end subroutine avl_retrieve
|
||||
|
||||
recursive subroutine avl_retrieve_recursion (less_than, key, p, found, data)
|
||||
procedure(avl_less_than_t) :: less_than
|
||||
class(*), intent(in) :: key
|
||||
type(avl_node_t), pointer, intent(in) :: p
|
||||
logical, intent(out) :: found
|
||||
class(*), allocatable, intent(inout) :: data
|
||||
|
||||
if (.not. associated (p)) then
|
||||
found = .false.
|
||||
else if (less_than (key, p%key)) then
|
||||
call avl_retrieve_recursion (less_than, key, p%left, found, data)
|
||||
else if (less_than (p%key, key)) then
|
||||
call avl_retrieve_recursion (less_than, key, p%right, found, data)
|
||||
else
|
||||
found = .true.
|
||||
data = p%data
|
||||
end if
|
||||
end subroutine avl_retrieve_recursion
|
||||
|
||||
subroutine avl_insert (less_than, key, data, tree)
|
||||
procedure(avl_less_than_t) :: less_than
|
||||
class(*), intent(in) :: key, data
|
||||
class(avl_tree_t), intent(inout) :: tree
|
||||
|
||||
call avl_insert_or_modify (less_than, insert_or_replace, key, data, tree)
|
||||
end subroutine avl_insert
|
||||
|
||||
subroutine insert_or_replace (key, data, p_is_new, p)
|
||||
class(*), intent(in) :: key, data
|
||||
logical, intent(in) :: p_is_new
|
||||
type(avl_node_t), pointer, intent(inout) :: p
|
||||
|
||||
p%data = data
|
||||
end subroutine insert_or_replace
|
||||
|
||||
subroutine avl_insert_or_modify (less_than, insertion, key, data, tree)
|
||||
procedure(avl_less_than_t) :: less_than
|
||||
procedure(avl_insertion_t) :: insertion ! Or modification in place.
|
||||
class(*), intent(in) :: key, data
|
||||
class(avl_tree_t), intent(inout) :: tree
|
||||
|
||||
logical :: fix_balance
|
||||
|
||||
fix_balance = .false.
|
||||
call insertion_search (less_than, insertion, key, data, tree%p, fix_balance)
|
||||
end subroutine avl_insert_or_modify
|
||||
|
||||
recursive subroutine insertion_search (less_than, insertion, key, data, p, fix_balance)
|
||||
procedure(avl_less_than_t) :: less_than
|
||||
procedure(avl_insertion_t) :: insertion
|
||||
class(*), intent(in) :: key, data
|
||||
type(avl_node_t), pointer, intent(inout) :: p
|
||||
logical, intent(inout) :: fix_balance
|
||||
|
||||
type(avl_node_t), pointer :: p1, p2
|
||||
|
||||
if (.not. associated (p)) then
|
||||
! The key was not found. Make a new node.
|
||||
allocate (p)
|
||||
p%key = key
|
||||
p%left => null ()
|
||||
p%right => null ()
|
||||
p%bal = 0
|
||||
call insertion (key, data, .true., p)
|
||||
fix_balance = .true.
|
||||
else if (less_than (key, p%key)) then
|
||||
! Continue searching.
|
||||
call insertion_search (less_than, insertion, key, data, p%left, fix_balance)
|
||||
if (fix_balance) then
|
||||
! A new node has been inserted on the left side.
|
||||
select case (p%bal)
|
||||
case (1)
|
||||
p%bal = 0
|
||||
fix_balance = .false.
|
||||
case (0)
|
||||
p%bal = -1
|
||||
case (-1)
|
||||
! Rebalance.
|
||||
p1 => p%left
|
||||
select case (p1%bal)
|
||||
case (-1)
|
||||
! A single LL rotation.
|
||||
p%left => p1%right
|
||||
p1%right => p
|
||||
p%bal = 0
|
||||
p => p1
|
||||
p%bal = 0
|
||||
fix_balance = .false.
|
||||
case (0, 1)
|
||||
! A double LR rotation.
|
||||
p2 => p1%right
|
||||
p1%right => p2%left
|
||||
p2%left => p1
|
||||
p%left => p2%right
|
||||
p2%right => p
|
||||
p%bal = -(min (p2%bal, 0))
|
||||
p1%bal = -(max (p2%bal, 0))
|
||||
p => p2
|
||||
p%bal = 0
|
||||
fix_balance = .false.
|
||||
case default
|
||||
error stop
|
||||
end select
|
||||
case default
|
||||
error stop
|
||||
end select
|
||||
end if
|
||||
else if (less_than (p%key, key)) then
|
||||
call insertion_search (less_than, insertion, key, data, p%right, fix_balance)
|
||||
if (fix_balance) then
|
||||
! A new node has been inserted on the right side.
|
||||
select case (p%bal)
|
||||
case (-1)
|
||||
p%bal = 0
|
||||
fix_balance = .false.
|
||||
case (0)
|
||||
p%bal = 1
|
||||
case (1)
|
||||
! Rebalance.
|
||||
p1 => p%right
|
||||
select case (p1%bal)
|
||||
case (1)
|
||||
! A single RR rotation.
|
||||
p%right => p1%left
|
||||
p1%left => p
|
||||
p%bal = 0
|
||||
p => p1
|
||||
p%bal = 0
|
||||
fix_balance = .false.
|
||||
case (-1, 0)
|
||||
! A double RL rotation.
|
||||
p2 => p1%left
|
||||
p1%left => p2%right
|
||||
p2%right => p1
|
||||
p%right => p2%left
|
||||
p2%left => p
|
||||
p%bal = -(max (p2%bal, 0))
|
||||
p1%bal = -(min (p2%bal, 0))
|
||||
p => p2
|
||||
p%bal = 0
|
||||
fix_balance = .false.
|
||||
case default
|
||||
error stop
|
||||
end select
|
||||
case default
|
||||
error stop
|
||||
end select
|
||||
end if
|
||||
else
|
||||
! The key was found. The pointer p points to an existing node.
|
||||
call insertion (key, data, .false., p)
|
||||
end if
|
||||
end subroutine insertion_search
|
||||
|
||||
subroutine avl_delete_with_found (less_than, key, tree, found)
|
||||
procedure(avl_less_than_t) :: less_than
|
||||
class(*), intent(in) :: key
|
||||
class(avl_tree_t), intent(inout) :: tree
|
||||
logical, intent(out) :: found
|
||||
|
||||
logical :: fix_balance
|
||||
|
||||
fix_balance = .false.
|
||||
call deletion_search (less_than, key, tree%p, fix_balance, found)
|
||||
end subroutine avl_delete_with_found
|
||||
|
||||
subroutine avl_delete_without_found (less_than, key, tree)
|
||||
procedure(avl_less_than_t) :: less_than
|
||||
class(*), intent(in) :: key
|
||||
class(avl_tree_t), intent(inout) :: tree
|
||||
|
||||
logical :: found
|
||||
|
||||
call avl_delete_with_found (less_than, key, tree, found)
|
||||
end subroutine avl_delete_without_found
|
||||
|
||||
recursive subroutine deletion_search (less_than, key, p, fix_balance, found)
|
||||
procedure(avl_less_than_t) :: less_than
|
||||
class(*), intent(in) :: key
|
||||
type(avl_node_t), pointer, intent(inout) :: p
|
||||
logical, intent(inout) :: fix_balance
|
||||
logical, intent(out) :: found
|
||||
|
||||
type(avl_node_t), pointer :: q
|
||||
|
||||
if (.not. associated (p)) then
|
||||
! The key is not in the tree.
|
||||
found = .false.
|
||||
else if (less_than (key, p%key)) then
|
||||
call deletion_search (less_than, key, p%left, fix_balance, found)
|
||||
if (fix_balance) call balance_for_shrunken_left (p, fix_balance)
|
||||
else if (less_than (p%key, key)) then
|
||||
call deletion_search (less_than, key, p%right, fix_balance, found)
|
||||
if (fix_balance) call balance_for_shrunken_right (p, fix_balance)
|
||||
else
|
||||
q => p
|
||||
if (.not. associated (q%right)) then
|
||||
p => q%left
|
||||
fix_balance = .true.
|
||||
else if (.not. associated (q%left)) then
|
||||
p => q%right
|
||||
fix_balance = .true.
|
||||
else
|
||||
call del (q%left, q, fix_balance)
|
||||
if (fix_balance) call balance_for_shrunken_left (p, fix_balance)
|
||||
end if
|
||||
deallocate (q)
|
||||
found = .true.
|
||||
end if
|
||||
end subroutine deletion_search
|
||||
|
||||
recursive subroutine del (r, q, fix_balance)
|
||||
type(avl_node_t), pointer, intent(inout) :: r, q
|
||||
logical, intent(inout) :: fix_balance
|
||||
|
||||
if (associated (r%right)) then
|
||||
call del (r%right, q, fix_balance)
|
||||
if (fix_balance) call balance_for_shrunken_right (r, fix_balance)
|
||||
else
|
||||
q%key = r%key
|
||||
q%data = r%data
|
||||
q => r
|
||||
r => r%left
|
||||
fix_balance = .true.
|
||||
end if
|
||||
end subroutine del
|
||||
|
||||
subroutine balance_for_shrunken_left (p, fix_balance)
|
||||
type(avl_node_t), pointer, intent(inout) :: p
|
||||
logical, intent(inout) :: fix_balance
|
||||
|
||||
! The left side has lost a node.
|
||||
|
||||
type(avl_node_t), pointer :: p1, p2
|
||||
|
||||
if (.not. fix_balance) error stop
|
||||
|
||||
select case (p%bal)
|
||||
case (-1)
|
||||
p%bal = 0
|
||||
case (0)
|
||||
p%bal = 1
|
||||
fix_balance = .false.
|
||||
case (1)
|
||||
! Rebalance.
|
||||
p1 => p%right
|
||||
select case (p1%bal)
|
||||
case (0)
|
||||
! A single RR rotation.
|
||||
p%right => p1%left
|
||||
p1%left => p
|
||||
p%bal = 1
|
||||
p1%bal = -1
|
||||
p => p1
|
||||
fix_balance = .false.
|
||||
case (1)
|
||||
! A single RR rotation.
|
||||
p%right => p1%left
|
||||
p1%left => p
|
||||
p%bal = 0
|
||||
p1%bal = 0
|
||||
p => p1
|
||||
fix_balance = .true.
|
||||
case (-1)
|
||||
! A double RL rotation.
|
||||
p2 => p1%left
|
||||
p1%left => p2%right
|
||||
p2%right => p1
|
||||
p%right => p2%left
|
||||
p2%left => p
|
||||
p%bal = -(max (p2%bal, 0))
|
||||
p1%bal = -(min (p2%bal, 0))
|
||||
p => p2
|
||||
p2%bal = 0
|
||||
case default
|
||||
error stop
|
||||
end select
|
||||
case default
|
||||
error stop
|
||||
end select
|
||||
end subroutine balance_for_shrunken_left
|
||||
|
||||
subroutine balance_for_shrunken_right (p, fix_balance)
|
||||
type(avl_node_t), pointer, intent(inout) :: p
|
||||
logical, intent(inout) :: fix_balance
|
||||
|
||||
! The right side has lost a node.
|
||||
|
||||
type(avl_node_t), pointer :: p1, p2
|
||||
|
||||
if (.not. fix_balance) error stop
|
||||
|
||||
select case (p%bal)
|
||||
case (1)
|
||||
p%bal = 0
|
||||
case (0)
|
||||
p%bal = -1
|
||||
fix_balance = .false.
|
||||
case (-1)
|
||||
! Rebalance.
|
||||
p1 => p%left
|
||||
select case (p1%bal)
|
||||
case (0)
|
||||
! A single LL rotation.
|
||||
p%left => p1%right
|
||||
p1%right => p
|
||||
p1%bal = 1
|
||||
p%bal = -1
|
||||
p => p1
|
||||
fix_balance = .false.
|
||||
case (-1)
|
||||
! A single LL rotation.
|
||||
p%left => p1%right
|
||||
p1%right => p
|
||||
p1%bal = 0
|
||||
p%bal = 0
|
||||
p => p1
|
||||
fix_balance = .true.
|
||||
case (1)
|
||||
! A double LR rotation.
|
||||
p2 => p1%right
|
||||
p1%right => p2%left
|
||||
p2%left => p1
|
||||
p%left => p2%right
|
||||
p2%right => p
|
||||
p%bal = -(min (p2%bal, 0))
|
||||
p1%bal = -(max (p2%bal, 0))
|
||||
p => p2
|
||||
p2%bal = 0
|
||||
case default
|
||||
error stop
|
||||
end select
|
||||
case default
|
||||
error stop
|
||||
end select
|
||||
end subroutine balance_for_shrunken_right
|
||||
|
||||
function avl_size (tree) result (size)
|
||||
class(avl_tree_t), intent(in) :: tree
|
||||
integer :: size
|
||||
|
||||
size = traverse (tree%p)
|
||||
|
||||
contains
|
||||
|
||||
recursive function traverse (p) result (size)
|
||||
type(avl_node_t), pointer, intent(in) :: p
|
||||
integer :: size
|
||||
|
||||
if (associated (p)) then
|
||||
! The order of traversal is arbitrary.
|
||||
size = 1 + traverse (p%left) + traverse (p%right)
|
||||
else
|
||||
size = 0
|
||||
end if
|
||||
end function traverse
|
||||
|
||||
end function avl_size
|
||||
|
||||
function avl_pointer_pairs (tree) result (lst)
|
||||
class(avl_tree_t), intent(in) :: tree
|
||||
type(avl_pointer_pair_t), pointer :: lst
|
||||
|
||||
! Reverse in-order traversal of the tree, to produce a CONS-list
|
||||
! of pointers to the contents.
|
||||
|
||||
lst => null ()
|
||||
if (associated (tree%p)) lst => traverse (tree%p, lst)
|
||||
|
||||
contains
|
||||
|
||||
recursive function traverse (p, lst1) result (lst2)
|
||||
type(avl_node_t), pointer, intent(in) :: p
|
||||
type(avl_pointer_pair_t), pointer, intent(in) :: lst1
|
||||
type(avl_pointer_pair_t), pointer :: lst2
|
||||
|
||||
type(avl_pointer_pair_t), pointer :: new_entry
|
||||
|
||||
lst2 => lst1
|
||||
if (associated (p%right)) lst2 => traverse (p%right, lst2)
|
||||
allocate (new_entry)
|
||||
new_entry%p_key => p%key
|
||||
new_entry%p_data => p%data
|
||||
new_entry%next => lst2
|
||||
lst2 => new_entry
|
||||
if (associated (p%left)) lst2 => traverse (p%left, lst2)
|
||||
end function traverse
|
||||
|
||||
end function avl_pointer_pairs
|
||||
|
||||
subroutine avl_write (write_key_data, unit, tree)
|
||||
procedure(avl_key_data_writer_t) :: write_key_data
|
||||
integer, intent(in) :: unit
|
||||
class(avl_tree_t), intent(in) :: tree
|
||||
|
||||
character(len = *), parameter :: tab = achar (9)
|
||||
|
||||
type(avl_node_t), pointer :: p
|
||||
|
||||
p => tree%p
|
||||
if (.not. associated (p)) then
|
||||
continue
|
||||
else
|
||||
call traverse (p%left, 1, .true.)
|
||||
call write_key_data (unit, p%key, p%data)
|
||||
write (unit, '(2A, "depth = ", I0, " bal = ", I0)') tab, tab, 0, p%bal
|
||||
call traverse (p%right, 1, .false.)
|
||||
end if
|
||||
|
||||
contains
|
||||
|
||||
recursive subroutine traverse (p, depth, left)
|
||||
type(avl_node_t), pointer, intent(in) :: p
|
||||
integer, value :: depth
|
||||
logical, value :: left
|
||||
|
||||
if (.not. associated (p)) then
|
||||
continue
|
||||
else
|
||||
call traverse (p%left, depth + 1, .true.)
|
||||
call pad (depth, left)
|
||||
call write_key_data (unit, p%key, p%data)
|
||||
write (unit, '(2A, "depth = ", I0, " bal = ", I0)') tab, tab, depth, p%bal
|
||||
call traverse (p%right, depth + 1, .false.)
|
||||
end if
|
||||
end subroutine traverse
|
||||
|
||||
subroutine pad (depth, left)
|
||||
integer, value :: depth
|
||||
logical, value :: left
|
||||
|
||||
integer :: i
|
||||
|
||||
do i = 1, depth
|
||||
write (unit, '(2X)', advance = 'no')
|
||||
end do
|
||||
end subroutine pad
|
||||
|
||||
end subroutine avl_write
|
||||
|
||||
subroutine avl_check (tree)
|
||||
use, intrinsic :: iso_fortran_env, only: error_unit
|
||||
class(avl_tree_t), intent(in) :: tree
|
||||
|
||||
type(avl_node_t), pointer :: p
|
||||
integer :: height_L, height_R
|
||||
|
||||
p => tree%p
|
||||
call get_heights (p, height_L, height_R)
|
||||
call check_heights (height_L, height_R)
|
||||
|
||||
contains
|
||||
|
||||
recursive subroutine get_heights (p, height_L, height_R)
|
||||
type(avl_node_t), pointer, intent(in) :: p
|
||||
integer, intent(out) :: height_L, height_R
|
||||
|
||||
integer :: height_LL, height_LR
|
||||
integer :: height_RL, height_RR
|
||||
|
||||
height_L = 0
|
||||
height_R = 0
|
||||
if (associated (p)) then
|
||||
call get_heights (p%left, height_LL, height_LR)
|
||||
call check_heights (height_LL, height_LR)
|
||||
height_L = height_LL + height_LR
|
||||
call get_heights (p%right, height_RL, height_RR)
|
||||
call check_heights (height_RL, height_RR)
|
||||
height_R = height_RL + height_RR
|
||||
end if
|
||||
end subroutine get_heights
|
||||
|
||||
subroutine check_heights (height_L, height_R)
|
||||
integer, value :: height_L, height_R
|
||||
|
||||
if (2 <= abs (height_L - height_R)) then
|
||||
write (error_unit, '("*** AVL condition violated ***")')
|
||||
error stop
|
||||
end if
|
||||
end subroutine check_heights
|
||||
|
||||
end subroutine avl_check
|
||||
|
||||
end module avl_trees
|
||||
|
||||
program avl_trees_demo
|
||||
use, intrinsic :: iso_fortran_env, only: output_unit
|
||||
use, non_intrinsic :: avl_trees
|
||||
|
||||
implicit none
|
||||
|
||||
integer, parameter :: keys_count = 20
|
||||
|
||||
type(avl_tree_t) :: tree
|
||||
logical :: found
|
||||
class(*), allocatable :: retval
|
||||
integer :: the_keys(1:keys_count)
|
||||
integer :: i, j
|
||||
|
||||
do i = 1, keys_count
|
||||
the_keys(i) = i
|
||||
end do
|
||||
call fisher_yates_shuffle (the_keys, keys_count)
|
||||
|
||||
call avl_check (tree)
|
||||
do i = 1, keys_count
|
||||
call avl_insert (lt, the_keys(i), real (the_keys(i)), tree)
|
||||
call avl_check (tree)
|
||||
if (avl_size (tree) /= i) error stop
|
||||
do j = 1, keys_count
|
||||
if (avl_contains (lt, the_keys(j), tree) .neqv. (j <= i)) error stop
|
||||
end do
|
||||
do j = 1, keys_count
|
||||
call avl_retrieve (lt, the_keys(j), tree, found, retval)
|
||||
if (found .neqv. (j <= i)) error stop
|
||||
if (found) then
|
||||
! This crazy way to write ‘/=’ is to quell those tiresome
|
||||
! warnings about using ‘==’ or ‘/=’ with floating point
|
||||
! numbers. Floating point numbers can represent integers
|
||||
! *exactly*.
|
||||
if (0 < abs (real_cast (retval) - real (the_keys(j)))) error stop
|
||||
end if
|
||||
if (found) then
|
||||
block
|
||||
character(len = 1), parameter :: ch = '*'
|
||||
!
|
||||
! Try replacing the data with a character and then
|
||||
! restoring the number.
|
||||
!
|
||||
call avl_insert (lt, the_keys(j), ch, tree)
|
||||
call avl_retrieve (lt, the_keys(j), tree, found, retval)
|
||||
if (.not. found) error stop
|
||||
if (char_cast (retval) /= ch) error stop
|
||||
call avl_insert (lt, the_keys(j), real (the_keys(j)), tree)
|
||||
call avl_retrieve (lt, the_keys(j), tree, found, retval)
|
||||
if (.not. found) error stop
|
||||
if (0 < abs (real_cast (retval) - real (the_keys(j)))) error stop
|
||||
end block
|
||||
end if
|
||||
end do
|
||||
end do
|
||||
|
||||
write (output_unit, '(70("-"))')
|
||||
call avl_write (int_real_writer, output_unit, tree)
|
||||
write (output_unit, '(70("-"))')
|
||||
call print_contents (output_unit, tree)
|
||||
write (output_unit, '(70("-"))')
|
||||
|
||||
call fisher_yates_shuffle (the_keys, keys_count)
|
||||
do i = 1, keys_count
|
||||
call avl_delete (lt, the_keys(i), tree)
|
||||
call avl_check (tree)
|
||||
if (avl_size (tree) /= keys_count - i) error stop
|
||||
! Try deleting a second time.
|
||||
call avl_delete (lt, the_keys(i), tree)
|
||||
call avl_check (tree)
|
||||
if (avl_size (tree) /= keys_count - i) error stop
|
||||
do j = 1, keys_count
|
||||
if (avl_contains (lt, the_keys(j), tree) .neqv. (i < j)) error stop
|
||||
end do
|
||||
do j = 1, keys_count
|
||||
call avl_retrieve (lt, the_keys(j), tree, found, retval)
|
||||
if (found .neqv. (i < j)) error stop
|
||||
if (found) then
|
||||
if (0 < abs (real_cast (retval) - real (the_keys(j)))) error stop
|
||||
end if
|
||||
end do
|
||||
end do
|
||||
|
||||
contains
|
||||
|
||||
subroutine fisher_yates_shuffle (keys, n)
|
||||
integer, intent(inout) :: keys(*)
|
||||
integer, intent(in) :: n
|
||||
|
||||
integer :: i, j
|
||||
real :: randnum
|
||||
integer :: tmp
|
||||
|
||||
do i = 1, n - 1
|
||||
call random_number (randnum)
|
||||
j = i + floor (randnum * (n - i + 1))
|
||||
tmp = keys(i)
|
||||
keys(i) = keys(j)
|
||||
keys(j) = tmp
|
||||
end do
|
||||
end subroutine fisher_yates_shuffle
|
||||
|
||||
function int_cast (u) result (v)
|
||||
class(*), intent(in) :: u
|
||||
integer :: v
|
||||
|
||||
select type (u)
|
||||
type is (integer)
|
||||
v = u
|
||||
class default
|
||||
! This case is not handled.
|
||||
error stop
|
||||
end select
|
||||
end function int_cast
|
||||
|
||||
function real_cast (u) result (v)
|
||||
class(*), intent(in) :: u
|
||||
real :: v
|
||||
|
||||
select type (u)
|
||||
type is (real)
|
||||
v = u
|
||||
class default
|
||||
! This case is not handled.
|
||||
error stop
|
||||
end select
|
||||
end function real_cast
|
||||
|
||||
function char_cast (u) result (v)
|
||||
class(*), intent(in) :: u
|
||||
character(len = 1) :: v
|
||||
|
||||
select type (u)
|
||||
type is (character(*))
|
||||
v = u
|
||||
class default
|
||||
! This case is not handled.
|
||||
error stop
|
||||
end select
|
||||
end function char_cast
|
||||
|
||||
function lt (u, v) result (u_lt_v)
|
||||
class(*), intent(in) :: u, v
|
||||
logical :: u_lt_v
|
||||
|
||||
select type (u)
|
||||
type is (integer)
|
||||
select type (v)
|
||||
type is (integer)
|
||||
u_lt_v = (u < v)
|
||||
class default
|
||||
! This case is not handled.
|
||||
error stop
|
||||
end select
|
||||
class default
|
||||
! This case is not handled.
|
||||
error stop
|
||||
end select
|
||||
end function lt
|
||||
|
||||
subroutine int_real_writer (unit, key, data)
|
||||
integer, intent(in) :: unit
|
||||
class(*), intent(in) :: key, data
|
||||
|
||||
write (unit, '("(", I0, ", ", F0.1, ")")', advance = 'no') &
|
||||
& int_cast(key), real_cast(data)
|
||||
end subroutine int_real_writer
|
||||
|
||||
subroutine print_contents (unit, tree)
|
||||
integer, intent(in) :: unit
|
||||
class(avl_tree_t), intent(in) :: tree
|
||||
|
||||
type(avl_pointer_pair_t), pointer :: ppairs, pp
|
||||
|
||||
write (unit, '("tree size = ", I0)') avl_size (tree)
|
||||
ppairs => avl_pointer_pairs (tree)
|
||||
pp => ppairs
|
||||
do while (associated (pp))
|
||||
write (unit, '("(", I0, ", ", F0.1, ")")') &
|
||||
& int_cast (pp%p_key), real_cast (pp%p_data)
|
||||
pp => pp%next
|
||||
end do
|
||||
if (associated (ppairs)) deallocate (ppairs)
|
||||
end subroutine print_contents
|
||||
|
||||
end program avl_trees_demo
|
||||
166
Task/AVL-tree/Go/avl-tree-1.go
Normal file
166
Task/AVL-tree/Go/avl-tree-1.go
Normal file
|
|
@ -0,0 +1,166 @@
|
|||
package avl
|
||||
|
||||
// AVL tree adapted from Julienne Walker's presentation at
|
||||
// http://eternallyconfuzzled.com/tuts/datastructures/jsw_tut_avl.aspx.
|
||||
// This port uses similar indentifier names.
|
||||
|
||||
// The Key interface must be supported by data stored in the AVL tree.
|
||||
type Key interface {
|
||||
Less(Key) bool
|
||||
Eq(Key) bool
|
||||
}
|
||||
|
||||
// Node is a node in an AVL tree.
|
||||
type Node struct {
|
||||
Data Key // anything comparable with Less and Eq.
|
||||
Balance int // balance factor
|
||||
Link [2]*Node // children, indexed by "direction", 0 or 1.
|
||||
}
|
||||
|
||||
// A little readability function for returning the opposite of a direction,
|
||||
// where a direction is 0 or 1. Go inlines this.
|
||||
// Where JW writes !dir, this code has opp(dir).
|
||||
func opp(dir int) int {
|
||||
return 1 - dir
|
||||
}
|
||||
|
||||
// single rotation
|
||||
func single(root *Node, dir int) *Node {
|
||||
save := root.Link[opp(dir)]
|
||||
root.Link[opp(dir)] = save.Link[dir]
|
||||
save.Link[dir] = root
|
||||
return save
|
||||
}
|
||||
|
||||
// double rotation
|
||||
func double(root *Node, dir int) *Node {
|
||||
save := root.Link[opp(dir)].Link[dir]
|
||||
|
||||
root.Link[opp(dir)].Link[dir] = save.Link[opp(dir)]
|
||||
save.Link[opp(dir)] = root.Link[opp(dir)]
|
||||
root.Link[opp(dir)] = save
|
||||
|
||||
save = root.Link[opp(dir)]
|
||||
root.Link[opp(dir)] = save.Link[dir]
|
||||
save.Link[dir] = root
|
||||
return save
|
||||
}
|
||||
|
||||
// adjust valance factors after double rotation
|
||||
func adjustBalance(root *Node, dir, bal int) {
|
||||
n := root.Link[dir]
|
||||
nn := n.Link[opp(dir)]
|
||||
switch nn.Balance {
|
||||
case 0:
|
||||
root.Balance = 0
|
||||
n.Balance = 0
|
||||
case bal:
|
||||
root.Balance = -bal
|
||||
n.Balance = 0
|
||||
default:
|
||||
root.Balance = 0
|
||||
n.Balance = bal
|
||||
}
|
||||
nn.Balance = 0
|
||||
}
|
||||
|
||||
func insertBalance(root *Node, dir int) *Node {
|
||||
n := root.Link[dir]
|
||||
bal := 2*dir - 1
|
||||
if n.Balance == bal {
|
||||
root.Balance = 0
|
||||
n.Balance = 0
|
||||
return single(root, opp(dir))
|
||||
}
|
||||
adjustBalance(root, dir, bal)
|
||||
return double(root, opp(dir))
|
||||
}
|
||||
|
||||
func insertR(root *Node, data Key) (*Node, bool) {
|
||||
if root == nil {
|
||||
return &Node{Data: data}, false
|
||||
}
|
||||
dir := 0
|
||||
if root.Data.Less(data) {
|
||||
dir = 1
|
||||
}
|
||||
var done bool
|
||||
root.Link[dir], done = insertR(root.Link[dir], data)
|
||||
if done {
|
||||
return root, true
|
||||
}
|
||||
root.Balance += 2*dir - 1
|
||||
switch root.Balance {
|
||||
case 0:
|
||||
return root, true
|
||||
case 1, -1:
|
||||
return root, false
|
||||
}
|
||||
return insertBalance(root, dir), true
|
||||
}
|
||||
|
||||
// Insert a node into the AVL tree.
|
||||
// Data is inserted even if other data with the same key already exists.
|
||||
func Insert(tree **Node, data Key) {
|
||||
*tree, _ = insertR(*tree, data)
|
||||
}
|
||||
|
||||
func removeBalance(root *Node, dir int) (*Node, bool) {
|
||||
n := root.Link[opp(dir)]
|
||||
bal := 2*dir - 1
|
||||
switch n.Balance {
|
||||
case -bal:
|
||||
root.Balance = 0
|
||||
n.Balance = 0
|
||||
return single(root, dir), false
|
||||
case bal:
|
||||
adjustBalance(root, opp(dir), -bal)
|
||||
return double(root, dir), false
|
||||
}
|
||||
root.Balance = -bal
|
||||
n.Balance = bal
|
||||
return single(root, dir), true
|
||||
}
|
||||
|
||||
func removeR(root *Node, data Key) (*Node, bool) {
|
||||
if root == nil {
|
||||
return nil, false
|
||||
}
|
||||
if root.Data.Eq(data) {
|
||||
switch {
|
||||
case root.Link[0] == nil:
|
||||
return root.Link[1], false
|
||||
case root.Link[1] == nil:
|
||||
return root.Link[0], false
|
||||
}
|
||||
heir := root.Link[0]
|
||||
for heir.Link[1] != nil {
|
||||
heir = heir.Link[1]
|
||||
}
|
||||
root.Data = heir.Data
|
||||
data = heir.Data
|
||||
}
|
||||
dir := 0
|
||||
if root.Data.Less(data) {
|
||||
dir = 1
|
||||
}
|
||||
var done bool
|
||||
root.Link[dir], done = removeR(root.Link[dir], data)
|
||||
if done {
|
||||
return root, true
|
||||
}
|
||||
root.Balance += 1 - 2*dir
|
||||
switch root.Balance {
|
||||
case 1, -1:
|
||||
return root, true
|
||||
case 0:
|
||||
return root, false
|
||||
}
|
||||
return removeBalance(root, dir)
|
||||
}
|
||||
|
||||
// Remove a single item from an AVL tree.
|
||||
// If key does not exist, function has no effect.
|
||||
func Remove(tree **Node, data Key) {
|
||||
*tree, _ = removeR(*tree, data)
|
||||
}
|
||||
43
Task/AVL-tree/Go/avl-tree-2.go
Normal file
43
Task/AVL-tree/Go/avl-tree-2.go
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"log"
|
||||
|
||||
"avl"
|
||||
)
|
||||
|
||||
type intKey int
|
||||
|
||||
// satisfy avl.Key
|
||||
func (k intKey) Less(k2 avl.Key) bool { return k < k2.(intKey) }
|
||||
func (k intKey) Eq(k2 avl.Key) bool { return k == k2.(intKey) }
|
||||
|
||||
// use json for cheap tree visualization
|
||||
func dump(tree *avl.Node) {
|
||||
b, err := json.MarshalIndent(tree, "", " ")
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
fmt.Println(string(b))
|
||||
}
|
||||
|
||||
func main() {
|
||||
var tree *avl.Node
|
||||
fmt.Println("Empty tree:")
|
||||
dump(tree)
|
||||
|
||||
fmt.Println("\nInsert test:")
|
||||
avl.Insert(&tree, intKey(3))
|
||||
avl.Insert(&tree, intKey(1))
|
||||
avl.Insert(&tree, intKey(4))
|
||||
avl.Insert(&tree, intKey(1))
|
||||
avl.Insert(&tree, intKey(5))
|
||||
dump(tree)
|
||||
|
||||
fmt.Println("\nRemove test:")
|
||||
avl.Remove(&tree, intKey(3))
|
||||
avl.Remove(&tree, intKey(1))
|
||||
dump(tree)
|
||||
}
|
||||
75
Task/AVL-tree/Haskell/avl-tree.hs
Normal file
75
Task/AVL-tree/Haskell/avl-tree.hs
Normal file
|
|
@ -0,0 +1,75 @@
|
|||
data Tree a
|
||||
= Leaf
|
||||
| Node
|
||||
Int
|
||||
(Tree a)
|
||||
a
|
||||
(Tree a)
|
||||
deriving (Show, Eq)
|
||||
|
||||
foldTree :: Ord a => [a] -> Tree a
|
||||
foldTree = foldr insert Leaf
|
||||
|
||||
height :: Tree a -> Int
|
||||
height Leaf = -1
|
||||
height (Node h _ _ _) = h
|
||||
|
||||
depth :: Tree a -> Tree a -> Int
|
||||
depth a b = succ (max (height a) (height b))
|
||||
|
||||
insert :: Ord a => a -> Tree a -> Tree a
|
||||
insert v Leaf = Node 1 Leaf v Leaf
|
||||
insert v t@(Node n left v_ right)
|
||||
| v_ < v = rotate $ Node n left v_ (insert v right)
|
||||
| v_ > v = rotate $ Node n (insert v left) v_ right
|
||||
| otherwise = t
|
||||
|
||||
max_ :: Ord a => Tree a -> Maybe a
|
||||
max_ Leaf = Nothing
|
||||
max_ (Node _ _ v right) =
|
||||
case right of
|
||||
Leaf -> Just v
|
||||
_ -> max_ right
|
||||
|
||||
delete :: Ord a => a -> Tree a -> Tree a
|
||||
delete _ Leaf = Leaf
|
||||
delete x (Node h left v right)
|
||||
| x == v =
|
||||
maybe left (rotate . (Node h left <*> (`delete` right))) (max_ right)
|
||||
| x > v = rotate $ Node h left v (delete x right)
|
||||
| x < v = rotate $ Node h (delete x left) v right
|
||||
|
||||
rotate :: Tree a -> Tree a
|
||||
rotate Leaf = Leaf
|
||||
rotate (Node h (Node lh ll lv lr) v r)
|
||||
-- Left Left.
|
||||
| lh - height r > 1 && height ll - height lr > 0 =
|
||||
Node lh ll lv (Node (depth r lr) lr v r)
|
||||
rotate (Node h l v (Node rh rl rv rr))
|
||||
-- Right Right.
|
||||
| rh - height l > 1 && height rr - height rl > 0 =
|
||||
Node rh (Node (depth l rl) l v rl) rv rr
|
||||
rotate (Node h (Node lh ll lv (Node rh rl rv rr)) v r)
|
||||
-- Left Right.
|
||||
| lh - height r > 1 =
|
||||
Node h (Node (rh + 1) (Node (lh - 1) ll lv rl) rv rr) v r
|
||||
rotate (Node h l v (Node rh (Node lh ll lv lr) rv rr))
|
||||
-- Right Left.
|
||||
| rh - height l > 1 =
|
||||
Node h l v (Node (lh + 1) ll lv (Node (rh - 1) lr rv rr))
|
||||
rotate (Node h l v r) =
|
||||
-- Re-weighting.
|
||||
let (l_, r_) = (rotate l, rotate r)
|
||||
in Node (depth l_ r_) l_ v r_
|
||||
|
||||
draw :: Show a => Tree a -> String
|
||||
draw t = '\n' : draw_ t 0 <> "\n"
|
||||
where
|
||||
draw_ Leaf _ = []
|
||||
draw_ (Node h l v r) d = draw_ r (d + 1) <> node <> draw_ l (d + 1)
|
||||
where
|
||||
node = padding d <> show (v, h) <> "\n"
|
||||
padding n = replicate (n * 4) ' '
|
||||
|
||||
main :: IO ()
|
||||
main = putStr $ draw $ foldTree [1 .. 31]
|
||||
90
Task/AVL-tree/J/avl-tree.j
Normal file
90
Task/AVL-tree/J/avl-tree.j
Normal file
|
|
@ -0,0 +1,90 @@
|
|||
insert=: {{
|
||||
X=.1 {::2{.x,x NB. middle element of x (don't fail on empty x)
|
||||
Y=.1 {::2{.y,y NB. middle element of y (don't fail on empty y)
|
||||
select.#y
|
||||
case.0 do.x NB. y is an empty node
|
||||
case.1 do. NB. y is a leaf node
|
||||
select.*Y-X
|
||||
case._1 do.a:,y;<x
|
||||
case. 0 do.y
|
||||
case. 1 do.x;y;a:
|
||||
end.
|
||||
case.3 do. NB. y is a parent node
|
||||
select.*Y-X
|
||||
case._1 do.balance (}:y),<x insert 2{::y
|
||||
case. 0 do.y
|
||||
case. 1 do.balance (x insert 0{::y);}.y
|
||||
end.
|
||||
end.
|
||||
}}
|
||||
|
||||
delete=: {{
|
||||
select.#y
|
||||
case.0 do.y
|
||||
case.1 do.y-.x
|
||||
case.3 do.
|
||||
select.*(1{::y)-x
|
||||
case._1 do.balance (}:y),<x delete 2{::y
|
||||
case. 0 do.balance (0{::y) insert 2{::y
|
||||
case. 1 do.balance (x delete 0{::y);}.y
|
||||
end.
|
||||
end.
|
||||
}}
|
||||
|
||||
lookup=: {{
|
||||
select.#y
|
||||
case.0 do.y
|
||||
case.1 do.if.x=y do.y else.'' end.
|
||||
case.3 do.
|
||||
select.*(1{::y)-x
|
||||
case._1 do.x lookup 2{::y
|
||||
case. 0 do.y
|
||||
case. 1 do.x lookup 0{::y
|
||||
end.
|
||||
end.
|
||||
}}
|
||||
|
||||
clean=: {{
|
||||
's0 x s2'=. #every y
|
||||
if.*/0=s0,s2 do. 1{:: y NB. degenerate to leaf
|
||||
else. y end.
|
||||
}}
|
||||
|
||||
balance=: {{
|
||||
if. 2>#y do. y return.end. NB. leaf or empty
|
||||
's0 x s2'=. ,#every y
|
||||
if. */0=s0,s2 do. 1{:: y return.end. NB. degenerate to leaf
|
||||
'l0 x l2'=. L.every y
|
||||
if. 2>|l2-l0 do. y return.end. NB. adequately balanced
|
||||
if. l2>l0 do.
|
||||
'l20 x l22'=. L.every 2{::y
|
||||
if. l22 >: l20 do. rotLeft y
|
||||
else. rotRightLeft y end.
|
||||
else.
|
||||
'l00 x l02'=. L.every 0{::y
|
||||
if. l00 >: l02 do. rotRight y
|
||||
else. rotLeftRight y end.
|
||||
end.
|
||||
}}
|
||||
|
||||
rotLeft=: {{
|
||||
't0 t1 t2'=. y
|
||||
't20 t21 t22'=. t2
|
||||
(clean t0;t1;<t20);t21;<t22
|
||||
}}
|
||||
|
||||
rotRight=: {{
|
||||
't0 t1 t2'=. y
|
||||
't00 t01 t02'=. t0
|
||||
t00;t01;<clean t02;t1;<t2
|
||||
}}
|
||||
|
||||
rotRightLeft=: {{
|
||||
't0 t1 t2'=. y
|
||||
rotLeft t0;t1;<rotRight t2
|
||||
}}
|
||||
|
||||
rotLeftRight=: {{
|
||||
't0 t1 t2'=. y
|
||||
rotRight (rotLeft t0);t1;<t2
|
||||
}}
|
||||
218
Task/AVL-tree/Java/avl-tree.java
Normal file
218
Task/AVL-tree/Java/avl-tree.java
Normal file
|
|
@ -0,0 +1,218 @@
|
|||
public class AVLtree {
|
||||
|
||||
private Node root;
|
||||
|
||||
private static class Node {
|
||||
private int key;
|
||||
private int balance;
|
||||
private int height;
|
||||
private Node left;
|
||||
private Node right;
|
||||
private Node parent;
|
||||
|
||||
Node(int key, Node parent) {
|
||||
this.key = key;
|
||||
this.parent = parent;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean insert(int key) {
|
||||
if (root == null) {
|
||||
root = new Node(key, null);
|
||||
return true;
|
||||
}
|
||||
|
||||
Node n = root;
|
||||
while (true) {
|
||||
if (n.key == key)
|
||||
return false;
|
||||
|
||||
Node parent = n;
|
||||
|
||||
boolean goLeft = n.key > key;
|
||||
n = goLeft ? n.left : n.right;
|
||||
|
||||
if (n == null) {
|
||||
if (goLeft) {
|
||||
parent.left = new Node(key, parent);
|
||||
} else {
|
||||
parent.right = new Node(key, parent);
|
||||
}
|
||||
rebalance(parent);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private void delete(Node node) {
|
||||
if (node.left == null && node.right == null) {
|
||||
if (node.parent == null) {
|
||||
root = null;
|
||||
} else {
|
||||
Node parent = node.parent;
|
||||
if (parent.left == node) {
|
||||
parent.left = null;
|
||||
} else {
|
||||
parent.right = null;
|
||||
}
|
||||
rebalance(parent);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (node.left != null) {
|
||||
Node child = node.left;
|
||||
while (child.right != null) child = child.right;
|
||||
node.key = child.key;
|
||||
delete(child);
|
||||
} else {
|
||||
Node child = node.right;
|
||||
while (child.left != null) child = child.left;
|
||||
node.key = child.key;
|
||||
delete(child);
|
||||
}
|
||||
}
|
||||
|
||||
public void delete(int delKey) {
|
||||
if (root == null)
|
||||
return;
|
||||
|
||||
Node child = root;
|
||||
while (child != null) {
|
||||
Node node = child;
|
||||
child = delKey >= node.key ? node.right : node.left;
|
||||
if (delKey == node.key) {
|
||||
delete(node);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void rebalance(Node n) {
|
||||
setBalance(n);
|
||||
|
||||
if (n.balance == -2) {
|
||||
if (height(n.left.left) >= height(n.left.right))
|
||||
n = rotateRight(n);
|
||||
else
|
||||
n = rotateLeftThenRight(n);
|
||||
|
||||
} else if (n.balance == 2) {
|
||||
if (height(n.right.right) >= height(n.right.left))
|
||||
n = rotateLeft(n);
|
||||
else
|
||||
n = rotateRightThenLeft(n);
|
||||
}
|
||||
|
||||
if (n.parent != null) {
|
||||
rebalance(n.parent);
|
||||
} else {
|
||||
root = n;
|
||||
}
|
||||
}
|
||||
|
||||
private Node rotateLeft(Node a) {
|
||||
|
||||
Node b = a.right;
|
||||
b.parent = a.parent;
|
||||
|
||||
a.right = b.left;
|
||||
|
||||
if (a.right != null)
|
||||
a.right.parent = a;
|
||||
|
||||
b.left = a;
|
||||
a.parent = b;
|
||||
|
||||
if (b.parent != null) {
|
||||
if (b.parent.right == a) {
|
||||
b.parent.right = b;
|
||||
} else {
|
||||
b.parent.left = b;
|
||||
}
|
||||
}
|
||||
|
||||
setBalance(a, b);
|
||||
|
||||
return b;
|
||||
}
|
||||
|
||||
private Node rotateRight(Node a) {
|
||||
|
||||
Node b = a.left;
|
||||
b.parent = a.parent;
|
||||
|
||||
a.left = b.right;
|
||||
|
||||
if (a.left != null)
|
||||
a.left.parent = a;
|
||||
|
||||
b.right = a;
|
||||
a.parent = b;
|
||||
|
||||
if (b.parent != null) {
|
||||
if (b.parent.right == a) {
|
||||
b.parent.right = b;
|
||||
} else {
|
||||
b.parent.left = b;
|
||||
}
|
||||
}
|
||||
|
||||
setBalance(a, b);
|
||||
|
||||
return b;
|
||||
}
|
||||
|
||||
private Node rotateLeftThenRight(Node n) {
|
||||
n.left = rotateLeft(n.left);
|
||||
return rotateRight(n);
|
||||
}
|
||||
|
||||
private Node rotateRightThenLeft(Node n) {
|
||||
n.right = rotateRight(n.right);
|
||||
return rotateLeft(n);
|
||||
}
|
||||
|
||||
private int height(Node n) {
|
||||
if (n == null)
|
||||
return -1;
|
||||
return n.height;
|
||||
}
|
||||
|
||||
private void setBalance(Node... nodes) {
|
||||
for (Node n : nodes) {
|
||||
reheight(n);
|
||||
n.balance = height(n.right) - height(n.left);
|
||||
}
|
||||
}
|
||||
|
||||
public void printBalance() {
|
||||
printBalance(root);
|
||||
}
|
||||
|
||||
private void printBalance(Node n) {
|
||||
if (n != null) {
|
||||
printBalance(n.left);
|
||||
System.out.printf("%s ", n.balance);
|
||||
printBalance(n.right);
|
||||
}
|
||||
}
|
||||
|
||||
private void reheight(Node node) {
|
||||
if (node != null) {
|
||||
node.height = 1 + Math.max(height(node.left), height(node.right));
|
||||
}
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
AVLtree tree = new AVLtree();
|
||||
|
||||
System.out.println("Inserting values 1 to 10");
|
||||
for (int i = 1; i < 10; i++)
|
||||
tree.insert(i);
|
||||
|
||||
System.out.print("Printing balance: ");
|
||||
tree.printBalance();
|
||||
}
|
||||
}
|
||||
91
Task/AVL-tree/JavaScript/avl-tree-1.js
Normal file
91
Task/AVL-tree/JavaScript/avl-tree-1.js
Normal file
|
|
@ -0,0 +1,91 @@
|
|||
function tree(less, val, more) {
|
||||
return {
|
||||
depth: 1+Math.max(less.depth, more.depth),
|
||||
less: less,
|
||||
val: val,
|
||||
more: more,
|
||||
};
|
||||
}
|
||||
|
||||
function node(val) {
|
||||
return tree({depth: 0}, val, {depth: 0});
|
||||
}
|
||||
|
||||
function insert(x,y) {
|
||||
if (0 == y.depth) return x;
|
||||
if (0 == x.depth) return y;
|
||||
if (1 == x.depth && 1 == y.depth) {
|
||||
switch (Math.sign(y.val)-x.val) {
|
||||
case -1: return tree(y, x.val, {depth: 0});
|
||||
case 0: return y;
|
||||
case 1: return tree(x, y.val, {depth: 0});
|
||||
}
|
||||
}
|
||||
switch (Math.sign(y.val-x.val)) {
|
||||
case -1: return balance(insert(x.less, y), x.val, x.more);
|
||||
case 0: return balance(insert(x.less, y.less), x.val, insert(x.more, y.more));
|
||||
case 1: return balance(x.less. x.val, insert(x.more, y));
|
||||
}
|
||||
}
|
||||
|
||||
function balance(less,val,more) {
|
||||
if (2 > Math.abs(less.depth-more.depth))
|
||||
return tree(less,val,more);
|
||||
if (more.depth > less.depth) {
|
||||
if (more.more.depth >= more.less.depth) {
|
||||
// 'more' was heavy
|
||||
return moreHeavy(less, val, more);
|
||||
} else {
|
||||
return moreHeavy(less,val,lessHeavy(more.less, more.val, more.more));
|
||||
}
|
||||
} else {
|
||||
if(less.less.depth >= less.more.depth) {
|
||||
return lessHeavy(less, val, more);
|
||||
} else {
|
||||
return lessHeavy(moreHeavy(less.less, less.val, less.more), val, more);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function moreHeavy(less,val,more) {
|
||||
return tree(tree(less,val,more.less), more.val, more.more)
|
||||
}
|
||||
|
||||
function lessHeavy(less,val,more) {
|
||||
return tree(less.less, less.val, tree(less.more, val, more));
|
||||
}
|
||||
|
||||
function remove(val, y) {
|
||||
switch (y.depth) {
|
||||
case 0: return y;
|
||||
case 1:
|
||||
if (val == y.val) {
|
||||
return y.less;
|
||||
} else {
|
||||
return y;
|
||||
}
|
||||
default:
|
||||
switch (Math.sign(y.val - val)) {
|
||||
case -1: return balance(y.less, y.val, remove(val, y.more));
|
||||
case 0: return insert(y.less, y.more);
|
||||
case 1: return balance(remove(val, y.less), y.val, y.more)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function lookup(val, y) {
|
||||
switch (y.depth) {
|
||||
case 0: return y;
|
||||
case 1: if (val == y.val) {
|
||||
return y;
|
||||
} else {
|
||||
return {depth: 0};
|
||||
}
|
||||
default:
|
||||
switch (Math.sign(y.val-val)) {
|
||||
case -1: return lookup(val, y.more);
|
||||
case 0: return y;
|
||||
case 1: return lookup(val, y.less);
|
||||
}
|
||||
}
|
||||
}
|
||||
20
Task/AVL-tree/JavaScript/avl-tree-2.js
Normal file
20
Task/AVL-tree/JavaScript/avl-tree-2.js
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
function dumptree(t) {
|
||||
switch (t.depth) {
|
||||
case 0: return '';
|
||||
case 1: return t.val;
|
||||
default: return '('+dumptree(t.less)+','+t.val+','+dumptree(t.more)+')';
|
||||
}
|
||||
}
|
||||
function example() {
|
||||
let t= node(0);
|
||||
for (let j= 1; j<20; j++) {
|
||||
t= insert(node(j), t);
|
||||
}
|
||||
console.log(dumptree(t));
|
||||
t= remove(2, t);
|
||||
console.log(dumptree(t));
|
||||
console.log(dumptree(lookup(5, t)));
|
||||
console.log(dumptree(remove(5, t)));
|
||||
}
|
||||
|
||||
example();
|
||||
180
Task/AVL-tree/Julia/avl-tree.julia
Normal file
180
Task/AVL-tree/Julia/avl-tree.julia
Normal file
|
|
@ -0,0 +1,180 @@
|
|||
module AVLTrees
|
||||
|
||||
import Base.print
|
||||
export AVLNode, AVLTree, insert, deletekey, deletevalue, findnodebykey, findnodebyvalue, allnodes
|
||||
|
||||
@enum Direction LEFT RIGHT
|
||||
avlhash(x) = Int32(hash(x) & 0xfffffff)
|
||||
const MIDHASH = Int32(div(0xfffffff, 2))
|
||||
|
||||
mutable struct AVLNode{T}
|
||||
value::T
|
||||
key::Int32
|
||||
balance::Int32
|
||||
left::Union{AVLNode, Nothing}
|
||||
right::Union{AVLNode, Nothing}
|
||||
parent::Union{AVLNode, Nothing}
|
||||
end
|
||||
AVLNode(v::T, b, l, r, p) where T <: Real = AVLNode(v, avlhash(v), Int32(b), l, r, p)
|
||||
AVLNode(v::T, h, b::Int64, l, r, p) where T <: Real = AVLNode(v, h, Int32(b), l, r, p)
|
||||
AVLNode(v::T) where T <: Real = AVLNode(v, avlhash(v), Int32(0), nothing, nothing, nothing)
|
||||
|
||||
AVLTree(typ::Type) = AVLNode(typ(0), MIDHASH, Int32(0), nothing, nothing, nothing)
|
||||
const MaybeAVL = Union{AVLNode, Nothing}
|
||||
|
||||
height(node::MaybeAVL) = (node == nothing) ? 0 : 1 + max(height(node.right), height(node.left))
|
||||
|
||||
function insert(node, value)
|
||||
if node == nothing
|
||||
node = AVLNode(value)
|
||||
return true
|
||||
end
|
||||
key, n, parent::MaybeAVL = avlhash(value), node, nothing
|
||||
while true
|
||||
if n.key == key
|
||||
return false
|
||||
end
|
||||
parent = n
|
||||
ngreater = n.key > key
|
||||
n = ngreater ? n.left : n.right
|
||||
if n == nothing
|
||||
if ngreater
|
||||
parent.left = AVLNode(value, key, 0, nothing, nothing, parent)
|
||||
else
|
||||
parent.right = AVLNode(value, key, 0, nothing, nothing, parent)
|
||||
end
|
||||
rebalance(parent)
|
||||
break
|
||||
end
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
function deletekey(node, delkey)
|
||||
node == nothing && return nothing
|
||||
n, parent = MaybeAVL(node), MaybeAVL(node)
|
||||
delnode, child = MaybeAVL(nothing), MaybeAVL(node)
|
||||
while child != nothing
|
||||
parent, n = n, child
|
||||
child = delkey >= n.key ? n.right : n.left
|
||||
if delkey == n.key
|
||||
delnode = n
|
||||
end
|
||||
end
|
||||
if delnode != nothing
|
||||
delnode.key = n.key
|
||||
delnode.value = n.value
|
||||
child = (n.left != nothing) ? n.left : n.right
|
||||
if node.key == delkey
|
||||
root = child
|
||||
else
|
||||
if parent.left == n
|
||||
parent.left = child
|
||||
else
|
||||
parent.right = child
|
||||
end
|
||||
rebalance(parent)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
deletevalue(node, val) = deletekey(node, avlhash(val))
|
||||
|
||||
function rebalance(node::MaybeAVL)
|
||||
node == nothing && return nothing
|
||||
setbalance(node)
|
||||
if node.balance < -1
|
||||
if height(node.left.left) >= height(node.left.right)
|
||||
node = rotate(node, RIGHT)
|
||||
else
|
||||
node = rotatetwice(node, LEFT, RIGHT)
|
||||
end
|
||||
elseif node.balance > 1
|
||||
if node.right != nothing && height(node.right.right) >= height(node.right.left)
|
||||
node = rotate(node, LEFT)
|
||||
else
|
||||
node = rotatetwice(node, RIGHT, LEFT)
|
||||
end
|
||||
end
|
||||
if node != nothing && node.parent != nothing
|
||||
rebalance(node.parent)
|
||||
end
|
||||
end
|
||||
|
||||
function rotate(a, direction)
|
||||
(a == nothing || a.parent == nothing) && return nothing
|
||||
b = direction == LEFT ? a.right : a.left
|
||||
b == nothing && return
|
||||
b.parent = a.parent
|
||||
if direction == LEFT
|
||||
a.right = b.left
|
||||
else
|
||||
a.left = b.right
|
||||
end
|
||||
if a.right != nothing
|
||||
a.right.parent = a
|
||||
end
|
||||
if direction == LEFT
|
||||
b.left = a
|
||||
else
|
||||
b.right = a
|
||||
end
|
||||
a.parent = b
|
||||
if b.parent != nothing
|
||||
if b.parent.right == a
|
||||
b.parent.right = b
|
||||
else
|
||||
b.parent.left = b
|
||||
end
|
||||
end
|
||||
setbalance([a, b])
|
||||
return b
|
||||
end
|
||||
|
||||
function rotatetwice(n, dir1, dir2)
|
||||
n.left = rotate(n.left, dir1)
|
||||
rotate(n, dir2)
|
||||
end
|
||||
|
||||
setbalance(n::AVLNode) = begin n.balance = height(n.right) - height(n.left) end
|
||||
setbalance(n::Nothing) = 0
|
||||
setbalance(nodes::Vector) = for n in nodes setbalance(n) end
|
||||
|
||||
function findnodebykey(node, key)
|
||||
result::MaybeAVL = node == nothing ? nothing : node.key == key ? node :
|
||||
node.left != nothing && (n = findbykey(n, key) != nothing) ? n :
|
||||
node.right != nothing ? findbykey(node.right, key) : nothing
|
||||
return result
|
||||
end
|
||||
findnodebyvalue(node, val) = findnodebykey(node, avlhash(v))
|
||||
|
||||
function allnodes(node)
|
||||
result = AVLNode[]
|
||||
if node != nothing
|
||||
append!(result, allnodes(node.left))
|
||||
if node.key != MIDHASH
|
||||
push!(result, node)
|
||||
end
|
||||
append!(result, node.right)
|
||||
end
|
||||
return result
|
||||
end
|
||||
|
||||
function Base.print(io::IO, n::MaybeAVL)
|
||||
if n != nothing
|
||||
n.left != nothing && print(io, n.left)
|
||||
print(io, n.key == MIDHASH ? "<ROOT> " : "<$(n.key):$(n.value):$(n.balance)> ")
|
||||
n.right != nothing && print(io, n.right)
|
||||
end
|
||||
end
|
||||
|
||||
end # module
|
||||
|
||||
using .AVLTrees
|
||||
|
||||
const tree = AVLTree(Int)
|
||||
|
||||
println("Inserting 10 values.")
|
||||
foreach(x -> insert(tree, x), rand(collect(1:80), 10))
|
||||
println("Printing tree after insertion: ")
|
||||
println(tree)
|
||||
175
Task/AVL-tree/Kotlin/avl-tree.kotlin
Normal file
175
Task/AVL-tree/Kotlin/avl-tree.kotlin
Normal file
|
|
@ -0,0 +1,175 @@
|
|||
class AvlTree {
|
||||
private var root: Node? = null
|
||||
|
||||
private class Node(var key: Int, var parent: Node?) {
|
||||
var balance: Int = 0
|
||||
var left : Node? = null
|
||||
var right: Node? = null
|
||||
}
|
||||
|
||||
fun insert(key: Int): Boolean {
|
||||
if (root == null)
|
||||
root = Node(key, null)
|
||||
else {
|
||||
var n: Node? = root
|
||||
var parent: Node
|
||||
while (true) {
|
||||
if (n!!.key == key) return false
|
||||
parent = n
|
||||
val goLeft = n.key > key
|
||||
n = if (goLeft) n.left else n.right
|
||||
if (n == null) {
|
||||
if (goLeft)
|
||||
parent.left = Node(key, parent)
|
||||
else
|
||||
parent.right = Node(key, parent)
|
||||
rebalance(parent)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
fun delete(delKey: Int) {
|
||||
if (root == null) return
|
||||
var n: Node? = root
|
||||
var parent: Node? = root
|
||||
var delNode: Node? = null
|
||||
var child: Node? = root
|
||||
while (child != null) {
|
||||
parent = n
|
||||
n = child
|
||||
child = if (delKey >= n.key) n.right else n.left
|
||||
if (delKey == n.key) delNode = n
|
||||
}
|
||||
if (delNode != null) {
|
||||
delNode.key = n!!.key
|
||||
child = if (n.left != null) n.left else n.right
|
||||
if (0 == root!!.key.compareTo(delKey)) {
|
||||
root = child
|
||||
|
||||
if (null != root) {
|
||||
root!!.parent = null
|
||||
}
|
||||
|
||||
} else {
|
||||
if (parent!!.left == n)
|
||||
parent.left = child
|
||||
else
|
||||
parent.right = child
|
||||
|
||||
if (null != child) {
|
||||
child.parent = parent
|
||||
}
|
||||
|
||||
rebalance(parent)
|
||||
}
|
||||
}
|
||||
|
||||
private fun rebalance(n: Node) {
|
||||
setBalance(n)
|
||||
var nn = n
|
||||
if (nn.balance == -2)
|
||||
if (height(nn.left!!.left) >= height(nn.left!!.right))
|
||||
nn = rotateRight(nn)
|
||||
else
|
||||
nn = rotateLeftThenRight(nn)
|
||||
else if (nn.balance == 2)
|
||||
if (height(nn.right!!.right) >= height(nn.right!!.left))
|
||||
nn = rotateLeft(nn)
|
||||
else
|
||||
nn = rotateRightThenLeft(nn)
|
||||
if (nn.parent != null) rebalance(nn.parent!!)
|
||||
else root = nn
|
||||
}
|
||||
|
||||
private fun rotateLeft(a: Node): Node {
|
||||
val b: Node? = a.right
|
||||
b!!.parent = a.parent
|
||||
a.right = b.left
|
||||
if (a.right != null) a.right!!.parent = a
|
||||
b.left = a
|
||||
a.parent = b
|
||||
if (b.parent != null) {
|
||||
if (b.parent!!.right == a)
|
||||
b.parent!!.right = b
|
||||
else
|
||||
b.parent!!.left = b
|
||||
}
|
||||
setBalance(a, b)
|
||||
return b
|
||||
}
|
||||
|
||||
private fun rotateRight(a: Node): Node {
|
||||
val b: Node? = a.left
|
||||
b!!.parent = a.parent
|
||||
a.left = b.right
|
||||
if (a.left != null) a.left!!.parent = a
|
||||
b.right = a
|
||||
a.parent = b
|
||||
if (b.parent != null) {
|
||||
if (b.parent!!.right == a)
|
||||
b.parent!!.right = b
|
||||
else
|
||||
b.parent!!.left = b
|
||||
}
|
||||
setBalance(a, b)
|
||||
return b
|
||||
}
|
||||
|
||||
private fun rotateLeftThenRight(n: Node): Node {
|
||||
n.left = rotateLeft(n.left!!)
|
||||
return rotateRight(n)
|
||||
}
|
||||
|
||||
private fun rotateRightThenLeft(n: Node): Node {
|
||||
n.right = rotateRight(n.right!!)
|
||||
return rotateLeft(n)
|
||||
}
|
||||
|
||||
private fun height(n: Node?): Int {
|
||||
if (n == null) return -1
|
||||
return 1 + Math.max(height(n.left), height(n.right))
|
||||
}
|
||||
|
||||
private fun setBalance(vararg nodes: Node) {
|
||||
for (n in nodes) n.balance = height(n.right) - height(n.left)
|
||||
}
|
||||
|
||||
fun printKey() {
|
||||
printKey(root)
|
||||
println()
|
||||
}
|
||||
|
||||
private fun printKey(n: Node?) {
|
||||
if (n != null) {
|
||||
printKey(n.left)
|
||||
print("${n.key} ")
|
||||
printKey(n.right)
|
||||
}
|
||||
}
|
||||
|
||||
fun printBalance() {
|
||||
printBalance(root)
|
||||
println()
|
||||
}
|
||||
|
||||
private fun printBalance(n: Node?) {
|
||||
if (n != null) {
|
||||
printBalance(n.left)
|
||||
print("${n.balance} ")
|
||||
printBalance(n.right)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun main(args: Array<String>) {
|
||||
val tree = AvlTree()
|
||||
println("Inserting values 1 to 10")
|
||||
for (i in 1..10) tree.insert(i)
|
||||
print("Printing key : ")
|
||||
tree.printKey()
|
||||
print("Printing balance : ")
|
||||
tree.printBalance()
|
||||
}
|
||||
7
Task/AVL-tree/Logtalk/avl-tree.logtalk
Normal file
7
Task/AVL-tree/Logtalk/avl-tree.logtalk
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
:- object(avltree,
|
||||
implements(dictionaryp),
|
||||
extends(term)).
|
||||
|
||||
% ... lots of elision ...
|
||||
|
||||
:- end_object.
|
||||
132
Task/AVL-tree/Lua/avl-tree.lua
Normal file
132
Task/AVL-tree/Lua/avl-tree.lua
Normal file
|
|
@ -0,0 +1,132 @@
|
|||
AVL={balance=0}
|
||||
AVL.__mt={__index = AVL}
|
||||
|
||||
|
||||
function AVL:new(list)
|
||||
local o={}
|
||||
setmetatable(o, AVL.__mt)
|
||||
for _,v in ipairs(list or {}) do
|
||||
o=o:insert(v)
|
||||
end
|
||||
return o
|
||||
end
|
||||
|
||||
function AVL:rebalance()
|
||||
local rotated=false
|
||||
if self.balance>1 then
|
||||
if self.right.balance<0 then
|
||||
self.right, self.right.left.right, self.right.left = self.right.left, self.right, self.right.left.right
|
||||
self.right.right.balance=self.right.balance>-1 and 0 or 1
|
||||
self.right.balance=self.right.balance>0 and 2 or 1
|
||||
end
|
||||
self, self.right.left, self.right = self.right, self, self.right.left
|
||||
self.left.balance=1-self.balance
|
||||
self.balance=self.balance==0 and -1 or 0
|
||||
rotated=true
|
||||
elseif self.balance<-1 then
|
||||
if self.left.balance>0 then
|
||||
self.left, self.left.right.left, self.left.right = self.left.right, self.left, self.left.right.left
|
||||
self.left.left.balance=self.left.balance<1 and 0 or -1
|
||||
self.left.balance=self.left.balance<0 and -2 or -1
|
||||
end
|
||||
self, self.left.right, self.left = self.left, self, self.left.right
|
||||
self.right.balance=-1-self.balance
|
||||
self.balance=self.balance==0 and 1 or 0
|
||||
rotated=true
|
||||
end
|
||||
return self,rotated
|
||||
end
|
||||
|
||||
function AVL:insert(v)
|
||||
if not self.value then
|
||||
self.value=v
|
||||
self.balance=0
|
||||
return self,1
|
||||
end
|
||||
local grow
|
||||
if v==self.value then
|
||||
return self,0
|
||||
elseif v<self.value then
|
||||
if not self.left then self.left=self:new() end
|
||||
self.left,grow=self.left:insert(v)
|
||||
self.balance=self.balance-grow
|
||||
else
|
||||
if not self.right then self.right=self:new() end
|
||||
self.right,grow=self.right:insert(v)
|
||||
self.balance=self.balance+grow
|
||||
end
|
||||
self,rotated=self:rebalance()
|
||||
return self, (rotated or self.balance==0) and 0 or grow
|
||||
end
|
||||
|
||||
function AVL:delete_move(dir,other,mul)
|
||||
if self[dir] then
|
||||
local sb2,v
|
||||
self[dir], sb2, v=self[dir]:delete_move(dir,other,mul)
|
||||
self.balance=self.balance+sb2*mul
|
||||
self,sb2=self:rebalance()
|
||||
return self,(sb2 or self.balance==0) and -1 or 0,v
|
||||
else
|
||||
return self[other],-1,self.value
|
||||
end
|
||||
end
|
||||
|
||||
function AVL:delete(v,isSubtree)
|
||||
local grow=0
|
||||
if v==self.value then
|
||||
local v
|
||||
if self.balance>0 then
|
||||
self.right,grow,v=self.right:delete_move("left","right",-1)
|
||||
elseif self.left then
|
||||
self.left,grow,v=self.left:delete_move("right","left",1)
|
||||
grow=-grow
|
||||
else
|
||||
return not isSubtree and AVL:new(),-1
|
||||
end
|
||||
self.value=v
|
||||
self.balance=self.balance+grow
|
||||
elseif v<self.value and self.left then
|
||||
self.left,grow=self.left:delete(v,true)
|
||||
self.balance=self.balance-grow
|
||||
elseif v>self.value and self.right then
|
||||
self.right,grow=self.right:delete(v,true)
|
||||
self.balance=self.balance+grow
|
||||
else
|
||||
return self,0
|
||||
end
|
||||
self,rotated=self:rebalance()
|
||||
return self, grow~=0 and (rotated or self.balance==0) and -1 or 0
|
||||
end
|
||||
|
||||
-- output functions
|
||||
|
||||
function AVL:toList(list)
|
||||
if not self.value then return {} end
|
||||
list=list or {}
|
||||
if self.left then self.left:toList(list) end
|
||||
list[#list+1]=self.value
|
||||
if self.right then self.right:toList(list) end
|
||||
return list
|
||||
end
|
||||
|
||||
function AVL:dump(depth)
|
||||
if not self.value then return end
|
||||
depth=depth or 0
|
||||
if self.right then self.right:dump(depth+1) end
|
||||
print(string.rep(" ",depth)..self.value.." ("..self.balance..")")
|
||||
if self.left then self.left:dump(depth+1) end
|
||||
end
|
||||
|
||||
-- test
|
||||
|
||||
local test=AVL:new{1,10,5,15,20,3,5,14,7,13,2,8,3,4,5,10,9,8,7}
|
||||
|
||||
test:dump()
|
||||
print("\ninsert 17:")
|
||||
test=test:insert(17)
|
||||
test:dump()
|
||||
print("\ndelete 10:")
|
||||
test=test:delete(10)
|
||||
test:dump()
|
||||
print("\nlist:")
|
||||
print(unpack(test:toList()))
|
||||
198
Task/AVL-tree/Nim/avl-tree.nim
Normal file
198
Task/AVL-tree/Nim/avl-tree.nim
Normal file
|
|
@ -0,0 +1,198 @@
|
|||
#[ AVL tree adapted from Julienne Walker's presentation at
|
||||
http://eternallyconfuzzled.com/tuts/datastructures/jsw_tut_avl.aspx.
|
||||
|
||||
Uses bounded recursive versions for insertion and deletion.
|
||||
]#
|
||||
|
||||
type
|
||||
|
||||
# Objects strored in the tree must be comparable.
|
||||
Comparable = concept x, y
|
||||
(x == y) is bool
|
||||
(x < y) is bool
|
||||
|
||||
# Direction used to select a child.
|
||||
Direction = enum Left, Right
|
||||
|
||||
# Description of the tree node.
|
||||
Node[T: Comparable] = ref object
|
||||
data: T # Payload.
|
||||
balance: range[-2..2] # Balance factor (bounded).
|
||||
links: array[Direction, Node[T]] # Children.
|
||||
|
||||
# Description of a tree.
|
||||
AvlTree[T: Comparable] = object
|
||||
root: Node[T]
|
||||
|
||||
|
||||
#---------------------------------------------------------------------------------------------------
|
||||
|
||||
func opp(dir: Direction): Direction {.inline.} =
|
||||
## Return the opposite of a direction.
|
||||
Direction(1 - ord(dir))
|
||||
|
||||
#---------------------------------------------------------------------------------------------------
|
||||
|
||||
func single(root: Node; dir: Direction): Node =
|
||||
## Single rotation.
|
||||
|
||||
result = root.links[opp(dir)]
|
||||
root.links[opp(dir)] = result.links[dir]
|
||||
result.links[dir] = root
|
||||
|
||||
#---------------------------------------------------------------------------------------------------
|
||||
|
||||
func double(root: Node; dir: Direction): Node =
|
||||
## Double rotation.
|
||||
|
||||
let save = root.links[opp(dir)].links[dir]
|
||||
|
||||
root.links[opp(dir)].links[dir] = save.links[opp(dir)]
|
||||
save.links[opp(dir)] = root.links[opp(dir)]
|
||||
root.links[opp(dir)] = save
|
||||
|
||||
result = root.links[opp(dir)]
|
||||
root.links[opp(dir)] = result.links[dir]
|
||||
result.links[dir] = root
|
||||
|
||||
#---------------------------------------------------------------------------------------------------
|
||||
|
||||
func adjustBalance(root: Node; dir: Direction; balance: int) =
|
||||
## Adjust balance factors after double rotation.
|
||||
|
||||
let node1 = root.links[dir]
|
||||
let node2 = node1.links[opp(dir)]
|
||||
|
||||
if node2.balance == 0:
|
||||
root.balance = 0
|
||||
node1.balance = 0
|
||||
|
||||
elif node2.balance == balance:
|
||||
root.balance = -balance
|
||||
node1.balance = 0
|
||||
|
||||
else:
|
||||
root.balance = 0
|
||||
node1.balance = balance
|
||||
|
||||
node2.balance = 0
|
||||
|
||||
#---------------------------------------------------------------------------------------------------
|
||||
|
||||
func insertBalance(root: Node; dir: Direction): Node =
|
||||
## Rebalancing after an insertion.
|
||||
|
||||
let node = root.links[dir]
|
||||
let balance = 2 * ord(dir) - 1
|
||||
|
||||
if node.balance == balance:
|
||||
root.balance = 0
|
||||
node.balance = 0
|
||||
result = root.single(opp(dir))
|
||||
|
||||
else:
|
||||
root.adjustBalance(dir, balance)
|
||||
result = root.double(opp(dir))
|
||||
|
||||
#---------------------------------------------------------------------------------------------------
|
||||
|
||||
func insertR(root: Node; data: root.T): tuple[node: Node, done: bool] =
|
||||
## Insert data (recursive way).
|
||||
|
||||
if root.isNil:
|
||||
return (Node(data: data), false)
|
||||
|
||||
let dir = if root.data < data: Right else: Left
|
||||
var done: bool
|
||||
(root.links[dir], done) = root.links[dir].insertR(data)
|
||||
if done:
|
||||
return (root, true)
|
||||
|
||||
inc root.balance, 2 * ord(dir) - 1
|
||||
result = case root.balance
|
||||
of 0: (root, true)
|
||||
of -1, 1: (root, false)
|
||||
else: (root.insertBalance(dir), true)
|
||||
|
||||
#---------------------------------------------------------------------------------------------------
|
||||
|
||||
func removeBalance(root: Node; dir: Direction): tuple[node: Node, done: bool] =
|
||||
## Rebalancing after a deletion.
|
||||
|
||||
let node = root.links[opp(dir)]
|
||||
let balance = 2 * ord(dir) - 1
|
||||
if node.balance == -balance:
|
||||
root.balance = 0
|
||||
node.balance = 0
|
||||
result = (root.single(dir), false)
|
||||
elif node.balance == balance:
|
||||
root.adjustBalance(opp(dir), -balance)
|
||||
result = (root.double(dir), false)
|
||||
else:
|
||||
root.balance = -balance
|
||||
node.balance = balance
|
||||
result = (root.single(dir), true)
|
||||
|
||||
#---------------------------------------------------------------------------------------------------
|
||||
|
||||
func removeR(root: Node; data: root.T): tuple[node: Node, done: bool] =
|
||||
## Remove data (recursive way).
|
||||
|
||||
if root.isNil:
|
||||
return (nil, false)
|
||||
|
||||
var data = data
|
||||
if root.data == data:
|
||||
if root.links[Left].isNil:
|
||||
return (root.links[Right], false)
|
||||
if root.links[Right].isNil:
|
||||
return (root.links[Left], false)
|
||||
var heir = root.links[Left]
|
||||
while not heir.links[Right].isNil:
|
||||
heir = heir.links[Right]
|
||||
root.data = heir.data
|
||||
data = heir.data
|
||||
|
||||
let dir = if root.data < data: Right else: Left
|
||||
var done: bool
|
||||
(root.links[dir], done) = root.links[dir].removeR(data)
|
||||
if done:
|
||||
return (root, true)
|
||||
dec root.balance, 2 * ord(dir) - 1
|
||||
result = case root.balance
|
||||
of -1, 1: (root, true)
|
||||
of 0: (root, false)
|
||||
else: root.removeBalance(dir)
|
||||
|
||||
#---------------------------------------------------------------------------------------------------
|
||||
|
||||
func insert(tree: var AvlTree; data: tree.T) =
|
||||
## Insert data in an AVL tree.
|
||||
tree.root = tree.root.insertR(data).node
|
||||
|
||||
#---------------------------------------------------------------------------------------------------
|
||||
|
||||
func remove(tree: var AvlTree; data: tree.T) =
|
||||
## Remove data from an AVL tree.
|
||||
tree.root = tree.root.removeR(data).node
|
||||
|
||||
#———————————————————————————————————————————————————————————————————————————————————————————————————
|
||||
|
||||
import json
|
||||
|
||||
var tree: AvlTree[int]
|
||||
echo pretty(%tree)
|
||||
|
||||
echo "Insert test:"
|
||||
tree.insert(3)
|
||||
tree.insert(1)
|
||||
tree.insert(4)
|
||||
tree.insert(1)
|
||||
tree.insert(5)
|
||||
echo pretty(%tree)
|
||||
|
||||
echo ""
|
||||
echo "Remove test:"
|
||||
tree.remove(3)
|
||||
tree.remove(1)
|
||||
echo pretty(%tree)
|
||||
283
Task/AVL-tree/Objeck/avl-tree.objeck
Normal file
283
Task/AVL-tree/Objeck/avl-tree.objeck
Normal file
|
|
@ -0,0 +1,283 @@
|
|||
class AVLNode {
|
||||
@key : Int;
|
||||
@balance : Int;
|
||||
@height : Int;
|
||||
@left : AVLNode;
|
||||
@right : AVLNode;
|
||||
@above : AVLNode;
|
||||
|
||||
New(key : Int, above : AVLNode) {
|
||||
@key := key;
|
||||
@above := above;
|
||||
}
|
||||
|
||||
method : public : GetKey() ~ Int {
|
||||
return @key;
|
||||
}
|
||||
|
||||
method : public : GetLeft() ~ AVLNode {
|
||||
return @left;
|
||||
}
|
||||
|
||||
method : public : GetRight() ~ AVLNode {
|
||||
return @right;
|
||||
}
|
||||
|
||||
method : public : GetAbove() ~ AVLNode {
|
||||
return @above;
|
||||
}
|
||||
|
||||
method : public : GetBalance() ~ Int {
|
||||
return @balance;
|
||||
}
|
||||
|
||||
method : public : GetHeight() ~ Int {
|
||||
return @height;
|
||||
}
|
||||
|
||||
method : public : SetBalance(balance : Int) ~ Nil {
|
||||
@balance := balance;
|
||||
}
|
||||
|
||||
method : public : SetHeight(height : Int) ~ Nil {
|
||||
@height := height;
|
||||
}
|
||||
|
||||
method : public : SetAbove(above : AVLNode) ~ Nil {
|
||||
@above := above;
|
||||
}
|
||||
|
||||
method : public : SetLeft(left : AVLNode) ~ Nil {
|
||||
@left := left;
|
||||
}
|
||||
|
||||
method : public : SetRight(right : AVLNode) ~ Nil {
|
||||
@right := right;
|
||||
}
|
||||
|
||||
method : public : SetKey(key : Int) ~ Nil {
|
||||
@key := key;
|
||||
}
|
||||
}
|
||||
|
||||
class AVLTree {
|
||||
@root : AVLNode;
|
||||
|
||||
New() {}
|
||||
|
||||
method : public : Insert(key : Int) ~ Bool {
|
||||
if(@root = Nil) {
|
||||
@root := AVLNode->New( key, Nil);
|
||||
return true;
|
||||
};
|
||||
|
||||
n := @root;
|
||||
while(true) {
|
||||
if(n->GetKey() = key) {
|
||||
return false;
|
||||
};
|
||||
|
||||
parent := n;
|
||||
goLeft := n->GetKey() > key;
|
||||
n := goLeft ? n->GetLeft() : n->GetRight();
|
||||
|
||||
if(n = Nil) {
|
||||
if(goLeft) {
|
||||
parent->SetLeft(AVLNode->New( key, parent));
|
||||
} else {
|
||||
parent->SetRight(AVLNode->New( key, parent));
|
||||
};
|
||||
Rebalance(parent);
|
||||
break;
|
||||
};
|
||||
};
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
method : Delete(node : AVLNode) ~ Nil {
|
||||
if (node->GetLeft() = Nil & node->GetRight() = Nil) {
|
||||
if (node ->GetAbove() = Nil) {
|
||||
@root := Nil;
|
||||
} else {
|
||||
parent := node ->GetAbove();
|
||||
if (parent->GetLeft() = node) {
|
||||
parent->SetLeft(Nil);
|
||||
} else {
|
||||
parent->SetRight(Nil);
|
||||
};
|
||||
Rebalance(parent);
|
||||
};
|
||||
return;
|
||||
};
|
||||
|
||||
if (node->GetLeft() <> Nil) {
|
||||
child := node->GetLeft();
|
||||
while (child->GetRight() <> Nil) {
|
||||
child := child->GetRight();
|
||||
};
|
||||
node->SetKey(child->GetKey());
|
||||
Delete(child);
|
||||
} else {
|
||||
child := node->GetRight();
|
||||
while (child->GetLeft() <> Nil) {
|
||||
child := child->GetLeft();
|
||||
};
|
||||
node->SetKey(child->GetKey());
|
||||
Delete(child);
|
||||
};
|
||||
}
|
||||
|
||||
method : public : Delete(delKey : Int) ~ Nil {
|
||||
if (@root = Nil) {
|
||||
return;
|
||||
};
|
||||
|
||||
child := @root;
|
||||
while (child <> Nil) {
|
||||
node := child;
|
||||
child := delKey >= node->GetKey() ? node->GetRight() : node->GetLeft();
|
||||
if (delKey = node->GetKey()) {
|
||||
Delete(node);
|
||||
return;
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
method : Rebalance(n : AVLNode) ~ Nil {
|
||||
SetBalance(n);
|
||||
|
||||
if (n->GetBalance() = -2) {
|
||||
if (Height(n->GetLeft()->GetLeft()) >= Height(n->GetLeft()->GetRight())) {
|
||||
n := RotateRight(n);
|
||||
}
|
||||
else {
|
||||
n := RotateLeftThenRight(n);
|
||||
};
|
||||
|
||||
} else if (n->GetBalance() = 2) {
|
||||
if(Height(n->GetRight()->GetRight()) >= Height(n->GetRight()->GetLeft())) {
|
||||
n := RotateLeft(n);
|
||||
}
|
||||
else {
|
||||
n := RotateRightThenLeft(n);
|
||||
};
|
||||
};
|
||||
|
||||
if(n->GetAbove() <> Nil) {
|
||||
Rebalance(n->GetAbove());
|
||||
} else {
|
||||
@root := n;
|
||||
};
|
||||
}
|
||||
|
||||
method : RotateLeft(a : AVLNode) ~ AVLNode {
|
||||
b := a->GetRight();
|
||||
b->SetAbove(a->GetAbove());
|
||||
|
||||
a->SetRight(b->GetLeft());
|
||||
|
||||
if(a->GetRight() <> Nil) {
|
||||
a->GetRight()->SetAbove(a);
|
||||
};
|
||||
|
||||
b->SetLeft(a);
|
||||
a->SetAbove(b);
|
||||
|
||||
if (b->GetAbove() <> Nil) {
|
||||
if (b->GetAbove()->GetRight() = a) {
|
||||
b->GetAbove()->SetRight(b);
|
||||
} else {
|
||||
b->GetAbove()->SetLeft(b);
|
||||
};
|
||||
};
|
||||
|
||||
SetBalance(a);
|
||||
SetBalance(b);
|
||||
|
||||
return b;
|
||||
}
|
||||
|
||||
method : RotateRight(a : AVLNode) ~ AVLNode {
|
||||
b := a->GetLeft();
|
||||
b->SetAbove(a->GetAbove());
|
||||
|
||||
a->SetLeft(b->GetRight());
|
||||
|
||||
if (a->GetLeft() <> Nil) {
|
||||
a->GetLeft()->SetAbove(a);
|
||||
};
|
||||
|
||||
b->SetRight(a);
|
||||
a->SetAbove(b);
|
||||
|
||||
if (b->GetAbove() <> Nil) {
|
||||
if (b->GetAbove()->GetRight() = a) {
|
||||
b->GetAbove()->SetRight(b);
|
||||
} else {
|
||||
b->GetAbove()->SetLeft(b);
|
||||
};
|
||||
};
|
||||
|
||||
SetBalance(a);
|
||||
SetBalance(b);
|
||||
|
||||
return b;
|
||||
}
|
||||
|
||||
method : RotateLeftThenRight(n : AVLNode) ~ AVLNode {
|
||||
n->SetLeft(RotateLeft(n->GetLeft()));
|
||||
return RotateRight(n);
|
||||
}
|
||||
|
||||
method : RotateRightThenLeft(n : AVLNode) ~ AVLNode {
|
||||
n->SetRight(RotateRight(n->GetRight()));
|
||||
return RotateLeft(n);
|
||||
}
|
||||
|
||||
method : SetBalance(n : AVLNode) ~ Nil {
|
||||
Reheight(n);
|
||||
n->SetBalance(Height(n->GetRight()) - Height(n->GetLeft()));
|
||||
}
|
||||
|
||||
method : Reheight(node : AVLNode) ~ Nil {
|
||||
if(node <> Nil) {
|
||||
node->SetHeight(1 + Int->Max(Height(node->GetLeft()), Height(node->GetRight())));
|
||||
};
|
||||
}
|
||||
|
||||
method : Height(n : AVLNode) ~ Int {
|
||||
if(n = Nil) {
|
||||
return -1;
|
||||
};
|
||||
|
||||
return n->GetHeight();
|
||||
}
|
||||
|
||||
method : public : PrintBalance() ~ Nil {
|
||||
PrintBalance(@root);
|
||||
}
|
||||
|
||||
method : PrintBalance(n : AVLNode) ~ Nil {
|
||||
if (n <> Nil) {
|
||||
PrintBalance(n->GetLeft());
|
||||
balance := n->GetBalance();
|
||||
"{$balance} "->Print();
|
||||
PrintBalance(n->GetRight());
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
class Test {
|
||||
function : Main(args : String[]) ~ Nil {
|
||||
tree := AVLTree->New();
|
||||
|
||||
"Inserting values 1 to 10"->PrintLine();
|
||||
for(i := 1; i < 10; i+=1;) {
|
||||
tree->Insert(i);
|
||||
};
|
||||
|
||||
"Printing balance: "->Print();
|
||||
tree->PrintBalance();
|
||||
}
|
||||
}
|
||||
194
Task/AVL-tree/Objective-C/avl-tree.m
Normal file
194
Task/AVL-tree/Objective-C/avl-tree.m
Normal file
|
|
@ -0,0 +1,194 @@
|
|||
@implementation AVLTree
|
||||
|
||||
-(BOOL)insertWithKey:(NSInteger)key {
|
||||
|
||||
if (self.root == nil) {
|
||||
self.root = [[AVLTreeNode alloc]initWithKey:key andParent:nil];
|
||||
} else {
|
||||
|
||||
AVLTreeNode *n = self.root;
|
||||
AVLTreeNode *parent;
|
||||
|
||||
while (true) {
|
||||
|
||||
if (n.key == key) {
|
||||
return false;
|
||||
}
|
||||
|
||||
parent = n;
|
||||
|
||||
BOOL goLeft = n.key > key;
|
||||
n = goLeft ? n.left : n.right;
|
||||
|
||||
if (n == nil) {
|
||||
|
||||
if (goLeft) {
|
||||
parent.left = [[AVLTreeNode alloc]initWithKey:key andParent:parent];
|
||||
} else {
|
||||
parent.right = [[AVLTreeNode alloc]initWithKey:key andParent:parent];
|
||||
}
|
||||
[self rebalanceStartingAtNode:parent];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
-(void)rebalanceStartingAtNode:(AVLTreeNode*)n {
|
||||
|
||||
[self setBalance:@[n]];
|
||||
|
||||
if (n.balance == -2) {
|
||||
if ([self height:(n.left.left)] >= [self height:n.left.right]) {
|
||||
n = [self rotateRight:n];
|
||||
} else {
|
||||
n = [self rotateLeftThenRight:n];
|
||||
}
|
||||
} else if (n.balance == 2) {
|
||||
if ([self height:n.right.right] >= [self height:n.right.left]) {
|
||||
n = [self rotateLeft:n];
|
||||
} else {
|
||||
n = [self rotateRightThenLeft:n];
|
||||
}
|
||||
}
|
||||
|
||||
if (n.parent != nil) {
|
||||
[self rebalanceStartingAtNode:n.parent];
|
||||
} else {
|
||||
self.root = n;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
-(AVLTreeNode*)rotateRight:(AVLTreeNode*)a {
|
||||
|
||||
AVLTreeNode *b = a.left;
|
||||
b.parent = a.parent;
|
||||
|
||||
a.left = b.right;
|
||||
|
||||
if (a.left != nil) {
|
||||
a.left.parent = a;
|
||||
}
|
||||
|
||||
b.right = a;
|
||||
a.parent = b;
|
||||
|
||||
if (b.parent != nil) {
|
||||
if (b.parent.right == a) {
|
||||
b.parent.right = b;
|
||||
} else {
|
||||
b.parent.left = b;
|
||||
}
|
||||
}
|
||||
|
||||
[self setBalance:@[a,b]];
|
||||
return b;
|
||||
|
||||
}
|
||||
|
||||
-(AVLTreeNode*)rotateLeftThenRight:(AVLTreeNode*)n {
|
||||
|
||||
n.left = [self rotateLeft:n.left];
|
||||
return [self rotateRight:n];
|
||||
|
||||
}
|
||||
|
||||
-(AVLTreeNode*)rotateRightThenLeft:(AVLTreeNode*)n {
|
||||
|
||||
n.right = [self rotateRight:n.right];
|
||||
return [self rotateLeft:n];
|
||||
}
|
||||
|
||||
-(AVLTreeNode*)rotateLeft:(AVLTreeNode*)a {
|
||||
|
||||
//set a's right node as b
|
||||
AVLTreeNode* b = a.right;
|
||||
//set b's parent as a's parent (which could be nil)
|
||||
b.parent = a.parent;
|
||||
//in case b had a left child transfer it to a
|
||||
a.right = b.left;
|
||||
|
||||
// after changing a's reference to the right child, make sure the parent is set too
|
||||
if (a.right != nil) {
|
||||
a.right.parent = a;
|
||||
}
|
||||
|
||||
// switch a over to the left to be b's left child
|
||||
b.left = a;
|
||||
a.parent = b;
|
||||
|
||||
if (b.parent != nil) {
|
||||
if (b.parent.right == a) {
|
||||
b.parent.right = b;
|
||||
} else {
|
||||
b.parent.right = b;
|
||||
}
|
||||
}
|
||||
|
||||
[self setBalance:@[a,b]];
|
||||
|
||||
return b;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
-(void) setBalance:(NSArray*)nodesArray {
|
||||
|
||||
for (AVLTreeNode* n in nodesArray) {
|
||||
|
||||
n.balance = [self height:n.right] - [self height:n.left];
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
-(int)height:(AVLTreeNode*)n {
|
||||
|
||||
if (n == nil) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 1 + MAX([self height:n.left], [self height:n.right]);
|
||||
}
|
||||
|
||||
-(void)printKey:(AVLTreeNode*)n {
|
||||
if (n != nil) {
|
||||
[self printKey:n.left];
|
||||
NSLog(@"%ld", n.key);
|
||||
[self printKey:n.right];
|
||||
}
|
||||
}
|
||||
|
||||
-(void)printBalance:(AVLTreeNode*)n {
|
||||
if (n != nil) {
|
||||
[self printBalance:n.left];
|
||||
NSLog(@"%ld", n.balance);
|
||||
[self printBalance:n.right];
|
||||
}
|
||||
}
|
||||
@end
|
||||
-- test
|
||||
|
||||
int main(int argc, const char * argv[]) {
|
||||
@autoreleasepool {
|
||||
|
||||
AVLTree *tree = [AVLTree new];
|
||||
NSLog(@"inserting values 1 to 6");
|
||||
[tree insertWithKey:1];
|
||||
[tree insertWithKey:2];
|
||||
[tree insertWithKey:3];
|
||||
[tree insertWithKey:4];
|
||||
[tree insertWithKey:5];
|
||||
[tree insertWithKey:6];
|
||||
|
||||
NSLog(@"printing balance: ");
|
||||
[tree printBalance:tree.root];
|
||||
|
||||
NSLog(@"printing key: ");
|
||||
[tree printKey:tree.root];
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
136
Task/AVL-tree/Phix/avl-tree.phix
Normal file
136
Task/AVL-tree/Phix/avl-tree.phix
Normal file
|
|
@ -0,0 +1,136 @@
|
|||
(phixonline)-->
|
||||
<span style="color: #008080;">with</span> <span style="color: #008080;">javascript_semantics</span>
|
||||
<span style="color: #008080;">enum</span> <span style="color: #000000;">KEY</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">0</span><span style="color: #0000FF;">,</span>
|
||||
<span style="color: #000000;">LEFT</span><span style="color: #0000FF;">,</span>
|
||||
<span style="color: #000000;">HEIGHT</span><span style="color: #0000FF;">,</span> <span style="color: #000080;font-style:italic;">-- (NB +/-1 gives LEFT or RIGHT)</span>
|
||||
<span style="color: #000000;">RIGHT</span>
|
||||
|
||||
<span style="color: #004080;">sequence</span> <span style="color: #000000;">tree</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">{}</span>
|
||||
<span style="color: #004080;">integer</span> <span style="color: #000000;">freelist</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">0</span>
|
||||
|
||||
<span style="color: #008080;">function</span> <span style="color: #000000;">newNode</span><span style="color: #0000FF;">(</span><span style="color: #004080;">object</span> <span style="color: #000000;">key</span><span style="color: #0000FF;">)</span>
|
||||
<span style="color: #004080;">integer</span> <span style="color: #000000;">node</span>
|
||||
<span style="color: #008080;">if</span> <span style="color: #000000;">freelist</span><span style="color: #0000FF;">=</span><span style="color: #000000;">0</span> <span style="color: #008080;">then</span>
|
||||
<span style="color: #000000;">node</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">tree</span><span style="color: #0000FF;">)+</span><span style="color: #000000;">1</span>
|
||||
<span style="color: #000000;">tree</span> <span style="color: #0000FF;">&=</span> <span style="color: #0000FF;">{</span><span style="color: #000000;">key</span><span style="color: #0000FF;">,</span><span style="color: #004600;">NULL</span><span style="color: #0000FF;">,</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #004600;">NULL</span><span style="color: #0000FF;">}</span>
|
||||
<span style="color: #008080;">else</span>
|
||||
<span style="color: #000000;">node</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">freelist</span>
|
||||
<span style="color: #000000;">freelist</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">tree</span><span style="color: #0000FF;">[</span><span style="color: #000000;">freelist</span><span style="color: #0000FF;">]</span>
|
||||
<span style="color: #000000;">tree</span><span style="color: #0000FF;">[</span><span style="color: #000000;">node</span><span style="color: #0000FF;">+</span><span style="color: #000000;">KEY</span><span style="color: #0000FF;">..</span><span style="color: #000000;">node</span><span style="color: #0000FF;">+</span><span style="color: #000000;">RIGHT</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">{</span><span style="color: #000000;">key</span><span style="color: #0000FF;">,</span><span style="color: #004600;">NULL</span><span style="color: #0000FF;">,</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #004600;">NULL</span><span style="color: #0000FF;">}</span>
|
||||
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
|
||||
<span style="color: #008080;">return</span> <span style="color: #000000;">node</span>
|
||||
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span>
|
||||
|
||||
<span style="color: #008080;">function</span> <span style="color: #000000;">height</span><span style="color: #0000FF;">(</span><span style="color: #004080;">integer</span> <span style="color: #000000;">node</span><span style="color: #0000FF;">)</span>
|
||||
<span style="color: #008080;">return</span> <span style="color: #008080;">iff</span><span style="color: #0000FF;">(</span><span style="color: #000000;">node</span><span style="color: #0000FF;">=</span><span style="color: #004600;">NULL</span><span style="color: #0000FF;">?</span><span style="color: #000000;">0</span><span style="color: #0000FF;">:</span><span style="color: #000000;">tree</span><span style="color: #0000FF;">[</span><span style="color: #000000;">node</span><span style="color: #0000FF;">+</span><span style="color: #000000;">HEIGHT</span><span style="color: #0000FF;">])</span>
|
||||
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span>
|
||||
|
||||
<span style="color: #008080;">procedure</span> <span style="color: #000000;">setHeight</span><span style="color: #0000FF;">(</span><span style="color: #004080;">integer</span> <span style="color: #000000;">node</span><span style="color: #0000FF;">)</span>
|
||||
<span style="color: #000000;">tree</span><span style="color: #0000FF;">[</span><span style="color: #000000;">node</span><span style="color: #0000FF;">+</span><span style="color: #000000;">HEIGHT</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">max</span><span style="color: #0000FF;">(</span><span style="color: #000000;">height</span><span style="color: #0000FF;">(</span><span style="color: #000000;">tree</span><span style="color: #0000FF;">[</span><span style="color: #000000;">node</span><span style="color: #0000FF;">+</span><span style="color: #000000;">LEFT</span><span style="color: #0000FF;">]),</span> <span style="color: #000000;">height</span><span style="color: #0000FF;">(</span><span style="color: #000000;">tree</span><span style="color: #0000FF;">[</span><span style="color: #000000;">node</span><span style="color: #0000FF;">+</span><span style="color: #000000;">RIGHT</span><span style="color: #0000FF;">]))+</span><span style="color: #000000;">1</span>
|
||||
<span style="color: #008080;">end</span> <span style="color: #008080;">procedure</span>
|
||||
|
||||
<span style="color: #008080;">function</span> <span style="color: #000000;">rotate</span><span style="color: #0000FF;">(</span><span style="color: #004080;">integer</span> <span style="color: #000000;">node</span><span style="color: #0000FF;">,</span> <span style="color: #004080;">integer</span> <span style="color: #000000;">direction</span><span style="color: #0000FF;">)</span>
|
||||
<span style="color: #004080;">integer</span> <span style="color: #000000;">idirection</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">LEFT</span><span style="color: #0000FF;">+</span><span style="color: #000000;">RIGHT</span><span style="color: #0000FF;">-</span><span style="color: #000000;">direction</span>
|
||||
<span style="color: #004080;">integer</span> <span style="color: #000000;">pivot</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">tree</span><span style="color: #0000FF;">[</span><span style="color: #000000;">node</span><span style="color: #0000FF;">+</span><span style="color: #000000;">idirection</span><span style="color: #0000FF;">]</span>
|
||||
<span style="color: #0000FF;">{</span><span style="color: #000000;">tree</span><span style="color: #0000FF;">[</span><span style="color: #000000;">pivot</span><span style="color: #0000FF;">+</span><span style="color: #000000;">direction</span><span style="color: #0000FF;">],</span><span style="color: #000000;">tree</span><span style="color: #0000FF;">[</span><span style="color: #000000;">node</span><span style="color: #0000FF;">+</span><span style="color: #000000;">idirection</span><span style="color: #0000FF;">]}</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">{</span><span style="color: #000000;">node</span><span style="color: #0000FF;">,</span><span style="color: #000000;">tree</span><span style="color: #0000FF;">[</span><span style="color: #000000;">pivot</span><span style="color: #0000FF;">+</span><span style="color: #000000;">direction</span><span style="color: #0000FF;">]}</span>
|
||||
<span style="color: #000000;">setHeight</span><span style="color: #0000FF;">(</span><span style="color: #000000;">node</span><span style="color: #0000FF;">)</span>
|
||||
<span style="color: #000000;">setHeight</span><span style="color: #0000FF;">(</span><span style="color: #000000;">pivot</span><span style="color: #0000FF;">)</span>
|
||||
<span style="color: #008080;">return</span> <span style="color: #000000;">pivot</span>
|
||||
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span>
|
||||
|
||||
<span style="color: #008080;">function</span> <span style="color: #000000;">getBalance</span><span style="color: #0000FF;">(</span><span style="color: #004080;">integer</span> <span style="color: #000000;">N</span><span style="color: #0000FF;">)</span>
|
||||
<span style="color: #008080;">return</span> <span style="color: #008080;">iff</span><span style="color: #0000FF;">(</span><span style="color: #000000;">N</span><span style="color: #0000FF;">==</span><span style="color: #004600;">NULL</span> <span style="color: #0000FF;">?</span> <span style="color: #000000;">0</span> <span style="color: #0000FF;">:</span> <span style="color: #000000;">height</span><span style="color: #0000FF;">(</span><span style="color: #000000;">tree</span><span style="color: #0000FF;">[</span><span style="color: #000000;">N</span><span style="color: #0000FF;">+</span><span style="color: #000000;">LEFT</span><span style="color: #0000FF;">])-</span><span style="color: #000000;">height</span><span style="color: #0000FF;">(</span><span style="color: #000000;">tree</span><span style="color: #0000FF;">[</span><span style="color: #000000;">N</span><span style="color: #0000FF;">+</span><span style="color: #000000;">RIGHT</span><span style="color: #0000FF;">]))</span>
|
||||
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span>
|
||||
|
||||
<span style="color: #008080;">function</span> <span style="color: #000000;">insertNode</span><span style="color: #0000FF;">(</span><span style="color: #004080;">integer</span> <span style="color: #000000;">node</span><span style="color: #0000FF;">,</span> <span style="color: #004080;">object</span> <span style="color: #000000;">key</span><span style="color: #0000FF;">)</span>
|
||||
<span style="color: #008080;">if</span> <span style="color: #000000;">node</span><span style="color: #0000FF;">==</span><span style="color: #004600;">NULL</span> <span style="color: #008080;">then</span>
|
||||
<span style="color: #008080;">return</span> <span style="color: #000000;">newNode</span><span style="color: #0000FF;">(</span><span style="color: #000000;">key</span><span style="color: #0000FF;">)</span>
|
||||
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
|
||||
<span style="color: #004080;">integer</span> <span style="color: #000000;">c</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">compare</span><span style="color: #0000FF;">(</span><span style="color: #000000;">key</span><span style="color: #0000FF;">,</span><span style="color: #000000;">tree</span><span style="color: #0000FF;">[</span><span style="color: #000000;">node</span><span style="color: #0000FF;">+</span><span style="color: #000000;">KEY</span><span style="color: #0000FF;">])</span>
|
||||
<span style="color: #008080;">if</span> <span style="color: #000000;">c</span><span style="color: #0000FF;">!=</span><span style="color: #000000;">0</span> <span style="color: #008080;">then</span>
|
||||
<span style="color: #004080;">integer</span> <span style="color: #000000;">direction</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">HEIGHT</span><span style="color: #0000FF;">+</span><span style="color: #000000;">c</span> <span style="color: #000080;font-style:italic;">-- LEFT or RIGHT
|
||||
-- note this crashes under p2js... (easy to fix, not so easy to find)
|
||||
-- tree[node+direction] = insertNode(tree[node+direction], key)</span>
|
||||
<span style="color: #004080;">atom</span> <span style="color: #000000;">tnd</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">insertNode</span><span style="color: #0000FF;">(</span><span style="color: #000000;">tree</span><span style="color: #0000FF;">[</span><span style="color: #000000;">node</span><span style="color: #0000FF;">+</span><span style="color: #000000;">direction</span><span style="color: #0000FF;">],</span> <span style="color: #000000;">key</span><span style="color: #0000FF;">)</span>
|
||||
<span style="color: #000000;">tree</span><span style="color: #0000FF;">[</span><span style="color: #000000;">node</span><span style="color: #0000FF;">+</span><span style="color: #000000;">direction</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">tnd</span>
|
||||
<span style="color: #000000;">setHeight</span><span style="color: #0000FF;">(</span><span style="color: #000000;">node</span><span style="color: #0000FF;">)</span>
|
||||
<span style="color: #004080;">integer</span> <span style="color: #000000;">balance</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">trunc</span><span style="color: #0000FF;">(</span><span style="color: #000000;">getBalance</span><span style="color: #0000FF;">(</span><span style="color: #000000;">node</span><span style="color: #0000FF;">)/</span><span style="color: #000000;">2</span><span style="color: #0000FF;">)</span> <span style="color: #000080;font-style:italic;">-- +/-1 (or 0)</span>
|
||||
<span style="color: #008080;">if</span> <span style="color: #000000;">balance</span> <span style="color: #008080;">then</span>
|
||||
<span style="color: #000000;">direction</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">HEIGHT</span><span style="color: #0000FF;">-</span><span style="color: #000000;">balance</span> <span style="color: #000080;font-style:italic;">-- LEFT or RIGHT</span>
|
||||
<span style="color: #000000;">c</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">compare</span><span style="color: #0000FF;">(</span><span style="color: #000000;">key</span><span style="color: #0000FF;">,</span><span style="color: #000000;">tree</span><span style="color: #0000FF;">[</span><span style="color: #000000;">tree</span><span style="color: #0000FF;">[</span><span style="color: #000000;">node</span><span style="color: #0000FF;">+</span><span style="color: #000000;">direction</span><span style="color: #0000FF;">]+</span><span style="color: #000000;">KEY</span><span style="color: #0000FF;">])</span>
|
||||
<span style="color: #008080;">if</span> <span style="color: #000000;">c</span><span style="color: #0000FF;">=</span><span style="color: #000000;">balance</span> <span style="color: #008080;">then</span>
|
||||
<span style="color: #000000;">tree</span><span style="color: #0000FF;">[</span><span style="color: #000000;">node</span><span style="color: #0000FF;">+</span><span style="color: #000000;">direction</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">rotate</span><span style="color: #0000FF;">(</span><span style="color: #000000;">tree</span><span style="color: #0000FF;">[</span><span style="color: #000000;">node</span><span style="color: #0000FF;">+</span><span style="color: #000000;">direction</span><span style="color: #0000FF;">],</span><span style="color: #000000;">direction</span><span style="color: #0000FF;">)</span>
|
||||
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
|
||||
<span style="color: #008080;">if</span> <span style="color: #000000;">c</span><span style="color: #0000FF;">!=</span><span style="color: #000000;">0</span> <span style="color: #008080;">then</span>
|
||||
<span style="color: #000000;">node</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">rotate</span><span style="color: #0000FF;">(</span><span style="color: #000000;">node</span><span style="color: #0000FF;">,</span><span style="color: #000000;">LEFT</span><span style="color: #0000FF;">+</span><span style="color: #000000;">RIGHT</span><span style="color: #0000FF;">-</span><span style="color: #000000;">direction</span><span style="color: #0000FF;">)</span>
|
||||
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
|
||||
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
|
||||
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
|
||||
<span style="color: #008080;">return</span> <span style="color: #000000;">node</span>
|
||||
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span>
|
||||
|
||||
<span style="color: #008080;">function</span> <span style="color: #000000;">minValueNode</span><span style="color: #0000FF;">(</span><span style="color: #004080;">integer</span> <span style="color: #000000;">node</span><span style="color: #0000FF;">)</span>
|
||||
<span style="color: #008080;">while</span> <span style="color: #000000;">1</span> <span style="color: #008080;">do</span>
|
||||
<span style="color: #004080;">integer</span> <span style="color: #000000;">next</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">tree</span><span style="color: #0000FF;">[</span><span style="color: #000000;">node</span><span style="color: #0000FF;">+</span><span style="color: #000000;">LEFT</span><span style="color: #0000FF;">]</span>
|
||||
<span style="color: #008080;">if</span> <span style="color: #000000;">next</span><span style="color: #0000FF;">=</span><span style="color: #004600;">NULL</span> <span style="color: #008080;">then</span> <span style="color: #008080;">exit</span> <span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
|
||||
<span style="color: #000000;">node</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">next</span>
|
||||
<span style="color: #008080;">end</span> <span style="color: #008080;">while</span>
|
||||
<span style="color: #008080;">return</span> <span style="color: #000000;">node</span>
|
||||
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span>
|
||||
|
||||
<span style="color: #008080;">function</span> <span style="color: #000000;">deleteNode</span><span style="color: #0000FF;">(</span><span style="color: #004080;">integer</span> <span style="color: #000000;">root</span><span style="color: #0000FF;">,</span> <span style="color: #004080;">object</span> <span style="color: #000000;">key</span><span style="color: #0000FF;">)</span>
|
||||
<span style="color: #004080;">integer</span> <span style="color: #000000;">c</span>
|
||||
<span style="color: #008080;">if</span> <span style="color: #000000;">root</span><span style="color: #0000FF;">=</span><span style="color: #004600;">NULL</span> <span style="color: #008080;">then</span> <span style="color: #008080;">return</span> <span style="color: #000000;">root</span> <span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
|
||||
<span style="color: #000000;">c</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">compare</span><span style="color: #0000FF;">(</span><span style="color: #000000;">key</span><span style="color: #0000FF;">,</span><span style="color: #000000;">tree</span><span style="color: #0000FF;">[</span><span style="color: #000000;">root</span><span style="color: #0000FF;">+</span><span style="color: #000000;">KEY</span><span style="color: #0000FF;">])</span>
|
||||
<span style="color: #008080;">if</span> <span style="color: #000000;">c</span><span style="color: #0000FF;">=-</span><span style="color: #000000;">1</span> <span style="color: #008080;">then</span>
|
||||
<span style="color: #000000;">tree</span><span style="color: #0000FF;">[</span><span style="color: #000000;">root</span><span style="color: #0000FF;">+</span><span style="color: #000000;">LEFT</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">deleteNode</span><span style="color: #0000FF;">(</span><span style="color: #000000;">tree</span><span style="color: #0000FF;">[</span><span style="color: #000000;">root</span><span style="color: #0000FF;">+</span><span style="color: #000000;">LEFT</span><span style="color: #0000FF;">],</span> <span style="color: #000000;">key</span><span style="color: #0000FF;">)</span>
|
||||
<span style="color: #008080;">elsif</span> <span style="color: #000000;">c</span><span style="color: #0000FF;">=+</span><span style="color: #000000;">1</span> <span style="color: #008080;">then</span>
|
||||
<span style="color: #000000;">tree</span><span style="color: #0000FF;">[</span><span style="color: #000000;">root</span><span style="color: #0000FF;">+</span><span style="color: #000000;">RIGHT</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">deleteNode</span><span style="color: #0000FF;">(</span><span style="color: #000000;">tree</span><span style="color: #0000FF;">[</span><span style="color: #000000;">root</span><span style="color: #0000FF;">+</span><span style="color: #000000;">RIGHT</span><span style="color: #0000FF;">],</span> <span style="color: #000000;">key</span><span style="color: #0000FF;">)</span>
|
||||
<span style="color: #008080;">elsif</span> <span style="color: #000000;">tree</span><span style="color: #0000FF;">[</span><span style="color: #000000;">root</span><span style="color: #0000FF;">+</span><span style="color: #000000;">LEFT</span><span style="color: #0000FF;">]==</span><span style="color: #004600;">NULL</span>
|
||||
<span style="color: #008080;">or</span> <span style="color: #000000;">tree</span><span style="color: #0000FF;">[</span><span style="color: #000000;">root</span><span style="color: #0000FF;">+</span><span style="color: #000000;">RIGHT</span><span style="color: #0000FF;">]==</span><span style="color: #004600;">NULL</span> <span style="color: #008080;">then</span>
|
||||
<span style="color: #004080;">integer</span> <span style="color: #000000;">temp</span> <span style="color: #0000FF;">=</span> <span style="color: #008080;">iff</span><span style="color: #0000FF;">(</span><span style="color: #000000;">tree</span><span style="color: #0000FF;">[</span><span style="color: #000000;">root</span><span style="color: #0000FF;">+</span><span style="color: #000000;">LEFT</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">?</span> <span style="color: #000000;">tree</span><span style="color: #0000FF;">[</span><span style="color: #000000;">root</span><span style="color: #0000FF;">+</span><span style="color: #000000;">LEFT</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">:</span> <span style="color: #000000;">tree</span><span style="color: #0000FF;">[</span><span style="color: #000000;">root</span><span style="color: #0000FF;">+</span><span style="color: #000000;">RIGHT</span><span style="color: #0000FF;">])</span>
|
||||
<span style="color: #008080;">if</span> <span style="color: #000000;">temp</span><span style="color: #0000FF;">==</span><span style="color: #004600;">NULL</span> <span style="color: #008080;">then</span> <span style="color: #000080;font-style:italic;">-- No child case</span>
|
||||
<span style="color: #0000FF;">{</span><span style="color: #000000;">temp</span><span style="color: #0000FF;">,</span><span style="color: #000000;">root</span><span style="color: #0000FF;">}</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">{</span><span style="color: #000000;">root</span><span style="color: #0000FF;">,</span><span style="color: #004600;">NULL</span><span style="color: #0000FF;">}</span>
|
||||
<span style="color: #008080;">else</span> <span style="color: #000080;font-style:italic;">-- One child case</span>
|
||||
<span style="color: #000000;">tree</span><span style="color: #0000FF;">[</span><span style="color: #000000;">root</span><span style="color: #0000FF;">+</span><span style="color: #000000;">KEY</span><span style="color: #0000FF;">..</span><span style="color: #000000;">root</span><span style="color: #0000FF;">+</span><span style="color: #000000;">RIGHT</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">tree</span><span style="color: #0000FF;">[</span><span style="color: #000000;">temp</span><span style="color: #0000FF;">+</span><span style="color: #000000;">KEY</span><span style="color: #0000FF;">..</span><span style="color: #000000;">temp</span><span style="color: #0000FF;">+</span><span style="color: #000000;">RIGHT</span><span style="color: #0000FF;">]</span>
|
||||
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
|
||||
<span style="color: #000000;">tree</span><span style="color: #0000FF;">[</span><span style="color: #000000;">temp</span><span style="color: #0000FF;">+</span><span style="color: #000000;">KEY</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">freelist</span>
|
||||
<span style="color: #000000;">freelist</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">temp</span>
|
||||
<span style="color: #008080;">else</span> <span style="color: #000080;font-style:italic;">-- Two child case</span>
|
||||
<span style="color: #004080;">integer</span> <span style="color: #000000;">temp</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">minValueNode</span><span style="color: #0000FF;">(</span><span style="color: #000000;">tree</span><span style="color: #0000FF;">[</span><span style="color: #000000;">root</span><span style="color: #0000FF;">+</span><span style="color: #000000;">RIGHT</span><span style="color: #0000FF;">])</span>
|
||||
<span style="color: #000000;">tree</span><span style="color: #0000FF;">[</span><span style="color: #000000;">root</span><span style="color: #0000FF;">+</span><span style="color: #000000;">KEY</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">tree</span><span style="color: #0000FF;">[</span><span style="color: #000000;">temp</span><span style="color: #0000FF;">+</span><span style="color: #000000;">KEY</span><span style="color: #0000FF;">]</span>
|
||||
<span style="color: #000000;">tree</span><span style="color: #0000FF;">[</span><span style="color: #000000;">root</span><span style="color: #0000FF;">+</span><span style="color: #000000;">RIGHT</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">deleteNode</span><span style="color: #0000FF;">(</span><span style="color: #000000;">tree</span><span style="color: #0000FF;">[</span><span style="color: #000000;">root</span><span style="color: #0000FF;">+</span><span style="color: #000000;">RIGHT</span><span style="color: #0000FF;">],</span> <span style="color: #000000;">tree</span><span style="color: #0000FF;">[</span><span style="color: #000000;">temp</span><span style="color: #0000FF;">+</span><span style="color: #000000;">KEY</span><span style="color: #0000FF;">])</span>
|
||||
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
|
||||
<span style="color: #008080;">if</span> <span style="color: #000000;">root</span><span style="color: #0000FF;">=</span><span style="color: #004600;">NULL</span> <span style="color: #008080;">then</span> <span style="color: #008080;">return</span> <span style="color: #000000;">root</span> <span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
|
||||
<span style="color: #000000;">setHeight</span><span style="color: #0000FF;">(</span><span style="color: #000000;">root</span><span style="color: #0000FF;">)</span>
|
||||
<span style="color: #004080;">integer</span> <span style="color: #000000;">balance</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">trunc</span><span style="color: #0000FF;">(</span><span style="color: #000000;">getBalance</span><span style="color: #0000FF;">(</span><span style="color: #000000;">root</span><span style="color: #0000FF;">)/</span><span style="color: #000000;">2</span><span style="color: #0000FF;">)</span>
|
||||
<span style="color: #008080;">if</span> <span style="color: #000000;">balance</span> <span style="color: #008080;">then</span>
|
||||
<span style="color: #004080;">integer</span> <span style="color: #000000;">direction</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">HEIGHT</span><span style="color: #0000FF;">-</span><span style="color: #000000;">balance</span>
|
||||
<span style="color: #000000;">c</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">compare</span><span style="color: #0000FF;">(</span><span style="color: #000000;">getBalance</span><span style="color: #0000FF;">(</span><span style="color: #000000;">tree</span><span style="color: #0000FF;">[</span><span style="color: #000000;">root</span><span style="color: #0000FF;">+</span><span style="color: #000000;">direction</span><span style="color: #0000FF;">]),</span><span style="color: #000000;">0</span><span style="color: #0000FF;">)</span>
|
||||
<span style="color: #008080;">if</span> <span style="color: #000000;">c</span><span style="color: #0000FF;">=-</span><span style="color: #000000;">balance</span> <span style="color: #008080;">then</span>
|
||||
<span style="color: #000000;">tree</span><span style="color: #0000FF;">[</span><span style="color: #000000;">root</span><span style="color: #0000FF;">+</span><span style="color: #000000;">direction</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">rotate</span><span style="color: #0000FF;">(</span><span style="color: #000000;">tree</span><span style="color: #0000FF;">[</span><span style="color: #000000;">root</span><span style="color: #0000FF;">+</span><span style="color: #000000;">direction</span><span style="color: #0000FF;">],</span><span style="color: #000000;">direction</span><span style="color: #0000FF;">)</span>
|
||||
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
|
||||
<span style="color: #000000;">root</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">rotate</span><span style="color: #0000FF;">(</span><span style="color: #000000;">root</span><span style="color: #0000FF;">,</span><span style="color: #000000;">LEFT</span><span style="color: #0000FF;">+</span><span style="color: #000000;">RIGHT</span><span style="color: #0000FF;">-</span><span style="color: #000000;">direction</span><span style="color: #0000FF;">)</span>
|
||||
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
|
||||
<span style="color: #008080;">return</span> <span style="color: #000000;">root</span>
|
||||
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span>
|
||||
|
||||
<span style="color: #008080;">procedure</span> <span style="color: #000000;">inOrder</span><span style="color: #0000FF;">(</span><span style="color: #004080;">integer</span> <span style="color: #000000;">node</span><span style="color: #0000FF;">)</span>
|
||||
<span style="color: #008080;">if</span> <span style="color: #000000;">node</span><span style="color: #0000FF;">!=</span><span style="color: #004600;">NULL</span> <span style="color: #008080;">then</span>
|
||||
<span style="color: #000000;">inOrder</span><span style="color: #0000FF;">(</span><span style="color: #000000;">tree</span><span style="color: #0000FF;">[</span><span style="color: #000000;">node</span><span style="color: #0000FF;">+</span><span style="color: #000000;">LEFT</span><span style="color: #0000FF;">])</span>
|
||||
<span style="color: #7060A8;">printf</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span> <span style="color: #008000;">"%d "</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">tree</span><span style="color: #0000FF;">[</span><span style="color: #000000;">node</span><span style="color: #0000FF;">+</span><span style="color: #000000;">KEY</span><span style="color: #0000FF;">])</span>
|
||||
<span style="color: #000000;">inOrder</span><span style="color: #0000FF;">(</span><span style="color: #000000;">tree</span><span style="color: #0000FF;">[</span><span style="color: #000000;">node</span><span style="color: #0000FF;">+</span><span style="color: #000000;">RIGHT</span><span style="color: #0000FF;">])</span>
|
||||
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
|
||||
<span style="color: #008080;">end</span> <span style="color: #008080;">procedure</span>
|
||||
|
||||
<span style="color: #004080;">integer</span> <span style="color: #000000;">root</span> <span style="color: #0000FF;">=</span> <span style="color: #004600;">NULL</span>
|
||||
<span style="color: #004080;">sequence</span> <span style="color: #000000;">test</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">shuffle</span><span style="color: #0000FF;">(</span><span style="color: #7060A8;">tagset</span><span style="color: #0000FF;">(</span><span style="color: #000000;">50003</span><span style="color: #0000FF;">))</span>
|
||||
<span style="color: #008080;">for</span> <span style="color: #000000;">i</span><span style="color: #0000FF;">=</span><span style="color: #000000;">1</span> <span style="color: #008080;">to</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">test</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">do</span>
|
||||
<span style="color: #000000;">root</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">insertNode</span><span style="color: #0000FF;">(</span><span style="color: #000000;">root</span><span style="color: #0000FF;">,</span><span style="color: #000000;">test</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">])</span>
|
||||
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
|
||||
<span style="color: #000000;">test</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">shuffle</span><span style="color: #0000FF;">(</span><span style="color: #7060A8;">tagset</span><span style="color: #0000FF;">(</span><span style="color: #000000;">50000</span><span style="color: #0000FF;">))</span>
|
||||
<span style="color: #008080;">for</span> <span style="color: #000000;">i</span><span style="color: #0000FF;">=</span><span style="color: #000000;">1</span> <span style="color: #008080;">to</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">test</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">do</span>
|
||||
<span style="color: #000000;">root</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">deleteNode</span><span style="color: #0000FF;">(</span><span style="color: #000000;">root</span><span style="color: #0000FF;">,</span><span style="color: #000000;">test</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">])</span>
|
||||
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
|
||||
<span style="color: #000000;">inOrder</span><span style="color: #0000FF;">(</span><span style="color: #000000;">root</span><span style="color: #0000FF;">)</span>
|
||||
<!--
|
||||
51
Task/AVL-tree/Picat/avl-tree.picat
Normal file
51
Task/AVL-tree/Picat/avl-tree.picat
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
main =>
|
||||
T = nil,
|
||||
foreach (X in 1..10)
|
||||
T := insert(X,T)
|
||||
end,
|
||||
output(T,0).
|
||||
|
||||
insert(X, nil) = {1,nil,X,nil}.
|
||||
insert(X, T@{H,L,V,R}) = Res =>
|
||||
if X < V then
|
||||
Res = rotate({H, insert(X,L) ,V,R})
|
||||
elseif X > V then
|
||||
Res = rotate({H,L,V, insert(X,R)})
|
||||
else
|
||||
Res = T
|
||||
end.
|
||||
|
||||
rotate(nil) = nil.
|
||||
rotate({H, {LH,LL,LV,LR}, V, R}) = Res,
|
||||
LH - height(R) > 1,
|
||||
height(LL) - height(LR) > 0
|
||||
=> % Left Left.
|
||||
Res = {LH,LL,LV, {depth(R,LR), LR,V,R}}.
|
||||
rotate({H,L,V, {RH,RL,RV,RR}}) = Res,
|
||||
RH - height(L) > 1,
|
||||
height(RR) - height(RL) > 0
|
||||
=> % Right Right.
|
||||
Res = {RH, {depth(L,RL),L,V,RL}, RV,RR}.
|
||||
rotate({H, {LH,LL,LV, {RH,RL,RV,RR}, V,R}}) = Res,
|
||||
LH - height(R) > 1
|
||||
=> % Left Right.
|
||||
Res = {H, {RH + 1, {LH - 1, LL, LV, RL}, RV, RR}, V, R}.
|
||||
rotate({H,L,V, {RH, {LH,LL,LV,LR},RV,RR}}) = Res,
|
||||
RH - height(L) > 1
|
||||
=> % Right Left.
|
||||
Res = {H,L,V, {LH+1, LL, LV, {RH-1, LR, RV, RR}}}.
|
||||
rotate({H,L,V,R}) = Res => % Re-weighting.
|
||||
L1 = rotate(L),
|
||||
R1 = rotate(R),
|
||||
Res = {depth(L1,R1), L1,V,R1}.
|
||||
|
||||
height(nil) = -1.
|
||||
height({H,_,_,_}) = H.
|
||||
|
||||
depth(A,B) = max(height(A), height(B)) + 1.
|
||||
|
||||
output(nil,Indent) => printf("%*w\n",Indent,nil).
|
||||
output({_,L,V,R},Indent) =>
|
||||
output(L,Indent+6),
|
||||
printf("%*w\n",Indent,V),
|
||||
output(R,Indent+6).
|
||||
1781
Task/AVL-tree/Python/avl-tree.py
Normal file
1781
Task/AVL-tree/Python/avl-tree.py
Normal file
File diff suppressed because it is too large
Load diff
281
Task/AVL-tree/Raku/avl-tree.raku
Normal file
281
Task/AVL-tree/Raku/avl-tree.raku
Normal file
|
|
@ -0,0 +1,281 @@
|
|||
class AVL-Tree {
|
||||
has $.root is rw = 0;
|
||||
|
||||
class Node {
|
||||
has $.key is rw = '';
|
||||
has $.parent is rw = 0;
|
||||
has $.data is rw = 0;
|
||||
has $.left is rw = 0;
|
||||
has $.right is rw = 0;
|
||||
has Int $.balance is rw = 0;
|
||||
has Int $.height is rw = 0;
|
||||
}
|
||||
|
||||
#=====================================================
|
||||
# public methods
|
||||
#=====================================================
|
||||
|
||||
#| returns a node object or 0 if not found
|
||||
method find($key) {
|
||||
return 0 if !$.root;
|
||||
self!find: $key, $.root;
|
||||
}
|
||||
|
||||
#| returns a list of tree keys
|
||||
method keys() {
|
||||
return () if !$.root;
|
||||
my @list;
|
||||
self!keys: $.root, @list;
|
||||
@list;
|
||||
}
|
||||
|
||||
#| returns a list of tree nodes
|
||||
method nodes() {
|
||||
return () if !$.root;
|
||||
my @list;
|
||||
self!nodes: $.root, @list;
|
||||
@list;
|
||||
}
|
||||
|
||||
#| insert a node key, optionally add data (the `parent` arg is for
|
||||
#| internal use only)
|
||||
method insert($key, :$data = 0, :$parent = 0,) {
|
||||
return $.root = Node.new: :$key, :$parent, :$data if !$.root;
|
||||
my $n = $.root;
|
||||
while True {
|
||||
return False if $n.key eq $key;
|
||||
my $parent = $n;
|
||||
my $goLeft = $n.key > $key;
|
||||
$n = $goLeft ?? $n.left !! $n.right;
|
||||
if !$n {
|
||||
if $goLeft {
|
||||
$parent.left = Node.new: :$key, :$parent, :$data;
|
||||
}
|
||||
else {
|
||||
$parent.right = Node.new: :$key, :$parent, :$data;
|
||||
}
|
||||
self!rebalance: $parent;
|
||||
last
|
||||
}
|
||||
}
|
||||
True
|
||||
}
|
||||
|
||||
#| delete one or more nodes by key
|
||||
method delete(*@del-key) {
|
||||
return if !$.root;
|
||||
for @del-key -> $del-key {
|
||||
my $child = $.root;
|
||||
while $child {
|
||||
my $node = $child;
|
||||
$child = $del-key >= $node.key ?? $node.right !! $node.left;
|
||||
if $del-key eq $node.key {
|
||||
self!delete: $node;
|
||||
next;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#| show a list of all nodes by key
|
||||
method show-keys {
|
||||
self!show-keys: $.root;
|
||||
say()
|
||||
}
|
||||
|
||||
#| show a list of all nodes' balances (not normally needed)
|
||||
method show-balances {
|
||||
self!show-balances: $.root;
|
||||
say()
|
||||
}
|
||||
|
||||
#=====================================================
|
||||
# private methods
|
||||
#=====================================================
|
||||
|
||||
method !delete($node) {
|
||||
if !$node.left && !$node.right {
|
||||
if !$node.parent {
|
||||
$.root = 0;
|
||||
}
|
||||
else {
|
||||
my $parent = $node.parent;
|
||||
if $parent.left === $node {
|
||||
$parent.left = 0;
|
||||
}
|
||||
else {
|
||||
$parent.right = 0;
|
||||
}
|
||||
self!rebalance: $parent;
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
if $node.left {
|
||||
my $child = $node.left;
|
||||
while $child.right {
|
||||
$child = $child.right;
|
||||
}
|
||||
$node.key = $child.key;
|
||||
self!delete: $child;
|
||||
}
|
||||
else {
|
||||
my $child = $node.right;
|
||||
while $child.left {
|
||||
$child = $child.left;
|
||||
}
|
||||
$node.key = $child.key;
|
||||
self!delete: $child;
|
||||
}
|
||||
}
|
||||
|
||||
method !rebalance($n is copy) {
|
||||
self!set-balance: $n;
|
||||
|
||||
if $n.balance == -2 {
|
||||
if self!height($n.left.left) >= self!height($n.left.right) {
|
||||
$n = self!rotate-right: $n;
|
||||
}
|
||||
else {
|
||||
$n = self!rotate-left'right: $n;
|
||||
}
|
||||
}
|
||||
elsif $n.balance == 2 {
|
||||
if self!height($n.right.right) >= self!height($n.right.left) {
|
||||
$n = self!rotate-left: $n;
|
||||
}
|
||||
else {
|
||||
$n = self!rotate-right'left: $n;
|
||||
}
|
||||
}
|
||||
|
||||
if $n.parent {
|
||||
self!rebalance: $n.parent;
|
||||
}
|
||||
else {
|
||||
$.root = $n;
|
||||
}
|
||||
}
|
||||
|
||||
method !rotate-left($a) {
|
||||
|
||||
my $b = $a.right;
|
||||
$b.parent = $a.parent;
|
||||
|
||||
$a.right = $b.left;
|
||||
|
||||
if $a.right {
|
||||
$a.right.parent = $a;
|
||||
}
|
||||
|
||||
$b.left = $a;
|
||||
$a.parent = $b;
|
||||
|
||||
if $b.parent {
|
||||
if $b.parent.right === $a {
|
||||
$b.parent.right = $b;
|
||||
}
|
||||
else {
|
||||
$b.parent.left = $b;
|
||||
}
|
||||
}
|
||||
|
||||
self!set-balance: $a, $b;
|
||||
$b;
|
||||
}
|
||||
|
||||
method !rotate-right($a) {
|
||||
|
||||
my $b = $a.left;
|
||||
$b.parent = $a.parent;
|
||||
|
||||
$a.left = $b.right;
|
||||
|
||||
if $a.left {
|
||||
$a.left.parent = $a;
|
||||
}
|
||||
|
||||
$b.right = $a;
|
||||
$a.parent = $b;
|
||||
|
||||
if $b.parent {
|
||||
if $b.parent.right === $a {
|
||||
$b.parent.right = $b;
|
||||
}
|
||||
else {
|
||||
$b.parent.left = $b;
|
||||
}
|
||||
}
|
||||
|
||||
self!set-balance: $a, $b;
|
||||
|
||||
$b;
|
||||
}
|
||||
|
||||
method !rotate-left'right($n) {
|
||||
$n.left = self!rotate-left: $n.left;
|
||||
self!rotate-right: $n;
|
||||
}
|
||||
|
||||
method !rotate-right'left($n) {
|
||||
$n.right = self!rotate-right: $n.right;
|
||||
self!rotate-left: $n;
|
||||
}
|
||||
|
||||
method !height($n) {
|
||||
$n ?? $n.height !! -1;
|
||||
}
|
||||
|
||||
method !set-balance(*@n) {
|
||||
for @n -> $n {
|
||||
self!reheight: $n;
|
||||
$n.balance = self!height($n.right) - self!height($n.left);
|
||||
}
|
||||
}
|
||||
|
||||
method !show-balances($n) {
|
||||
if $n {
|
||||
self!show-balances: $n.left;
|
||||
printf "%s ", $n.balance;
|
||||
self!show-balances: $n.right;
|
||||
}
|
||||
}
|
||||
|
||||
method !reheight($node) {
|
||||
if $node {
|
||||
$node.height = 1 + max self!height($node.left), self!height($node.right);
|
||||
}
|
||||
}
|
||||
|
||||
method !show-keys($n) {
|
||||
if $n {
|
||||
self!show-keys: $n.left;
|
||||
printf "%s ", $n.key;
|
||||
self!show-keys: $n.right;
|
||||
}
|
||||
}
|
||||
|
||||
method !nodes($n, @list) {
|
||||
if $n {
|
||||
self!nodes: $n.left, @list;
|
||||
@list.push: $n if $n;
|
||||
self!nodes: $n.right, @list;
|
||||
}
|
||||
}
|
||||
|
||||
method !keys($n, @list) {
|
||||
if $n {
|
||||
self!keys: $n.left, @list;
|
||||
@list.push: $n.key if $n;
|
||||
self!keys: $n.right, @list;
|
||||
}
|
||||
}
|
||||
|
||||
method !find($key, $n) {
|
||||
if $n {
|
||||
self!find: $key, $n.left;
|
||||
return $n if $n.key eq $key;
|
||||
self!find: $key, $n.right;
|
||||
}
|
||||
}
|
||||
}
|
||||
327
Task/AVL-tree/Scala/avl-tree.scala
Normal file
327
Task/AVL-tree/Scala/avl-tree.scala
Normal file
|
|
@ -0,0 +1,327 @@
|
|||
import scala.collection.mutable
|
||||
|
||||
class AVLTree[A](implicit val ordering: Ordering[A]) extends mutable.SortedSet[A] {
|
||||
|
||||
if (ordering eq null) throw new NullPointerException("ordering must not be null")
|
||||
|
||||
private var _root: AVLNode = _
|
||||
private var _size = 0
|
||||
|
||||
override def size: Int = _size
|
||||
|
||||
override def foreach[U](f: A => U): Unit = {
|
||||
val stack = mutable.Stack[AVLNode]()
|
||||
var current = root
|
||||
var done = false
|
||||
|
||||
while (!done) {
|
||||
if (current != null) {
|
||||
stack.push(current)
|
||||
current = current.left
|
||||
} else if (stack.nonEmpty) {
|
||||
current = stack.pop()
|
||||
f.apply(current.key)
|
||||
|
||||
current = current.right
|
||||
} else {
|
||||
done = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
def root: AVLNode = _root
|
||||
|
||||
override def isEmpty: Boolean = root == null
|
||||
|
||||
override def min[B >: A](implicit cmp: Ordering[B]): A = minNode().key
|
||||
|
||||
def minNode(): AVLNode = {
|
||||
if (root == null) throw new UnsupportedOperationException("empty tree")
|
||||
var node = root
|
||||
while (node.left != null) node = node.left
|
||||
node
|
||||
}
|
||||
|
||||
override def max[B >: A](implicit cmp: Ordering[B]): A = maxNode().key
|
||||
|
||||
def maxNode(): AVLNode = {
|
||||
if (root == null) throw new UnsupportedOperationException("empty tree")
|
||||
var node = root
|
||||
while (node.right != null) node = node.right
|
||||
node
|
||||
}
|
||||
|
||||
def next(node: AVLNode): Option[AVLNode] = {
|
||||
var successor = node
|
||||
if (successor != null) {
|
||||
if (successor.right != null) {
|
||||
successor = successor.right
|
||||
while (successor != null && successor.left != null) {
|
||||
successor = successor.left
|
||||
}
|
||||
} else {
|
||||
successor = node.parent
|
||||
var n = node
|
||||
while (successor != null && successor.right == n) {
|
||||
n = successor
|
||||
successor = successor.parent
|
||||
}
|
||||
}
|
||||
}
|
||||
Option(successor)
|
||||
}
|
||||
|
||||
def prev(node: AVLNode): Option[AVLNode] = {
|
||||
var predecessor = node
|
||||
if (predecessor != null) {
|
||||
if (predecessor.left != null) {
|
||||
predecessor = predecessor.left
|
||||
while (predecessor != null && predecessor.right != null) {
|
||||
predecessor = predecessor.right
|
||||
}
|
||||
} else {
|
||||
predecessor = node.parent
|
||||
var n = node
|
||||
while (predecessor != null && predecessor.left == n) {
|
||||
n = predecessor
|
||||
predecessor = predecessor.parent
|
||||
}
|
||||
}
|
||||
}
|
||||
Option(predecessor)
|
||||
}
|
||||
|
||||
override def rangeImpl(from: Option[A], until: Option[A]): mutable.SortedSet[A] = ???
|
||||
|
||||
override def +=(key: A): AVLTree.this.type = {
|
||||
insert(key)
|
||||
this
|
||||
}
|
||||
|
||||
def insert(key: A): AVLNode = {
|
||||
if (root == null) {
|
||||
_root = new AVLNode(key)
|
||||
_size += 1
|
||||
return root
|
||||
}
|
||||
|
||||
var node = root
|
||||
var parent: AVLNode = null
|
||||
var cmp = 0
|
||||
|
||||
while (node != null) {
|
||||
parent = node
|
||||
cmp = ordering.compare(key, node.key)
|
||||
if (cmp == 0) return node // duplicate
|
||||
node = node.matchNextChild(cmp)
|
||||
}
|
||||
|
||||
val newNode = new AVLNode(key, parent)
|
||||
if (cmp <= 0) parent._left = newNode
|
||||
else parent._right = newNode
|
||||
|
||||
while (parent != null) {
|
||||
cmp = ordering.compare(parent.key, key)
|
||||
if (cmp < 0) parent.balanceFactor -= 1
|
||||
else parent.balanceFactor += 1
|
||||
|
||||
parent = parent.balanceFactor match {
|
||||
case -1 | 1 => parent.parent
|
||||
case x if x < -1 =>
|
||||
if (parent.right.balanceFactor == 1) rotateRight(parent.right)
|
||||
val newRoot = rotateLeft(parent)
|
||||
if (parent == root) _root = newRoot
|
||||
null
|
||||
case x if x > 1 =>
|
||||
if (parent.left.balanceFactor == -1) rotateLeft(parent.left)
|
||||
val newRoot = rotateRight(parent)
|
||||
if (parent == root) _root = newRoot
|
||||
null
|
||||
case _ => null
|
||||
}
|
||||
}
|
||||
|
||||
_size += 1
|
||||
newNode
|
||||
}
|
||||
|
||||
override def -=(key: A): AVLTree.this.type = {
|
||||
remove(key)
|
||||
this
|
||||
}
|
||||
|
||||
override def remove(key: A): Boolean = {
|
||||
var node = findNode(key).orNull
|
||||
if (node == null) return false
|
||||
|
||||
if (node.left != null) {
|
||||
var max = node.left
|
||||
|
||||
while (max.left != null || max.right != null) {
|
||||
while (max.right != null) max = max.right
|
||||
|
||||
node._key = max.key
|
||||
if (max.left != null) {
|
||||
node = max
|
||||
max = max.left
|
||||
}
|
||||
}
|
||||
node._key = max.key
|
||||
node = max
|
||||
}
|
||||
|
||||
if (node.right != null) {
|
||||
var min = node.right
|
||||
|
||||
while (min.left != null || min.right != null) {
|
||||
while (min.left != null) min = min.left
|
||||
|
||||
node._key = min.key
|
||||
if (min.right != null) {
|
||||
node = min
|
||||
min = min.right
|
||||
}
|
||||
}
|
||||
node._key = min.key
|
||||
node = min
|
||||
}
|
||||
|
||||
var current = node
|
||||
var parent = node.parent
|
||||
while (parent != null) {
|
||||
parent.balanceFactor += (if (parent.left == current) -1 else 1)
|
||||
|
||||
current = parent.balanceFactor match {
|
||||
case x if x < -1 =>
|
||||
if (parent.right.balanceFactor == 1) rotateRight(parent.right)
|
||||
val newRoot = rotateLeft(parent)
|
||||
if (parent == root) _root = newRoot
|
||||
newRoot
|
||||
case x if x > 1 =>
|
||||
if (parent.left.balanceFactor == -1) rotateLeft(parent.left)
|
||||
val newRoot = rotateRight(parent)
|
||||
if (parent == root) _root = newRoot
|
||||
newRoot
|
||||
case _ => parent
|
||||
}
|
||||
|
||||
parent = current.balanceFactor match {
|
||||
case -1 | 1 => null
|
||||
case _ => current.parent
|
||||
}
|
||||
}
|
||||
|
||||
if (node.parent != null) {
|
||||
if (node.parent.left == node) {
|
||||
node.parent._left = null
|
||||
} else {
|
||||
node.parent._right = null
|
||||
}
|
||||
}
|
||||
|
||||
if (node == root) _root = null
|
||||
|
||||
_size -= 1
|
||||
true
|
||||
}
|
||||
|
||||
def findNode(key: A): Option[AVLNode] = {
|
||||
var node = root
|
||||
while (node != null) {
|
||||
val cmp = ordering.compare(key, node.key)
|
||||
if (cmp == 0) return Some(node)
|
||||
node = node.matchNextChild(cmp)
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
private def rotateLeft(node: AVLNode): AVLNode = {
|
||||
val rightNode = node.right
|
||||
node._right = rightNode.left
|
||||
if (node.right != null) node.right._parent = node
|
||||
|
||||
rightNode._parent = node.parent
|
||||
if (rightNode.parent != null) {
|
||||
if (rightNode.parent.left == node) {
|
||||
rightNode.parent._left = rightNode
|
||||
} else {
|
||||
rightNode.parent._right = rightNode
|
||||
}
|
||||
}
|
||||
|
||||
node._parent = rightNode
|
||||
rightNode._left = node
|
||||
|
||||
node.balanceFactor += 1
|
||||
if (rightNode.balanceFactor < 0) {
|
||||
node.balanceFactor -= rightNode.balanceFactor
|
||||
}
|
||||
|
||||
rightNode.balanceFactor += 1
|
||||
if (node.balanceFactor > 0) {
|
||||
rightNode.balanceFactor += node.balanceFactor
|
||||
}
|
||||
rightNode
|
||||
}
|
||||
|
||||
private def rotateRight(node: AVLNode): AVLNode = {
|
||||
val leftNode = node.left
|
||||
node._left = leftNode.right
|
||||
if (node.left != null) node.left._parent = node
|
||||
|
||||
leftNode._parent = node.parent
|
||||
if (leftNode.parent != null) {
|
||||
if (leftNode.parent.left == node) {
|
||||
leftNode.parent._left = leftNode
|
||||
} else {
|
||||
leftNode.parent._right = leftNode
|
||||
}
|
||||
}
|
||||
|
||||
node._parent = leftNode
|
||||
leftNode._right = node
|
||||
|
||||
node.balanceFactor -= 1
|
||||
if (leftNode.balanceFactor > 0) {
|
||||
node.balanceFactor -= leftNode.balanceFactor
|
||||
}
|
||||
|
||||
leftNode.balanceFactor -= 1
|
||||
if (node.balanceFactor < 0) {
|
||||
leftNode.balanceFactor += node.balanceFactor
|
||||
}
|
||||
leftNode
|
||||
}
|
||||
|
||||
override def contains(elem: A): Boolean = findNode(elem).isDefined
|
||||
|
||||
override def iterator: Iterator[A] = ???
|
||||
|
||||
override def keysIteratorFrom(start: A): Iterator[A] = ???
|
||||
|
||||
class AVLNode private[AVLTree](k: A, p: AVLNode = null) {
|
||||
|
||||
private[AVLTree] var _key: A = k
|
||||
private[AVLTree] var _parent: AVLNode = p
|
||||
private[AVLTree] var _left: AVLNode = _
|
||||
private[AVLTree] var _right: AVLNode = _
|
||||
private[AVLTree] var balanceFactor: Int = 0
|
||||
|
||||
def parent: AVLNode = _parent
|
||||
|
||||
private[AVLTree] def selectNextChild(key: A): AVLNode = matchNextChild(ordering.compare(key, this.key))
|
||||
|
||||
def key: A = _key
|
||||
|
||||
private[AVLTree] def matchNextChild(cmp: Int): AVLNode = cmp match {
|
||||
case x if x < 0 => left
|
||||
case x if x > 0 => right
|
||||
case _ => null
|
||||
}
|
||||
|
||||
def left: AVLNode = _left
|
||||
|
||||
def right: AVLNode = _right
|
||||
}
|
||||
|
||||
}
|
||||
803
Task/AVL-tree/Scheme/avl-tree.ss
Normal file
803
Task/AVL-tree/Scheme/avl-tree.ss
Normal file
|
|
@ -0,0 +1,803 @@
|
|||
(cond-expand
|
||||
(r7rs)
|
||||
(chicken (import r7rs)))
|
||||
|
||||
(define-library (avl-trees)
|
||||
|
||||
;;
|
||||
;; This library implements ‘persistent’ (that is, ‘immutable’) AVL
|
||||
;; trees for R7RS Scheme.
|
||||
;;
|
||||
;; Included are generators of the key-data pairs in a tree. Because
|
||||
;; the trees are persistent (‘immutable’), these generators are safe
|
||||
;; from alterations of the tree.
|
||||
;;
|
||||
;; References:
|
||||
;;
|
||||
;; * Niklaus Wirth, 1976. Algorithms + Data Structures =
|
||||
;; Programs. Prentice-Hall, Englewood Cliffs, New Jersey.
|
||||
;;
|
||||
;; * Niklaus Wirth, 2004. Algorithms and Data Structures. Updated
|
||||
;; by Fyodor Tkachov, 2014.
|
||||
;;
|
||||
;; Note that the references do not discuss persistent
|
||||
;; implementations. It seems worthwhile to compare the methods of
|
||||
;; implementation.
|
||||
;;
|
||||
|
||||
(export avl)
|
||||
(export alist->avl)
|
||||
(export avl->alist)
|
||||
(export avl?)
|
||||
(export avl-empty?)
|
||||
(export avl-size)
|
||||
(export avl-insert)
|
||||
(export avl-delete)
|
||||
(export avl-delete-values)
|
||||
(export avl-has-key?)
|
||||
(export avl-search)
|
||||
(export avl-search-values)
|
||||
(export avl-make-generator)
|
||||
(export avl-pretty-print)
|
||||
(export avl-check-avl-condition)
|
||||
(export avl-check-usage)
|
||||
|
||||
(import (scheme base))
|
||||
(import (scheme case-lambda))
|
||||
(import (scheme process-context))
|
||||
(import (scheme write))
|
||||
|
||||
(cond-expand
|
||||
(chicken
|
||||
(import (only (chicken base) define-record-printer))
|
||||
(import (only (chicken format) format))) ; For debugging.
|
||||
(else))
|
||||
|
||||
(begin
|
||||
|
||||
;; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
;;
|
||||
;; Tools for making generators. These use call/cc and so might be
|
||||
;; inefficient in your Scheme. I am using CHICKEN, in which
|
||||
;; call/cc is not so inefficient.
|
||||
;;
|
||||
;; Often I have made &fail a unique object rather than #f, but in
|
||||
;; this case #f will suffice.
|
||||
;;
|
||||
|
||||
(define &fail #f)
|
||||
|
||||
(define *suspend*
|
||||
(make-parameter (lambda (x) x)))
|
||||
|
||||
(define (suspend v)
|
||||
((*suspend*) v))
|
||||
|
||||
(define (fail-forever)
|
||||
(let loop ()
|
||||
(suspend &fail)
|
||||
(loop)))
|
||||
|
||||
(define (make-generator-procedure thunk)
|
||||
;; Make a suspendable procedure that takes no arguments. The
|
||||
;; result is a simple generator of values. (This can be
|
||||
;; elaborated upon for generators to take values on resumption,
|
||||
;; in the manner of Icon co-expressions.)
|
||||
(define (next-run return)
|
||||
(define (my-suspend v)
|
||||
(set! return (call/cc (lambda (resumption-point)
|
||||
(set! next-run resumption-point)
|
||||
(return v)))))
|
||||
(parameterize ((*suspend* my-suspend))
|
||||
(suspend (thunk))
|
||||
(fail-forever)))
|
||||
(lambda () (call/cc next-run)))
|
||||
|
||||
;; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
||||
(define-syntax avl-check-usage
|
||||
(syntax-rules ()
|
||||
((_ pred msg)
|
||||
(or pred (usage-error msg)))))
|
||||
|
||||
;; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
||||
(define-record-type <avl>
|
||||
(%avl key data bal left right)
|
||||
avl?
|
||||
(key %key)
|
||||
(data %data)
|
||||
(bal %bal)
|
||||
(left %left)
|
||||
(right %right))
|
||||
|
||||
(cond-expand
|
||||
(chicken (define-record-printer (<avl> rt out)
|
||||
(display "#<avl " out)
|
||||
(display (%key rt) out)
|
||||
(display " " out)
|
||||
(display (%data rt) out)
|
||||
(display " " out)
|
||||
(display (%bal rt) out)
|
||||
(display " " out)
|
||||
(display (%left rt) out)
|
||||
(display " " out)
|
||||
(display (%right rt) out)
|
||||
(display ">" out)))
|
||||
(else))
|
||||
|
||||
;; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
||||
(define avl
|
||||
(case-lambda
|
||||
(() (%avl #f #f #f #f #f))
|
||||
((pred<? . args) (alist->avl pred<? args))))
|
||||
|
||||
(define (avl-empty? tree)
|
||||
(avl-check-usage
|
||||
(avl? tree)
|
||||
"avl-empty? expects an AVL tree as argument")
|
||||
(not (%bal tree)))
|
||||
|
||||
(define (avl-size tree)
|
||||
(define (traverse p sz)
|
||||
(if (not p)
|
||||
sz
|
||||
(traverse (%left p) (traverse (%right p) (+ sz 1)))))
|
||||
(if (avl-empty? tree)
|
||||
0
|
||||
(traverse tree 0)))
|
||||
|
||||
(define (avl-has-key? pred<? tree key)
|
||||
(define (search p)
|
||||
(and p
|
||||
(let ((k (%key p)))
|
||||
(cond ((pred<? key k) (search (%left p)))
|
||||
((pred<? k key) (search (%right p)))
|
||||
(else #t)))))
|
||||
(avl-check-usage
|
||||
(procedure? pred<?)
|
||||
"avl-has-key? expects a procedure as first argument")
|
||||
(and (not (avl-empty? tree))
|
||||
(search tree)))
|
||||
|
||||
(define (avl-search pred<? tree key)
|
||||
;; Return the data matching a key, or #f if the key is not
|
||||
;; found. (Note that the data matching the key might be #f.)
|
||||
(define (search p)
|
||||
(and p
|
||||
(let ((k (%key p)))
|
||||
(cond ((pred<? key k) (search (%left p)))
|
||||
((pred<? k key) (search (%right p)))
|
||||
(else (%data p))))))
|
||||
(avl-check-usage
|
||||
(procedure? pred<?)
|
||||
"avl-search expects a procedure as first argument")
|
||||
(and (not (avl-empty? tree))
|
||||
(search tree)))
|
||||
|
||||
(define (avl-search-values pred<? tree key)
|
||||
;; Return two values: the data matching the key, or #f is the
|
||||
;; key is not found; and a second value that is either #f or #t,
|
||||
;; depending on whether the key is found.
|
||||
(define (search p)
|
||||
(if (not p)
|
||||
(values #f #f)
|
||||
(let ((k (%key p)))
|
||||
(cond ((pred<? key k) (search (%left p)))
|
||||
((pred<? k key) (search (%right p)))
|
||||
(else (values (%data p) #t))))))
|
||||
(avl-check-usage
|
||||
(procedure? pred<?)
|
||||
"avl-search-values expects a procedure as first argument")
|
||||
(if (avl-empty? tree)
|
||||
(values #f #f)
|
||||
(search tree)))
|
||||
|
||||
(define (alist->avl pred<? alst)
|
||||
;; Go from association list to AVL tree.
|
||||
(avl-check-usage
|
||||
(procedure? pred<?)
|
||||
"alist->avl expects a procedure as first argument")
|
||||
(let loop ((tree (avl))
|
||||
(lst alst))
|
||||
(if (null? lst)
|
||||
tree
|
||||
(let ((head (car lst)))
|
||||
(loop (avl-insert pred<? tree (car head) (cdr head))
|
||||
(cdr lst))))))
|
||||
|
||||
(define (avl->alist tree)
|
||||
;; Go from AVL tree to association list. The output will be in
|
||||
;; order.
|
||||
(define (traverse p lst)
|
||||
;; Reverse in-order traversal of the tree, to produce an
|
||||
;; in-order cons-list.
|
||||
(if (not p)
|
||||
lst
|
||||
(traverse (%left p) (cons (cons (%key p) (%data p))
|
||||
(traverse (%right p) lst)))))
|
||||
(if (avl-empty? tree)
|
||||
'()
|
||||
(traverse tree '())))
|
||||
|
||||
(define (avl-insert pred<? tree key data)
|
||||
|
||||
(define (search p fix-balance?)
|
||||
(cond
|
||||
((not p)
|
||||
;; The key was not found. Make a new node and set
|
||||
;; fix-balance?
|
||||
(values (%avl key data 0 #f #f) #t))
|
||||
|
||||
((pred<? key (%key p))
|
||||
;; Continue searching.
|
||||
(let-values (((p1 fix-balance?)
|
||||
(search (%left p) fix-balance?)))
|
||||
(cond
|
||||
((not fix-balance?)
|
||||
(let ((p^ (%avl (%key p) (%data p) (%bal p)
|
||||
p1 (%right p))))
|
||||
(values p^ #f)))
|
||||
(else
|
||||
;; A new node has been inserted on the left side.
|
||||
(case (%bal p)
|
||||
((1)
|
||||
(let ((p^ (%avl (%key p) (%data p) 0
|
||||
p1 (%right p))))
|
||||
(values p^ #f)))
|
||||
((0)
|
||||
(let ((p^ (%avl (%key p) (%data p) -1
|
||||
p1 (%right p))))
|
||||
(values p^ fix-balance?)))
|
||||
((-1)
|
||||
;; Rebalance.
|
||||
(case (%bal p1)
|
||||
((-1)
|
||||
;; A single LL rotation.
|
||||
(let* ((p^ (%avl (%key p) (%data p) 0
|
||||
(%right p1) (%right p)))
|
||||
(p1^ (%avl (%key p1) (%data p1) 0
|
||||
(%left p1) p^)))
|
||||
(values p1^ #f)))
|
||||
((0 1)
|
||||
;; A double LR rotation.
|
||||
(let* ((p2 (%right p1))
|
||||
(bal2 (%bal p2))
|
||||
(p^ (%avl (%key p) (%data p)
|
||||
(- (min bal2 0))
|
||||
(%right p2) (%right p)))
|
||||
(p1^ (%avl (%key p1) (%data p1)
|
||||
(- (max bal2 0))
|
||||
(%left p1) (%left p2)))
|
||||
(p2^ (%avl (%key p2) (%data p2) 0
|
||||
p1^ p^)))
|
||||
(values p2^ #f)))
|
||||
(else (internal-error))))
|
||||
(else (internal-error)))))))
|
||||
|
||||
((pred<? (%key p) key)
|
||||
;; Continue searching.
|
||||
(let-values (((p1 fix-balance?)
|
||||
(search (%right p) fix-balance?)))
|
||||
(cond
|
||||
((not fix-balance?)
|
||||
(let ((p^ (%avl (%key p) (%data p) (%bal p)
|
||||
(%left p) p1)))
|
||||
(values p^ #f)))
|
||||
(else
|
||||
;; A new node has been inserted on the right side.
|
||||
(case (%bal p)
|
||||
((-1)
|
||||
(let ((p^ (%avl (%key p) (%data p) 0
|
||||
(%left p) p1)))
|
||||
(values p^ #f)))
|
||||
((0)
|
||||
(let ((p^ (%avl (%key p) (%data p) 1
|
||||
(%left p) p1)))
|
||||
(values p^ fix-balance?)))
|
||||
((1)
|
||||
;; Rebalance.
|
||||
(case (%bal p1)
|
||||
((1)
|
||||
;; A single RR rotation.
|
||||
(let* ((p^ (%avl (%key p) (%data p) 0
|
||||
(%left p) (%left p1)))
|
||||
(p1^ (%avl (%key p1) (%data p1) 0
|
||||
p^ (%right p1))))
|
||||
(values p1^ #f)))
|
||||
((-1 0)
|
||||
;; A double RL rotation.
|
||||
(let* ((p2 (%left p1))
|
||||
(bal2 (%bal p2))
|
||||
(p^ (%avl (%key p) (%data p)
|
||||
(- (max bal2 0))
|
||||
(%left p) (%left p2)))
|
||||
(p1^ (%avl (%key p1) (%data p1)
|
||||
(- (min bal2 0))
|
||||
(%right p2) (%right p1)))
|
||||
(p2^ (%avl (%key p2) (%data p2) 0
|
||||
p^ p1^)))
|
||||
(values p2^ #f)))
|
||||
(else (internal-error))))
|
||||
(else (internal-error)))))))
|
||||
|
||||
(else
|
||||
;; The key was found; p is an existing node.
|
||||
(values (%avl key data (%bal p) (%left p) (%right p))
|
||||
#f))))
|
||||
|
||||
(avl-check-usage
|
||||
(procedure? pred<?)
|
||||
"avl-insert expects a procedure as first argument")
|
||||
(if (avl-empty? tree)
|
||||
(%avl key data 0 #f #f)
|
||||
(let-values (((p fix-balance?) (search tree #f)))
|
||||
p)))
|
||||
|
||||
(define (avl-delete pred<? tree key)
|
||||
;; If one is not interested in whether the key was in the tree,
|
||||
;; then throw away that information.
|
||||
(let-values (((tree had-key?)
|
||||
(avl-delete-values pred<? tree key)))
|
||||
tree))
|
||||
|
||||
(define (balance-for-shrunken-left p)
|
||||
;; Returns two values: a new p and a new fix-balance?
|
||||
(case (%bal p)
|
||||
((-1) (values (%avl (%key p) (%data p) 0
|
||||
(%left p) (%right p))
|
||||
#t))
|
||||
((0) (values (%avl (%key p) (%data p) 1
|
||||
(%left p) (%right p))
|
||||
#f))
|
||||
((1)
|
||||
;; Rebalance.
|
||||
(let* ((p1 (%right p))
|
||||
(bal1 (%bal p1)))
|
||||
(case bal1
|
||||
((0)
|
||||
;; A single RR rotation.
|
||||
(let* ((p^ (%avl (%key p) (%data p) 1
|
||||
(%left p) (%left p1)))
|
||||
(p1^ (%avl (%key p1) (%data p1) -1
|
||||
p^ (%right p1))))
|
||||
(values p1^ #f)))
|
||||
((1)
|
||||
;; A single RR rotation.
|
||||
(let* ((p^ (%avl (%key p) (%data p) 0
|
||||
(%left p) (%left p1)))
|
||||
(p1^ (%avl (%key p1) (%data p1) 0
|
||||
p^ (%right p1))))
|
||||
(values p1^ #t)))
|
||||
((-1)
|
||||
;; A double RL rotation.
|
||||
(let* ((p2 (%left p1))
|
||||
(bal2 (%bal p2))
|
||||
(p^ (%avl (%key p) (%data p) (- (max bal2 0))
|
||||
(%left p) (%left p2)))
|
||||
(p1^ (%avl (%key p1) (%data p1) (- (min bal2 0))
|
||||
(%right p2) (%right p1)))
|
||||
(p2^ (%avl (%key p2) (%data p2) 0 p^ p1^)))
|
||||
(values p2^ #t)))
|
||||
(else (internal-error)))))
|
||||
(else (internal-error))))
|
||||
|
||||
(define (balance-for-shrunken-right p)
|
||||
;; Returns two values: a new p and a new fix-balance?
|
||||
(case (%bal p)
|
||||
((1) (values (%avl (%key p) (%data p) 0
|
||||
(%left p) (%right p))
|
||||
#t))
|
||||
((0) (values (%avl (%key p) (%data p) -1
|
||||
(%left p) (%right p))
|
||||
#f))
|
||||
((-1)
|
||||
;; Rebalance.
|
||||
(let* ((p1 (%left p))
|
||||
(bal1 (%bal p1)))
|
||||
(case bal1
|
||||
((0)
|
||||
;; A single LL rotation.
|
||||
(let* ((p^ (%avl (%key p) (%data p) -1
|
||||
(%right p1) (%right p)))
|
||||
(p1^ (%avl (%key p1) (%data p1) 1
|
||||
(%left p1) p^)))
|
||||
(values p1^ #f)))
|
||||
((-1)
|
||||
;; A single LL rotation.
|
||||
(let* ((p^ (%avl (%key p) (%data p) 0
|
||||
(%right p1) (%right p)))
|
||||
(p1^ (%avl (%key p1) (%data p1) 0
|
||||
(%left p1) p^)))
|
||||
(values p1^ #t)))
|
||||
((1)
|
||||
;; A double LR rotation.
|
||||
(let* ((p2 (%right p1))
|
||||
(bal2 (%bal p2))
|
||||
(p^ (%avl (%key p) (%data p) (- (min bal2 0))
|
||||
(%right p2) (%right p)))
|
||||
(p1^ (%avl (%key p1) (%data p1) (- (max bal2 0))
|
||||
(%left p1) (%left p2)))
|
||||
(p2^ (%avl (%key p2) (%data p2) 0 p1^ p^)))
|
||||
(values p2^ #t)))
|
||||
(else (internal-error)))))
|
||||
(else (internal-error))))
|
||||
|
||||
(define (avl-delete-values pred<? tree key)
|
||||
|
||||
(define-syntax balance-L
|
||||
(syntax-rules ()
|
||||
((_ p fix-balance?)
|
||||
(if fix-balance?
|
||||
(balance-for-shrunken-left p)
|
||||
(values p #f)))))
|
||||
|
||||
(define-syntax balance-R
|
||||
(syntax-rules ()
|
||||
((_ p fix-balance?)
|
||||
(if fix-balance?
|
||||
(balance-for-shrunken-right p)
|
||||
(values p #f)))))
|
||||
|
||||
(define (del r fix-balance?)
|
||||
;; Returns a new r, a new fix-balance?, and key and data to be
|
||||
;; ‘moved up the tree’.
|
||||
(if (%right r)
|
||||
(let*-values
|
||||
(((q fix-balance? key^ data^)
|
||||
(del (%right r) fix-balance?))
|
||||
((r fix-balance?)
|
||||
(balance-R (%avl (%key r) (%data r) (%bal r)
|
||||
(%left r) q)
|
||||
fix-balance?)))
|
||||
(values r fix-balance? key^ data^))
|
||||
(values (%left r) #t (%key r) (%data r))))
|
||||
|
||||
(define (search p fix-balance?)
|
||||
;; Return three values: a new p, a new fix-balance, and
|
||||
;; whether the key was found.
|
||||
(cond
|
||||
((not p) (values #f #f #f))
|
||||
((pred<? key (%key p))
|
||||
;; Recursive search down the left branch.
|
||||
(let*-values
|
||||
(((q fix-balance? found?)
|
||||
(search (%left p) fix-balance?))
|
||||
((p fix-balance?)
|
||||
(balance-L (%avl (%key p) (%data p) (%bal p)
|
||||
q (%right p))
|
||||
fix-balance?)))
|
||||
(values p fix-balance? found?)))
|
||||
((pred<? (%key p) key)
|
||||
;; Recursive search down the right branch.
|
||||
(let*-values
|
||||
(((q fix-balance? found?)
|
||||
(search (%right p) fix-balance?))
|
||||
((p fix-balance?)
|
||||
(balance-R (%avl (%key p) (%data p) (%bal p)
|
||||
(%left p) q)
|
||||
fix-balance?)))
|
||||
(values p fix-balance? found?)))
|
||||
((not (%right p))
|
||||
;; Delete p, replace it with its left branch, then
|
||||
;; rebalance.
|
||||
(values (%left p) #t #t))
|
||||
((not (%left p))
|
||||
;; Delete p, replace it with its right branch, then
|
||||
;; rebalance.
|
||||
(values (%right p) #t #t))
|
||||
(else
|
||||
;; Delete p, but it has both left and right branches,
|
||||
;; and therefore may have complicated branch structure.
|
||||
(let*-values
|
||||
(((q fix-balance? key^ data^)
|
||||
(del (%left p) fix-balance?))
|
||||
((p fix-balance?)
|
||||
(balance-L (%avl key^ data^ (%bal p) q (%right p))
|
||||
fix-balance?)))
|
||||
(values p fix-balance? #t)))))
|
||||
|
||||
(avl-check-usage
|
||||
(procedure? pred<?)
|
||||
"avl-delete-values expects a procedure as first argument")
|
||||
(if (avl-empty? tree)
|
||||
(values tree #f)
|
||||
(let-values (((tree fix-balance? found?)
|
||||
(search tree #f)))
|
||||
(if found?
|
||||
(values (or tree (avl)) #t)
|
||||
(values tree #f)))))
|
||||
|
||||
(define avl-make-generator
|
||||
(case-lambda
|
||||
((tree) (avl-make-generator tree 1))
|
||||
((tree direction)
|
||||
(if (negative? direction)
|
||||
(make-generator-procedure
|
||||
(lambda ()
|
||||
(define (traverse p)
|
||||
(unless (or (not p) (avl-empty? p))
|
||||
(traverse (%right p))
|
||||
(suspend (cons (%key p) (%data p)))
|
||||
(traverse (%left p)))
|
||||
&fail)
|
||||
(traverse tree)))
|
||||
(make-generator-procedure
|
||||
(lambda ()
|
||||
(define (traverse p)
|
||||
(unless (or (not p) (avl-empty? p))
|
||||
(traverse (%left p))
|
||||
(suspend (cons (%key p) (%data p)))
|
||||
(traverse (%right p)))
|
||||
&fail)
|
||||
(traverse tree)))))))
|
||||
|
||||
(define avl-pretty-print
|
||||
(case-lambda
|
||||
((tree)
|
||||
(avl-pretty-print tree (current-output-port)))
|
||||
((tree port)
|
||||
(avl-pretty-print tree port
|
||||
(lambda (port key data)
|
||||
(display "(" port)
|
||||
(write key port)
|
||||
(display ", " port)
|
||||
(write data port)
|
||||
(display ")" port))))
|
||||
((tree port key-data-printer)
|
||||
;; In-order traversal, so the printing is done in
|
||||
;; order. Reflect the display diagonally to get the more
|
||||
;; usual orientation of left-to-right, top-to-bottom.
|
||||
(define (pad depth)
|
||||
(unless (zero? depth)
|
||||
(display " " port)
|
||||
(pad (- depth 1))))
|
||||
(define (traverse p depth)
|
||||
(when p
|
||||
(traverse (%left p) (+ depth 1))
|
||||
(pad depth)
|
||||
(key-data-printer port (%key p) (%data p))
|
||||
(display "\t\tdepth = " port)
|
||||
(display depth port)
|
||||
(display " bal = " port)
|
||||
(display (%bal p) port)
|
||||
(display "\n" port)
|
||||
(traverse (%right p) (+ depth 1))))
|
||||
(unless (avl-empty? tree)
|
||||
(traverse (%left tree) 1)
|
||||
(key-data-printer port (%key tree) (%data tree))
|
||||
(display "\t\tdepth = 0 bal = " port)
|
||||
(display (%bal tree) port)
|
||||
(display "\n" port)
|
||||
(traverse (%right tree) 1)))))
|
||||
|
||||
(define (avl-check-avl-condition tree)
|
||||
;; Check that the AVL condition is satisfied.
|
||||
(define (check-heights height-L height-R)
|
||||
(when (<= 2 (abs (- height-L height-R)))
|
||||
(display "*** AVL condition violated ***"
|
||||
(current-error-port))
|
||||
(internal-error)))
|
||||
(define (get-heights p)
|
||||
(if (not p)
|
||||
(values 0 0)
|
||||
(let-values (((height-LL height-LR)
|
||||
(get-heights (%left p)))
|
||||
((height-RL height-RR)
|
||||
(get-heights (%right p))))
|
||||
(check-heights height-LL height-LR)
|
||||
(check-heights height-RL height-RR)
|
||||
(values (+ height-LL height-LR)
|
||||
(+ height-RL height-RR)))))
|
||||
(unless (avl-empty? tree)
|
||||
(let-values (((height-L height-R) (get-heights tree)))
|
||||
(check-heights height-L height-R))))
|
||||
|
||||
(define (internal-error)
|
||||
(display "internal error\n" (current-error-port))
|
||||
(emergency-exit 123))
|
||||
|
||||
(define (usage-error msg)
|
||||
(display "Procedure usage error:\n" (current-error-port))
|
||||
(display " " (current-error-port))
|
||||
(display msg (current-error-port))
|
||||
(newline (current-error-port))
|
||||
(exit 1))
|
||||
|
||||
)) ;; end library (avl-trees)
|
||||
|
||||
|
||||
(cond-expand
|
||||
(DEMONSTRATION
|
||||
(begin
|
||||
(import (avl-trees))
|
||||
(import (scheme base))
|
||||
(import (scheme time))
|
||||
(import (scheme process-context))
|
||||
(import (scheme write))
|
||||
|
||||
(cond-expand
|
||||
(chicken
|
||||
(import (only (chicken format) format))) ; For debugging.
|
||||
(else))
|
||||
|
||||
(define 2**64 (expt 2 64))
|
||||
|
||||
(define seed (truncate-remainder (exact (current-second)) 2**64))
|
||||
(define random
|
||||
;; A really slow (but presumably highly portable)
|
||||
;; implementation of Donald Knuth’s linear congruential random
|
||||
;; number generator, returning a rational number in [0,1). See
|
||||
;; https://en.wikipedia.org/w/index.php?title=Linear_congruential_generator&oldid=1076681286
|
||||
(let ((a 6364136223846793005)
|
||||
(c 1442695040888963407))
|
||||
(lambda ()
|
||||
(let ((result (/ seed 2**64)))
|
||||
(set! seed (truncate-remainder (+ (* a seed) c) 2**64))
|
||||
result))))
|
||||
(do ((i 0 (+ i 1)))
|
||||
((= i 10))
|
||||
(random))
|
||||
|
||||
(define (fisher-yates-shuffle keys)
|
||||
(let ((n (vector-length keys)))
|
||||
(do ((i 1 (+ i 1)))
|
||||
((= i n))
|
||||
(let* ((randnum (random))
|
||||
(j (+ i (floor (* randnum (- n i)))))
|
||||
(xi (vector-ref keys i))
|
||||
(xj (vector-ref keys j)))
|
||||
(vector-set! keys i xj)
|
||||
(vector-set! keys j xi)))))
|
||||
|
||||
(define (display-key-data key data)
|
||||
(display "(")
|
||||
(write key)
|
||||
(display ", ")
|
||||
(write data)
|
||||
(display ")"))
|
||||
|
||||
(define (display-tree-contents tree)
|
||||
(do ((p (avl->alist tree) (cdr p)))
|
||||
((null? p))
|
||||
(display-key-data (caar p) (cdar p))
|
||||
(newline)))
|
||||
|
||||
(define (error-stop)
|
||||
(display "*** ERROR STOP ***\n" (current-error-port))
|
||||
(emergency-exit 1))
|
||||
|
||||
(define n 20)
|
||||
(define keys (make-vector (+ n 1)))
|
||||
(do ((i 0 (+ i 1)))
|
||||
((= i n))
|
||||
;; To keep things more like Fortran, do not use index zero.
|
||||
(vector-set! keys (+ i 1) (+ i 1)))
|
||||
|
||||
(fisher-yates-shuffle keys)
|
||||
|
||||
;; Insert key-data pairs in the shuffled order.
|
||||
(define tree (avl))
|
||||
(avl-check-avl-condition tree)
|
||||
(do ((i 1 (+ i 1)))
|
||||
((= i (+ n 1)))
|
||||
(let ((ix (vector-ref keys i)))
|
||||
(set! tree (avl-insert < tree ix (inexact ix)))
|
||||
(avl-check-avl-condition tree)
|
||||
(do ((j 1 (+ j 1)))
|
||||
((= j (+ n 1)))
|
||||
(let*-values (((k) (vector-ref keys j))
|
||||
((has-key?) (avl-has-key? < tree k))
|
||||
((data) (avl-search < tree k))
|
||||
((data^ has-key?^)
|
||||
(avl-search-values < tree k)))
|
||||
(unless (exact? k) (error-stop))
|
||||
(if (<= j i)
|
||||
(unless (and has-key? data data^ has-key?^
|
||||
(inexact? data) (= data k)
|
||||
(inexact? data^) (= data^ k))
|
||||
(error-stop))
|
||||
(when (or has-key? data data^ has-key?^)
|
||||
(error-stop)))))))
|
||||
|
||||
(display "----------------------------------------------------------------------\n")
|
||||
(display "keys = ")
|
||||
(write (cdr (vector->list keys)))
|
||||
(newline)
|
||||
(display "----------------------------------------------------------------------\n")
|
||||
(avl-pretty-print tree)
|
||||
(display "----------------------------------------------------------------------\n")
|
||||
(display "tree size = ")
|
||||
(display (avl-size tree))
|
||||
(newline)
|
||||
(display-tree-contents tree)
|
||||
(display "----------------------------------------------------------------------\n")
|
||||
|
||||
;;
|
||||
;; Reshuffle the keys, and change the data from inexact numbers
|
||||
;; to strings.
|
||||
;;
|
||||
|
||||
(fisher-yates-shuffle keys)
|
||||
|
||||
(do ((i 1 (+ i 1)))
|
||||
((= i (+ n 1)))
|
||||
(let ((ix (vector-ref keys i)))
|
||||
(set! tree (avl-insert < tree ix (number->string ix)))
|
||||
(avl-check-avl-condition tree)))
|
||||
|
||||
(avl-pretty-print tree)
|
||||
(display "----------------------------------------------------------------------\n")
|
||||
(display "tree size = ")
|
||||
(display (avl-size tree))
|
||||
(newline)
|
||||
(display-tree-contents tree)
|
||||
(display "----------------------------------------------------------------------\n")
|
||||
|
||||
;;
|
||||
;; Reshuffle the keys, and delete the contents of the tree, but
|
||||
;; also keep the original tree by saving it in a variable. Check
|
||||
;; persistence of the tree.
|
||||
;;
|
||||
|
||||
(fisher-yates-shuffle keys)
|
||||
|
||||
(define saved-tree tree)
|
||||
|
||||
(do ((i 1 (+ i 1)))
|
||||
((= i (+ n 1)))
|
||||
(let ((ix (vector-ref keys i)))
|
||||
(set! tree (avl-delete < tree ix))
|
||||
(avl-check-avl-condition tree)
|
||||
(unless (= (avl-size tree) (- n i)) (error-stop))
|
||||
;; Try deleting a second time.
|
||||
(set! tree (avl-delete < tree ix))
|
||||
(avl-check-avl-condition tree)
|
||||
(unless (= (avl-size tree) (- n i)) (error-stop))
|
||||
(do ((j 1 (+ j 1)))
|
||||
((= j (+ n 1)))
|
||||
(let ((jx (vector-ref keys j)))
|
||||
(unless (eq? (avl-has-key? < tree jx) (< i j))
|
||||
(error-stop))
|
||||
(let ((data (avl-search < tree jx)))
|
||||
(unless (eq? (not (not data)) (< i j))
|
||||
(error-stop))
|
||||
(unless (or (not data)
|
||||
(= (string->number data) jx))
|
||||
(error-stop)))
|
||||
(let-values (((data found?)
|
||||
(avl-search-values < tree jx)))
|
||||
(unless (eq? found? (< i j)) (error-stop))
|
||||
(unless (or (and (not data) (<= j i))
|
||||
(and data (= (string->number data) jx)))
|
||||
(error-stop)))))))
|
||||
(do ((i 1 (+ i 1)))
|
||||
((= i (+ n 1)))
|
||||
;; Is save-tree the persistent value of the tree we just
|
||||
;; deleted?
|
||||
(let ((ix (vector-ref keys i)))
|
||||
(unless (equal? (avl-search < saved-tree ix)
|
||||
(number->string ix))
|
||||
(error-stop))))
|
||||
|
||||
(display "forwards generator:\n")
|
||||
(let ((gen (avl-make-generator saved-tree)))
|
||||
(do ((pair (gen) (gen)))
|
||||
((not pair))
|
||||
(display-key-data (car pair) (cdr pair))
|
||||
(newline)))
|
||||
|
||||
(display "----------------------------------------------------------------------\n")
|
||||
|
||||
(display "backwards generator:\n")
|
||||
(let ((gen (avl-make-generator saved-tree -1)))
|
||||
(do ((pair (gen) (gen)))
|
||||
((not pair))
|
||||
(display-key-data (car pair) (cdr pair))
|
||||
(newline)))
|
||||
|
||||
(display "----------------------------------------------------------------------\n")
|
||||
|
||||
))
|
||||
(else))
|
||||
174
Task/AVL-tree/Sidef/avl-tree.sidef
Normal file
174
Task/AVL-tree/Sidef/avl-tree.sidef
Normal file
|
|
@ -0,0 +1,174 @@
|
|||
class AVLtree {
|
||||
|
||||
has root = nil
|
||||
|
||||
struct Node {
|
||||
Number key,
|
||||
Number balance = 0,
|
||||
Node left = nil,
|
||||
Node right = nil,
|
||||
Node parent = nil,
|
||||
}
|
||||
|
||||
method insert(key) {
|
||||
if (root == nil) {
|
||||
root = Node(key)
|
||||
return true
|
||||
}
|
||||
|
||||
var n = root
|
||||
var parent = nil
|
||||
|
||||
loop {
|
||||
if (n.key == key) {
|
||||
return false
|
||||
}
|
||||
parent = n
|
||||
var goLeft = (n.key > key)
|
||||
n = (goLeft ? n.left : n.right)
|
||||
|
||||
if (n == nil) {
|
||||
var tn = Node(key, parent: parent)
|
||||
if (goLeft) {
|
||||
parent.left = tn
|
||||
}
|
||||
else {
|
||||
parent.right = tn
|
||||
}
|
||||
self.rebalance(parent)
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
method delete_key(delKey) {
|
||||
if (root == nil) { return nil }
|
||||
|
||||
var n = root
|
||||
var parent = root
|
||||
var delNode = nil
|
||||
var child = root
|
||||
|
||||
while (child != nil) {
|
||||
parent = n
|
||||
n = child
|
||||
child = (delKey >= n.key ? n.right : n.left)
|
||||
if (delKey == n.key) {
|
||||
delNode = n
|
||||
}
|
||||
}
|
||||
|
||||
if (delNode != nil) {
|
||||
delNode.key = n.key
|
||||
child = (n.left != nil ? n.left : n.right)
|
||||
|
||||
if (root.key == delKey) {
|
||||
root = child
|
||||
}
|
||||
else {
|
||||
if (parent.left == n) {
|
||||
parent.left = child
|
||||
}
|
||||
else {
|
||||
parent.right = child
|
||||
}
|
||||
self.rebalance(parent)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
method rebalance(n) {
|
||||
if (n == nil) { return nil }
|
||||
self.setBalance(n)
|
||||
|
||||
given (n.balance) {
|
||||
when (-2) {
|
||||
if (self.height(n.left.left) >= self.height(n.left.right)) {
|
||||
n = self.rotate(n, :right)
|
||||
}
|
||||
else {
|
||||
n = self.rotate_twice(n, :left, :right)
|
||||
}
|
||||
}
|
||||
when (2) {
|
||||
if (self.height(n.right.right) >= self.height(n.right.left)) {
|
||||
n = self.rotate(n, :left)
|
||||
}
|
||||
else {
|
||||
n = self.rotate_twice(n, :right, :left)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (n.parent != nil) {
|
||||
self.rebalance(n.parent)
|
||||
}
|
||||
else {
|
||||
root = n
|
||||
}
|
||||
}
|
||||
|
||||
method rotate(a, dir) {
|
||||
var b = (dir == :left ? a.right : a.left)
|
||||
b.parent = a.parent
|
||||
|
||||
(dir == :left) ? (a.right = b.left)
|
||||
: (a.left = b.right)
|
||||
|
||||
if (a.right != nil) {
|
||||
a.right.parent = a
|
||||
}
|
||||
|
||||
b.$dir = a
|
||||
a.parent = b
|
||||
|
||||
if (b.parent != nil) {
|
||||
if (b.parent.right == a) {
|
||||
b.parent.right = b
|
||||
}
|
||||
else {
|
||||
b.parent.left = b
|
||||
}
|
||||
}
|
||||
|
||||
self.setBalance(a, b)
|
||||
return b
|
||||
}
|
||||
|
||||
method rotate_twice(n, dir1, dir2) {
|
||||
n.left = self.rotate(n.left, dir1)
|
||||
self.rotate(n, dir2)
|
||||
}
|
||||
|
||||
method height(n) {
|
||||
if (n == nil) { return -1 }
|
||||
1 + Math.max(self.height(n.left), self.height(n.right))
|
||||
}
|
||||
|
||||
method setBalance(*nodes) {
|
||||
nodes.each { |n|
|
||||
n.balance = (self.height(n.right) - self.height(n.left))
|
||||
}
|
||||
}
|
||||
|
||||
method printBalance {
|
||||
self.printBalance(root)
|
||||
}
|
||||
|
||||
method printBalance(n) {
|
||||
if (n != nil) {
|
||||
self.printBalance(n.left)
|
||||
print(n.balance, ' ')
|
||||
self.printBalance(n.right)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var tree = AVLtree()
|
||||
|
||||
say "Inserting values 1 to 10"
|
||||
{|i| tree.insert(i) } << 1..10
|
||||
print "Printing balance: "
|
||||
tree.printBalance
|
||||
200
Task/AVL-tree/Simula/avl-tree-1.simula
Normal file
200
Task/AVL-tree/Simula/avl-tree-1.simula
Normal file
|
|
@ -0,0 +1,200 @@
|
|||
CLASS AVL;
|
||||
BEGIN
|
||||
|
||||
! AVL TREE ADAPTED FROM JULIENNE WALKER'S PRESENTATION AT ;
|
||||
! HTTP://ETERNALLYCONFUZZLED.COM/TUTS/DATASTRUCTURES/JSW_TUT_AVL.ASPX. ;
|
||||
! THIS PORT USES SIMILAR INDENTIFIER NAMES. ;
|
||||
|
||||
! THE KEY INTERFACE MUST BE SUPPORTED BY DATA STORED IN THE AVL TREE. ;
|
||||
CLASS KEY;
|
||||
VIRTUAL:
|
||||
PROCEDURE LESS IS BOOLEAN PROCEDURE LESS (K); REF(KEY) K;;
|
||||
PROCEDURE EQUAL IS BOOLEAN PROCEDURE EQUAL(K); REF(KEY) K;;
|
||||
BEGIN
|
||||
END KEY;
|
||||
|
||||
! NODE IS A NODE IN AN AVL TREE. ;
|
||||
CLASS NODE(DATA); REF(KEY) DATA; ! ANYTHING COMPARABLE WITH LESS AND EQUAL. ;
|
||||
BEGIN
|
||||
INTEGER BALANCE; ! BALANCE FACTOR ;
|
||||
REF(NODE) ARRAY LINK(0:1); ! CHILDREN, INDEXED BY "DIRECTION", 0 OR 1. ;
|
||||
END NODE;
|
||||
|
||||
! A LITTLE READABILITY FUNCTION FOR RETURNING THE OPPOSITE OF A DIRECTION, ;
|
||||
! WHERE A DIRECTION IS 0 OR 1. ;
|
||||
! WHERE JW WRITES !DIR, THIS CODE HAS OPP(DIR). ;
|
||||
INTEGER PROCEDURE OPP(DIR); INTEGER DIR;
|
||||
BEGIN
|
||||
OPP := 1 - DIR;
|
||||
END OPP;
|
||||
|
||||
! SINGLE ROTATION ;
|
||||
REF(NODE) PROCEDURE SINGLE(ROOT, DIR); REF(NODE) ROOT; INTEGER DIR;
|
||||
BEGIN
|
||||
REF(NODE) SAVE;
|
||||
SAVE :- ROOT.LINK(OPP(DIR));
|
||||
ROOT.LINK(OPP(DIR)) :- SAVE.LINK(DIR);
|
||||
SAVE.LINK(DIR) :- ROOT;
|
||||
SINGLE :- SAVE;
|
||||
END SINGLE;
|
||||
|
||||
! DOUBLE ROTATION ;
|
||||
REF(NODE) PROCEDURE DOUBLE(ROOT, DIR); REF(NODE) ROOT; INTEGER DIR;
|
||||
BEGIN
|
||||
REF(NODE) SAVE;
|
||||
SAVE :- ROOT.LINK(OPP(DIR)).LINK(DIR);
|
||||
|
||||
ROOT.LINK(OPP(DIR)).LINK(DIR) :- SAVE.LINK(OPP(DIR));
|
||||
SAVE.LINK(OPP(DIR)) :- ROOT.LINK(OPP(DIR));
|
||||
ROOT.LINK(OPP(DIR)) :- SAVE;
|
||||
|
||||
SAVE :- ROOT.LINK(OPP(DIR));
|
||||
ROOT.LINK(OPP(DIR)) :- SAVE.LINK(DIR);
|
||||
SAVE.LINK(DIR) :- ROOT;
|
||||
DOUBLE :- SAVE;
|
||||
END DOUBLE;
|
||||
|
||||
! ADJUST BALANCE FACTORS AFTER DOUBLE ROTATION ;
|
||||
PROCEDURE ADJUSTBALANCE(ROOT, DIR, BAL); REF(NODE) ROOT; INTEGER DIR, BAL;
|
||||
BEGIN
|
||||
REF(NODE) N, NN;
|
||||
N :- ROOT.LINK(DIR);
|
||||
NN :- N.LINK(OPP(DIR));
|
||||
IF NN.BALANCE = 0 THEN BEGIN ROOT.BALANCE := 0; N.BALANCE := 0; END ELSE
|
||||
IF NN.BALANCE = BAL THEN BEGIN ROOT.BALANCE := -BAL; N.BALANCE := 0; END
|
||||
ELSE BEGIN ROOT.BALANCE := 0; N.BALANCE := BAL; END;
|
||||
NN.BALANCE := 0;
|
||||
END ADJUSTBALANCE;
|
||||
|
||||
REF(NODE) PROCEDURE INSERTBALANCE(ROOT, DIR); REF(NODE) ROOT; INTEGER DIR;
|
||||
BEGIN REF(NODE) N; INTEGER BAL;
|
||||
N :- ROOT.LINK(DIR);
|
||||
BAL := 2*DIR - 1;
|
||||
IF N.BALANCE = BAL THEN
|
||||
BEGIN
|
||||
ROOT.BALANCE := 0;
|
||||
N.BALANCE := 0;
|
||||
INSERTBALANCE :- SINGLE(ROOT, OPP(DIR));
|
||||
END ELSE
|
||||
BEGIN
|
||||
ADJUSTBALANCE(ROOT, DIR, BAL);
|
||||
INSERTBALANCE :- DOUBLE(ROOT, OPP(DIR));
|
||||
END;
|
||||
END INSERTBALANCE;
|
||||
|
||||
CLASS TUPLE(N,B); REF(NODE) N; BOOLEAN B;;
|
||||
|
||||
REF(TUPLE) PROCEDURE INSERTR(ROOT, DATA); REF(NODE) ROOT; REF(KEY) DATA;
|
||||
BEGIN
|
||||
IF ROOT == NONE THEN
|
||||
INSERTR :- NEW TUPLE(NEW NODE(DATA), FALSE)
|
||||
ELSE
|
||||
BEGIN
|
||||
REF(TUPLE) T; BOOLEAN DONE; INTEGER DIR;
|
||||
DIR := 0;
|
||||
IF ROOT.DATA.LESS(DATA) THEN
|
||||
DIR := 1;
|
||||
T :- INSERTR(ROOT.LINK(DIR), DATA);
|
||||
ROOT.LINK(DIR) :- T.N;
|
||||
DONE := T.B;
|
||||
IF DONE THEN INSERTR :- NEW TUPLE(ROOT, TRUE) ELSE
|
||||
BEGIN
|
||||
ROOT.BALANCE := ROOT.BALANCE + 2*DIR - 1;
|
||||
IF ROOT.BALANCE = 0 THEN
|
||||
INSERTR :- NEW TUPLE(ROOT, TRUE) ELSE
|
||||
IF ROOT.BALANCE = 1 OR ROOT.BALANCE = -1 THEN
|
||||
INSERTR :- NEW TUPLE(ROOT, FALSE)
|
||||
ELSE
|
||||
INSERTR :- NEW TUPLE(INSERTBALANCE(ROOT, DIR), TRUE);
|
||||
END;
|
||||
END;
|
||||
END INSERTR;
|
||||
|
||||
! INSERT A NODE INTO THE AVL TREE. ;
|
||||
! DATA IS INSERTED EVEN IF OTHER DATA WITH THE SAME KEY ALREADY EXISTS. ;
|
||||
PROCEDURE INSERT(TREE, DATA); NAME TREE; REF(NODE) TREE; REF(KEY) DATA;
|
||||
BEGIN
|
||||
REF(TUPLE) T;
|
||||
T :- INSERTR(TREE, DATA);
|
||||
TREE :- T.N;
|
||||
END INSERT;
|
||||
|
||||
REF(TUPLE) PROCEDURE REMOVEBALANCE(ROOT, DIR); REF(NODE) ROOT; INTEGER DIR;
|
||||
BEGIN REF(NODE) N; INTEGER BAL;
|
||||
N :- ROOT.LINK(OPP(DIR));
|
||||
BAL := 2*DIR - 1;
|
||||
|
||||
IF N.BALANCE = -BAL THEN
|
||||
BEGIN ROOT.BALANCE := 0; N.BALANCE := 0;
|
||||
REMOVEBALANCE :- NEW TUPLE(SINGLE(ROOT, DIR), FALSE);
|
||||
END ELSE
|
||||
|
||||
IF N.BALANCE = BAL THEN
|
||||
BEGIN ADJUSTBALANCE(ROOT, OPP(DIR), -BAL);
|
||||
REMOVEBALANCE :- NEW TUPLE(DOUBLE(ROOT, DIR), FALSE);
|
||||
END ELSE
|
||||
|
||||
BEGIN ROOT.BALANCE := -BAL; N.BALANCE := BAL;
|
||||
REMOVEBALANCE :- NEW TUPLE(SINGLE(ROOT, DIR), TRUE);
|
||||
END
|
||||
END REMOVEBALANCE;
|
||||
|
||||
REF(TUPLE) PROCEDURE REMOVER(ROOT, DATA); REF(NODE) ROOT; REF(KEY) DATA;
|
||||
BEGIN INTEGER DIR; BOOLEAN DONE; REF(TUPLE) T;
|
||||
|
||||
IF ROOT == NONE THEN
|
||||
REMOVER :- NEW TUPLE(NONE, FALSE)
|
||||
ELSE
|
||||
IF ROOT.DATA.EQUAL(DATA) THEN
|
||||
BEGIN
|
||||
IF ROOT.LINK(0) == NONE THEN
|
||||
BEGIN
|
||||
REMOVER :- NEW TUPLE(ROOT.LINK(1), FALSE);
|
||||
GOTO L;
|
||||
END
|
||||
|
||||
ELSE IF ROOT.LINK(1) == NONE THEN
|
||||
BEGIN
|
||||
REMOVER :- NEW TUPLE(ROOT.LINK(0), FALSE);
|
||||
GOTO L;
|
||||
END
|
||||
|
||||
ELSE
|
||||
BEGIN REF(NODE) HEIR;
|
||||
HEIR :- ROOT.LINK(0);
|
||||
WHILE HEIR.LINK(1) =/= NONE DO
|
||||
HEIR :- HEIR.LINK(1);
|
||||
ROOT.DATA :- HEIR.DATA;
|
||||
DATA :- HEIR.DATA;
|
||||
END;
|
||||
END;
|
||||
DIR := 0;
|
||||
IF ROOT.DATA.LESS(DATA) THEN
|
||||
DIR := 1;
|
||||
T :- REMOVER(ROOT.LINK(DIR), DATA); ROOT.LINK(DIR) :- T.N; DONE := T.B;
|
||||
IF DONE THEN
|
||||
BEGIN
|
||||
REMOVER :- NEW TUPLE(ROOT, TRUE);
|
||||
GOTO L;
|
||||
END;
|
||||
ROOT.BALANCE := ROOT.BALANCE + 1 - 2*DIR;
|
||||
IF ROOT.BALANCE = 1 OR ROOT.BALANCE = -1 THEN
|
||||
REMOVER :- NEW TUPLE(ROOT, TRUE)
|
||||
|
||||
ELSE IF ROOT.BALANCE = 0 THEN
|
||||
REMOVER :- NEW TUPLE(ROOT, FALSE)
|
||||
|
||||
ELSE
|
||||
REMOVER :- REMOVEBALANCE(ROOT, DIR);
|
||||
L:
|
||||
END REMOVER;
|
||||
|
||||
! REMOVE A SINGLE ITEM FROM AN AVL TREE. ;
|
||||
! IF KEY DOES NOT EXIST, FUNCTION HAS NO EFFECT. ;
|
||||
PROCEDURE REMOVE(TREE, DATA); NAME TREE; REF(NODE) TREE; REF(KEY) DATA;
|
||||
BEGIN REF(TUPLE) T;
|
||||
T :- REMOVER(TREE, DATA);
|
||||
TREE :- T.N;
|
||||
END REMOVEM;
|
||||
|
||||
END.
|
||||
36
Task/AVL-tree/Simula/avl-tree-2.simula
Normal file
36
Task/AVL-tree/Simula/avl-tree-2.simula
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
EXTERNAL CLASS AVL;
|
||||
|
||||
AVL
|
||||
BEGIN
|
||||
|
||||
KEY CLASS INTEGERKEY(I); INTEGER I;
|
||||
BEGIN
|
||||
BOOLEAN PROCEDURE LESS (K); REF(KEY) K; LESS := I < K QUA INTEGERKEY.I;
|
||||
BOOLEAN PROCEDURE EQUAL(K); REF(KEY) K; EQUAL := I = K QUA INTEGERKEY.I;
|
||||
END INTEGERKEY;
|
||||
|
||||
PROCEDURE DUMP(ROOT); REF(NODE) ROOT;
|
||||
BEGIN
|
||||
IF ROOT =/= NONE THEN
|
||||
BEGIN
|
||||
DUMP(ROOT.LINK(0));
|
||||
OUTINT(ROOT.DATA QUA INTEGERKEY.I, 0); OUTTEXT(" ");
|
||||
DUMP(ROOT.LINK(1));
|
||||
END
|
||||
END DUMP;
|
||||
|
||||
INTEGER I;
|
||||
REF(NODE) TREE;
|
||||
OUTTEXT("Empty tree: "); DUMP(TREE); OUTIMAGE;
|
||||
|
||||
FOR I := 3, 1, 4, 1, 5 DO
|
||||
BEGIN OUTTEXT("Insert "); OUTINT(I, 0); OUTTEXT(": ");
|
||||
INSERT(TREE, NEW INTEGERKEY(I)); DUMP(TREE); OUTIMAGE;
|
||||
END;
|
||||
|
||||
FOR I := 3, 1 DO
|
||||
BEGIN OUTTEXT("Remove "); OUTINT(I, 0); OUTTEXT(": ");
|
||||
REMOVE(TREE, NEW INTEGERKEY(I)); DUMP(TREE); OUTIMAGE;
|
||||
END;
|
||||
|
||||
END.
|
||||
181
Task/AVL-tree/Tcl/avl-tree-1.tcl
Normal file
181
Task/AVL-tree/Tcl/avl-tree-1.tcl
Normal file
|
|
@ -0,0 +1,181 @@
|
|||
package require TclOO
|
||||
|
||||
namespace eval AVL {
|
||||
# Class for the overall tree; manages real public API
|
||||
oo::class create Tree {
|
||||
variable root nil class
|
||||
constructor {{nodeClass AVL::Node}} {
|
||||
set class [oo::class create Node [list superclass $nodeClass]]
|
||||
|
||||
# Create a nil instance to act as a leaf sentinel
|
||||
set nil [my NewNode ""]
|
||||
set root [$nil ref]
|
||||
|
||||
# Make nil be special
|
||||
oo::objdefine $nil {
|
||||
method height {} {return 0}
|
||||
method key {} {error "no key possible"}
|
||||
method value {} {error "no value possible"}
|
||||
method destroy {} {
|
||||
# Do nothing (doesn't prohibit destruction entirely)
|
||||
}
|
||||
method print {indent increment} {
|
||||
# Do nothing
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# How to actually manufacture a new node
|
||||
method NewNode {key} {
|
||||
if {![info exists nil]} {set nil ""}
|
||||
$class new $key $nil [list [namespace current]::my NewNode]
|
||||
}
|
||||
|
||||
# Create a new node in the tree and return it
|
||||
method insert {key} {
|
||||
set node [my NewNode $key]
|
||||
if {$root eq $nil} {
|
||||
set root $node
|
||||
} else {
|
||||
$root insert $node
|
||||
}
|
||||
return $node
|
||||
}
|
||||
|
||||
# Find the node for a particular key
|
||||
method lookup {key} {
|
||||
for {set node $root} {$node ne $nil} {} {
|
||||
if {[$node key] == $key} {
|
||||
return $node
|
||||
} elseif {[$node key] > $key} {
|
||||
set node [$node left]
|
||||
} else {
|
||||
set node [$node right]
|
||||
}
|
||||
}
|
||||
error "no such node"
|
||||
}
|
||||
|
||||
# Print a tree out, one node per line
|
||||
method print {{indent 0} {increment 1}} {
|
||||
$root print $indent $increment
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
# Class of an individual node; may be subclassed
|
||||
oo::class create Node {
|
||||
variable key value left right 0 refcount newNode
|
||||
constructor {n nil instanceFactory} {
|
||||
set newNode $instanceFactory
|
||||
set 0 [expr {$nil eq "" ? [self] : $nil}]
|
||||
set key $n
|
||||
set value {}
|
||||
set left [set right $0]
|
||||
set refcount 0
|
||||
}
|
||||
method ref {} {
|
||||
incr refcount
|
||||
return [self]
|
||||
}
|
||||
method destroy {} {
|
||||
if {[incr refcount -1] < 1} next
|
||||
}
|
||||
method New {key value} {
|
||||
set n [{*}$newNode $key]
|
||||
$n setValue $value
|
||||
return $n
|
||||
}
|
||||
|
||||
# Getters
|
||||
method key {} {return $key}
|
||||
method value {} {return $value}
|
||||
method left {} {return $left}
|
||||
method right {args} {return $right}
|
||||
|
||||
# Setters
|
||||
method setValue {newValue} {
|
||||
set value $newValue
|
||||
}
|
||||
method setLeft {node} {
|
||||
# Non-trivial because of reference management
|
||||
$node ref
|
||||
$left destroy
|
||||
set left $node
|
||||
return
|
||||
}
|
||||
method setRight {node} {
|
||||
# Non-trivial because of reference management
|
||||
$node ref
|
||||
$right destroy
|
||||
set right $node
|
||||
return
|
||||
}
|
||||
|
||||
# Print a node and its descendents
|
||||
method print {indent increment} {
|
||||
puts [format "%s%s => %s" [string repeat " " $indent] $key $value]
|
||||
incr indent $increment
|
||||
$left print $indent $increment
|
||||
$right print $indent $increment
|
||||
}
|
||||
|
||||
method height {} {
|
||||
return [expr {max([$left height], [$right height]) + 1}]
|
||||
}
|
||||
method balanceFactor {} {
|
||||
expr {[$left height] - [$right height]}
|
||||
}
|
||||
|
||||
method insert {node} {
|
||||
# Simple insertion
|
||||
if {$key > [$node key]} {
|
||||
if {$left eq $0} {
|
||||
my setLeft $node
|
||||
} else {
|
||||
$left insert $node
|
||||
}
|
||||
} else {
|
||||
if {$right eq $0} {
|
||||
my setRight $node
|
||||
} else {
|
||||
$right insert $node
|
||||
}
|
||||
}
|
||||
|
||||
# Rebalance this node
|
||||
if {[my balanceFactor] > 1} {
|
||||
if {[$left balanceFactor] < 0} {
|
||||
$left rotateLeft
|
||||
}
|
||||
my rotateRight
|
||||
} elseif {[my balanceFactor] < -1} {
|
||||
if {[$right balanceFactor] > 0} {
|
||||
$right rotateRight
|
||||
}
|
||||
my rotateLeft
|
||||
}
|
||||
}
|
||||
|
||||
# AVL Rotations
|
||||
method rotateLeft {} {
|
||||
set new [my New $key $value]
|
||||
set key [$right key]
|
||||
set value [$right value]
|
||||
$new setLeft $left
|
||||
$new setRight [$right left]
|
||||
my setLeft $new
|
||||
my setRight [$right right]
|
||||
}
|
||||
|
||||
method rotateRight {} {
|
||||
set new [my New $key $value]
|
||||
set key [$left key]
|
||||
set value [$left value]
|
||||
$new setLeft [$left right]
|
||||
$new setRight $right
|
||||
my setLeft [$left left]
|
||||
my setRight $new
|
||||
}
|
||||
}
|
||||
}
|
||||
20
Task/AVL-tree/Tcl/avl-tree-2.tcl
Normal file
20
Task/AVL-tree/Tcl/avl-tree-2.tcl
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
# Create an AVL tree
|
||||
AVL::Tree create tree
|
||||
|
||||
# Populate it with some semi-random data
|
||||
for {set i 33} {$i < 127} {incr i} {
|
||||
[tree insert $i] setValue \
|
||||
[string repeat [format %c $i] [expr {1+int(rand()*5)}]]
|
||||
}
|
||||
|
||||
# Print it out
|
||||
tree print
|
||||
|
||||
# Look up a few values in the tree
|
||||
for {set i 0} {$i < 10} {incr i} {
|
||||
set k [expr {33+int((127-33)*rand())}]
|
||||
puts $k=>[[tree lookup $k] value]
|
||||
}
|
||||
|
||||
# Destroy the tree and all its nodes
|
||||
tree destroy
|
||||
213
Task/AVL-tree/TypeScript/avl-tree.ts
Normal file
213
Task/AVL-tree/TypeScript/avl-tree.ts
Normal file
|
|
@ -0,0 +1,213 @@
|
|||
/** A single node in an AVL tree */
|
||||
class AVLnode <T> {
|
||||
balance: number
|
||||
left: AVLnode<T>
|
||||
right: AVLnode<T>
|
||||
|
||||
constructor(public key: T, public parent: AVLnode<T> = null) {
|
||||
this.balance = 0
|
||||
this.left = null
|
||||
this.right = null
|
||||
}
|
||||
}
|
||||
|
||||
/** The balanced AVL tree */
|
||||
class AVLtree <T> {
|
||||
// public members organized here
|
||||
constructor() {
|
||||
this.root = null
|
||||
}
|
||||
|
||||
insert(key: T): boolean {
|
||||
if (this.root === null) {
|
||||
this.root = new AVLnode<T>(key)
|
||||
} else {
|
||||
let n: AVLnode<T> = this.root,
|
||||
parent: AVLnode<T> = null
|
||||
|
||||
while (true) {
|
||||
if(n.key === key) {
|
||||
return false
|
||||
}
|
||||
|
||||
parent = n
|
||||
|
||||
let goLeft: boolean = n.key > key
|
||||
n = goLeft ? n.left : n.right
|
||||
|
||||
if (n === null) {
|
||||
if (goLeft) {
|
||||
parent.left = new AVLnode<T>(key, parent)
|
||||
} else {
|
||||
parent.right = new AVLnode<T>(key, parent)
|
||||
}
|
||||
|
||||
this.rebalance(parent)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
deleteKey(delKey: T): void {
|
||||
if (this.root === null) {
|
||||
return
|
||||
}
|
||||
|
||||
let n: AVLnode<T> = this.root,
|
||||
parent: AVLnode<T> = this.root,
|
||||
delNode: AVLnode<T> = null,
|
||||
child: AVLnode<T> = this.root
|
||||
|
||||
while (child !== null) {
|
||||
parent = n
|
||||
n = child
|
||||
child = delKey >= n.key ? n.right : n.left
|
||||
if (delKey === n.key) {
|
||||
delNode = n
|
||||
}
|
||||
}
|
||||
|
||||
if (delNode !== null) {
|
||||
delNode.key = n.key
|
||||
|
||||
child = n.left !== null ? n.left : n.right
|
||||
|
||||
if (this.root.key === delKey) {
|
||||
this.root = child
|
||||
} else {
|
||||
if (parent.left === n) {
|
||||
parent.left = child
|
||||
} else {
|
||||
parent.right = child
|
||||
}
|
||||
|
||||
this.rebalance(parent)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
treeBalanceString(n: AVLnode<T> = this.root): string {
|
||||
if (n !== null) {
|
||||
return `${this.treeBalanceString(n.left)} ${n.balance} ${this.treeBalanceString(n.right)}`
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
toString(n: AVLnode<T> = this.root): string {
|
||||
if (n !== null) {
|
||||
return `${this.toString(n.left)} ${n.key} ${this.toString(n.right)}`
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
|
||||
// private members organized here
|
||||
private root: AVLnode<T>
|
||||
|
||||
private rotateLeft(a: AVLnode<T>): AVLnode<T> {
|
||||
let b: AVLnode<T> = a.right
|
||||
b.parent = a.parent
|
||||
a.right = b.left
|
||||
|
||||
if (a.right !== null) {
|
||||
a.right.parent = a
|
||||
}
|
||||
|
||||
b.left = a
|
||||
a.parent = b
|
||||
|
||||
if (b.parent !== null) {
|
||||
if (b.parent.right === a) {
|
||||
b.parent.right = b
|
||||
} else {
|
||||
b.parent.left = b
|
||||
}
|
||||
}
|
||||
|
||||
this.setBalance(a)
|
||||
this.setBalance(b)
|
||||
|
||||
return b
|
||||
}
|
||||
|
||||
private rotateRight(a: AVLnode<T>): AVLnode<T> {
|
||||
let b: AVLnode<T> = a.left
|
||||
b.parent = a.parent
|
||||
a.left = b.right
|
||||
|
||||
if (a.left !== null) {
|
||||
a.left.parent = a
|
||||
}
|
||||
|
||||
b.right = a
|
||||
a.parent = b
|
||||
|
||||
if (b.parent !== null) {
|
||||
if (b.parent.right === a) {
|
||||
b.parent.right = b
|
||||
} else {
|
||||
b.parent.left = b
|
||||
}
|
||||
}
|
||||
|
||||
this.setBalance(a)
|
||||
this.setBalance(b)
|
||||
|
||||
return b
|
||||
}
|
||||
|
||||
private rotateLeftThenRight(n: AVLnode<T>): AVLnode<T> {
|
||||
n.left = this.rotateLeft(n.left)
|
||||
return this.rotateRight(n)
|
||||
}
|
||||
|
||||
private rotateRightThenLeft(n: AVLnode<T>): AVLnode<T> {
|
||||
n.right = this.rotateRight(n.right)
|
||||
return this.rotateLeft(n)
|
||||
}
|
||||
|
||||
private rebalance(n: AVLnode<T>): void {
|
||||
this.setBalance(n)
|
||||
|
||||
if (n.balance === -2) {
|
||||
if(this.height(n.left.left) >= this.height(n.left.right)) {
|
||||
n = this.rotateRight(n)
|
||||
} else {
|
||||
n = this.rotateLeftThenRight(n)
|
||||
}
|
||||
} else if (n.balance === 2) {
|
||||
if(this.height(n.right.right) >= this.height(n.right.left)) {
|
||||
n = this.rotateLeft(n)
|
||||
} else {
|
||||
n = this.rotateRightThenLeft(n)
|
||||
}
|
||||
}
|
||||
|
||||
if (n.parent !== null) {
|
||||
this.rebalance(n.parent)
|
||||
} else {
|
||||
this.root = n
|
||||
}
|
||||
}
|
||||
|
||||
private height(n: AVLnode<T>): number {
|
||||
if (n === null) {
|
||||
return -1
|
||||
}
|
||||
return 1 + Math.max(this.height(n.left), this.height(n.right))
|
||||
}
|
||||
|
||||
private setBalance(n: AVLnode<T>): void {
|
||||
n.balance = this.height(n.right) - this.height(n.left)
|
||||
}
|
||||
|
||||
public showNodeBalance(n: AVLnode<T>): string {
|
||||
if (n !== null) {
|
||||
return `${this.showNodeBalance(n.left)} ${n.balance} ${this.showNodeBalance(n.right)}`
|
||||
}
|
||||
return ""
|
||||
}
|
||||
}
|
||||
189
Task/AVL-tree/Wren/avl-tree.wren
Normal file
189
Task/AVL-tree/Wren/avl-tree.wren
Normal file
|
|
@ -0,0 +1,189 @@
|
|||
class Node {
|
||||
construct new(key, parent) {
|
||||
_key = key
|
||||
_parent = parent
|
||||
_balance = 0
|
||||
_left = null
|
||||
_right = null
|
||||
}
|
||||
|
||||
key { _key }
|
||||
parent { _parent }
|
||||
balance { _balance }
|
||||
left { _left }
|
||||
right { _right }
|
||||
|
||||
key=(k) { _key = k }
|
||||
parent=(p) { _parent = p }
|
||||
balance=(v) { _balance = v }
|
||||
left=(n) { _left = n }
|
||||
right= (n) { _right = n }
|
||||
}
|
||||
|
||||
class AvlTree {
|
||||
construct new() {
|
||||
_root = null
|
||||
}
|
||||
|
||||
insert(key) {
|
||||
if (!_root) {
|
||||
_root = Node.new(key, null)
|
||||
} else {
|
||||
var n = _root
|
||||
while (true) {
|
||||
if (n.key == key) return false
|
||||
var parent = n
|
||||
var goLeft = n.key > key
|
||||
n = goLeft ? n.left : n.right
|
||||
if (!n) {
|
||||
if (goLeft) {
|
||||
parent.left = Node.new(key, parent)
|
||||
} else {
|
||||
parent.right = Node.new(key, parent)
|
||||
}
|
||||
rebalance(parent)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
delete(delKey) {
|
||||
if (!_root) return
|
||||
var n = _root
|
||||
var parent = _root
|
||||
var delNode = null
|
||||
var child = _root
|
||||
while (child) {
|
||||
parent = n
|
||||
n = child
|
||||
child = (delKey >= n.key) ? n.right : n.left
|
||||
if (delKey == n.key) delNode = n
|
||||
}
|
||||
if (delNode) {
|
||||
delNode.key = n.key
|
||||
child = n.left ? n.left : n.right
|
||||
if (_root.key == delKey) {
|
||||
_root = child
|
||||
if (_root) _root.parent = null
|
||||
} else {
|
||||
if (parent.left == n) {
|
||||
parent.left = child
|
||||
} else {
|
||||
parent.right = child
|
||||
}
|
||||
if (child) child.parent = parent
|
||||
rebalance(parent)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
rebalance(n) {
|
||||
setBalance([n])
|
||||
var nn = n
|
||||
if (nn.balance == -2) {
|
||||
if (height(nn.left.left) >= height(nn.left.right)) {
|
||||
nn = rotateRight(nn)
|
||||
} else {
|
||||
nn = rotateLeftThenRight(nn)
|
||||
}
|
||||
} else if (nn.balance == 2) {
|
||||
if (height(nn.right.right) >= height(nn.right.left)) {
|
||||
nn = rotateLeft(nn)
|
||||
} else {
|
||||
nn = rotateRightThenLeft(nn)
|
||||
}
|
||||
}
|
||||
if (nn.parent) rebalance(nn.parent) else _root = nn
|
||||
}
|
||||
|
||||
rotateLeft(a) {
|
||||
var b = a.right
|
||||
b.parent = a.parent
|
||||
a.right = b.left
|
||||
if (a.right) a.right.parent = a
|
||||
b.left = a
|
||||
a.parent = b
|
||||
if (b.parent) {
|
||||
if (b.parent.right == a) {
|
||||
b.parent.right = b
|
||||
} else {
|
||||
b.parent.left = b
|
||||
}
|
||||
}
|
||||
setBalance([a, b])
|
||||
return b
|
||||
}
|
||||
|
||||
rotateRight(a) {
|
||||
var b = a.left
|
||||
b.parent = a.parent
|
||||
a.left = b.right
|
||||
if (a.left) a.left.parent = a
|
||||
b.right = a
|
||||
a.parent = b
|
||||
if (b.parent) {
|
||||
if (b.parent.right == a) {
|
||||
b.parent.right = b
|
||||
} else {
|
||||
b.parent.left = b
|
||||
}
|
||||
}
|
||||
setBalance([a, b])
|
||||
return b
|
||||
}
|
||||
|
||||
rotateLeftThenRight(n) {
|
||||
n.left = rotateLeft(n.left)
|
||||
return rotateRight(n)
|
||||
}
|
||||
|
||||
rotateRightThenLeft(n) {
|
||||
n.right = rotateRight(n.right)
|
||||
return rotateLeft(n)
|
||||
}
|
||||
|
||||
height(n) {
|
||||
if (!n) return -1
|
||||
return 1 + height(n.left).max(height(n.right))
|
||||
}
|
||||
|
||||
setBalance(nodes) {
|
||||
for (n in nodes) n.balance = height(n.right) - height(n.left)
|
||||
}
|
||||
|
||||
printKey() {
|
||||
printKey(_root)
|
||||
System.print()
|
||||
}
|
||||
|
||||
printKey(n) {
|
||||
if (n) {
|
||||
printKey(n.left)
|
||||
System.write("%(n.key) ")
|
||||
printKey(n.right)
|
||||
}
|
||||
}
|
||||
|
||||
printBalance() {
|
||||
printBalance(_root)
|
||||
System.print()
|
||||
}
|
||||
|
||||
printBalance(n) {
|
||||
if (n) {
|
||||
printBalance(n.left)
|
||||
System.write("%(n.balance) ")
|
||||
printBalance(n.right)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var tree = AvlTree.new()
|
||||
System.print("Inserting values 1 to 10")
|
||||
for (i in 1..10) tree.insert(i)
|
||||
System.write("Printing key : ")
|
||||
tree.printKey()
|
||||
System.write("Printing balance : ")
|
||||
tree.printBalance()
|
||||
147
Task/AVL-tree/Yabasic/avl-tree.basic
Normal file
147
Task/AVL-tree/Yabasic/avl-tree.basic
Normal file
|
|
@ -0,0 +1,147 @@
|
|||
// AVL-Tree C code, https://www.programiz.com/dsa/avl-tree
|
||||
// Ported to Yabasic by Galileo 2022/07
|
||||
|
||||
KEY = 1 : LRIGHT = 2 : LLEFT = 3 : HEIGHT = 4
|
||||
|
||||
root = 0 : ramas = 5 : indice = 0
|
||||
|
||||
dim arbol(ramas, 4)
|
||||
|
||||
|
||||
sub rotateRight(y)
|
||||
local x, T2
|
||||
|
||||
x = arbol(y, LLEFT)
|
||||
T2 = arbol(x, LRIGHT)
|
||||
arbol(x, LRIGHT) = y
|
||||
arbol(y, LLEFT) = T2
|
||||
arbol(y, HEIGHT) = max(height(arbol(y, LLEFT)), height(arbol(y, LRIGHT))) + 1
|
||||
arbol(x, HEIGHT) = max(height(arbol(x, LLEFT)), height(arbol(x, LRIGHT))) + 1
|
||||
return x
|
||||
end sub
|
||||
|
||||
|
||||
sub rotateLeft(x)
|
||||
local y, T2
|
||||
|
||||
y = arbol(x, LRIGHT)
|
||||
T2 = arbol(y, LLEFT)
|
||||
arbol(y, LLEFT) = x
|
||||
arbol(x, LRIGHT) = T2
|
||||
arbol(x, HEIGHT) = max(height(arbol(x, LLEFT)), height(arbol(x, LRIGHT))) + 1
|
||||
arbol(y, HEIGHT) = max(height(arbol(y, LLEFT)), height(arbol(y, LRIGHT))) + 1
|
||||
return y
|
||||
end sub
|
||||
|
||||
|
||||
sub Balance(current)
|
||||
return height(arbol(current, LLEFT)) - height(arbol(current, LRIGHT))
|
||||
end sub
|
||||
|
||||
|
||||
sub height(current)
|
||||
return arbol(current, HEIGHT)
|
||||
end sub
|
||||
|
||||
|
||||
sub insert(current, key)
|
||||
local balance
|
||||
|
||||
if current = 0 indice = indice + 1 : if indice > ramas then ramas = ramas + 5 : redim arbol(ramas, 4) endif : arbol(indice, KEY) = key : arbol(indice, HEIGHT) = 1 : return indice
|
||||
if key < arbol(current, KEY) then
|
||||
arbol(current, LLEFT) = insert(arbol(current, LLEFT), key)
|
||||
elsif key > arbol(current, KEY) then
|
||||
arbol(current, LRIGHT) = insert(arbol(current, LRIGHT), key)
|
||||
else
|
||||
return current
|
||||
endif
|
||||
|
||||
arbol(current, HEIGHT) = max(height(arbol(current, LLEFT)), height(arbol(current, LRIGHT))) + 1
|
||||
balance = Balance(current)
|
||||
if balance > 1 and key < arbol(arbol(current, LLEFT), KEY) return rotateRight(current)
|
||||
if balance < -1 and key > arbol(arbol(current, LRIGHT), KEY) return rotateLeft(current)
|
||||
if balance > 1 and key > arbol(arbol(current, LLEFT), KEY) then
|
||||
arbol(current, LLEFT) = rotateLeft(arbol(current, LLEFT))
|
||||
return rotateRight(current)
|
||||
endif
|
||||
if balance < -1 and key < arbol(arbol(current, LRIGHT), KEY) then
|
||||
arbol(current, LRIGHT) = rotateRight(arbol(current, LRIGHT))
|
||||
return rotateLeft(current)
|
||||
endif
|
||||
return current
|
||||
end sub
|
||||
|
||||
|
||||
sub minValueNode(current)
|
||||
while arbol(current, LLEFT)
|
||||
current = arbol(current, LLEFT)
|
||||
wend
|
||||
|
||||
return current
|
||||
end sub
|
||||
|
||||
// Delete a nodes
|
||||
sub deleteNode(root, key)
|
||||
local temp, balance
|
||||
// Find the node and delete it
|
||||
if root = 0 return root
|
||||
|
||||
if key < arbol(root, KEY) then
|
||||
arbol(root, LLEFT) = deleteNode(arbol(root, LLEFT), key)
|
||||
elsif key > arbol(root, KEY) then
|
||||
arbol(root, LRIGHT) = deleteNode(arbol(root, LRIGHT), key)
|
||||
else
|
||||
if arbol(root, LLEFT) = 0 or arbol(root, LRIGHT) = 0 then
|
||||
temp = max(arbol(root, LLEFT), arbol(root, LRIGHT))
|
||||
|
||||
if temp = 0 then
|
||||
temp = root
|
||||
root = 0
|
||||
else
|
||||
root = temp
|
||||
endif
|
||||
else
|
||||
temp = minValueNode(arbol(root, LRIGHT))
|
||||
arbol(root, KEY) = arbol(temp, KEY)
|
||||
arbol(root, LRIGHT) = deleteNode(arbol(root, LRIGHT), arbol(temp, KEY))
|
||||
endif
|
||||
endif
|
||||
|
||||
if root = 0 return root
|
||||
|
||||
// Update the balance factor of each node and
|
||||
// balance the tree
|
||||
arbol(root, HEIGHT) = 1 + max(height(arbol(root, LLEFT)), height(arbol(root, LRIGHT)))
|
||||
|
||||
balance = Balance(root)
|
||||
if balance > 1 and Balance(arbol(root, LLEFT)) >= 0 return rightRotate(root)
|
||||
if balance > 1 and Balance(arbol(root, LLEFT)) < 0 arbol(root, LLEFT) = leftRotate(arbol(root, LLEFT)) : return rightRotate(root)
|
||||
if balance < -1 and Balance(arbol(root, LRIGHT)) <= 0 return leftRotate(root)
|
||||
if balance < -1 and Balance(arbol(root, LRIGHT)) > 0 arbol(root, LRIGHT) = rightRotate(arbol(root, LRIGHT)) : return leftRotate(root)
|
||||
|
||||
return root
|
||||
end sub
|
||||
|
||||
sub preOrder(temp)
|
||||
if temp then
|
||||
print arbol(temp, KEY), " ", arbol(temp, HEIGHT), " ", Balance(temp)
|
||||
preOrder(arbol(temp, LLEFT))
|
||||
preOrder(arbol(temp, LRIGHT))
|
||||
endif
|
||||
end sub
|
||||
|
||||
|
||||
root = insert(root, 2)
|
||||
root = insert(root, 1)
|
||||
root = insert(root, 7)
|
||||
root = insert(root, 4)
|
||||
root = insert(root, 5)
|
||||
root = insert(root, 3)
|
||||
root = insert(root, 8)
|
||||
|
||||
preOrder(root)
|
||||
|
||||
root = deleteNode(root, 3)
|
||||
|
||||
print "\nAfter deletion: "
|
||||
preOrder(root)
|
||||
Loading…
Add table
Add a link
Reference in a new issue