package com.radix2.algorithms.week4

import java.util.*

interface SymbolTable<K : Comparable<K>, V> {
    fun put(key: K, value: V)

    fun get(key: K): V?

    fun min(): Pair<K, V>?

    fun max(): Pair<K, V>?

    fun floor(key: K): Pair<K, V>?

    fun ceil(key: K): Pair<K, V>?

    fun size(): Int

    fun rank(key: K): Int

    fun deleteMin()

    fun deleteMax()

    fun delete(key: K)

    override fun toString(): String
}

class BST<K : Comparable<K>, V> : SymbolTable<K, V> {
    private class Node<K : Any, V>(
        var key: K,
        var data: V,
        var left: Node<K, V>? = null,
        var right: Node<K, V>? = null,
        var count: Int = 1
    ) {
        override fun toString(): String = (key to data).toString()
    }

    private var root: Node<K, V>? = null

    override fun put(key: K, value: V) {
        root = put(root, key, value)
    }

    override fun get(key: K): V? = get(root, key)?.data

    override fun min(): Pair<K, V>? = min(root)?.let { it.key to it.data }

    override fun max(): Pair<K, V>? = max(root)?.let { it.key to it.data }

    override fun floor(key: K): Pair<K, V>? = floor(root, key)?.let { it.key to it.data }

    override fun ceil(key: K): Pair<K, V>? = ceil(root, key)?.let { it.key to it.data }

    override fun size(): Int = root?.count ?: 0

    override fun rank(key: K): Int = rank(root, key)

    override fun deleteMin() {
        deleteMin(root)
    }

    override fun deleteMax() {
        deleteMax(root)
    }

    override fun delete(key: K) {
        delete(root, key)
    }

    override fun toString(): String = buildString {
        levelOrder(root, this)

        //inOrderWithStack(root, this)
        //inOrderRecursive(root, this)
    }

    private fun put(root: Node<K, V>?, key: K, value: V): Node<K, V>? {
        if (root == null)
            return Node(key, value)

        val cmp = key.compareTo(root.key)

        when {
            cmp < 0 -> root.left = put(root.left, key, value)

            cmp > 0 -> root.right = put(root.right, key, value)

            else -> root.data = value
        }

        root.count = 1 + (root.left?.count ?: 0) + (root.right?.count ?: 0)

        return root
    }

    private fun get(root: Node<K, V>?, key: K): Node<K, V>? {
        if (root == null)
            return root

        val cmp = key.compareTo(root.key)

        return when {
            cmp < 0 -> get(root.left, key)

            cmp > 0 -> get(root.right, key)

            else -> root
        }
    }

    private fun min(root: Node<K, V>?): Node<K, V>? {
        if (root?.left == null)
            return root

        return min(root.left)
    }

    private fun max(root: Node<K, V>?): Node<K, V>? {
        if (root?.right == null)
            return root

        return max(root.right)
    }

    private fun floor(root: Node<K, V>?, key: K): Node<K, V>? {
        if (root == null)
            return null

        val cmp = key.compareTo(root.key)

        return when {
            cmp == 0 -> root

            cmp < 0 -> floor(root.left, key)

            else -> floor(root.right, key) ?: root
        }
    }

    private fun ceil(root: Node<K, V>?, key: K): Node<K, V>? {
        if (root == null)
            return null

        val cmp = key.compareTo(root.key)

        return when {
            cmp == 0 -> root

            cmp < 0 -> ceil(root.left, key) ?: root

            else -> ceil(root.right, key)
        }
    }

    private fun rank(root: Node<K, V>?, key: K): Int {
        if (root == null)
            return 0

        val cmp = key.compareTo(root.key)

        return when {
            cmp == 0 -> root.left?.count ?: 0

            cmp < 0 -> rank(root.left, key)

            else -> 1 + (root.left?.count ?: 0) + rank(root.right, key)
        }
    }

    private fun deleteMin(root: Node<K, V>?): Node<K, V>? {
        if (root?.left == null)
            return root?.right

        root.left = deleteMin(root.left)

        root.count = 1 + (root.left?.count ?: 0) + (root.right?.count ?: 0)

        return root
    }

    private fun deleteMax(root: Node<K, V>?): Node<K, V>? {
        if (root?.right == null)
            return root?.left

        root.right = deleteMax(root.right)

        root.count = 1 + (root.right?.count ?: 0) + (root.left?.count ?: 0)

        return root
    }

    private fun delete(root: Node<K, V>?, key: K): Node<K, V>? {
        if (root == null)
            return null

        var trav = root

        val cmp = key.compareTo(trav.key)

        when {
            cmp < 0 -> trav.left = delete(trav.left, key)
            cmp > 0 -> trav.right = delete(trav.right, key)

            else -> {
                if (trav.left == null)
                    return trav.right

                if (trav.right == null)
                    return trav.left

                val temp = trav

                trav = min(temp.right)

                trav?.right = deleteMin(temp.right)

                trav?.left = temp.left
            }
        }

        trav?.count = 1 + (trav?.left?.count ?: 0) + (trav?.right?.count ?: 0)

        return trav
    }

    private fun inOrderRecursive(root: Node<K, V>?, builder: StringBuilder) {
        if (root == null)
            return

        inOrderRecursive(root.left, builder)

        builder.append(root.key to root.data)

        inOrderRecursive(root.right, builder)
    }

    private fun inOrderWithStack(root: Node<K, V>?, builder: StringBuilder) {
        if (root == null)
            return

        var trav = root

        val stack = Stack<Node<K, V>>()

        while (trav != null || !stack.isEmpty()) {
            while (trav != null) {
                stack.push(trav)
                trav = trav.left
            }

            val top = stack.pop()

            builder.append(top.key to top.data)

            trav = top.right
        }
    }

    private fun levelOrder(root: Node<K, V>?, builder: StringBuilder) {
        if (root == null)
            return

        val queue: Queue<Node<K, V>> = LinkedList()

        queue.add(root)

        with(queue) {
            while (!queue.isEmpty()) {

                if (builder.isNotEmpty()) {
                    builder.append(", ")
                }

                builder.append(peek())

                val front = queue.poll()

                if (front.left != null) {
                    add(front.left)
                }

                if (front.right != null) {
                    add(front.right)
                }
            }
        }
    }
}

fun <K : Comparable<K>, V> SymbolTable<K, V?>.put(key: K) = this.put(key, null)

fun main() {
    val st: SymbolTable<Int, String?> = BST()
    st.put(6)

    st.put(7)

    st.put(4)

    st.put(1)

    println(st)
}

Compiled from "BST.kt"
final class com.radix2.algorithms.week4.BST$Node<K, V> {
  private K key;

  private V data;

  private com.radix2.algorithms.week4.BST$Node<K, V> left;

  private com.radix2.algorithms.week4.BST$Node<K, V> right;

  private int count;

  public com.radix2.algorithms.week4.BST$Node(K, V, com.radix2.algorithms.week4.BST$Node<K, V>, com.radix2.algorithms.week4.BST$Node<K, V>, int);
    Code:
       0: aload_1
       1: ldc           #12                 // String key
       3: invokestatic  #18                 // Method kotlin/jvm/internal/Intrinsics.checkNotNullParameter:(Ljava/lang/Object;Ljava/lang/String;)V
       6: aload_0
       7: invokespecial #21                 // Method java/lang/Object."<init>":()V
      10: aload_0
      11: aload_1
      12: putfield      #24                 // Field key:Ljava/lang/Object;
      15: aload_0
      16: aload_2
      17: putfield      #27                 // Field data:Ljava/lang/Object;
      20: aload_0
      21: aload_3
      22: putfield      #31                 // Field left:Lcom/radix2/algorithms/week4/BST$Node;
      25: aload_0
      26: aload         4
      28: putfield      #34                 // Field right:Lcom/radix2/algorithms/week4/BST$Node;
      31: aload_0
      32: iload         5
      34: putfield      #38                 // Field count:I
      37: return

  public com.radix2.algorithms.week4.BST$Node(java.lang.Object, java.lang.Object, com.radix2.algorithms.week4.BST$Node, com.radix2.algorithms.week4.BST$Node, int, int, kotlin.jvm.internal.DefaultConstructorMarker);
    Code:
       0: iload         6
       2: iconst_4
       3: iand
       4: ifeq          9
       7: aconst_null
       8: astore_3
       9: iload         6
      11: bipush        8
      13: iand
      14: ifeq          20
      17: aconst_null
      18: astore        4
      20: iload         6
      22: bipush        16
      24: iand
      25: ifeq          31
      28: iconst_1
      29: istore        5
      31: aload_0
      32: aload_1
      33: aload_2
      34: aload_3
      35: aload         4
      37: iload         5
      39: invokespecial #42                 // Method "<init>":(Ljava/lang/Object;Ljava/lang/Object;Lcom/radix2/algorithms/week4/BST$Node;Lcom/radix2/algorithms/week4/BST$Node;I)V
      42: return

  public final K getKey();
    Code:
       0: aload_0
       1: getfield      #24                 // Field key:Ljava/lang/Object;
       4: areturn

  public final void setKey(K);
    Code:
       0: aload_1
       1: ldc           #50                 // String <set-?>
       3: invokestatic  #18                 // Method kotlin/jvm/internal/Intrinsics.checkNotNullParameter:(Ljava/lang/Object;Ljava/lang/String;)V
       6: aload_0
       7: aload_1
       8: putfield      #24                 // Field key:Ljava/lang/Object;
      11: return

  public final V getData();
    Code:
       0: aload_0
       1: getfield      #27                 // Field data:Ljava/lang/Object;
       4: areturn

  public final void setData(V);
    Code:
       0: aload_0
       1: aload_1
       2: putfield      #27                 // Field data:Ljava/lang/Object;
       5: return

  public final com.radix2.algorithms.week4.BST$Node<K, V> getLeft();
    Code:
       0: aload_0
       1: getfield      #31                 // Field left:Lcom/radix2/algorithms/week4/BST$Node;
       4: areturn

  public final void setLeft(com.radix2.algorithms.week4.BST$Node<K, V>);
    Code:
       0: aload_0
       1: aload_1
       2: putfield      #31                 // Field left:Lcom/radix2/algorithms/week4/BST$Node;
       5: return

  public final com.radix2.algorithms.week4.BST$Node<K, V> getRight();
    Code:
       0: aload_0
       1: getfield      #34                 // Field right:Lcom/radix2/algorithms/week4/BST$Node;
       4: areturn

  public final void setRight(com.radix2.algorithms.week4.BST$Node<K, V>);
    Code:
       0: aload_0
       1: aload_1
       2: putfield      #34                 // Field right:Lcom/radix2/algorithms/week4/BST$Node;
       5: return

  public final int getCount();
    Code:
       0: aload_0
       1: getfield      #38                 // Field count:I
       4: ireturn

  public final void setCount(int);
    Code:
       0: aload_0
       1: iload_1
       2: putfield      #38                 // Field count:I
       5: return

  public java.lang.String toString();
    Code:
       0: aload_0
       1: getfield      #24                 // Field key:Ljava/lang/Object;
       4: aload_0
       5: getfield      #27                 // Field data:Ljava/lang/Object;
       8: invokestatic  #74                 // Method kotlin/TuplesKt.to:(Ljava/lang/Object;Ljava/lang/Object;)Lkotlin/Pair;
      11: invokevirtual #78                 // Method kotlin/Pair.toString:()Ljava/lang/String;
      14: areturn
}

Compiled from "BST.kt"
public final class com.radix2.algorithms.week4.BST<K extends java.lang.Comparable<? super K>, V> implements com.radix2.algorithms.week4.SymbolTable<K, V> {
  private com.radix2.algorithms.week4.BST$Node<K, V> root;

  public com.radix2.algorithms.week4.BST();
    Code:
       0: aload_0
       1: invokespecial #11                 // Method java/lang/Object."<init>":()V
       4: return

  public void put(K, V);
    Code:
       0: aload_1
       1: ldc           #19                 // String key
       3: invokestatic  #25                 // Method kotlin/jvm/internal/Intrinsics.checkNotNullParameter:(Ljava/lang/Object;Ljava/lang/String;)V
       6: aload_0
       7: aload_0
       8: aload_0
       9: getfield      #29                 // Field root:Lcom/radix2/algorithms/week4/BST$Node;
      12: aload_1
      13: aload_2
      14: invokespecial #32                 // Method put:(Lcom/radix2/algorithms/week4/BST$Node;Ljava/lang/Comparable;Ljava/lang/Object;)Lcom/radix2/algorithms/week4/BST$Node;
      17: putfield      #29                 // Field root:Lcom/radix2/algorithms/week4/BST$Node;
      20: return

  public V get(K);
    Code:
       0: aload_1
       1: ldc           #19                 // String key
       3: invokestatic  #25                 // Method kotlin/jvm/internal/Intrinsics.checkNotNullParameter:(Ljava/lang/Object;Ljava/lang/String;)V
       6: aload_0
       7: aload_0
       8: getfield      #29                 // Field root:Lcom/radix2/algorithms/week4/BST$Node;
      11: aload_1
      12: invokespecial #42                 // Method get:(Lcom/radix2/algorithms/week4/BST$Node;Ljava/lang/Comparable;)Lcom/radix2/algorithms/week4/BST$Node;
      15: dup
      16: ifnull        25
      19: invokevirtual #48                 // Method com/radix2/algorithms/week4/BST$Node.getData:()Ljava/lang/Object;
      22: goto          27
      25: pop
      26: aconst_null
      27: areturn

  public kotlin.Pair<K, V> min();
    Code:
       0: aload_0
       1: aload_0
       2: getfield      #29                 // Field root:Lcom/radix2/algorithms/week4/BST$Node;
       5: invokespecial #54                 // Method min:(Lcom/radix2/algorithms/week4/BST$Node;)Lcom/radix2/algorithms/week4/BST$Node;
       8: dup
       9: ifnull        29
      12: astore_1
      13: iconst_0
      14: istore_2
      15: aload_1
      16: invokevirtual #57                 // Method com/radix2/algorithms/week4/BST$Node.getKey:()Ljava/lang/Object;
      19: aload_1
      20: invokevirtual #48                 // Method com/radix2/algorithms/week4/BST$Node.getData:()Ljava/lang/Object;
      23: invokestatic  #63                 // Method kotlin/TuplesKt.to:(Ljava/lang/Object;Ljava/lang/Object;)Lkotlin/Pair;
      26: goto          31
      29: pop
      30: aconst_null
      31: areturn

  public kotlin.Pair<K, V> max();
    Code:
       0: aload_0
       1: aload_0
       2: getfield      #29                 // Field root:Lcom/radix2/algorithms/week4/BST$Node;
       5: invokespecial #71                 // Method max:(Lcom/radix2/algorithms/week4/BST$Node;)Lcom/radix2/algorithms/week4/BST$Node;
       8: dup
       9: ifnull        29
      12: astore_1
      13: iconst_0
      14: istore_2
      15: aload_1
      16: invokevirtual #57                 // Method com/radix2/algorithms/week4/BST$Node.getKey:()Ljava/lang/Object;
      19: aload_1
      20: invokevirtual #48                 // Method com/radix2/algorithms/week4/BST$Node.getData:()Ljava/lang/Object;
      23: invokestatic  #63                 // Method kotlin/TuplesKt.to:(Ljava/lang/Object;Ljava/lang/Object;)Lkotlin/Pair;
      26: goto          31
      29: pop
      30: aconst_null
      31: areturn

  public kotlin.Pair<K, V> floor(K);
    Code:
       0: aload_1
       1: ldc           #19                 // String key
       3: invokestatic  #25                 // Method kotlin/jvm/internal/Intrinsics.checkNotNullParameter:(Ljava/lang/Object;Ljava/lang/String;)V
       6: aload_0
       7: aload_0
       8: getfield      #29                 // Field root:Lcom/radix2/algorithms/week4/BST$Node;
      11: aload_1
      12: invokespecial #77                 // Method floor:(Lcom/radix2/algorithms/week4/BST$Node;Ljava/lang/Comparable;)Lcom/radix2/algorithms/week4/BST$Node;
      15: dup
      16: ifnull        36
      19: astore_2
      20: iconst_0
      21: istore_3
      22: aload_2
      23: invokevirtual #57                 // Method com/radix2/algorithms/week4/BST$Node.getKey:()Ljava/lang/Object;
      26: aload_2
      27: invokevirtual #48                 // Method com/radix2/algorithms/week4/BST$Node.getData:()Ljava/lang/Object;
      30: invokestatic  #63                 // Method kotlin/TuplesKt.to:(Ljava/lang/Object;Ljava/lang/Object;)Lkotlin/Pair;
      33: goto          38
      36: pop
      37: aconst_null
      38: areturn

  public kotlin.Pair<K, V> ceil(K);
    Code:
       0: aload_1
       1: ldc           #19                 // String key
       3: invokestatic  #25                 // Method kotlin/jvm/internal/Intrinsics.checkNotNullParameter:(Ljava/lang/Object;Ljava/lang/String;)V
       6: aload_0
       7: aload_0
       8: getfield      #29                 // Field root:Lcom/radix2/algorithms/week4/BST$Node;
      11: aload_1
      12: invokespecial #81                 // Method ceil:(Lcom/radix2/algorithms/week4/BST$Node;Ljava/lang/Comparable;)Lcom/radix2/algorithms/week4/BST$Node;
      15: dup
      16: ifnull        36
      19: astore_2
      20: iconst_0
      21: istore_3
      22: aload_2
      23: invokevirtual #57                 // Method com/radix2/algorithms/week4/BST$Node.getKey:()Ljava/lang/Object;
      26: aload_2
      27: invokevirtual #48                 // Method com/radix2/algorithms/week4/BST$Node.getData:()Ljava/lang/Object;
      30: invokestatic  #63                 // Method kotlin/TuplesKt.to:(Ljava/lang/Object;Ljava/lang/Object;)Lkotlin/Pair;
      33: goto          38
      36: pop
      37: aconst_null
      38: areturn

  public int size();
    Code:
       0: aload_0
       1: getfield      #29                 // Field root:Lcom/radix2/algorithms/week4/BST$Node;
       4: dup
       5: ifnull        14
       8: invokevirtual #87                 // Method com/radix2/algorithms/week4/BST$Node.getCount:()I
      11: goto          16
      14: pop
      15: iconst_0
      16: ireturn

  public int rank(K);
    Code:
       0: aload_1
       1: ldc           #19                 // String key
       3: invokestatic  #25                 // Method kotlin/jvm/internal/Intrinsics.checkNotNullParameter:(Ljava/lang/Object;Ljava/lang/String;)V
       6: aload_0
       7: aload_0
       8: getfield      #29                 // Field root:Lcom/radix2/algorithms/week4/BST$Node;
      11: aload_1
      12: invokespecial #93                 // Method rank:(Lcom/radix2/algorithms/week4/BST$Node;Ljava/lang/Comparable;)I
      15: ireturn

  public void deleteMin();
    Code:
       0: aload_0
       1: aload_0
       2: getfield      #29                 // Field root:Lcom/radix2/algorithms/week4/BST$Node;
       5: invokespecial #96                 // Method deleteMin:(Lcom/radix2/algorithms/week4/BST$Node;)Lcom/radix2/algorithms/week4/BST$Node;
       8: pop
       9: return

  public void deleteMax();
    Code:
       0: aload_0
       1: aload_0
       2: getfield      #29                 // Field root:Lcom/radix2/algorithms/week4/BST$Node;
       5: invokespecial #99                 // Method deleteMax:(Lcom/radix2/algorithms/week4/BST$Node;)Lcom/radix2/algorithms/week4/BST$Node;
       8: pop
       9: return

  public void delete(K);
    Code:
       0: aload_1
       1: ldc           #19                 // String key
       3: invokestatic  #25                 // Method kotlin/jvm/internal/Intrinsics.checkNotNullParameter:(Ljava/lang/Object;Ljava/lang/String;)V
       6: aload_0
       7: aload_0
       8: getfield      #29                 // Field root:Lcom/radix2/algorithms/week4/BST$Node;
      11: aload_1
      12: invokespecial #104                // Method delete:(Lcom/radix2/algorithms/week4/BST$Node;Ljava/lang/Comparable;)Lcom/radix2/algorithms/week4/BST$Node;
      15: pop
      16: return

  public java.lang.String toString();
    Code:
       0: new           #108                // class java/lang/StringBuilder
       3: dup
       4: invokespecial #109                // Method java/lang/StringBuilder."<init>":()V
       7: astore_1
       8: aload_1
       9: astore_2
      10: iconst_0
      11: istore_3
      12: aload_0
      13: aload_0
      14: getfield      #29                 // Field root:Lcom/radix2/algorithms/week4/BST$Node;
      17: aload_2
      18: invokespecial #113                // Method levelOrder:(Lcom/radix2/algorithms/week4/BST$Node;Ljava/lang/StringBuilder;)V
      21: nop
      22: aload_1
      23: invokevirtual #115                // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
      26: areturn

  private final com.radix2.algorithms.week4.BST$Node<K, V> put(com.radix2.algorithms.week4.BST$Node<K, V>, K, V);
    Code:
       0: aload_1
       1: ifnonnull     20
       4: new           #44                 // class com/radix2/algorithms/week4/BST$Node
       7: dup
       8: aload_2
       9: aload_3
      10: aconst_null
      11: aconst_null
      12: iconst_0
      13: bipush        28
      15: aconst_null
      16: invokespecial #122                // Method com/radix2/algorithms/week4/BST$Node."<init>":(Ljava/lang/Object;Ljava/lang/Object;Lcom/radix2/algorithms/week4/BST$Node;Lcom/radix2/algorithms/week4/BST$Node;IILkotlin/jvm/internal/DefaultConstructorMarker;)V
      19: areturn
      20: aload_2
      21: aload_1
      22: invokevirtual #57                 // Method com/radix2/algorithms/week4/BST$Node.getKey:()Ljava/lang/Object;
      25: invokeinterface #128,  2          // InterfaceMethod java/lang/Comparable.compareTo:(Ljava/lang/Object;)I
      30: istore        4
      32: nop
      33: iload         4
      35: ifge          55
      38: aload_1
      39: aload_0
      40: aload_1
      41: invokevirtual #132                // Method com/radix2/algorithms/week4/BST$Node.getLeft:()Lcom/radix2/algorithms/week4/BST$Node;
      44: aload_2
      45: aload_3
      46: invokespecial #32                 // Method put:(Lcom/radix2/algorithms/week4/BST$Node;Ljava/lang/Comparable;Ljava/lang/Object;)Lcom/radix2/algorithms/week4/BST$Node;
      49: invokevirtual #136                // Method com/radix2/algorithms/week4/BST$Node.setLeft:(Lcom/radix2/algorithms/week4/BST$Node;)V
      52: goto          82
      55: iload         4
      57: ifle          77
      60: aload_1
      61: aload_0
      62: aload_1
      63: invokevirtual #139                // Method com/radix2/algorithms/week4/BST$Node.getRight:()Lcom/radix2/algorithms/week4/BST$Node;
      66: aload_2
      67: aload_3
      68: invokespecial #32                 // Method put:(Lcom/radix2/algorithms/week4/BST$Node;Ljava/lang/Comparable;Ljava/lang/Object;)Lcom/radix2/algorithms/week4/BST$Node;
      71: invokevirtual #142                // Method com/radix2/algorithms/week4/BST$Node.setRight:(Lcom/radix2/algorithms/week4/BST$Node;)V
      74: goto          82
      77: aload_1
      78: aload_3
      79: invokevirtual #146                // Method com/radix2/algorithms/week4/BST$Node.setData:(Ljava/lang/Object;)V
      82: aload_1
      83: iconst_1
      84: aload_1
      85: invokevirtual #132                // Method com/radix2/algorithms/week4/BST$Node.getLeft:()Lcom/radix2/algorithms/week4/BST$Node;
      88: dup
      89: ifnull        98
      92: invokevirtual #87                 // Method com/radix2/algorithms/week4/BST$Node.getCount:()I
      95: goto          100
      98: pop
      99: iconst_0
     100: iadd
     101: aload_1
     102: invokevirtual #139                // Method com/radix2/algorithms/week4/BST$Node.getRight:()Lcom/radix2/algorithms/week4/BST$Node;
     105: dup
     106: ifnull        115
     109: invokevirtual #87                 // Method com/radix2/algorithms/week4/BST$Node.getCount:()I
     112: goto          117
     115: pop
     116: iconst_0
     117: iadd
     118: invokevirtual #150                // Method com/radix2/algorithms/week4/BST$Node.setCount:(I)V
     121: aload_1
     122: areturn

  private final com.radix2.algorithms.week4.BST$Node<K, V> get(com.radix2.algorithms.week4.BST$Node<K, V>, K);
    Code:
       0: aload_1
       1: ifnonnull     6
       4: aload_1
       5: areturn
       6: aload_2
       7: aload_1
       8: invokevirtual #57                 // Method com/radix2/algorithms/week4/BST$Node.getKey:()Ljava/lang/Object;
      11: invokeinterface #128,  2          // InterfaceMethod java/lang/Comparable.compareTo:(Ljava/lang/Object;)I
      16: istore_3
      17: nop
      18: iload_3
      19: ifge          34
      22: aload_0
      23: aload_1
      24: invokevirtual #132                // Method com/radix2/algorithms/week4/BST$Node.getLeft:()Lcom/radix2/algorithms/week4/BST$Node;
      27: aload_2
      28: invokespecial #42                 // Method get:(Lcom/radix2/algorithms/week4/BST$Node;Ljava/lang/Comparable;)Lcom/radix2/algorithms/week4/BST$Node;
      31: goto          51
      34: iload_3
      35: ifle          50
      38: aload_0
      39: aload_1
      40: invokevirtual #139                // Method com/radix2/algorithms/week4/BST$Node.getRight:()Lcom/radix2/algorithms/week4/BST$Node;
      43: aload_2
      44: invokespecial #42                 // Method get:(Lcom/radix2/algorithms/week4/BST$Node;Ljava/lang/Comparable;)Lcom/radix2/algorithms/week4/BST$Node;
      47: goto          51
      50: aload_1
      51: areturn

  private final com.radix2.algorithms.week4.BST$Node<K, V> min(com.radix2.algorithms.week4.BST$Node<K, V>);
    Code:
       0: aload_1
       1: dup
       2: ifnull        11
       5: invokevirtual #132                // Method com/radix2/algorithms/week4/BST$Node.getLeft:()Lcom/radix2/algorithms/week4/BST$Node;
       8: goto          13
      11: pop
      12: aconst_null
      13: ifnonnull     18
      16: aload_1
      17: areturn
      18: aload_0
      19: aload_1
      20: invokevirtual #132                // Method com/radix2/algorithms/week4/BST$Node.getLeft:()Lcom/radix2/algorithms/week4/BST$Node;
      23: invokespecial #54                 // Method min:(Lcom/radix2/algorithms/week4/BST$Node;)Lcom/radix2/algorithms/week4/BST$Node;
      26: areturn

  private final com.radix2.algorithms.week4.BST$Node<K, V> max(com.radix2.algorithms.week4.BST$Node<K, V>);
    Code:
       0: aload_1
       1: dup
       2: ifnull        11
       5: invokevirtual #139                // Method com/radix2/algorithms/week4/BST$Node.getRight:()Lcom/radix2/algorithms/week4/BST$Node;
       8: goto          13
      11: pop
      12: aconst_null
      13: ifnonnull     18
      16: aload_1
      17: areturn
      18: aload_0
      19: aload_1
      20: invokevirtual #139                // Method com/radix2/algorithms/week4/BST$Node.getRight:()Lcom/radix2/algorithms/week4/BST$Node;
      23: invokespecial #71                 // Method max:(Lcom/radix2/algorithms/week4/BST$Node;)Lcom/radix2/algorithms/week4/BST$Node;
      26: areturn

  private final com.radix2.algorithms.week4.BST$Node<K, V> floor(com.radix2.algorithms.week4.BST$Node<K, V>, K);
    Code:
       0: aload_1
       1: ifnonnull     6
       4: aconst_null
       5: areturn
       6: aload_2
       7: aload_1
       8: invokevirtual #57                 // Method com/radix2/algorithms/week4/BST$Node.getKey:()Ljava/lang/Object;
      11: invokeinterface #128,  2          // InterfaceMethod java/lang/Comparable.compareTo:(Ljava/lang/Object;)I
      16: istore_3
      17: nop
      18: iload_3
      19: ifne          26
      22: aload_1
      23: goto          57
      26: iload_3
      27: ifge          42
      30: aload_0
      31: aload_1
      32: invokevirtual #132                // Method com/radix2/algorithms/week4/BST$Node.getLeft:()Lcom/radix2/algorithms/week4/BST$Node;
      35: aload_2
      36: invokespecial #77                 // Method floor:(Lcom/radix2/algorithms/week4/BST$Node;Ljava/lang/Comparable;)Lcom/radix2/algorithms/week4/BST$Node;
      39: goto          57
      42: aload_0
      43: aload_1
      44: invokevirtual #139                // Method com/radix2/algorithms/week4/BST$Node.getRight:()Lcom/radix2/algorithms/week4/BST$Node;
      47: aload_2
      48: invokespecial #77                 // Method floor:(Lcom/radix2/algorithms/week4/BST$Node;Ljava/lang/Comparable;)Lcom/radix2/algorithms/week4/BST$Node;
      51: dup
      52: ifnonnull     57
      55: pop
      56: aload_1
      57: areturn

  private final com.radix2.algorithms.week4.BST$Node<K, V> ceil(com.radix2.algorithms.week4.BST$Node<K, V>, K);
    Code:
       0: aload_1
       1: ifnonnull     6
       4: aconst_null
       5: areturn
       6: aload_2
       7: aload_1
       8: invokevirtual #57                 // Method com/radix2/algorithms/week4/BST$Node.getKey:()Ljava/lang/Object;
      11: invokeinterface #128,  2          // InterfaceMethod java/lang/Comparable.compareTo:(Ljava/lang/Object;)I
      16: istore_3
      17: nop
      18: iload_3
      19: ifne          26
      22: aload_1
      23: goto          57
      26: iload_3
      27: ifge          48
      30: aload_0
      31: aload_1
      32: invokevirtual #132                // Method com/radix2/algorithms/week4/BST$Node.getLeft:()Lcom/radix2/algorithms/week4/BST$Node;
      35: aload_2
      36: invokespecial #81                 // Method ceil:(Lcom/radix2/algorithms/week4/BST$Node;Ljava/lang/Comparable;)Lcom/radix2/algorithms/week4/BST$Node;
      39: dup
      40: ifnonnull     57
      43: pop
      44: aload_1
      45: goto          57
      48: aload_0
      49: aload_1
      50: invokevirtual #139                // Method com/radix2/algorithms/week4/BST$Node.getRight:()Lcom/radix2/algorithms/week4/BST$Node;
      53: aload_2
      54: invokespecial #81                 // Method ceil:(Lcom/radix2/algorithms/week4/BST$Node;Ljava/lang/Comparable;)Lcom/radix2/algorithms/week4/BST$Node;
      57: areturn

  private final int rank(com.radix2.algorithms.week4.BST$Node<K, V>, K);
    Code:
       0: aload_1
       1: ifnonnull     6
       4: iconst_0
       5: ireturn
       6: aload_2
       7: aload_1
       8: invokevirtual #57                 // Method com/radix2/algorithms/week4/BST$Node.getKey:()Ljava/lang/Object;
      11: invokeinterface #128,  2          // InterfaceMethod java/lang/Comparable.compareTo:(Ljava/lang/Object;)I
      16: istore_3
      17: nop
      18: iload_3
      19: ifne          41
      22: aload_1
      23: invokevirtual #132                // Method com/radix2/algorithms/week4/BST$Node.getLeft:()Lcom/radix2/algorithms/week4/BST$Node;
      26: dup
      27: ifnull        36
      30: invokevirtual #87                 // Method com/radix2/algorithms/week4/BST$Node.getCount:()I
      33: goto          85
      36: pop
      37: iconst_0
      38: goto          85
      41: iload_3
      42: ifge          57
      45: aload_0
      46: aload_1
      47: invokevirtual #132                // Method com/radix2/algorithms/week4/BST$Node.getLeft:()Lcom/radix2/algorithms/week4/BST$Node;
      50: aload_2
      51: invokespecial #93                 // Method rank:(Lcom/radix2/algorithms/week4/BST$Node;Ljava/lang/Comparable;)I
      54: goto          85
      57: iconst_1
      58: aload_1
      59: invokevirtual #132                // Method com/radix2/algorithms/week4/BST$Node.getLeft:()Lcom/radix2/algorithms/week4/BST$Node;
      62: dup
      63: ifnull        72
      66: invokevirtual #87                 // Method com/radix2/algorithms/week4/BST$Node.getCount:()I
      69: goto          74
      72: pop
      73: iconst_0
      74: iadd
      75: aload_0
      76: aload_1
      77: invokevirtual #139                // Method com/radix2/algorithms/week4/BST$Node.getRight:()Lcom/radix2/algorithms/week4/BST$Node;
      80: aload_2
      81: invokespecial #93                 // Method rank:(Lcom/radix2/algorithms/week4/BST$Node;Ljava/lang/Comparable;)I
      84: iadd
      85: ireturn

  private final com.radix2.algorithms.week4.BST$Node<K, V> deleteMin(com.radix2.algorithms.week4.BST$Node<K, V>);
    Code:
       0: aload_1
       1: dup
       2: ifnull        11
       5: invokevirtual #132                // Method com/radix2/algorithms/week4/BST$Node.getLeft:()Lcom/radix2/algorithms/week4/BST$Node;
       8: goto          13
      11: pop
      12: aconst_null
      13: ifnonnull     30
      16: aload_1
      17: dup
      18: ifnull        27
      21: invokevirtual #139                // Method com/radix2/algorithms/week4/BST$Node.getRight:()Lcom/radix2/algorithms/week4/BST$Node;
      24: goto          29
      27: pop
      28: aconst_null
      29: areturn
      30: aload_1
      31: aload_0
      32: aload_1
      33: invokevirtual #132                // Method com/radix2/algorithms/week4/BST$Node.getLeft:()Lcom/radix2/algorithms/week4/BST$Node;
      36: invokespecial #96                 // Method deleteMin:(Lcom/radix2/algorithms/week4/BST$Node;)Lcom/radix2/algorithms/week4/BST$Node;
      39: invokevirtual #136                // Method com/radix2/algorithms/week4/BST$Node.setLeft:(Lcom/radix2/algorithms/week4/BST$Node;)V
      42: aload_1
      43: iconst_1
      44: aload_1
      45: invokevirtual #132                // Method com/radix2/algorithms/week4/BST$Node.getLeft:()Lcom/radix2/algorithms/week4/BST$Node;
      48: dup
      49: ifnull        58
      52: invokevirtual #87                 // Method com/radix2/algorithms/week4/BST$Node.getCount:()I
      55: goto          60
      58: pop
      59: iconst_0
      60: iadd
      61: aload_1
      62: invokevirtual #139                // Method com/radix2/algorithms/week4/BST$Node.getRight:()Lcom/radix2/algorithms/week4/BST$Node;
      65: dup
      66: ifnull        75
      69: invokevirtual #87                 // Method com/radix2/algorithms/week4/BST$Node.getCount:()I
      72: goto          77
      75: pop
      76: iconst_0
      77: iadd
      78: invokevirtual #150                // Method com/radix2/algorithms/week4/BST$Node.setCount:(I)V
      81: aload_1
      82: areturn

  private final com.radix2.algorithms.week4.BST$Node<K, V> deleteMax(com.radix2.algorithms.week4.BST$Node<K, V>);
    Code:
       0: aload_1
       1: dup
       2: ifnull        11
       5: invokevirtual #139                // Method com/radix2/algorithms/week4/BST$Node.getRight:()Lcom/radix2/algorithms/week4/BST$Node;
       8: goto          13
      11: pop
      12: aconst_null
      13: ifnonnull     30
      16: aload_1
      17: dup
      18: ifnull        27
      21: invokevirtual #132                // Method com/radix2/algorithms/week4/BST$Node.getLeft:()Lcom/radix2/algorithms/week4/BST$Node;
      24: goto          29
      27: pop
      28: aconst_null
      29: areturn
      30: aload_1
      31: aload_0
      32: aload_1
      33: invokevirtual #139                // Method com/radix2/algorithms/week4/BST$Node.getRight:()Lcom/radix2/algorithms/week4/BST$Node;
      36: invokespecial #99                 // Method deleteMax:(Lcom/radix2/algorithms/week4/BST$Node;)Lcom/radix2/algorithms/week4/BST$Node;
      39: invokevirtual #142                // Method com/radix2/algorithms/week4/BST$Node.setRight:(Lcom/radix2/algorithms/week4/BST$Node;)V
      42: aload_1
      43: iconst_1
      44: aload_1
      45: invokevirtual #139                // Method com/radix2/algorithms/week4/BST$Node.getRight:()Lcom/radix2/algorithms/week4/BST$Node;
      48: dup
      49: ifnull        58
      52: invokevirtual #87                 // Method com/radix2/algorithms/week4/BST$Node.getCount:()I
      55: goto          60
      58: pop
      59: iconst_0
      60: iadd
      61: aload_1
      62: invokevirtual #132                // Method com/radix2/algorithms/week4/BST$Node.getLeft:()Lcom/radix2/algorithms/week4/BST$Node;
      65: dup
      66: ifnull        75
      69: invokevirtual #87                 // Method com/radix2/algorithms/week4/BST$Node.getCount:()I
      72: goto          77
      75: pop
      76: iconst_0
      77: iadd
      78: invokevirtual #150                // Method com/radix2/algorithms/week4/BST$Node.setCount:(I)V
      81: aload_1
      82: areturn

  private final com.radix2.algorithms.week4.BST$Node<K, V> delete(com.radix2.algorithms.week4.BST$Node<K, V>, K);
    Code:
       0: aload_1
       1: ifnonnull     6
       4: aconst_null
       5: areturn
       6: aload_1
       7: astore_3
       8: aload_2
       9: aload_3
      10: invokevirtual #57                 // Method com/radix2/algorithms/week4/BST$Node.getKey:()Ljava/lang/Object;
      13: invokeinterface #128,  2          // InterfaceMethod java/lang/Comparable.compareTo:(Ljava/lang/Object;)I
      18: istore        4
      20: nop
      21: iload         4
      23: ifge          42
      26: aload_3
      27: aload_0
      28: aload_3
      29: invokevirtual #132                // Method com/radix2/algorithms/week4/BST$Node.getLeft:()Lcom/radix2/algorithms/week4/BST$Node;
      32: aload_2
      33: invokespecial #104                // Method delete:(Lcom/radix2/algorithms/week4/BST$Node;Ljava/lang/Comparable;)Lcom/radix2/algorithms/week4/BST$Node;
      36: invokevirtual #136                // Method com/radix2/algorithms/week4/BST$Node.setLeft:(Lcom/radix2/algorithms/week4/BST$Node;)V
      39: goto          138
      42: iload         4
      44: ifle          63
      47: aload_3
      48: aload_0
      49: aload_3
      50: invokevirtual #139                // Method com/radix2/algorithms/week4/BST$Node.getRight:()Lcom/radix2/algorithms/week4/BST$Node;
      53: aload_2
      54: invokespecial #104                // Method delete:(Lcom/radix2/algorithms/week4/BST$Node;Ljava/lang/Comparable;)Lcom/radix2/algorithms/week4/BST$Node;
      57: invokevirtual #142                // Method com/radix2/algorithms/week4/BST$Node.setRight:(Lcom/radix2/algorithms/week4/BST$Node;)V
      60: goto          138
      63: aload_3
      64: invokevirtual #132                // Method com/radix2/algorithms/week4/BST$Node.getLeft:()Lcom/radix2/algorithms/week4/BST$Node;
      67: ifnonnull     75
      70: aload_3
      71: invokevirtual #139                // Method com/radix2/algorithms/week4/BST$Node.getRight:()Lcom/radix2/algorithms/week4/BST$Node;
      74: areturn
      75: aload_3
      76: invokevirtual #139                // Method com/radix2/algorithms/week4/BST$Node.getRight:()Lcom/radix2/algorithms/week4/BST$Node;
      79: ifnonnull     87
      82: aload_3
      83: invokevirtual #132                // Method com/radix2/algorithms/week4/BST$Node.getLeft:()Lcom/radix2/algorithms/week4/BST$Node;
      86: areturn
      87: aload_3
      88: astore        5
      90: aload_0
      91: aload         5
      93: invokevirtual #139                // Method com/radix2/algorithms/week4/BST$Node.getRight:()Lcom/radix2/algorithms/week4/BST$Node;
      96: invokespecial #54                 // Method min:(Lcom/radix2/algorithms/week4/BST$Node;)Lcom/radix2/algorithms/week4/BST$Node;
      99: astore_3
     100: aload_3
     101: dup
     102: ifnull        120
     105: aload_0
     106: aload         5
     108: invokevirtual #139                // Method com/radix2/algorithms/week4/BST$Node.getRight:()Lcom/radix2/algorithms/week4/BST$Node;
     111: invokespecial #96                 // Method deleteMin:(Lcom/radix2/algorithms/week4/BST$Node;)Lcom/radix2/algorithms/week4/BST$Node;
     114: invokevirtual #142                // Method com/radix2/algorithms/week4/BST$Node.setRight:(Lcom/radix2/algorithms/week4/BST$Node;)V
     117: goto          121
     120: pop
     121: aload_3
     122: dup
     123: ifnull        137
     126: aload         5
     128: invokevirtual #132                // Method com/radix2/algorithms/week4/BST$Node.getLeft:()Lcom/radix2/algorithms/week4/BST$Node;
     131: invokevirtual #136                // Method com/radix2/algorithms/week4/BST$Node.setLeft:(Lcom/radix2/algorithms/week4/BST$Node;)V
     134: goto          138
     137: pop
     138: aload_3
     139: dup
     140: ifnull        192
     143: iconst_1
     144: aload_3
     145: dup
     146: ifnull        162
     149: invokevirtual #132                // Method com/radix2/algorithms/week4/BST$Node.getLeft:()Lcom/radix2/algorithms/week4/BST$Node;
     152: dup
     153: ifnull        162
     156: invokevirtual #87                 // Method com/radix2/algorithms/week4/BST$Node.getCount:()I
     159: goto          164
     162: pop
     163: iconst_0
     164: iadd
     165: aload_3
     166: dup
     167: ifnull        183
     170: invokevirtual #139                // Method com/radix2/algorithms/week4/BST$Node.getRight:()Lcom/radix2/algorithms/week4/BST$Node;
     173: dup
     174: ifnull        183
     177: invokevirtual #87                 // Method com/radix2/algorithms/week4/BST$Node.getCount:()I
     180: goto          185
     183: pop
     184: iconst_0
     185: iadd
     186: invokevirtual #150                // Method com/radix2/algorithms/week4/BST$Node.setCount:(I)V
     189: goto          193
     192: pop
     193: aload_3
     194: areturn

  private final void inOrderRecursive(com.radix2.algorithms.week4.BST$Node<K, V>, java.lang.StringBuilder);
    Code:
       0: aload_1
       1: ifnonnull     5
       4: return
       5: aload_0
       6: aload_1
       7: invokevirtual #132                // Method com/radix2/algorithms/week4/BST$Node.getLeft:()Lcom/radix2/algorithms/week4/BST$Node;
      10: aload_2
      11: invokespecial #160                // Method inOrderRecursive:(Lcom/radix2/algorithms/week4/BST$Node;Ljava/lang/StringBuilder;)V
      14: aload_2
      15: aload_1
      16: invokevirtual #57                 // Method com/radix2/algorithms/week4/BST$Node.getKey:()Ljava/lang/Object;
      19: aload_1
      20: invokevirtual #48                 // Method com/radix2/algorithms/week4/BST$Node.getData:()Ljava/lang/Object;
      23: invokestatic  #63                 // Method kotlin/TuplesKt.to:(Ljava/lang/Object;Ljava/lang/Object;)Lkotlin/Pair;
      26: invokevirtual #164                // Method java/lang/StringBuilder.append:(Ljava/lang/Object;)Ljava/lang/StringBuilder;
      29: pop
      30: aload_0
      31: aload_1
      32: invokevirtual #139                // Method com/radix2/algorithms/week4/BST$Node.getRight:()Lcom/radix2/algorithms/week4/BST$Node;
      35: aload_2
      36: invokespecial #160                // Method inOrderRecursive:(Lcom/radix2/algorithms/week4/BST$Node;Ljava/lang/StringBuilder;)V
      39: return

  private final void inOrderWithStack(com.radix2.algorithms.week4.BST$Node<K, V>, java.lang.StringBuilder);
    Code:
       0: aload_1
       1: ifnonnull     5
       4: return
       5: aload_1
       6: astore_3
       7: new           #168                // class java/util/Stack
      10: dup
      11: invokespecial #169                // Method java/util/Stack."<init>":()V
      14: astore        4
      16: aload_3
      17: ifnonnull     28
      20: aload         4
      22: invokevirtual #173                // Method java/util/Stack.isEmpty:()Z
      25: ifne          84
      28: aload_3
      29: ifnull        47
      32: aload         4
      34: aload_3
      35: invokevirtual #177                // Method java/util/Stack.push:(Ljava/lang/Object;)Ljava/lang/Object;
      38: pop
      39: aload_3
      40: invokevirtual #132                // Method com/radix2/algorithms/week4/BST$Node.getLeft:()Lcom/radix2/algorithms/week4/BST$Node;
      43: astore_3
      44: goto          28
      47: aload         4
      49: invokevirtual #180                // Method java/util/Stack.pop:()Ljava/lang/Object;
      52: checkcast     #44                 // class com/radix2/algorithms/week4/BST$Node
      55: astore        5
      57: aload_2
      58: aload         5
      60: invokevirtual #57                 // Method com/radix2/algorithms/week4/BST$Node.getKey:()Ljava/lang/Object;
      63: aload         5
      65: invokevirtual #48                 // Method com/radix2/algorithms/week4/BST$Node.getData:()Ljava/lang/Object;
      68: invokestatic  #63                 // Method kotlin/TuplesKt.to:(Ljava/lang/Object;Ljava/lang/Object;)Lkotlin/Pair;
      71: invokevirtual #164                // Method java/lang/StringBuilder.append:(Ljava/lang/Object;)Ljava/lang/StringBuilder;
      74: pop
      75: aload         5
      77: invokevirtual #139                // Method com/radix2/algorithms/week4/BST$Node.getRight:()Lcom/radix2/algorithms/week4/BST$Node;
      80: astore_3
      81: goto          16
      84: return

  private final void levelOrder(com.radix2.algorithms.week4.BST$Node<K, V>, java.lang.StringBuilder);
    Code:
       0: aload_1
       1: ifnonnull     5
       4: return
       5: new           #185                // class java/util/LinkedList
       8: dup
       9: invokespecial #186                // Method java/util/LinkedList."<init>":()V
      12: checkcast     #188                // class java/util/Queue
      15: astore_3
      16: aload_3
      17: aload_1
      18: invokeinterface #192,  2          // InterfaceMethod java/util/Queue.add:(Ljava/lang/Object;)Z
      23: pop
      24: aload_3
      25: astore        4
      27: iconst_0
      28: istore        5
      30: aload_3
      31: invokeinterface #193,  1          // InterfaceMethod java/util/Queue.isEmpty:()Z
      36: ifne          134
      39: aload_2
      40: checkcast     #195                // class java/lang/CharSequence
      43: invokeinterface #198,  1          // InterfaceMethod java/lang/CharSequence.length:()I
      48: ifle          55
      51: iconst_1
      52: goto          56
      55: iconst_0
      56: ifeq          66
      59: aload_2
      60: ldc           #200                // String ,
      62: invokevirtual #203                // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      65: pop
      66: aload_2
      67: aload         4
      69: invokeinterface #206,  1          // InterfaceMethod java/util/Queue.peek:()Ljava/lang/Object;
      74: invokevirtual #164                // Method java/lang/StringBuilder.append:(Ljava/lang/Object;)Ljava/lang/StringBuilder;
      77: pop
      78: aload_3
      79: invokeinterface #209,  1          // InterfaceMethod java/util/Queue.poll:()Ljava/lang/Object;
      84: checkcast     #44                 // class com/radix2/algorithms/week4/BST$Node
      87: astore        6
      89: aload         6
      91: invokevirtual #132                // Method com/radix2/algorithms/week4/BST$Node.getLeft:()Lcom/radix2/algorithms/week4/BST$Node;
      94: ifnull        110
      97: aload         4
      99: aload         6
     101: invokevirtual #132                // Method com/radix2/algorithms/week4/BST$Node.getLeft:()Lcom/radix2/algorithms/week4/BST$Node;
     104: invokeinterface #192,  2          // InterfaceMethod java/util/Queue.add:(Ljava/lang/Object;)Z
     109: pop
     110: aload         6
     112: invokevirtual #139                // Method com/radix2/algorithms/week4/BST$Node.getRight:()Lcom/radix2/algorithms/week4/BST$Node;
     115: ifnull        30
     118: aload         4
     120: aload         6
     122: invokevirtual #139                // Method com/radix2/algorithms/week4/BST$Node.getRight:()Lcom/radix2/algorithms/week4/BST$Node;
     125: invokeinterface #192,  2          // InterfaceMethod java/util/Queue.add:(Ljava/lang/Object;)Z
     130: pop
     131: goto          30
     134: nop
     135: nop
     136: return
}

Compiled from "BST.kt"
public final class com.radix2.algorithms.week4.BSTKt {
  public static final <K extends java.lang.Comparable<? super K>, V> void put(com.radix2.algorithms.week4.SymbolTable<K, V>, K);
    Code:
       0: aload_0
       1: ldc           #10                 // String <this>
       3: invokestatic  #16                 // Method kotlin/jvm/internal/Intrinsics.checkNotNullParameter:(Ljava/lang/Object;Ljava/lang/String;)V
       6: aload_1
       7: ldc           #18                 // String key
       9: invokestatic  #16                 // Method kotlin/jvm/internal/Intrinsics.checkNotNullParameter:(Ljava/lang/Object;Ljava/lang/String;)V
      12: aload_0
      13: aload_1
      14: aconst_null
      15: invokeinterface #23,  3           // InterfaceMethod com/radix2/algorithms/week4/SymbolTable.put:(Ljava/lang/Comparable;Ljava/lang/Object;)V
      20: return

  public static final void main();
    Code:
       0: new           #30                 // class com/radix2/algorithms/week4/BST
       3: dup
       4: invokespecial #33                 // Method com/radix2/algorithms/week4/BST."<init>":()V
       7: checkcast     #20                 // class com/radix2/algorithms/week4/SymbolTable
      10: astore_0
      11: aload_0
      12: bipush        6
      14: invokestatic  #39                 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
      17: checkcast     #41                 // class java/lang/Comparable
      20: invokestatic  #43                 // Method put:(Lcom/radix2/algorithms/week4/SymbolTable;Ljava/lang/Comparable;)V
      23: aload_0
      24: bipush        7
      26: invokestatic  #39                 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
      29: checkcast     #41                 // class java/lang/Comparable
      32: invokestatic  #43                 // Method put:(Lcom/radix2/algorithms/week4/SymbolTable;Ljava/lang/Comparable;)V
      35: aload_0
      36: iconst_4
      37: invokestatic  #39                 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
      40: checkcast     #41                 // class java/lang/Comparable
      43: invokestatic  #43                 // Method put:(Lcom/radix2/algorithms/week4/SymbolTable;Ljava/lang/Comparable;)V
      46: aload_0
      47: iconst_1
      48: invokestatic  #39                 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
      51: checkcast     #41                 // class java/lang/Comparable
      54: invokestatic  #43                 // Method put:(Lcom/radix2/algorithms/week4/SymbolTable;Ljava/lang/Comparable;)V
      57: getstatic     #49                 // Field java/lang/System.out:Ljava/io/PrintStream;
      60: aload_0
      61: invokevirtual #55                 // Method java/io/PrintStream.println:(Ljava/lang/Object;)V
      64: return

  public static void main(java.lang.String[]);
    Code:
       0: invokestatic  #59                 // Method main:()V
       3: return
}


package com.radix2.algorithms.week4

class MaxPQ<T : Comparable<T>>(capacity: Int) {
    private var array = Array<Comparable<Any>?>(capacity) { null }

    private var n = 0

    companion object {

        @Suppress("UNCHECKED_CAST")
        fun <T : Comparable<T>> sort(array: Array<Comparable<T>>) {
            for (i in array.lastIndex / 2 downTo 0) {
                sink(array as Array<Comparable<Any>>, i, array.lastIndex)
            }

            var n = array.lastIndex

            while (n > 0) {
                exch(array as Array<Comparable<Any>>, 0, n)
                sink(array as Array<Comparable<Any>>, 0, n--)
            }
        }

        private fun sink(array: Array<Comparable<Any>>, k: Int, n: Int) {
            var trav = k

            while (2 * trav + 1 < n) {
                var j = 2 * trav + 1

                if (j < n - 1 && less(array, j, j + 1))
                    j++

                if (!less(array, trav, j)) break

                exch(array, trav, j)

                trav = j
            }
        }

        private fun swim(array: Array<Comparable<Any>>, k: Int) {
            var trav = k

            while (trav > 0 && less(array,trav / 2, trav)) {
                exch(array, trav, trav / 2)
                trav /= 2
            }
        }

        private fun exch(array: Array<Comparable<Any>>, i: Int, j: Int) {
            val temp = array[i]
            array[i] = array[j]
            array[j] = temp
        }

        private fun less(array: Array<Comparable<Any>>, lhs: Int, rhs: Int): Boolean = array[lhs] < array[rhs]
    }

    @Suppress("UNCHECKED_CAST")
    fun add(t: T) {
        array[n++] = t as Comparable<Any>
        swim(array as Array<Comparable<Any>>, n - 1)
    }

    @Suppress("UNCHECKED_CAST")
    fun deleteMax(): T {
        val key = array[0]

        exch(array as Array<Comparable<Any>>,0, --n)
        sink(array as Array<Comparable<Any>>,0, n)
        array[n] = null

        return key as T
    }

    fun size() = n

    override fun toString(): String = array.filter { it != null }.joinToString()
}

fun main(args: Array<String>) {

    val maxPQ = MaxPQ<Int>(20)

    val list = mutableListOf(9, 2, 3, 8, 1, 10, 6, 17, 5, 16, 18, 12, 14, 11, 15, 20, 7, 4, 19, 13)

    for (i in 0 until 20) {
        maxPQ.add(list[i])
    }

    println(maxPQ)

    val array: Array<Comparable<Int>> = list.toTypedArray()

    MaxPQ.sort(array)

    println(array.joinToString())
}

Compiled from "MaxPQ.kt"
public final class com.radix2.algorithms.week4.MaxPQ$Companion {
  private com.radix2.algorithms.week4.MaxPQ$Companion();
    Code:
       0: aload_0
       1: invokespecial #8                  // Method java/lang/Object."<init>":()V
       4: return

  public final <T extends java.lang.Comparable<? super T>> void sort(java.lang.Comparable<T>[]);
    Code:
       0: aload_1
       1: ldc           #16                 // String array
       3: invokestatic  #22                 // Method kotlin/jvm/internal/Intrinsics.checkNotNullParameter:(Ljava/lang/Object;Ljava/lang/String;)V
       6: aload_1
       7: invokestatic  #28                 // Method kotlin/collections/ArraysKt.getLastIndex:([Ljava/lang/Object;)I
      10: iconst_2
      11: idiv
      12: istore_2
      13: iconst_m1
      14: iload_2
      15: if_icmpge     34
      18: aload_0
      19: aload_1
      20: iload_2
      21: aload_1
      22: invokestatic  #28                 // Method kotlin/collections/ArraysKt.getLastIndex:([Ljava/lang/Object;)I
      25: invokespecial #32                 // Method sink:([Ljava/lang/Comparable;II)V
      28: iinc          2, -1
      31: goto          13
      34: aload_1
      35: invokestatic  #28                 // Method kotlin/collections/ArraysKt.getLastIndex:([Ljava/lang/Object;)I
      38: istore_2
      39: iload_2
      40: ifle          63
      43: aload_0
      44: aload_1
      45: iconst_0
      46: iload_2
      47: invokespecial #35                 // Method exch:([Ljava/lang/Comparable;II)V
      50: aload_0
      51: aload_1
      52: iconst_0
      53: iload_2
      54: iinc          2, -1
      57: invokespecial #32                 // Method sink:([Ljava/lang/Comparable;II)V
      60: goto          39
      63: return

  private final void sink(java.lang.Comparable<java.lang.Object>[], int, int);
    Code:
       0: iload_2
       1: istore        4
       3: iconst_2
       4: iload         4
       6: imul
       7: iconst_1
       8: iadd
       9: iload_3
      10: if_icmpge     74
      13: iconst_2
      14: iload         4
      16: imul
      17: iconst_1
      18: iadd
      19: istore        5
      21: iload         5
      23: iload_3
      24: iconst_1
      25: isub
      26: if_icmpge     46
      29: aload_0
      30: aload_1
      31: iload         5
      33: iload         5
      35: iconst_1
      36: iadd
      37: invokespecial #44                 // Method less:([Ljava/lang/Comparable;II)Z
      40: ifeq          46
      43: iinc          5, 1
      46: aload_0
      47: aload_1
      48: iload         4
      50: iload         5
      52: invokespecial #44                 // Method less:([Ljava/lang/Comparable;II)Z
      55: ifeq          74
      58: aload_0
      59: aload_1
      60: iload         4
      62: iload         5
      64: invokespecial #35                 // Method exch:([Ljava/lang/Comparable;II)V
      67: iload         5
      69: istore        4
      71: goto          3
      74: return

  private final void swim(java.lang.Comparable<java.lang.Object>[], int);
    Code:
       0: iload_2
       1: istore_3
       2: iload_3
       3: ifle          34
       6: aload_0
       7: aload_1
       8: iload_3
       9: iconst_2
      10: idiv
      11: iload_3
      12: invokespecial #44                 // Method less:([Ljava/lang/Comparable;II)Z
      15: ifeq          34
      18: aload_0
      19: aload_1
      20: iload_3
      21: iload_3
      22: iconst_2
      23: idiv
      24: invokespecial #35                 // Method exch:([Ljava/lang/Comparable;II)V
      27: iload_3
      28: iconst_2
      29: idiv
      30: istore_3
      31: goto          2
      34: return

  private final void exch(java.lang.Comparable<java.lang.Object>[], int, int);
    Code:
       0: aload_1
       1: iload_2
       2: aaload
       3: astore        4
       5: aload_1
       6: iload_2
       7: aload_1
       8: iload_3
       9: aaload
      10: aastore
      11: aload_1
      12: iload_3
      13: aload         4
      15: aastore
      16: return

  private final boolean less(java.lang.Comparable<java.lang.Object>[], int, int);
    Code:
       0: aload_1
       1: iload_2
       2: aaload
       3: aload_1
       4: iload_3
       5: aaload
       6: invokeinterface #59,  2           // InterfaceMethod java/lang/Comparable.compareTo:(Ljava/lang/Object;)I
      11: ifge          18
      14: iconst_1
      15: goto          19
      18: iconst_0
      19: ireturn

  public static final void access$swim(com.radix2.algorithms.week4.MaxPQ$Companion, java.lang.Comparable[], int);
    Code:
       0: aload_0
       1: aload_1
       2: iload_2
       3: invokespecial #65                 // Method swim:([Ljava/lang/Comparable;I)V
       6: return

  public static final void access$exch(com.radix2.algorithms.week4.MaxPQ$Companion, java.lang.Comparable[], int, int);
    Code:
       0: aload_0
       1: aload_1
       2: iload_2
       3: iload_3
       4: invokespecial #35                 // Method exch:([Ljava/lang/Comparable;II)V
       7: return

  public static final void access$sink(com.radix2.algorithms.week4.MaxPQ$Companion, java.lang.Comparable[], int, int);
    Code:
       0: aload_0
       1: aload_1
       2: iload_2
       3: iload_3
       4: invokespecial #32                 // Method sink:([Ljava/lang/Comparable;II)V
       7: return

  public com.radix2.algorithms.week4.MaxPQ$Companion(kotlin.jvm.internal.DefaultConstructorMarker);
    Code:
       0: aload_0
       1: invokespecial #71                 // Method "<init>":()V
       4: return
}

Compiled from "MaxPQ.kt"
public final class com.radix2.algorithms.week4.MaxPQ<T extends java.lang.Comparable<? super T>> {
  public static final com.radix2.algorithms.week4.MaxPQ$Companion Companion;

  private java.lang.Comparable<java.lang.Object>[] array;

  private int n;

  public com.radix2.algorithms.week4.MaxPQ(int);
    Code:
       0: aload_0
       1: invokespecial #10                 // Method java/lang/Object."<init>":()V
       4: aload_0
       5: iconst_0
       6: istore_2
       7: iload_1
       8: anewarray     #12                 // class java/lang/Comparable
      11: astore_3
      12: astore        5
      14: iload_2
      15: iload_1
      16: if_icmpge     33
      19: iload_2
      20: istore        4
      22: aload_3
      23: iload         4
      25: aconst_null
      26: aastore
      27: iinc          2, 1
      30: goto          14
      33: aload         5
      35: aload_3
      36: putfield      #16                 // Field array:[Ljava/lang/Comparable;
      39: return

  public final void add(T);
    Code:
       0: aload_1
       1: ldc           #27                 // String t
       3: invokestatic  #33                 // Method kotlin/jvm/internal/Intrinsics.checkNotNullParameter:(Ljava/lang/Object;Ljava/lang/String;)V
       6: aload_0
       7: getfield      #16                 // Field array:[Ljava/lang/Comparable;
      10: aload_0
      11: getfield      #36                 // Field n:I
      14: istore_2
      15: aload_0
      16: iload_2
      17: iconst_1
      18: iadd
      19: putfield      #36                 // Field n:I
      22: iload_2
      23: aload_1
      24: aastore
      25: getstatic     #40                 // Field Companion:Lcom/radix2/algorithms/week4/MaxPQ$Companion;
      28: aload_0
      29: getfield      #16                 // Field array:[Ljava/lang/Comparable;
      32: aload_0
      33: getfield      #36                 // Field n:I
      36: iconst_1
      37: isub
      38: invokestatic  #46                 // Method com/radix2/algorithms/week4/MaxPQ$Companion.access$swim:(Lcom/radix2/algorithms/week4/MaxPQ$Companion;[Ljava/lang/Comparable;I)V
      41: return

  public final T deleteMax();
    Code:
       0: aload_0
       1: getfield      #16                 // Field array:[Ljava/lang/Comparable;
       4: iconst_0
       5: aaload
       6: astore_1
       7: getstatic     #40                 // Field Companion:Lcom/radix2/algorithms/week4/MaxPQ$Companion;
      10: aload_0
      11: getfield      #16                 // Field array:[Ljava/lang/Comparable;
      14: iconst_0
      15: aload_0
      16: aload_0
      17: getfield      #36                 // Field n:I
      20: iconst_m1
      21: iadd
      22: putfield      #36                 // Field n:I
      25: aload_0
      26: getfield      #36                 // Field n:I
      29: invokestatic  #54                 // Method com/radix2/algorithms/week4/MaxPQ$Companion.access$exch:(Lcom/radix2/algorithms/week4/MaxPQ$Companion;[Ljava/lang/Comparable;II)V
      32: getstatic     #40                 // Field Companion:Lcom/radix2/algorithms/week4/MaxPQ$Companion;
      35: aload_0
      36: getfield      #16                 // Field array:[Ljava/lang/Comparable;
      39: iconst_0
      40: aload_0
      41: getfield      #36                 // Field n:I
      44: invokestatic  #57                 // Method com/radix2/algorithms/week4/MaxPQ$Companion.access$sink:(Lcom/radix2/algorithms/week4/MaxPQ$Companion;[Ljava/lang/Comparable;II)V
      47: aload_0
      48: getfield      #16                 // Field array:[Ljava/lang/Comparable;
      51: aload_0
      52: getfield      #36                 // Field n:I
      55: aconst_null
      56: aastore
      57: aload_1
      58: ldc           #59                 // String null cannot be cast to non-null type T of com.radix2.algorithms.week4.MaxPQ
      60: invokestatic  #62                 // Method kotlin/jvm/internal/Intrinsics.checkNotNull:(Ljava/lang/Object;Ljava/lang/String;)V
      63: aload_1
      64: areturn

  public final int size();
    Code:
       0: aload_0
       1: getfield      #36                 // Field n:I
       4: ireturn

  public java.lang.String toString();
    Code:
       0: aload_0
       1: getfield      #16                 // Field array:[Ljava/lang/Comparable;
       4: astore_1
       5: iconst_0
       6: istore_2
       7: aload_1
       8: astore_3
       9: new           #69                 // class java/util/ArrayList
      12: dup
      13: invokespecial #70                 // Method java/util/ArrayList."<init>":()V
      16: checkcast     #72                 // class java/util/Collection
      19: astore        4
      21: iconst_0
      22: istore        5
      24: iconst_0
      25: istore        6
      27: aload_3
      28: arraylength
      29: istore        7
      31: iload         6
      33: iload         7
      35: if_icmpge     80
      38: aload_3
      39: iload         6
      41: aaload
      42: astore        8
      44: aload         8
      46: astore        9
      48: iconst_0
      49: istore        10
      51: aload         9
      53: ifnull        60
      56: iconst_1
      57: goto          61
      60: iconst_0
      61: ifeq          74
      64: aload         4
      66: aload         8
      68: invokeinterface #75,  2           // InterfaceMethod java/util/Collection.add:(Ljava/lang/Object;)Z
      73: pop
      74: iinc          6, 1
      77: goto          31
      80: aload         4
      82: checkcast     #77                 // class java/util/List
      85: nop
      86: checkcast     #79                 // class java/lang/Iterable
      89: aconst_null
      90: aconst_null
      91: aconst_null
      92: iconst_0
      93: aconst_null
      94: aconst_null
      95: bipush        63
      97: aconst_null
      98: invokestatic  #85                 // Method kotlin/collections/CollectionsKt.joinToString$default:(Ljava/lang/Iterable;Ljava/lang/CharSequence;Ljava/lang/CharSequence;Ljava/lang/CharSequence;ILjava/lang/CharSequence;Lkotlin/jvm/functions/Function1;ILjava/lang/Object;)Ljava/lang/String;
     101: areturn

  static {};
    Code:
       0: new           #42                 // class com/radix2/algorithms/week4/MaxPQ$Companion
       3: dup
       4: aconst_null
       5: invokespecial #100                // Method com/radix2/algorithms/week4/MaxPQ$Companion."<init>":(Lkotlin/jvm/internal/DefaultConstructorMarker;)V
       8: putstatic     #40                 // Field Companion:Lcom/radix2/algorithms/week4/MaxPQ$Companion;
      11: return
}

Compiled from "MaxPQ.kt"
public final class com.radix2.algorithms.week4.MaxPQKt {
  public static final void main(java.lang.String[]);
    Code:
       0: aload_0
       1: ldc           #9                  // String args
       3: invokestatic  #15                 // Method kotlin/jvm/internal/Intrinsics.checkNotNullParameter:(Ljava/lang/Object;Ljava/lang/String;)V
       6: new           #17                 // class com/radix2/algorithms/week4/MaxPQ
       9: dup
      10: bipush        20
      12: invokespecial #21                 // Method com/radix2/algorithms/week4/MaxPQ."<init>":(I)V
      15: astore_1
      16: bipush        20
      18: anewarray     #23                 // class java/lang/Integer
      21: astore_3
      22: aload_3
      23: iconst_0
      24: bipush        9
      26: invokestatic  #27                 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
      29: aastore
      30: aload_3
      31: iconst_1
      32: iconst_2
      33: invokestatic  #27                 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
      36: aastore
      37: aload_3
      38: iconst_2
      39: iconst_3
      40: invokestatic  #27                 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
      43: aastore
      44: aload_3
      45: iconst_3
      46: bipush        8
      48: invokestatic  #27                 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
      51: aastore
      52: aload_3
      53: iconst_4
      54: iconst_1
      55: invokestatic  #27                 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
      58: aastore
      59: aload_3
      60: iconst_5
      61: bipush        10
      63: invokestatic  #27                 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
      66: aastore
      67: aload_3
      68: bipush        6
      70: bipush        6
      72: invokestatic  #27                 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
      75: aastore
      76: aload_3
      77: bipush        7
      79: bipush        17
      81: invokestatic  #27                 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
      84: aastore
      85: aload_3
      86: bipush        8
      88: iconst_5
      89: invokestatic  #27                 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
      92: aastore
      93: aload_3
      94: bipush        9
      96: bipush        16
      98: invokestatic  #27                 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
     101: aastore
     102: aload_3
     103: bipush        10
     105: bipush        18
     107: invokestatic  #27                 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
     110: aastore
     111: aload_3
     112: bipush        11
     114: bipush        12
     116: invokestatic  #27                 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
     119: aastore
     120: aload_3
     121: bipush        12
     123: bipush        14
     125: invokestatic  #27                 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
     128: aastore
     129: aload_3
     130: bipush        13
     132: bipush        11
     134: invokestatic  #27                 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
     137: aastore
     138: aload_3
     139: bipush        14
     141: bipush        15
     143: invokestatic  #27                 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
     146: aastore
     147: aload_3
     148: bipush        15
     150: bipush        20
     152: invokestatic  #27                 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
     155: aastore
     156: aload_3
     157: bipush        16
     159: bipush        7
     161: invokestatic  #27                 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
     164: aastore
     165: aload_3
     166: bipush        17
     168: iconst_4
     169: invokestatic  #27                 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
     172: aastore
     173: aload_3
     174: bipush        18
     176: bipush        19
     178: invokestatic  #27                 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
     181: aastore
     182: aload_3
     183: bipush        19
     185: bipush        13
     187: invokestatic  #27                 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
     190: aastore
     191: aload_3
     192: invokestatic  #33                 // Method kotlin/collections/CollectionsKt.mutableListOf:([Ljava/lang/Object;)Ljava/util/List;
     195: astore_2
     196: iconst_0
     197: istore_3
     198: iload_3
     199: bipush        20
     201: if_icmpge     224
     204: aload_1
     205: aload_2
     206: iload_3
     207: invokeinterface #39,  2           // InterfaceMethod java/util/List.get:(I)Ljava/lang/Object;
     212: checkcast     #41                 // class java/lang/Comparable
     215: invokevirtual #45                 // Method com/radix2/algorithms/week4/MaxPQ.add:(Ljava/lang/Comparable;)V
     218: iinc          3, 1
     221: goto          198
     224: getstatic     #51                 // Field java/lang/System.out:Ljava/io/PrintStream;
     227: aload_1
     228: invokevirtual #57                 // Method java/io/PrintStream.println:(Ljava/lang/Object;)V
     231: aload_2
     232: checkcast     #59                 // class java/util/Collection
     235: astore        4
     237: iconst_0
     238: istore        5
     240: aload         4
     242: astore        6
     244: aload         6
     246: iconst_0
     247: anewarray     #41                 // class java/lang/Comparable
     250: invokeinterface #63,  2           // InterfaceMethod java/util/Collection.toArray:([Ljava/lang/Object;)[Ljava/lang/Object;
     255: checkcast     #65                 // class "[Ljava/lang/Comparable;"
     258: astore_3
     259: getstatic     #69                 // Field com/radix2/algorithms/week4/MaxPQ.Companion:Lcom/radix2/algorithms/week4/MaxPQ$Companion;
     262: aload_3
     263: invokevirtual #75                 // Method com/radix2/algorithms/week4/MaxPQ$Companion.sort:([Ljava/lang/Comparable;)V
     266: aload_3
     267: aconst_null
     268: aconst_null
     269: aconst_null
     270: iconst_0
     271: aconst_null
     272: aconst_null
     273: bipush        63
     275: aconst_null
     276: invokestatic  #81                 // Method kotlin/collections/ArraysKt.joinToString$default:([Ljava/lang/Object;Ljava/lang/CharSequence;Ljava/lang/CharSequence;Ljava/lang/CharSequence;ILjava/lang/CharSequence;Lkotlin/jvm/functions/Function1;ILjava/lang/Object;)Ljava/lang/String;
     279: getstatic     #51                 // Field java/lang/System.out:Ljava/io/PrintStream;
     282: swap
     283: invokevirtual #57                 // Method java/io/PrintStream.println:(Ljava/lang/Object;)V
     286: return
}


package com.radix2.algorithms.week3

import kotlin.random.Random

class LinkedList<T : Comparable<T>> {
    private var head: Node<T>? = null
    private val toss = intArrayOf(-1, 1)

    fun add(data: T) {
        val n = Node(data)
        n.next = head
        head = n
    }

    fun reverse() {
        var trav = head
        var prev: Node<T>? = null

        while (trav != null) {
            val temp = trav
            trav = trav.next
            temp.next = prev
            prev = temp
        }

        head = prev
    }

    fun reverseRecurrsive() {

        fun reverse(head: Node<T>?, prev: Node<T>?): Node<T>? {
            if (head == null)
                return prev

            val temp = head.next

            head.next = prev

            return reverse(temp, head)
        }

        head = reverse(head, null)
    }

    fun sort() {
        head = sort(head)
    }

    fun shuffle() {
        head = sort(head) { _, _ ->
            val index = Math.abs(Random.nextInt()) % 2
            toss[index]
        }
    }

    override fun toString() = buildString {
        var trav = head

        while (trav != null) {

            if (length > 0)
                append(", ")

            append(trav.data)

            trav = trav.next
        }
    }

    private fun sort(
        head: Node<T>?,
        comparator: (lhs: T, rhs: T) -> Int = { lhs, rhs -> lhs.compareTo(rhs) }
    ): Node<T>? {
        if (head?.next == null)
            return head

        val mid = getMiddleNode(head)
        val nextToMid = mid?.next
        mid?.next = null

        val left = sort(head)
        val right = sort(nextToMid)

        return merge(left, right, comparator)
    }

    private fun getMiddleNode(head: Node<T>?): Node<T>? {
        if (head == null) return null

        var slow = head
        var fast = head.next

        while (fast != null) {
            fast = fast.next

            if (fast != null) {
                fast = fast.next
                slow = slow?.next
            }
        }

        return slow
    }

    private fun merge(left: Node<T>?, right: Node<T>?, comparator: (lhs: T, rhs: T) -> Int): Node<T>? {
        if (left == null)
            return right

        if (right == null)
            return left

        val result: Node<T>?

        if (comparator(left.data, right.data) > 0) {
            result = right
            result.next = merge(left, right.next, comparator)
        } else {
            result = left
            result.next = merge(left.next, right, comparator)
        }

        return result
    }

    private class Node<E>(val data: E, var next: Node<E>? = null)
}

fun main(args: Array<String>) {

    val linkedList = LinkedList<Int>()

    for (i in 0..10) {
        linkedList.add(i)
    }

    linkedList.reverseRecurrsive()

    println(linkedList)
}

Compiled from "SortingLinkedList.kt"
public final class com.radix2.algorithms.week3.SortingLinkedListKt {
  public static final void main(java.lang.String[]);
    Code:
       0: aload_0
       1: ldc           #9                  // String args
       3: invokestatic  #15                 // Method kotlin/jvm/internal/Intrinsics.checkNotNullParameter:(Ljava/lang/Object;Ljava/lang/String;)V
       6: new           #17                 // class com/radix2/algorithms/week3/LinkedList
       9: dup
      10: invokespecial #21                 // Method com/radix2/algorithms/week3/LinkedList."<init>":()V
      13: astore_1
      14: iconst_0
      15: istore_2
      16: iload_2
      17: bipush        11
      19: if_icmpge     39
      22: aload_1
      23: iload_2
      24: invokestatic  #27                 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
      27: checkcast     #29                 // class java/lang/Comparable
      30: invokevirtual #33                 // Method com/radix2/algorithms/week3/LinkedList.add:(Ljava/lang/Comparable;)V
      33: iinc          2, 1
      36: goto          16
      39: aload_1
      40: invokevirtual #36                 // Method com/radix2/algorithms/week3/LinkedList.reverseRecurrsive:()V
      43: getstatic     #42                 // Field java/lang/System.out:Ljava/io/PrintStream;
      46: aload_1
      47: invokevirtual #48                 // Method java/io/PrintStream.println:(Ljava/lang/Object;)V
      50: return
}


package com.radix2.algorithms.week3

fun sort(array: Array<Int>): Long {
    return sort(array, Array(array.size) { 0 }, 0, array.size - 1)
}

fun sort(array: Array<Int>, aux: Array<Int>, lo: Int, hi: Int): Long {
    if (lo >= hi) return 0

    val mid = lo + (hi - lo) / 2

    var inversions: Long

    inversions = sort(array, aux, lo, mid)
    inversions += sort(array, aux, mid + 1, hi)

    return inversions + merge(array, aux, lo, mid, hi)
}

fun merge(array: Array<Int>, aux: Array<Int>, lo: Int, mid: Int, hi: Int): Long {
    var i = lo
    var j = mid + 1
    val nextToMid = j
    var k = lo

    var inversions = 0L

    while(i <= mid && j <= hi) {
        if (array[i] <= array[j]) {
            aux[k++] = array[i++]
        } else {
            aux[k++] = array[j++]
            inversions += nextToMid - i
        }
    }

    while(i <= mid)
        aux[k++] = array[i++]

    while(j <= hi)
        aux[k++] = array[j++]

    System.arraycopy(aux, lo, array, lo, (hi - lo) + 1)

    return inversions
}

fun main(args: Array<String>) {

    val array = arrayOf(7, 5, 3, 1)

    val inversions = sort(array)

    println(array.joinToString())
    println(inversions)
}

Compiled from "CountingInversionsV1.kt"
public final class com.radix2.algorithms.week3.CountingInversionsV1Kt {
  public static final long sort(java.lang.Integer[]);
    Code:
       0: aload_0
       1: ldc           #9                  // String array
       3: invokestatic  #15                 // Method kotlin/jvm/internal/Intrinsics.checkNotNullParameter:(Ljava/lang/Object;Ljava/lang/String;)V
       6: aload_0
       7: iconst_0
       8: istore_1
       9: aload_0
      10: arraylength
      11: istore_2
      12: iload_2
      13: anewarray     #17                 // class java/lang/Integer
      16: astore_3
      17: astore        5
      19: iload_1
      20: iload_2
      21: if_icmpge     41
      24: iload_1
      25: istore        4
      27: aload_3
      28: iload         4
      30: iconst_0
      31: invokestatic  #21                 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
      34: aastore
      35: iinc          1, 1
      38: goto          19
      41: aload         5
      43: aload_3
      44: iconst_0
      45: aload_0
      46: arraylength
      47: iconst_1
      48: isub
      49: invokestatic  #24                 // Method sort:([Ljava/lang/Integer;[Ljava/lang/Integer;II)J
      52: lreturn

  public static final long sort(java.lang.Integer[], java.lang.Integer[], int, int);
    Code:
       0: aload_0
       1: ldc           #9                  // String array
       3: invokestatic  #15                 // Method kotlin/jvm/internal/Intrinsics.checkNotNullParameter:(Ljava/lang/Object;Ljava/lang/String;)V
       6: aload_1
       7: ldc           #28                 // String aux
       9: invokestatic  #15                 // Method kotlin/jvm/internal/Intrinsics.checkNotNullParameter:(Ljava/lang/Object;Ljava/lang/String;)V
      12: iload_2
      13: iload_3
      14: if_icmplt     19
      17: lconst_0
      18: lreturn
      19: iload_2
      20: iload_3
      21: iload_2
      22: isub
      23: iconst_2
      24: idiv
      25: iadd
      26: istore        4
      28: lconst_0
      29: lstore        5
      31: aload_0
      32: aload_1
      33: iload_2
      34: iload         4
      36: invokestatic  #24                 // Method sort:([Ljava/lang/Integer;[Ljava/lang/Integer;II)J
      39: lstore        5
      41: lload         5
      43: aload_0
      44: aload_1
      45: iload         4
      47: iconst_1
      48: iadd
      49: iload_3
      50: invokestatic  #24                 // Method sort:([Ljava/lang/Integer;[Ljava/lang/Integer;II)J
      53: ladd
      54: lstore        5
      56: lload         5
      58: aload_0
      59: aload_1
      60: iload_2
      61: iload         4
      63: iload_3
      64: invokestatic  #32                 // Method merge:([Ljava/lang/Integer;[Ljava/lang/Integer;III)J
      67: ladd
      68: lreturn

  public static final long merge(java.lang.Integer[], java.lang.Integer[], int, int, int);
    Code:
       0: aload_0
       1: ldc           #9                  // String array
       3: invokestatic  #15                 // Method kotlin/jvm/internal/Intrinsics.checkNotNullParameter:(Ljava/lang/Object;Ljava/lang/String;)V
       6: aload_1
       7: ldc           #28                 // String aux
       9: invokestatic  #15                 // Method kotlin/jvm/internal/Intrinsics.checkNotNullParameter:(Ljava/lang/Object;Ljava/lang/String;)V
      12: iload_2
      13: istore        5
      15: iload_3
      16: iconst_1
      17: iadd
      18: istore        6
      20: iload         6
      22: istore        7
      24: iload_2
      25: istore        8
      27: lconst_0
      28: lstore        9
      30: iload         5
      32: iload_3
      33: if_icmpgt     105
      36: iload         6
      38: iload         4
      40: if_icmpgt     105
      43: aload_0
      44: iload         5
      46: aaload
      47: invokevirtual #42                 // Method java/lang/Integer.intValue:()I
      50: aload_0
      51: iload         6
      53: aaload
      54: invokevirtual #42                 // Method java/lang/Integer.intValue:()I
      57: if_icmpgt     77
      60: aload_1
      61: iload         8
      63: iinc          8, 1
      66: aload_0
      67: iload         5
      69: iinc          5, 1
      72: aaload
      73: aastore
      74: goto          30
      77: aload_1
      78: iload         8
      80: iinc          8, 1
      83: aload_0
      84: iload         6
      86: iinc          6, 1
      89: aaload
      90: aastore
      91: lload         9
      93: iload         7
      95: iload         5
      97: isub
      98: i2l
      99: ladd
     100: lstore        9
     102: goto          30
     105: iload         5
     107: iload_3
     108: if_icmpgt     128
     111: aload_1
     112: iload         8
     114: iinc          8, 1
     117: aload_0
     118: iload         5
     120: iinc          5, 1
     123: aaload
     124: aastore
     125: goto          105
     128: iload         6
     130: iload         4
     132: if_icmpgt     152
     135: aload_1
     136: iload         8
     138: iinc          8, 1
     141: aload_0
     142: iload         6
     144: iinc          6, 1
     147: aaload
     148: aastore
     149: goto          128
     152: aload_1
     153: iload_2
     154: aload_0
     155: iload_2
     156: iload         4
     158: iload_2
     159: isub
     160: iconst_1
     161: iadd
     162: invokestatic  #48                 // Method java/lang/System.arraycopy:(Ljava/lang/Object;ILjava/lang/Object;II)V
     165: lload         9
     167: lreturn

  public static final void main(java.lang.String[]);
    Code:
       0: aload_0
       1: ldc           #56                 // String args
       3: invokestatic  #15                 // Method kotlin/jvm/internal/Intrinsics.checkNotNullParameter:(Ljava/lang/Object;Ljava/lang/String;)V
       6: iconst_4
       7: anewarray     #17                 // class java/lang/Integer
      10: astore_2
      11: aload_2
      12: iconst_0
      13: bipush        7
      15: invokestatic  #21                 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
      18: aastore
      19: aload_2
      20: iconst_1
      21: iconst_5
      22: invokestatic  #21                 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
      25: aastore
      26: aload_2
      27: iconst_2
      28: iconst_3
      29: invokestatic  #21                 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
      32: aastore
      33: aload_2
      34: iconst_3
      35: iconst_1
      36: invokestatic  #21                 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
      39: aastore
      40: aload_2
      41: astore_1
      42: aload_1
      43: invokestatic  #58                 // Method sort:([Ljava/lang/Integer;)J
      46: lstore_2
      47: aload_1
      48: aconst_null
      49: aconst_null
      50: aconst_null
      51: iconst_0
      52: aconst_null
      53: aconst_null
      54: bipush        63
      56: aconst_null
      57: invokestatic  #64                 // Method kotlin/collections/ArraysKt.joinToString$default:([Ljava/lang/Object;Ljava/lang/CharSequence;Ljava/lang/CharSequence;Ljava/lang/CharSequence;ILjava/lang/CharSequence;Lkotlin/jvm/functions/Function1;ILjava/lang/Object;)Ljava/lang/String;
      60: getstatic     #68                 // Field java/lang/System.out:Ljava/io/PrintStream;
      63: swap
      64: invokevirtual #74                 // Method java/io/PrintStream.println:(Ljava/lang/Object;)V
      67: getstatic     #68                 // Field java/lang/System.out:Ljava/io/PrintStream;
      70: lload_2
      71: invokevirtual #77                 // Method java/io/PrintStream.println:(J)V
      74: return
}


package com.radix2.algorithms.week3

object TraditionalMergeSort {
    fun sort(array: IntArray) {
        val aux = IntArray(array.size)
        sort(array, aux, 0, array.size - 1)
    }

    fun sort(array: IntArray, aux: IntArray, lo: Int, hi: Int) {
        if (lo >= hi) return

        val mid = lo + (hi - lo) / 2

        sort(array, aux, lo, mid)
        sort(array, aux, mid + 1, hi)
        merge(array, aux, lo, mid, hi)
    }

    fun merge(array: IntArray, aux: IntArray, lo: Int, mid: Int, hi: Int) {
        System.arraycopy(array, lo, aux, lo, (hi - lo) + 1)

        var i = lo
        var j = mid + 1

        for (k in lo..hi) {
            when {
                i > mid -> array[k] = aux[j++]
                j > hi -> array[k] = aux[i++]
                aux[i] > aux[j] -> {
                    array[k] = aux[j++]
                }
                else -> array[k] = aux[i++]
            }
        }
    }
}

fun main(args: Array<String>) {
    val array = intArrayOf(6, 2, 1, 0, 13, 89, 72, 4, 22, 28)
    TraditionalMergeSort.sort(array)
    println(array.joinToString())
}

Compiled from "TraditionalMergeSort.kt"
public final class com.radix2.algorithms.week3.TraditionalMergeSortKt {
  public static final void main(java.lang.String[]);
    Code:
       0: aload_0
       1: ldc           #9                  // String args
       3: invokestatic  #15                 // Method kotlin/jvm/internal/Intrinsics.checkNotNullParameter:(Ljava/lang/Object;Ljava/lang/String;)V
       6: bipush        10
       8: newarray       int
      10: astore_2
      11: aload_2
      12: iconst_0
      13: bipush        6
      15: iastore
      16: aload_2
      17: iconst_1
      18: iconst_2
      19: iastore
      20: aload_2
      21: iconst_2
      22: iconst_1
      23: iastore
      24: aload_2
      25: iconst_3
      26: iconst_0
      27: iastore
      28: aload_2
      29: iconst_4
      30: bipush        13
      32: iastore
      33: aload_2
      34: iconst_5
      35: bipush        89
      37: iastore
      38: aload_2
      39: bipush        6
      41: bipush        72
      43: iastore
      44: aload_2
      45: bipush        7
      47: iconst_4
      48: iastore
      49: aload_2
      50: bipush        8
      52: bipush        22
      54: iastore
      55: aload_2
      56: bipush        9
      58: bipush        28
      60: iastore
      61: aload_2
      62: astore_1
      63: getstatic     #21                 // Field com/radix2/algorithms/week3/TraditionalMergeSort.INSTANCE:Lcom/radix2/algorithms/week3/TraditionalMergeSort;
      66: aload_1
      67: invokevirtual #25                 // Method com/radix2/algorithms/week3/TraditionalMergeSort.sort:([I)V
      70: aload_1
      71: aconst_null
      72: aconst_null
      73: aconst_null
      74: iconst_0
      75: aconst_null
      76: aconst_null
      77: bipush        63
      79: aconst_null
      80: invokestatic  #31                 // Method kotlin/collections/ArraysKt.joinToString$default:([ILjava/lang/CharSequence;Ljava/lang/CharSequence;Ljava/lang/CharSequence;ILjava/lang/CharSequence;Lkotlin/jvm/functions/Function1;ILjava/lang/Object;)Ljava/lang/String;
      83: getstatic     #37                 // Field java/lang/System.out:Ljava/io/PrintStream;
      86: swap
      87: invokevirtual #43                 // Method java/io/PrintStream.println:(Ljava/lang/Object;)V
      90: return
}

Compiled from "TraditionalMergeSort.kt"
public final class com.radix2.algorithms.week3.TraditionalMergeSort {
  public static final com.radix2.algorithms.week3.TraditionalMergeSort INSTANCE;

  private com.radix2.algorithms.week3.TraditionalMergeSort();
    Code:
       0: aload_0
       1: invokespecial #8                  // Method java/lang/Object."<init>":()V
       4: return

  public final void sort(int[]);
    Code:
       0: aload_1
       1: ldc           #15                 // String array
       3: invokestatic  #21                 // Method kotlin/jvm/internal/Intrinsics.checkNotNullParameter:(Ljava/lang/Object;Ljava/lang/String;)V
       6: aload_1
       7: arraylength
       8: newarray       int
      10: astore_2
      11: aload_0
      12: aload_1
      13: aload_2
      14: iconst_0
      15: aload_1
      16: arraylength
      17: iconst_1
      18: isub
      19: invokevirtual #24                 // Method sort:([I[III)V
      22: return

  public final void sort(int[], int[], int, int);
    Code:
       0: aload_1
       1: ldc           #15                 // String array
       3: invokestatic  #21                 // Method kotlin/jvm/internal/Intrinsics.checkNotNullParameter:(Ljava/lang/Object;Ljava/lang/String;)V
       6: aload_2
       7: ldc           #27                 // String aux
       9: invokestatic  #21                 // Method kotlin/jvm/internal/Intrinsics.checkNotNullParameter:(Ljava/lang/Object;Ljava/lang/String;)V
      12: iload_3
      13: iload         4
      15: if_icmplt     19
      18: return
      19: iload_3
      20: iload         4
      22: iload_3
      23: isub
      24: iconst_2
      25: idiv
      26: iadd
      27: istore        5
      29: aload_0
      30: aload_1
      31: aload_2
      32: iload_3
      33: iload         5
      35: invokevirtual #24                 // Method sort:([I[III)V
      38: aload_0
      39: aload_1
      40: aload_2
      41: iload         5
      43: iconst_1
      44: iadd
      45: iload         4
      47: invokevirtual #24                 // Method sort:([I[III)V
      50: aload_0
      51: aload_1
      52: aload_2
      53: iload_3
      54: iload         5
      56: iload         4
      58: invokevirtual #31                 // Method merge:([I[IIII)V
      61: return

  public final void merge(int[], int[], int, int, int);
    Code:
       0: aload_1
       1: ldc           #15                 // String array
       3: invokestatic  #21                 // Method kotlin/jvm/internal/Intrinsics.checkNotNullParameter:(Ljava/lang/Object;Ljava/lang/String;)V
       6: aload_2
       7: ldc           #27                 // String aux
       9: invokestatic  #21                 // Method kotlin/jvm/internal/Intrinsics.checkNotNullParameter:(Ljava/lang/Object;Ljava/lang/String;)V
      12: aload_1
      13: iload_3
      14: aload_2
      15: iload_3
      16: iload         5
      18: iload_3
      19: isub
      20: iconst_1
      21: iadd
      22: invokestatic  #41                 // Method java/lang/System.arraycopy:(Ljava/lang/Object;ILjava/lang/Object;II)V
      25: iload_3
      26: istore        6
      28: iload         4
      30: iconst_1
      31: iadd
      32: istore        7
      34: iload_3
      35: istore        8
      37: iload         8
      39: iload         5
      41: if_icmpgt     136
      44: nop
      45: iload         6
      47: iload         4
      49: if_icmple     66
      52: aload_1
      53: iload         8
      55: aload_2
      56: iload         7
      58: iinc          7, 1
      61: iaload
      62: iastore
      63: goto          123
      66: iload         7
      68: iload         5
      70: if_icmple     87
      73: aload_1
      74: iload         8
      76: aload_2
      77: iload         6
      79: iinc          6, 1
      82: iaload
      83: iastore
      84: goto          123
      87: aload_2
      88: iload         6
      90: iaload
      91: aload_2
      92: iload         7
      94: iaload
      95: if_icmple     112
      98: aload_1
      99: iload         8
     101: aload_2
     102: iload         7
     104: iinc          7, 1
     107: iaload
     108: iastore
     109: goto          123
     112: aload_1
     113: iload         8
     115: aload_2
     116: iload         6
     118: iinc          6, 1
     121: iaload
     122: iastore
     123: iload         8
     125: iload         5
     127: if_icmpeq     136
     130: iinc          8, 1
     133: goto          44
     136: return

  static {};
    Code:
       0: new           #2                  // class com/radix2/algorithms/week3/TraditionalMergeSort
       3: dup
       4: invokespecial #46                 // Method "<init>":()V
       7: putstatic     #49                 // Field INSTANCE:Lcom/radix2/algorithms/week3/TraditionalMergeSort;
      10: return
}