【问题标题】:Is the following code snippet a valid implementation of QuickSort?下面的代码片段是快速排序的有效实现吗?
【发布时间】:2020-01-02 02:00:25
【问题描述】:

我目前正在研究大学算法的理论领域,并根据我对算法工作原理的理解实现了快速排序的一个版本。之后,我将其与现有解决方案进行了比较,我的实现似乎与我发现的不同。也许有经验的人可以给我反馈:

function quicksort(array) {
	let leftIndex = 0
	let rightIndex = array.length - 2
	if (leftIndex >= rightIndex) {
		return array
	}
	
	let pivotIndex = array.length - 1
	let finalPivotIndex;
	
	do {
		while (array[leftIndex] < array[pivotIndex]) {
			leftIndex++
		}
		while (array[rightIndex] > array[pivotIndex]) {
			rightIndex--
		}
		if (leftIndex < rightIndex) {
			array = quickSwap(leftIndex, rightIndex, array)
		} else {
			finalPivotIndex = leftIndex
		}
	} while (leftIndex < rightIndex)
	
	if (array[finalPivotIndex] > array[pivotIndex]) {
		array = quickSwap(finalPivotIndex, pivotIndex, array)
	}
	
	let leftPivotArray = array.slice(0, finalPivotIndex)
	let rightPivotArray = array.slice(finalPivotIndex + 1)
	
	let sortedLeftArray = quicksort(leftPivotArray)
	let sortedRightArray = quicksort(rightPivotArray)
	let mergedArray = sortedLeftArray.concat([array[finalPivotIndex]])
	mergedArray = mergedArray.concat(sortedRightArray)
	return mergedArray
}

function quickSwap(firstIndex, secondIndex, array) {
	let tmp = array[firstIndex]
	array[firstIndex] = array[secondIndex]
	array[secondIndex] = tmp
	return array
}

【问题讨论】:

  • 一个或多个索引比较应该是 leftIndex &lt;= rightIndex 。可能还有其他问题。

标签: javascript quicksort


【解决方案1】:

问题中的代码似乎是 Hoare 分区方案的一种变体,但它正在创建数组的切片,此时它只能在原始数组上使用交换,并将索引传递给快速排序函数。如果需要,我可以稍后尝试调试问题的代码,但与此同时,这里是一个使用预递增和预递减的传统 Hoare 分区方案的示例,并通过仅在较小的分区上使用递归来避免堆栈溢出,并循环返回更大的分区。在我的系统上,使用 Chrome,对 1000 万个值进行排序只需不到 2 秒。

function quicksort(a, lo, hi) {
  while (lo < hi){
    var p = a[Math.floor(lo+(hi-lo)/2)];
    var i = lo - 1;
    var j = hi + 1;
    var t;
    while (true){
      while (a[++i] < p);
      while (a[--j] > p);
      if (i >= j)
        break;
      t = a[i];
      a[i] = a[j];
      a[j] = t;
    }
    if(j - lo < hi - j){
      quicksort(a, lo, j);
      lo = j+1;
    } else {
      quicksort(a, j+1, hi);
      hi = j;
    }
  }
}

var arr = new Array(10000000)
for (i = 0; i < arr.length; i++) {
  arr[i] = parseInt(Math.random() * 1000000000);
}
console.time('measure');
quicksort(arr, 0, arr.length-1);
console.timeEnd('measure');
for (i = 1; i < arr.length; i++) {
  if(arr[i-1] > arr[i]){
    console.log('error');     
    break;
  }
}

【讨论】:

    【解决方案2】:

    首先我不会使用单独的函数来进行交换,这通常会增加一些开销,如果涉及到大型数组,你不希望这样。

    我在将你的代码翻译成 python 后测试了它,它似乎无法正常工作,它坏了,目前正试图找到原因。

    编辑:

    我稍微更改了代码,保留了基本结构,现在它似乎可以正常工作了:

    (0) 做

    if (leftIndex > rightIndex){
            return array
        }
    

    而不是

    if (leftIndex >= rightIndex) {
            return array
        }
    

    并添加

    if ((array.length <= 2) && (array[0] < array[1])){
            return array
        }
    

    紧随其后 (这是相当伪代码没有在java中测试它(是python))

    最后一个块确保你在递归结束后离开函数不需要继续对子数组进行排序

    (1) 将枢轴设置在数组的中间,这样可以获得 log() 性能,长度为 1 的快速排序并不比其他任何方法快

    (2) 将枢轴保存在局部变量中,不通过索引访问,索引后面的元素可能会改变

    (3) 删除最后一个 if 语句 (array[finalPivotIndex] &gt; array[pivotIndex]) { 如果你在一个简单的数组上手动执行算法,你会看到这个块实际上改变了你刚刚所做的,这样你最终会得到错误的结果

    希望这就是我所做的全部更改,这是我的代码(在 Python 中,应该类似于阅读),以便您进行比较和故障排除:

    import random
    
    def Quicksort(array):
        leftIndex = 0
        rightIndex = len(array)-2
    
    
        if(leftIndex > rightIndex): #(0)
            return array
    
        if(len(array) <= 2 and array[0] < array[1]):#(0)
            return array
        pivotIndex = int(len(array)/2) #(1)
        finalPivotIndex = pivotIndex
    
        rightIndex = len(array)-1
        pivot = array[pivotIndex] #(2)
        while True:
            while array[leftIndex] < pivot: #(2)
                leftIndex += 1
            while array[rightIndex] > pivot: #(2)
                rightIndex -= 1
            if leftIndex < rightIndex:
                array[leftIndex], array[rightIndex] = array[rightIndex], array[leftIndex] #swapping in python
                #swapping alternative (without extra function) :
                #tmp = array[leftiIndex]
                #array[leftIndex] = array[rightIndex]
                #array[rightIndex] = tmp
                #this way you save the function-call-overhead and the problem of passing the whole array to ten function and back, this could hurt the performance quite a bit
                print(array, pivot, leftIndex, rightIndex) #debugging / slows down quite a bit
            else:
                finalPivotIndex = leftIndex
                break
       # (3)
       # if(array[finalPivotIndex] > array[pivotIndex]):
       #     array[finalPivotIndex], array[pivotIndex] = array[pivotIndex], array[finalPivotIndex]
       #     print(array)
    
        leftPivotArray = array[0:finalPivotIndex+1]
        rightPivotArray = array[finalPivotIndex+1:]
    
        sortedLeftArray = Quicksort(leftPivotArray)
        sortedRightArray = Quicksort(rightPivotArray)
        mergedArray = sortedLeftArray+sortedRightArray
    
        return mergedArray
    
    #how I generated the array for testing
    array = []
    for i in range(50):
        array.append(i)
    array = random.sample(array, 50)
    qsorted = Quicksort(array)
    array.sort()
    #testing the function against the python-implementation  --> returns true
    print(qsorted == array)
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-08-02
      • 1970-01-01
      • 2016-01-10
      • 2011-11-03
      • 2021-09-05
      • 2019-03-27
      • 1970-01-01
      相关资源
      最近更新 更多