【问题标题】:How to find pivoting element properly while performing quick sort?如何在执行快速排序时正确找到枢轴元素?
【发布时间】:2020-03-15 00:41:02
【问题描述】:

我有一个包含以下元素的数组:var arr = Array[Int](10,16,8,12,15,6,3,9,5) 我正在尝试使用快速排序技术对其进行排序。 以下是我编写的用于快速排序的代码:

object Quick {
def main(args: Array[String]): Unit = {
    var arr   = Array[Int](10,16,8,12,15,6,3,9,5)
    var low   = 0
    var high  = arr.length-1
    quickSort(low, high)
    arr.foreach(println)

    def quickSort(low:Int, high:Int):Unit = {
        if(low<high) {
            var j = partition(low, high)
            quickSort(low, j)
            quickSort(j+1, high)
        }
    }

    def partition(low:Int, high:Int): Int = {
        var pivot = arr(low)
        var i = low
        var j = high
        while(i<j) {
            do {
                i += 1
            } while(arr(i) <= pivot)
            do {
                j -= 1
            } while(arr(j) > pivot)
            if(i<j) swap(i, j)
        }
        swap(i, j)
        j
    }

    def swap(ai:Int, aj:Int): Unit = {
        var tmp = arr(ai)
        arr(ai) = arr(aj)
        arr(aj) = tmp
    }
}

}

当我运行代码时,它在以下行中断:while(arr(i) &lt;= pivot) 索引变为9 我通过添加条件if(i &lt; arr.length-1) i += 1 处理了第一个 do while 在第二个 do 中也会发生同样的情况,其中行中的索引:while(arr(j) &gt; pivot) 变为 -1 并以 ArrayOutOfBoundsException 结尾。我通过添加条件来处理它:if(j&gt;0) j-= 1 如果我添加这些条件但我删除了它们,代码将进入无限循环,它会导致 ArrayOutOfBoundsException 索引:9 & -1 分别表示低和高。

谁能告诉我我在这里做错了什么?

【问题讨论】:

  • whiledo/whilevar、返回Unit的函数(在大多数情况下)等都被认为是Scala中的代码异味......我不确定快速排序算法,但试图通过函数的约束来解决这个问题,函数总是返回一个有用的类型并且不改变任何变量。它还使调试更容易,因为您不必在任何给定时间跟踪变异变量的值。
  • 这是真的,但实施高效的算法可能需要有效地访问和更改数据。使用纯函数方法可能会更困难

标签: arrays algorithm scala sorting quicksort


【解决方案1】:

我认为您在分区中的代码太复杂了。 正确示例:

def partition(low:Int, high:Int): Int = {
  val pivot = arr(high)
  var i = low - 1
  var j = low
  while (j <= high - 1) {
    if (arr(j) < pivot) {
      i += 1
      swap(i, j)
    }
    j += 1
  }
  swap(i + 1, high)
  i + 1
}

def quickSort(low:Int, high:Int):Unit = {
  if(low<high) {
    val j = partition(low, high)
    quickSort(low, j - 1)
    quickSort(j+1, high)
  }
}

其余代码相同。 算法来自:geeksforgeeks

【讨论】:

  • 明白这一点。我试图通过首先移动数组的索引来找到枢轴值,看看它是否可以工作。这就是它看起来有点冗长的原因。
【解决方案2】:

我不知道 scala,但问题中的代码可能会超出 (low, high) 的范围。分区循环依赖于停止元素 == pivot 来防止这种情况。 cmets 中记录的修复:

        var pivot = arr(low)           // any but arr(high)
        var i = low-1                  // fix
        var j = high+1                 // fix
        while(i<j) {
            do {
                i += 1
            } while(arr(i) < pivot)    // fix (not <=) 
            do {
                j -= 1
            } while(arr(j) > pivot)
            if(i<j) swap(i, j)
        }
                                       // fix (no post loop swap)
        j
    }

您可能会考虑稍作改动(可能会提高性能)。请注意,while(true) 的唯一方法是返回 j。

        var pivot = arr(low)
        var i = low-1
        var j = high+1
        while(true) {
            do {
                i += 1
            } while(arr(i) < pivot)
            do {
                j -= 1
            } while(arr(j) > pivot)
            if(i >= j) return j
            swap(i, j)
        }
    }

【讨论】:

    猜你喜欢
    • 2023-03-04
    • 2011-08-31
    • 1970-01-01
    • 2021-04-19
    • 2010-09-14
    • 2017-07-11
    • 2019-11-23
    • 1970-01-01
    • 2015-01-13
    相关资源
    最近更新 更多