kotlin list binarySearch

时间:2018-03-23 23:18:23

标签: performance list kotlin binary-search-tree

我正在玩扩展功能,并尝试在列表上执行binarySearch功能。我意识到已经有一个内置于Kotlin的扩展功能。但是,它很慢: -

public fun <T: Comparable<T>> List<T?>.binarySearch(element: T?, fromIndex: Int = 0, toIndex: Int = size): Int {
     rangeCheck(size, fromIndex, toIndex)

     var low = fromIndex
     var high = toIndex - 1

     while (low <= high) {
         val mid = (low + high).ushr(1) // safe from overflows
         val midVal = get(mid)
         val cmp = compareValues(midVal, element)

         if (cmp < 0)
             low = mid + 1
         else if (cmp > 0)
             high = mid - 1
         else
             return mid // key found
     }
     return -(low + 1)  // key not found
}

我编辑了函数并删除了函数调用(compareValues),替换函数更快

test_buildin_binary_search         8s35m
test_binary_search           584ms

^根据我的测试,我会把它附上。

新的: -

fun rangeCheck(size: Int, fromIndex: Int, toIndex: Int) {
    when {
        fromIndex > toIndex -> throw IllegalArgumentException("fromIndex ($fromIndex) is greater than toIndex ($toIndex).")
        fromIndex < 0 -> throw IndexOutOfBoundsException("fromIndex ($fromIndex) is less than zero.")
        toIndex > size -> throw IndexOutOfBoundsException("toIndex ($toIndex) is greater than size ($size).")
    }
}

fun <T : Comparable<T>> binarySearch(list: List<T?>, element: T?, fromIndex: Int = 0, toIndex: Int = list.size): Int {
    rangeCheck(list.size, fromIndex, toIndex)

    var low = fromIndex
    var high = toIndex - 1

    while (low <= high) {
        val mid = (low + high).ushr(1) // safe from overflows
        val midVal = list.get(mid)
        val cmp = element?.compareTo(midVal as T) as Int

        if (cmp < 0)
            low = mid + 1
        else if (cmp > 0)
            high = mid - 1
        else
            return mid // key found
    }
    return -(low + 1)  // key not found
}

到目前为止,它不是扩展功能。但我相信内部函数调用是使它变慢的原因。

Q1。为什么compareValues不是内联函数?可能是由于设计决定?内联它并不总是一个好主意?

Q2。是否有一个关键字,让程序员可以自由地内联函数“f1”,例如f1不是内联函数?

我的意思是为什么没有像“inlineit”这样的关键字,它被用作: -

 fun f1() {
    println("something")
 }

 fun main() {
     inlineit f1() // line 1
     f1() // line 2
 }

在这种情况下,只有当我们在名称前面使用关键字inlineit时才会内联f1(),在上面的代码中,第1行中的代码f1()是内联的,而第2行则不是。

junit测试: -

class BinarySearchTests() {
    private val max = 10_000_000
    private val times = 10_000_000
    private val largNumbers = (0..max).toList()
    private val r = Random(System.currentTimeMillis())

    @Test
    fun test_binary_search() {
        var found = false

        repeat(times) {
            val item = r.nextInt(max)

            val r = binarySearch(largNumbers, item)

            if (r != null) found = true
        }

        assert(found)
    }


    @Test
    fun test_buildin_binary_search() {
        var found = false

        repeat(times) {
            val item = r.nextInt(max)

            val r = largNumbers.binarySearch(item)

            if (r != -1) found = true
        }

        assert(found)
    }

}

谢谢

0 个答案:

没有答案