如何改进快速排序算法(Python)

时间:2016-05-16 04:18:07

标签: python arrays sorting

在阅读了快速排序算法后,我决定在查看任何代码之前编写自己的实现。下面的代码是我想出的。在将我的代码与其他实现进行比较后,我观察到,而不是从快速排序函数返回已排序的数组,其他实现倾向于利用列表的可变性并简单地在未排序的数组上运行该函数,将对数组进行排序,而不必引用函数调用。我很好奇与我的代码和我正在使用的书中的代码的时空比较,我在下面提供了这些代码。我假设在时间方面,算法执行的方式相似,也许我正在执行的连接操作会产生负面影响?在空间方面,由于我没有直接修改输入数组,我假设我正在创建/返回一个明显效率低的新数组,这很重要,因为快速排序比合并排序的主要优点是节省的空间。总的来说,我只是在寻找一些额外的见解和方法来提高算法的效率。

我的代码:

from random import randint

def quick(arr):
  if len(arr) == 1:
    return arr
  else:

    pivot = arr[0]
    R = len(arr)-1
    L = 1

    while L <= len(arr)-1 and R >= 1:
        if R == L:
            if arr[0] > arr[R]:
                arr[0], arr[R] = arr[R], arr[0]
            break
        if arr[R] >= pivot:
            R = R - 1
            continue
        if arr[L] <= pivot:
            L = L + 1
            continue
        arr[L], arr[R] = arr[R], arr[L]
    return quick(arr[:R]) + quick(arr[R:])

print quick([randint(0,1000) for i in range(1000)])

我正在使用的书,使用Python解决算法和使用Python的数据结构作者:Brad Miller和David Ranum,提供了这个快速排序代码:

def quickSort(alist):
  quickSortHelper(alist,0,len(alist)-1)

def quickSortHelper(alist,first,last):
  if first<last:

   splitpoint = partition(alist,first,last)

   quickSortHelper(alist,first,splitpoint-1)
   quickSortHelper(alist,splitpoint+1,last)


def partition(alist,first,last):
  pivotvalue = alist[first]

  leftmark = first+1
  rightmark = last

 done = False
 while not done:

   while leftmark <= rightmark and alist[leftmark] <= pivotvalue:
     leftmark = leftmark + 1

   while alist[rightmark] >= pivotvalue and rightmark >= leftmark:
     rightmark = rightmark -1

     if rightmark < leftmark:
       done = True
     else:
       temp = alist[leftmark]
       alist[leftmark] = alist[rightmark]
       alist[rightmark] = temp

 temp = alist[first]
 alist[first] = alist[rightmark]
 alist[rightmark] = temp

return rightmark

# alist = [54,26,93,17,77,31,44,55,20]
# quickSort(alist)
# print(alist)

1 个答案:

答案 0 :(得分:1)

这是很好的代码。

与已完成的快速排序版本(仅使用一个阵列)相比,由于复制/连接,您的速度可能会慢一些。

Quicksort表演在很大程度上依赖于枢轴的选择。通过选择第一个元素,有些情况下代码以二次方运行,例如在排序已排序的数组时。 最着名的优化是:

  • 选择一个更好的支点,例如应用Tukey的ninther(几乎可以肯定地避免那些最糟糕的情况)。
  • 当子阵列足够小时执行插入排序(例如,<10)。

另外,有一些快速排序的变种运行得更快,比如3-way quicksort使用Bentley-McIlroy的sheme或双枢轴快速排序(用于对java中的原始数组进行排序)。插入加速仍然适用于那些。