Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/algorithm/12.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Algorithm 如何使quickselect算法更快_Algorithm_Scala - Fatal编程技术网

Algorithm 如何使quickselect算法更快

Algorithm 如何使quickselect算法更快,algorithm,scala,Algorithm,Scala,我参加了一门研究算法的课程,我们有一个任务,要用quickselect做经典的第k个最小元素(0是最小的,sequence.length-1是最大的) 该算法应比排序方法平均快2* Arrays.sort 我的算法可行,但速度不够快。它平均比上述排序数组的方法慢5倍。以下是我迄今为止的实施情况: def find(sequence: Seq[Int], k: Int): Int = { require(0 <= k && k < sequence.len

我参加了一门研究算法的课程,我们有一个任务,要用quickselect做经典的第k个最小元素(0是最小的,
sequence.length-1
是最大的)

该算法应比排序方法平均快2*

Arrays.sort
我的算法可行,但速度不够快。它平均比上述排序数组的方法慢5倍。以下是我迄今为止的实施情况:

  def find(sequence: Seq[Int], k: Int): Int = {
    require(0 <= k && k < sequence.length)
    val a: Array[Int] = sequence.toArray[Int]
    select(a,k)
  }

  def select(a: Array[Int], k: Int): Int = {
    val pivot = rand.nextInt(a.length)     
    val (low, middle, high) = partition(a,a(pivot))
    if (low.length == k) a(pivot)
    else if(low.length > k) select(low, k) 
    else if (low.length + middle.length >= k+1) middle(0)
    else if (low.length == 0) select(high, k - low.length-middle.length)
    else  findFast(high, k - low.length-middle.length)
  }

  def partition(array: Array[Int],pivot: Int): (Array[Int],Array[Int],Array[Int])={
    (array.filter(_<pivot),array.filter(_==pivot),array.filter(_>pivot))
  }
def find(序列:Seq[Int],k:Int):Int={
要求(0 k)选择(低,k)
如果(low.length+middle.length>=k+1)中间(0),则为else
如果(low.length==0)选择(high,k-low.length-middle.length)
else findFast(高,k-低。长度中间。长度)
}
def分区(数组:数组[Int],pivot:Int):(数组[Int],数组[Int],数组[Int])={
(array.filter(_pivot))
}

你能给我一些技巧来改进我的实现的运行时间吗?

在你的实现中,
分区
函数执行
array.filter
三次

为了避免这种情况,您可以使用Scala
partition
方法作为-注意,代码不会执行
partition
两次(不知道实际运行时间)


(虽然实际上并不需要
equal
部分-您可以从另一个长度中获得它的长度)

在您的实现中
分区
函数执行
数组。过滤器
三次

为了避免这种情况,您可以使用Scala
partition
方法作为-注意,代码不会执行
partition
两次(不知道实际运行时间)


(虽然实际上并不需要相等的部分-您可以从其他长度中获得它的长度)

尽管quickSelect上通常有许多帖子,而且伪代码的标准模板已经足够好了,我总是很难在Scala中找到好的实现,Rosetta博客中的代码很好,但可能会进入无限循环,特别是当左分区或右分区数组之一被排序时

下面是Scala的一个稍加修改的工作解决方案(包括重复元素和排序数组等情况)

如果输入数组已排序,则基本上返回第k个元素

def isSorted[T](arr: List[T])(implicit ord: Ordering[T]): Boolean = arr match {
        case Nil => true
        case x :: Nil => true
        case x :: xs => ord.lteq(x, xs.head) && isSorted(xs)
}
def quickSelect(nums: List[Int], k: Int): Int = {
        // if the input array is sorted then no point partitioning further
        // and go into a potential infinite loop even with random pivot
        // logical to pick the kth element from sorted array
        if (isSorted(nums)) return nums(k)
        // else start the partition logic
        val pvt = (new scala.util.Random).nextInt(nums.length)
        val (lower, higher) = nums.partition( _ < nums(pvt))
        if (lower.length > k) quickSelect(lower, k)
        else if (lower.length < k) quickSelect(higher, k - lower.length)
        else nums(pvt)
}
def-isSorted[T](arr:List[T])(隐式order:Ordering[T]):Boolean=arr-match{
案例Nil=>true
案例x::Nil=>true
案例x::xs=>ord.lteq(x,xs.head)和&isSorted(xs)
}
def quickSelect(nums:List[Int],k:Int):Int={
//如果输入数组已排序,则没有进一步的点分区
//并进入一个潜在的无限循环,即使是随机轴
//从排序数组中选取第k个元素的逻辑
if(isSorted(nums))返回nums(k)
//否则启动分区逻辑
val pvt=(new scala.util.Random).nextInt(nums.length)
val(较低,较高)=nums.分区(uuk)快速选择(lower,k)
否则如果(较低的.length

希望这会有所帮助。

尽管quickSelect上有很多帖子,而且伪代码的标准模板已经足够好了,我总是很难在Scala中找到好的实现,Rosetta博客中的代码很好,但可能会进入无限循环,特别是当左分区或右分区数组之一被排序时

下面是Scala的一个稍加修改的工作解决方案(包括重复元素和排序数组等情况)

如果输入数组已排序,则基本上返回第k个元素

def isSorted[T](arr: List[T])(implicit ord: Ordering[T]): Boolean = arr match {
        case Nil => true
        case x :: Nil => true
        case x :: xs => ord.lteq(x, xs.head) && isSorted(xs)
}
def quickSelect(nums: List[Int], k: Int): Int = {
        // if the input array is sorted then no point partitioning further
        // and go into a potential infinite loop even with random pivot
        // logical to pick the kth element from sorted array
        if (isSorted(nums)) return nums(k)
        // else start the partition logic
        val pvt = (new scala.util.Random).nextInt(nums.length)
        val (lower, higher) = nums.partition( _ < nums(pvt))
        if (lower.length > k) quickSelect(lower, k)
        else if (lower.length < k) quickSelect(higher, k - lower.length)
        else nums(pvt)
}
def-isSorted[T](arr:List[T])(隐式order:Ordering[T]):Boolean=arr-match{
案例Nil=>true
案例x::Nil=>true
案例x::xs=>ord.lteq(x,xs.head)和&isSorted(xs)
}
def quickSelect(nums:List[Int],k:Int):Int={
//如果输入数组已排序,则没有进一步的点分区
//并进入一个潜在的无限循环,即使是随机轴
//从排序数组中选取第k个元素的逻辑
if(isSorted(nums))返回nums(k)
//否则启动分区逻辑
val pvt=(new scala.util.Random).nextInt(nums.length)
val(较低,较高)=nums.分区(uuk)快速选择(lower,k)
否则如果(较低的.length

希望这会有所帮助。

您确定
array.filter
的工作速度与通常的霍尔分区方案一样快吗?看来这是三重的工作!我还看到scala有内置的
分区
为什么要使用随机轴心位置?如果数组已经排序,中间的元素是理想的选择,因为它可以将每个小节的工作量减半。@MBo你说得对!数组被迭代三次,这会导致问题!分区函数也是有问题的,因为我必须遍历数组两次,因为我要将数组分成三部分。有没有一种方法可以通过一轮迭代对数组进行分区?将您的测试序列延长1000倍您是否确保
array.filter
与通常的霍尔分区方案一样快?看来这是三重的工作!我还看到scala有内置的
分区
为什么要使用随机轴心位置?如果数组已经排序,中间的元素是理想的选择,因为它可以将每个小节的工作量减半。@MBo你说得对!数组被迭代三次,这会导致问题!分区函数也是有问题的,因为我必须遍历数组两次,因为我要将数组分成三部分。有没有一种方法可以通过一轮迭代对数组进行分区?将测试序列延长1000倍
def partition(A,low,equal,high, pivot):
   for item in A:
      if item < pivot:
          low[lowidx++] = item
      elif item > pivot:
          high[highidx++] = item
      else:
          equal[eqidx++] = item
def isSorted[T](arr: List[T])(implicit ord: Ordering[T]): Boolean = arr match {
        case Nil => true
        case x :: Nil => true
        case x :: xs => ord.lteq(x, xs.head) && isSorted(xs)
}
def quickSelect(nums: List[Int], k: Int): Int = {
        // if the input array is sorted then no point partitioning further
        // and go into a potential infinite loop even with random pivot
        // logical to pick the kth element from sorted array
        if (isSorted(nums)) return nums(k)
        // else start the partition logic
        val pvt = (new scala.util.Random).nextInt(nums.length)
        val (lower, higher) = nums.partition( _ < nums(pvt))
        if (lower.length > k) quickSelect(lower, k)
        else if (lower.length < k) quickSelect(higher, k - lower.length)
        else nums(pvt)
}