From 59e39e9cabf80ad70e5b88f9b9843b735ef68bf1 Mon Sep 17 00:00:00 2001
From: Mahdi Hasnat Siyam <mahdibuet3@gmail.com>
Date: Fri, 6 Dec 2024 21:59:34 +0600
Subject: [PATCH 1/7] Add insert implementation with illustrations

---
 Algorithms/DataStructures/AVLTree.fs | 233 +++++++++++++++++++++++++++
 1 file changed, 233 insertions(+)
 create mode 100644 Algorithms/DataStructures/AVLTree.fs

diff --git a/Algorithms/DataStructures/AVLTree.fs b/Algorithms/DataStructures/AVLTree.fs
new file mode 100644
index 0000000..6a1c12e
--- /dev/null
+++ b/Algorithms/DataStructures/AVLTree.fs
@@ -0,0 +1,233 @@
+namespace Algorithms.DataStructures
+
+module AVLTree =
+
+    type AVLNode = {
+        Value: int
+        Height: int
+        LeftChild: Option<AVLNode>
+        RightChild: Option<AVLNode>
+    }
+
+    module AVLNode =
+        let create (value: int) : AVLNode =
+            {
+                Value = value
+                Height = 0
+                LeftChild = None
+                RightChild = None
+            }
+
+        let height (maybeNode: Option<AVLNode>) : int =
+            maybeNode
+            |> Option.map (fun node -> node.Height)
+            |> Option.defaultValue -1
+
+        let balanceFactor (node: AVLNode) : int =
+            height node.RightChild - height node.LeftChild
+
+    type AVLNode
+    with
+        member this.UpdateLeftChild (leftChild: Option<AVLNode>) : AVLNode =
+            {
+                this with
+                    LeftChild = leftChild
+                    Height = 1 + max (AVLNode.height leftChild) (AVLNode.height this.RightChild)
+            }
+        member this.UpdateRightChild (rightChild: Option<AVLNode>) : AVLNode =
+            {
+                this with
+                    RightChild = rightChild
+                    Height = 1 + max (AVLNode.height this.LeftChild) (AVLNode.height rightChild)
+            }
+
+    module AVLTree =
+        let rotateRight (node: AVLNode) : AVLNode =
+            // Left child becomes the new root
+            let leftChild = node.LeftChild |> Option.get
+            let oldNode = node.UpdateLeftChild (leftChild.RightChild)
+            leftChild.UpdateRightChild (Some oldNode)
+
+        let rotateLeft (node: AVLNode) : AVLNode =
+            // Right child becomes the new root
+            let rightChild = node.RightChild |> Option.get
+            let oldNode = node.UpdateRightChild (rightChild.LeftChild)
+            rightChild.UpdateLeftChild (Some oldNode)
+
+
+    type AVLTree = {
+        Root: Option<AVLNode>
+    }
+
+    let insert (value: int) (tree: AVLTree) : AVLTree =
+        let rec insertImpl (maybeNode: Option<AVLNode>) : AVLNode =
+            match maybeNode with
+            | None ->
+                AVLNode.create value
+            | Some node ->
+                let node =
+                    if value < node.Value then
+                        node.UpdateLeftChild (Some (insertImpl node.LeftChild))
+                    elif value = node.Value then
+                        node
+                    else
+                        node.UpdateRightChild (Some (insertImpl node.RightChild))
+
+                if AVLNode.balanceFactor node > 1 then
+                    // Root node is right heavy, current balance factor is 2
+                    // check the balance factor of the right child
+                    if node.RightChild |> Option.get |> AVLNode.balanceFactor < 0 then
+                        // Right child is left heavy
+                        // rotate right around right child and rotate left around root
+
+                        // Illustration: possible heights are shown in brackets,
+                        // and the balance factor of the node is shown in parentheses
+
+                        // Initial state:
+                        //
+                        //                  b (+2) [h+3]
+                        //                 / \
+                        //           [h]  a   f (-1) [h+2]
+                        //                    /\
+                        //   [h+1] (0|-1|+1) d  g [h]
+                        //                   /\
+                        //         [h|h-1]  c  e [h|h-1]
+
+                        // rotate right around f (right child)
+                        //
+                        //              b (+2) [h+3]
+                        //             / \
+                        //        [h] a   d (+1|+2) [h+2]
+                        //                /\
+                        //       [h|h-1] c  f (0|-1) [h+1]
+                        //                  /\
+                        //         [h|h-1] e  g [h]
+
+                        // rotate left around b (root)
+                        //                            d (0) [h+2]
+                        //                  __________/\__________
+                        //                 /                       \
+                        //  [h+1] (0|-1)  b                         f (0|-1) [h+1]
+                        //               / \                        /\
+                        //          [h] a   c [h|h-1]    [h|h-1]   e  g [h]
+
+
+                        let node =node.UpdateRightChild (Some (AVLTree.rotateRight (node.RightChild |> Option.get)))
+                        AVLTree.rotateLeft node
+                    else
+                       // Right child is balanced or left heavy,
+                       // rotate left around root
+
+                       // Illustration if right child is balanced
+
+                       // Initial state:
+                       //              b (+2) [h+3]
+                       //             / \
+                       //        [h] a   d (0) [h+2]
+                       //                /\
+                       //        [h+1]  c  e [h+1]
+
+                       // rotate left around b (root)
+                       //                d (-1) [h+3]
+                       //               / \
+                       //   [h+2] (+1) b   e [h+1]
+                       //             / \
+                       //        [h] a   c [h+1]
+
+                       // Illustration if right child is right heavy
+
+                       // Initial state:
+                       //              b (+2) [h+3]
+                       //             / \
+                       //        [h] a   d (+1) [h+2]
+                       //                /\
+                       //          [h]  c  e [h+1]
+
+                       // rotate left around b (root)
+                       //                d (0) [h+2]
+                       //               / \
+                       //   [h+1] (0)  b   e [h+1]
+                       //             / \
+                       //        [h] a   c [h]
+
+                       AVLTree.rotateLeft node
+                elif AVLNode.balanceFactor node < -1 then
+                    // Root node is left heavy, current balance factor is -2
+                    // check the balance factor of the left child
+                    if node.LeftChild |> Option.get |> AVLNode.balanceFactor > 0 then
+                        // Left child is right heavy
+                        // rotate left around left child and rotate right around root
+
+                        // Initial state:
+                        //                  f (-2) [h+3]
+                        //                 / \
+                        //     [h+2] (+1) b   g [h]
+                        //                /\
+                        //           [h] a  d (0|-1|+1) [h+1]
+                        //                  /\
+                        //         [h|h-1] c  e [h|h-1]
+
+                        // rotate left around b (left child)
+                        //                 f (-2) [h+3]
+                        //                / \
+                        //    [h+2] (-2) d   g [h]
+                        //              / \
+                        //       [h+1] b   e [h|h-1]
+                        //            /\
+                        //       [h] a  c [h|h-1]
+
+                        // rotate right around f (root)
+                        //                            d (0) [h+2]
+                        //                  __________/\__________
+                        //                 /                       \
+                        //  [h+1] (0|-1)  b                         f (0|-1) [h+1]
+                        //               / \                        /\
+                        //          [h] a   c [h|h-1]      [h|h-1] e  g [h]
+
+                        let node = node.UpdateLeftChild (Some (AVLTree.rotateLeft (node.LeftChild |> Option.get)))
+                        AVLTree.rotateRight node
+                    else
+                        // Left child is balanced or left heavy
+                        // rotate right around root
+
+                        // Illustration if left child is balanced
+
+                        // Initial state:
+                        //              d (-2) [h+3]
+                        //             / \
+                        //  [h+2] (0) b    e [h]
+                        //           / \
+                        //    [h+1] a   c [h+1]
+
+                        // rotate right around d (root)
+                        //            b (+1) [h+3]
+                        //           / \
+                        //   [h+1] a    d (-1) [h+2]
+                        //             / \
+                        //       [h+1]c   e [h]
+
+                        // Illustration if left child is left heavy
+
+                        // Initial state:
+                        //              d (-2) [h+3]
+                        //             / \
+                        // [h+2] (-1) b    e [h]
+                        //           / \
+                        //    [h+1] a   c [h]
+
+                        // rotate right around d (root)
+                        //            b (0) [h+2]
+                        //           / \
+                        //   [h+1] a    d (0) [h+1]
+                        //             / \
+                        //        [h] c   e [h]
+
+                        AVLTree.rotateRight node
+                else
+                    // Balance of root is within acceptable range
+                    node
+
+
+        insertImpl tree.Root
+        |> fun root -> { Root = Some root }
+

From c76bdb53df04bc885ae8ff348ad9f6b6b37a8789 Mon Sep 17 00:00:00 2001
From: mahdihasnat <mahdihasnat@users.noreply.github.com>
Date: Fri, 6 Dec 2024 15:59:50 +0000
Subject: [PATCH 2/7] updating DIRECTORY.md

---
 DIRECTORY.md | 1 +
 1 file changed, 1 insertion(+)

diff --git a/DIRECTORY.md b/DIRECTORY.md
index e354294..d333615 100644
--- a/DIRECTORY.md
+++ b/DIRECTORY.md
@@ -41,6 +41,7 @@
 
 ## Algorithms
   * Datastructures
+    * [Avltree](https://github.com/TheAlgorithms/F-Sharp/blob/main/Algorithms/DataStructures/AVLTree.fs)
     * [Treap](https://github.com/TheAlgorithms/F-Sharp/blob/main/Algorithms/DataStructures/Treap.fs)
     * [Trie](https://github.com/TheAlgorithms/F-Sharp/blob/main/Algorithms/DataStructures/Trie.fs)
   * Math

From 8269cbadcf5956ea2b4fa6ab8135b534448152a6 Mon Sep 17 00:00:00 2001
From: Mahdi Hasnat Siyam <mahdibuet3@gmail.com>
Date: Fri, 6 Dec 2024 22:19:08 +0600
Subject: [PATCH 3/7] Add tests for insert

---
 Algorithms.Tests/DataStructures/AVLTree.fs | 173 +++++++++++++++++++++
 Algorithms/DataStructures/AVLTree.fs       |   2 +
 2 files changed, 175 insertions(+)
 create mode 100644 Algorithms.Tests/DataStructures/AVLTree.fs

diff --git a/Algorithms.Tests/DataStructures/AVLTree.fs b/Algorithms.Tests/DataStructures/AVLTree.fs
new file mode 100644
index 0000000..7be2ba9
--- /dev/null
+++ b/Algorithms.Tests/DataStructures/AVLTree.fs
@@ -0,0 +1,173 @@
+namespace Algorithms.Tests.DataStructures
+
+open Microsoft.VisualStudio.TestTools.UnitTesting
+open Algorithms.DataStructures.AVLTree
+
+[<TestClass>]
+type AVLTreeTests() =
+
+    let rec verifyBalance (maybeNode: Option<AVLNode>) =
+        match maybeNode with
+        | None -> ()
+        | Some node ->
+            let bf = AVLNode.balanceFactor node
+            Assert.IsTrue(bf >= -1 && bf <= 1, $"Balance factor {bf} is out of range")
+            verifyBalance node.LeftChild
+            verifyBalance node.RightChild
+
+    let rec verifyHeights (maybeNode: Option<AVLNode>) =
+        match maybeNode with
+        | None -> ()
+        | Some node ->
+            let leftHeight = AVLNode.height node.LeftChild
+            let rightHeight = AVLNode.height node.RightChild
+            Assert.AreEqual(node.Height, 1 + max leftHeight rightHeight)
+
+            verifyHeights node.LeftChild
+            verifyHeights node.RightChild
+
+    let rec verifyBST (maybeNode: Option<AVLNode>) : Option< (* Min *) int * (* Max*) int> =
+        match maybeNode with
+        | None -> None
+        | Some node ->
+            let maybeLeftMinMax = verifyBST node.LeftChild
+            let maybeRightMinMax = verifyBST node.RightChild
+            maybeLeftMinMax
+            |> Option.iter (fun (_, leftMax) ->
+                Assert.IsTrue(leftMax < node.Value, $"Left child {leftMax} is greater than parent {node.Value}")
+            )
+            maybeRightMinMax
+            |> Option.iter (fun (rightMin, _) ->
+                Assert.IsTrue(rightMin > node.Value, $"Right child {rightMin} is less than parent {node.Value}")
+            )
+            let minValue =
+                maybeLeftMinMax
+                |> Option.map fst
+                |> Option.defaultValue node.Value
+            let maxValue =
+                maybeRightMinMax
+                |> Option.map snd
+                |> Option.defaultValue node.Value
+            Some (minValue, maxValue)
+
+    let verifyProperties (tree: AVLTree) =
+        verifyBalance tree.Root
+        verifyHeights tree.Root
+        verifyBST tree.Root |> ignore
+        tree
+
+    [<TestMethod>]
+    member _.``Empty tree has no root``() =
+        let tree =
+            empty
+            |> verifyProperties
+
+        Assert.IsTrue(tree.Root.IsNone)
+
+    [<TestMethod>]
+    member _.``Insert maintains AVL properties``() =
+        let tree =
+            empty
+            |> verifyProperties
+            |> insert 5
+            |> verifyProperties
+            |> insert 3
+            |> verifyProperties
+            |> insert 7
+            |> verifyProperties
+            |> insert 1
+            |> verifyProperties
+            |> insert 9
+            |> verifyProperties
+            |> insert 1
+            |> verifyProperties
+        ()
+
+    [<TestMethod>]
+    member _.``Right-heavy case triggers rotation``() =
+        let tree =
+            empty
+            |> verifyProperties
+            |> insert 1
+            |> verifyProperties
+            |> insert 2
+            |> verifyProperties
+            |> insert 3
+            |> verifyProperties
+
+        Assert.IsTrue(tree.Root.IsSome)
+        let root = tree.Root.Value
+        Assert.AreEqual(2, root.Value)
+        Assert.AreEqual(Some 1, root.LeftChild |> Option.map (fun n -> n.Value))
+        Assert.AreEqual(Some 3, root.RightChild |> Option.map (fun n -> n.Value))
+
+    [<TestMethod>]
+    member _.``Left-heavy case triggers rotation``() =
+        let tree =
+            empty
+            |> verifyProperties
+            |> insert 3
+            |> verifyProperties
+            |> insert 2
+            |> verifyProperties
+            |> insert 1
+            |> verifyProperties
+
+        Assert.IsTrue(tree.Root.IsSome)
+        let root = tree.Root.Value
+        Assert.AreEqual(2, root.Value)
+        Assert.AreEqual(Some 1, root.LeftChild |> Option.map (fun n -> n.Value))
+        Assert.AreEqual(Some 3, root.RightChild |> Option.map (fun n -> n.Value))
+
+    [<TestMethod>]
+    member _.``Double rotation for right-left case``() =
+        let tree =
+            empty
+            |> verifyProperties
+            |> insert 1
+            |> verifyProperties
+            |> insert 3
+            |> verifyProperties
+            |> insert 2
+            |> verifyProperties
+
+        Assert.IsTrue(tree.Root.IsSome)
+        let root = tree.Root.Value
+        Assert.AreEqual(2, root.Value)
+        Assert.AreEqual(Some 1, root.LeftChild |> Option.map (fun n -> n.Value))
+        Assert.AreEqual(Some 3, root.RightChild |> Option.map (fun n -> n.Value))
+
+    [<TestMethod>]
+    member _.``Double rotation for left-right case``() =
+        let tree =
+            empty
+            |> verifyProperties
+            |> insert 3
+            |> verifyProperties
+            |> insert 1
+            |> verifyProperties
+            |> insert 2
+            |> verifyProperties
+
+        Assert.IsTrue(tree.Root.IsSome)
+        let root = tree.Root.Value
+        Assert.AreEqual(2, root.Value)
+        Assert.AreEqual(Some 1, root.LeftChild |> Option.map (fun n -> n.Value))
+        Assert.AreEqual(Some 3, root.RightChild |> Option.map (fun n -> n.Value))
+
+    [<TestMethod>]
+    member _.``Duplicate insert is idempotent``() =
+        let tree1 =
+            empty
+            |> verifyProperties
+            |> insert 1
+            |> verifyProperties
+            |> insert 2
+            |> verifyProperties
+
+        let tree2 =
+            insert 2 tree1
+            |> verifyProperties
+
+        Assert.AreEqual(tree1.Root |> Option.map (fun n -> n.Value),
+                       tree2.Root |> Option.map (fun n -> n.Value))
\ No newline at end of file
diff --git a/Algorithms/DataStructures/AVLTree.fs b/Algorithms/DataStructures/AVLTree.fs
index 6a1c12e..b13dd80 100644
--- a/Algorithms/DataStructures/AVLTree.fs
+++ b/Algorithms/DataStructures/AVLTree.fs
@@ -59,6 +59,8 @@ module AVLTree =
         Root: Option<AVLNode>
     }
 
+    let empty = { Root = None }
+
     let insert (value: int) (tree: AVLTree) : AVLTree =
         let rec insertImpl (maybeNode: Option<AVLNode>) : AVLNode =
             match maybeNode with

From 0f61b35e130cba55dfd0eb13c77d020243161ef3 Mon Sep 17 00:00:00 2001
From: Mahdi Hasnat Siyam <mahdibuet3@gmail.com>
Date: Fri, 6 Dec 2024 22:42:28 +0600
Subject: [PATCH 4/7] implement delete

---
 Algorithms/DataStructures/AVLTree.fs | 366 +++++++++++++++------------
 1 file changed, 206 insertions(+), 160 deletions(-)

diff --git a/Algorithms/DataStructures/AVLTree.fs b/Algorithms/DataStructures/AVLTree.fs
index b13dd80..599db32 100644
--- a/Algorithms/DataStructures/AVLTree.fs
+++ b/Algorithms/DataStructures/AVLTree.fs
@@ -61,175 +61,221 @@ module AVLTree =
 
     let empty = { Root = None }
 
+    let private rebalance (node: AVLNode) : AVLNode =
+        if AVLNode.balanceFactor node > 1 then
+            // Root node is right heavy, current balance factor is 2
+            // check the balance factor of the right child
+            if node.RightChild |> Option.get |> AVLNode.balanceFactor < 0 then
+                // Right child is left heavy
+                // rotate right around right child and rotate left around root
+
+                // Illustration: possible heights are shown in brackets,
+                // and the balance factor of the node is shown in parentheses
+
+                // Initial state:
+                //
+                //                  b (+2) [h+3]
+                //                 / \
+                //           [h]  a   f (-1) [h+2]
+                //                    /\
+                //   [h+1] (0|-1|+1) d  g [h]
+                //                   /\
+                //         [h|h-1]  c  e [h|h-1]
+
+                // rotate right around f (right child)
+                //
+                //              b (+2) [h+3]
+                //             / \
+                //        [h] a   d (+1|+2) [h+2]
+                //                /\
+                //       [h|h-1] c  f (0|-1) [h+1]
+                //                  /\
+                //         [h|h-1] e  g [h]
+
+                // rotate left around b (root)
+                //                            d (0) [h+2]
+                //                  __________/\__________
+                //                 /                       \
+                //  [h+1] (0|-1)  b                         f (0|-1) [h+1]
+                //               / \                        /\
+                //          [h] a   c [h|h-1]    [h|h-1]   e  g [h]
+
+
+                let node =node.UpdateRightChild (Some (AVLTree.rotateRight (node.RightChild |> Option.get)))
+                AVLTree.rotateLeft node
+            else
+               // Right child is balanced or left heavy,
+               // rotate left around root
+
+               // Illustration if right child is balanced
+
+               // Initial state:
+               //              b (+2) [h+3]
+               //             / \
+               //        [h] a   d (0) [h+2]
+               //                /\
+               //        [h+1]  c  e [h+1]
+
+               // rotate left around b (root)
+               //                d (-1) [h+3]
+               //               / \
+               //   [h+2] (+1) b   e [h+1]
+               //             / \
+               //        [h] a   c [h+1]
+
+               // Illustration if right child is right heavy
+
+               // Initial state:
+               //              b (+2) [h+3]
+               //             / \
+               //        [h] a   d (+1) [h+2]
+               //                /\
+               //          [h]  c  e [h+1]
+
+               // rotate left around b (root)
+               //                d (0) [h+2]
+               //               / \
+               //   [h+1] (0)  b   e [h+1]
+               //             / \
+               //        [h] a   c [h]
+
+               AVLTree.rotateLeft node
+        elif AVLNode.balanceFactor node < -1 then
+            // Root node is left heavy, current balance factor is -2
+            // check the balance factor of the left child
+            if node.LeftChild |> Option.get |> AVLNode.balanceFactor > 0 then
+                // Left child is right heavy
+                // rotate left around left child and rotate right around root
+
+                // Initial state:
+                //                  f (-2) [h+3]
+                //                 / \
+                //     [h+2] (+1) b   g [h]
+                //                /\
+                //           [h] a  d (0|-1|+1) [h+1]
+                //                  /\
+                //         [h|h-1] c  e [h|h-1]
+
+                // rotate left around b (left child)
+                //                 f (-2) [h+3]
+                //                / \
+                //    [h+2] (-2) d   g [h]
+                //              / \
+                //       [h+1] b   e [h|h-1]
+                //            /\
+                //       [h] a  c [h|h-1]
+
+                // rotate right around f (root)
+                //                            d (0) [h+2]
+                //                  __________/\__________
+                //                 /                       \
+                //  [h+1] (0|-1)  b                         f (0|-1) [h+1]
+                //               / \                        /\
+                //          [h] a   c [h|h-1]      [h|h-1] e  g [h]
+
+                let node = node.UpdateLeftChild (Some (AVLTree.rotateLeft (node.LeftChild |> Option.get)))
+                AVLTree.rotateRight node
+            else
+                // Left child is balanced or left heavy
+                // rotate right around root
+
+                // Illustration if left child is balanced
+
+                // Initial state:
+                //              d (-2) [h+3]
+                //             / \
+                //  [h+2] (0) b    e [h]
+                //           / \
+                //    [h+1] a   c [h+1]
+
+                // rotate right around d (root)
+                //            b (+1) [h+3]
+                //           / \
+                //   [h+1] a    d (-1) [h+2]
+                //             / \
+                //       [h+1]c   e [h]
+
+                // Illustration if left child is left heavy
+
+                // Initial state:
+                //              d (-2) [h+3]
+                //             / \
+                // [h+2] (-1) b    e [h]
+                //           / \
+                //    [h+1] a   c [h]
+
+                // rotate right around d (root)
+                //            b (0) [h+2]
+                //           / \
+                //   [h+1] a    d (0) [h+1]
+                //             / \
+                //        [h] c   e [h]
+
+                AVLTree.rotateRight node
+        else
+            // Balance of root is within acceptable range
+            node
+
+
     let insert (value: int) (tree: AVLTree) : AVLTree =
         let rec insertImpl (maybeNode: Option<AVLNode>) : AVLNode =
             match maybeNode with
             | None ->
                 AVLNode.create value
             | Some node ->
-                let node =
-                    if value < node.Value then
-                        node.UpdateLeftChild (Some (insertImpl node.LeftChild))
-                    elif value = node.Value then
-                        node
-                    else
-                        node.UpdateRightChild (Some (insertImpl node.RightChild))
-
-                if AVLNode.balanceFactor node > 1 then
-                    // Root node is right heavy, current balance factor is 2
-                    // check the balance factor of the right child
-                    if node.RightChild |> Option.get |> AVLNode.balanceFactor < 0 then
-                        // Right child is left heavy
-                        // rotate right around right child and rotate left around root
-
-                        // Illustration: possible heights are shown in brackets,
-                        // and the balance factor of the node is shown in parentheses
-
-                        // Initial state:
-                        //
-                        //                  b (+2) [h+3]
-                        //                 / \
-                        //           [h]  a   f (-1) [h+2]
-                        //                    /\
-                        //   [h+1] (0|-1|+1) d  g [h]
-                        //                   /\
-                        //         [h|h-1]  c  e [h|h-1]
-
-                        // rotate right around f (right child)
-                        //
-                        //              b (+2) [h+3]
-                        //             / \
-                        //        [h] a   d (+1|+2) [h+2]
-                        //                /\
-                        //       [h|h-1] c  f (0|-1) [h+1]
-                        //                  /\
-                        //         [h|h-1] e  g [h]
-
-                        // rotate left around b (root)
-                        //                            d (0) [h+2]
-                        //                  __________/\__________
-                        //                 /                       \
-                        //  [h+1] (0|-1)  b                         f (0|-1) [h+1]
-                        //               / \                        /\
-                        //          [h] a   c [h|h-1]    [h|h-1]   e  g [h]
-
-
-                        let node =node.UpdateRightChild (Some (AVLTree.rotateRight (node.RightChild |> Option.get)))
-                        AVLTree.rotateLeft node
-                    else
-                       // Right child is balanced or left heavy,
-                       // rotate left around root
-
-                       // Illustration if right child is balanced
-
-                       // Initial state:
-                       //              b (+2) [h+3]
-                       //             / \
-                       //        [h] a   d (0) [h+2]
-                       //                /\
-                       //        [h+1]  c  e [h+1]
-
-                       // rotate left around b (root)
-                       //                d (-1) [h+3]
-                       //               / \
-                       //   [h+2] (+1) b   e [h+1]
-                       //             / \
-                       //        [h] a   c [h+1]
-
-                       // Illustration if right child is right heavy
-
-                       // Initial state:
-                       //              b (+2) [h+3]
-                       //             / \
-                       //        [h] a   d (+1) [h+2]
-                       //                /\
-                       //          [h]  c  e [h+1]
-
-                       // rotate left around b (root)
-                       //                d (0) [h+2]
-                       //               / \
-                       //   [h+1] (0)  b   e [h+1]
-                       //             / \
-                       //        [h] a   c [h]
-
-                       AVLTree.rotateLeft node
-                elif AVLNode.balanceFactor node < -1 then
-                    // Root node is left heavy, current balance factor is -2
-                    // check the balance factor of the left child
-                    if node.LeftChild |> Option.get |> AVLNode.balanceFactor > 0 then
-                        // Left child is right heavy
-                        // rotate left around left child and rotate right around root
-
-                        // Initial state:
-                        //                  f (-2) [h+3]
-                        //                 / \
-                        //     [h+2] (+1) b   g [h]
-                        //                /\
-                        //           [h] a  d (0|-1|+1) [h+1]
-                        //                  /\
-                        //         [h|h-1] c  e [h|h-1]
-
-                        // rotate left around b (left child)
-                        //                 f (-2) [h+3]
-                        //                / \
-                        //    [h+2] (-2) d   g [h]
-                        //              / \
-                        //       [h+1] b   e [h|h-1]
-                        //            /\
-                        //       [h] a  c [h|h-1]
-
-                        // rotate right around f (root)
-                        //                            d (0) [h+2]
-                        //                  __________/\__________
-                        //                 /                       \
-                        //  [h+1] (0|-1)  b                         f (0|-1) [h+1]
-                        //               / \                        /\
-                        //          [h] a   c [h|h-1]      [h|h-1] e  g [h]
-
-                        let node = node.UpdateLeftChild (Some (AVLTree.rotateLeft (node.LeftChild |> Option.get)))
-                        AVLTree.rotateRight node
-                    else
-                        // Left child is balanced or left heavy
-                        // rotate right around root
-
-                        // Illustration if left child is balanced
-
-                        // Initial state:
-                        //              d (-2) [h+3]
-                        //             / \
-                        //  [h+2] (0) b    e [h]
-                        //           / \
-                        //    [h+1] a   c [h+1]
-
-                        // rotate right around d (root)
-                        //            b (+1) [h+3]
-                        //           / \
-                        //   [h+1] a    d (-1) [h+2]
-                        //             / \
-                        //       [h+1]c   e [h]
-
-                        // Illustration if left child is left heavy
-
-                        // Initial state:
-                        //              d (-2) [h+3]
-                        //             / \
-                        // [h+2] (-1) b    e [h]
-                        //           / \
-                        //    [h+1] a   c [h]
-
-                        // rotate right around d (root)
-                        //            b (0) [h+2]
-                        //           / \
-                        //   [h+1] a    d (0) [h+1]
-                        //             / \
-                        //        [h] c   e [h]
-
-                        AVLTree.rotateRight node
-                else
-                    // Balance of root is within acceptable range
+                if value < node.Value then
+                    node.UpdateLeftChild (Some (insertImpl node.LeftChild))
+                    |> rebalance
+                elif value = node.Value then
                     node
+                else
+                    node.UpdateRightChild (Some (insertImpl node.RightChild))
+                    |> rebalance
 
 
         insertImpl tree.Root
         |> fun root -> { Root = Some root }
 
+    let delete (value: int) (tree: AVLTree) : AVLTree =
+        let rec deleteMinValueNode (node: AVLNode) : Option<AVLNode> * (* MinValue *) int =
+            match node.LeftChild with
+            | None ->
+                // delete current node and return the value that was replaced
+                node.RightChild, node.Value
+            | Some leftChild ->
+                let leftChild, minValue = deleteMinValueNode leftChild
+                let node =
+                    node.UpdateLeftChild leftChild
+                    |> rebalance
+                Some node, minValue
+
+        let rec deleteImpl (maybeNode: Option<AVLNode>) : Option<AVLNode> =
+            match maybeNode with
+            | None -> None
+            | Some node ->
+                if value < node.Value then
+                    node.UpdateLeftChild (deleteImpl node.LeftChild)
+                    |> rebalance
+                    |> Some
+                elif value = node.Value then
+                    match node.LeftChild, node.RightChild with
+                    | None, None -> None
+                    | None, Some rightChild -> Some rightChild
+                    | Some leftChild, None -> Some leftChild
+                    | Some leftChild, Some rightChild ->
+                        let rightNode, currentValue  = deleteMinValueNode rightChild
+                        let node = { node with Value = currentValue }
+
+                        node.UpdateRightChild rightNode
+                        |> rebalance
+                        |> Some
+                else
+                    node.UpdateRightChild (deleteImpl node.RightChild)
+                    |> rebalance
+                    |> Some
+
+
+        deleteImpl tree.Root
+        |> fun root -> { Root = root }
+
+

From 7044a83f1d4f65af7f8b1e246d67578963fa63ca Mon Sep 17 00:00:00 2001
From: Mahdi Hasnat Siyam <mahdibuet3@gmail.com>
Date: Fri, 6 Dec 2024 22:49:20 +0600
Subject: [PATCH 5/7] add tests for delete

---
 Algorithms.Tests/DataStructures/AVLTree.fs | 148 ++++++++++++++++++++-
 1 file changed, 147 insertions(+), 1 deletion(-)

diff --git a/Algorithms.Tests/DataStructures/AVLTree.fs b/Algorithms.Tests/DataStructures/AVLTree.fs
index 7be2ba9..48826bc 100644
--- a/Algorithms.Tests/DataStructures/AVLTree.fs
+++ b/Algorithms.Tests/DataStructures/AVLTree.fs
@@ -170,4 +170,150 @@ type AVLTreeTests() =
             |> verifyProperties
 
         Assert.AreEqual(tree1.Root |> Option.map (fun n -> n.Value),
-                       tree2.Root |> Option.map (fun n -> n.Value))
\ No newline at end of file
+                       tree2.Root |> Option.map (fun n -> n.Value))
+    [<TestMethod>]
+    member _.``Delete maintains AVL properties``() =
+        let tree =
+            empty
+            |> insert 5
+            |> verifyProperties
+            |> insert 3
+            |> verifyProperties
+            |> insert 7
+            |> verifyProperties
+            |> insert 1
+            |> verifyProperties
+            |> insert 9
+            |> verifyProperties
+            |> insert 4
+            |> verifyProperties
+            |> insert 6
+            |> verifyProperties
+            |> insert 8
+            |> verifyProperties
+            |> insert 2
+            |> verifyProperties
+            |> delete 5  // Delete root
+            |> verifyProperties
+            |> delete 1  // Delete leaf
+            |> verifyProperties
+            |> delete 7  // Delete node with one child
+            |> verifyProperties
+            |> delete 3  // Delete node with two children
+            |> verifyProperties
+
+        Assert.IsTrue(tree.Root.IsSome)
+
+    [<TestMethod>]
+    member _.``Delete from empty tree returns empty tree``() =
+        let tree =
+            empty
+            |> delete 1
+            |> verifyProperties
+
+        Assert.IsTrue(tree.Root.IsNone)
+
+    [<TestMethod>]
+    member _.``Delete non-existent value maintains tree structure``() =
+        let tree1 =
+            empty
+            |> insert 2
+            |> verifyProperties
+            |> insert 1
+            |> verifyProperties
+            |> insert 3
+            |> verifyProperties
+
+        let tree2 =
+            tree1
+            |> delete 4
+            |> verifyProperties
+
+        Assert.AreEqual(
+            tree1.Root |> Option.map (fun n -> n.Value),
+            tree2.Root |> Option.map (fun n -> n.Value)
+        )
+
+    [<TestMethod>]
+    member _.``Complex deletion cases maintain balance``() =
+        let tree =
+            empty
+            |> insert 50  // Create a more complex tree
+            |> verifyProperties
+            |> insert 25
+            |> verifyProperties
+            |> insert 75
+            |> verifyProperties
+            |> insert 10
+            |> verifyProperties
+            |> insert 35
+            |> verifyProperties
+            |> insert 60
+            |> verifyProperties
+            |> insert 90
+            |> verifyProperties
+            |> insert 5
+            |> verifyProperties
+            |> insert 15
+            |> verifyProperties
+            |> insert 30
+            |> verifyProperties
+            |> insert 40
+            |> verifyProperties
+            |> insert 55
+            |> verifyProperties
+            |> insert 65
+            |> verifyProperties
+            |> insert 80
+            |> verifyProperties
+            |> insert 95
+            |> verifyProperties
+
+            // Test various deletion patterns
+            |> delete 50  // Delete root with two children
+            |> verifyProperties
+            |> delete 25  // Delete inner node with two children
+            |> verifyProperties
+            |> delete 5   // Delete leaf
+            |> verifyProperties
+            |> delete 95  // Delete leaf on opposite side
+            |> verifyProperties
+            |> delete 35  // Delete node with one child
+            |> verifyProperties
+            |> delete 75  // Delete node requiring rebalancing
+            |> verifyProperties
+
+        Assert.IsTrue(tree.Root.IsSome)
+
+    [<TestMethod>]
+    member _.``Sequential deletion maintains balance``() =
+        let mutable tree = empty
+
+        // Build tree with sequential inserts
+        for i in 1..10 do
+            tree <- insert i tree
+            tree <- verifyProperties tree
+
+        // Delete in reverse order
+        for i in seq{10..(-1)..1} do
+            tree <- delete i tree
+            tree <- verifyProperties tree
+
+        Assert.IsTrue(tree.Root.IsNone)
+
+    [<TestMethod>]
+    member _.``Random operations maintain AVL properties``() =
+        let rng = System.Random(42)
+        let mutable tree = empty
+
+        // Random inserts
+        for _ in 1..20 do
+            let value = rng.Next(1, 100)
+            tree <- insert value tree
+            tree <- verifyProperties tree
+
+        // Random deletes
+        for _ in 1..10 do
+            let value = rng.Next(1, 100)
+            tree <- delete value tree
+            tree <- verifyProperties tree
\ No newline at end of file

From 11792a06d762674296752e7bfaea78db9bd286b4 Mon Sep 17 00:00:00 2001
From: mahdihasnat <mahdihasnat@users.noreply.github.com>
Date: Fri, 6 Dec 2024 16:49:35 +0000
Subject: [PATCH 6/7] updating DIRECTORY.md

---
 DIRECTORY.md | 1 +
 1 file changed, 1 insertion(+)

diff --git a/DIRECTORY.md b/DIRECTORY.md
index d333615..4c17128 100644
--- a/DIRECTORY.md
+++ b/DIRECTORY.md
@@ -2,6 +2,7 @@
 
 ## Algorithms.Tests
   * Datastructures
+    * [Avltree](https://github.com/TheAlgorithms/F-Sharp/blob/main/Algorithms.Tests/DataStructures/AVLTree.fs)
     * [Treap](https://github.com/TheAlgorithms/F-Sharp/blob/main/Algorithms.Tests/DataStructures/Treap.fs)
     * [Trie](https://github.com/TheAlgorithms/F-Sharp/blob/main/Algorithms.Tests/DataStructures/Trie.fs)
   * Math

From 8c1e28bd0a345f82914ae3f4df4bda86e52317b4 Mon Sep 17 00:00:00 2001
From: Mahdi Hasnat Siyam <mahdibuet3@gmail.com>
Date: Fri, 6 Dec 2024 22:50:15 +0600
Subject: [PATCH 7/7] ignore unused variable

---
 Algorithms/DataStructures/AVLTree.fs | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/Algorithms/DataStructures/AVLTree.fs b/Algorithms/DataStructures/AVLTree.fs
index 599db32..4043d54 100644
--- a/Algorithms/DataStructures/AVLTree.fs
+++ b/Algorithms/DataStructures/AVLTree.fs
@@ -262,7 +262,7 @@ module AVLTree =
                     | None, None -> None
                     | None, Some rightChild -> Some rightChild
                     | Some leftChild, None -> Some leftChild
-                    | Some leftChild, Some rightChild ->
+                    | Some _leftChild, Some rightChild ->
                         let rightNode, currentValue  = deleteMinValueNode rightChild
                         let node = { node with Value = currentValue }