您的位置:首页 > 编程语言 > Python开发

Quick Sort的两种实现方法---Python

2019-01-28 20:40 204 查看

1.思想:

  1. 取一个参考值,让序列所有的元素排序后,左侧子序列的值都比参考值小,右侧子序列的值都比参考值大。

  2. 分别对左侧和右侧的子序列做1中的递归操作。

基于上述思想,常用的实现方法有两种,一种是简单、容易理解的Lomuto scheme,另一种是效率更高的Hoare scheme。下面的代码参考自维基百科的伪代码实现,不清楚的可以移步维基,仔细研究。

2.Lomuto partition scheme:

《Programming Pearls》and 《Introduction to Algorithms》都采用这种框架。这个框架通常选择最后一个元素作为

pivot
,设置游标
i
,使用
j
作为索引遍历数组,保证游标
i
左侧的元素都
<= pivot
,右侧的元素全都
>pivot
。 ​

Python Implementation-1

[code]# Segment 1

def partition(array, l, r):
   pivot = array[r]
   i = l - 1
   for j in range(l, r):
       if array[j] <= pivot:
           i += 1
           array[i], array[j] = array[j], array[i]
   array[i + 1], array[r] = array[r], array[i + 1]
   return i + 1
​
# Segment 2

def partition(array, l, r):
   pivot = array[r]
   i = l
   for j in range(l, r):
       if array[j] <= pivot:
           array[i], array[j] = array[j], array[i]
           i += 1
   array[i], array[r] = array[r], array[i]
   return i

def QuickSort(array, l, r):
if l < r:
q = partition(array, l, r)
QuickSort(array, l, q - 1)
QuickSort(array, q + 1, r)
return array
​
# from wikipedia: segment 1 or 2 is both ok.

 

3.Hoare partition scheme

--- From wikipedia

该方法设置两个索引,从数组的两端相向移动,直到它们分别发现了可转换的元素:左索引

array[i]>pivot
,右索引
array[j]<=pivot
,显然,这两个位置的元素应该交换。当两个索引相遇,停止移动,返回最后一个index。

优点

  1. 效率高,交换次数相当于Lumoto 方法的1/3,平均来看;

  2. 对于等值数组,交换次数为0;

  3. 对于已排序数组,

    pivot=array[first],array[last]
    都会导致​的时间复杂度,而
    pivot=array[mid]
    反而会达到最优时间复杂度​。

Python Implementation-2

[code]# Modified from wiki

def partition(array,l,r):
   pivot = array[l]
   left = l +1
   right = r
   while left <= right:
       while left <= right and array[left] <= pivot:
           left += 1
       while left <= right and array[right] >= pivot:
           right -= 1
       if left <= right:
           array[left],array[right] = array[right],array[left]
   array[l],array[right] = array[right],array[l]
   return right
​
# Copy from online resource

def partition(array,l,r):
   pivot = array[l]
   left = l+1
   right = r
   done = False
   while not done:
       while left<=right and array[left]<=pivot:
           left += 1
       while left<=right and array[right]>=pivot:
           right -= 1
       if right < left:
           done = True
       else:
           array[left],array[right]= array[right],array[left]
   array[right],array[l]= array[l],array[right]
   return right

def QuickSort(array, l, r):
if l<r:
k = partition(array, l, r)
QuickSort(array,l,k-1)
QuickSort(array,k+1,r)
return array

边界条件分析:

为什么

array[l],array[right] = array[right],array[l]
是对的

  1. array[left]<=pivot
    时,
    left
    会不断增加,但是由于前面有
    array[right]>pivot
    阻隔,至多到
    left=right
    ,然后
    right
    还可以左移一位,从而使
    left>right
    ,此时
    array[left]>pivot,array[right]<=pivot
    显然交换是对的;

  2. array[left]>pivot
    时,
    left
    暂停,
    array[right]>=pivot
    不断左移,至
    right=left
    ,此时
    right
    再左移一位,
    right<left, array[left]>pivot,array[right]<=pivot

  3. 所有的情况只有上面两种结局,最后的状态都是

    array[right]<=pivot,array[left]>pivot
    (等值数组显然不是这种情况)。

Python Implementation-3

[code]def QuickSort(array,l,r):
   if l>=r:
       return
   left = l
   right = r
   pivot = array[left]
   while left < right:
       while left < right and array[right] > pivot:
           right -= 1
       array[left] = array[right]
       while left < right and array[left] <= pivot:
           left += 1
       array[right] = array[left]
   array[right] = pivot
   QuickSort(array, l, left-1)
   QuickSort(array, left+, r)
   return array

边界条件分析:

  1. while left<right
    终止条件为
    left=right
    ,保证不会出现索引溢出。

  2. array[right]>pivot
    使
    right -= 1
    直至
    left=right
    ,由于此时
    array[left]<=pivot
    ,那么整个过程相当于交换了
    array[left] and array[right]

  3. array[right]<=pivot
    left<right
    ,那么
    array[right]
    先复制进
    left
    位置,当
    array[left]<=pivot
    使得
    left+=1
    直至
    left=right
    时,注意此时
    array[right]<=pivot
    但是
    left<right
    的限制使得至多
    left=right

  4. 所有的情况都可以归结为这两种结束方式,

    left added to right
    or
    right decreased to left
    ,构成一个交换的闭环。

另外一点需要注意的是,

array[right]>pivot and array[left]<=pivot
一定是完整的
> and <=
,不然无法处理元素和
pivot
相等的情况,而且由于不是
>= and <=
right and left
至多以
=
结束,不会出现上面实现方式中的
left>right
,所以终止判别条件是
left<right , instead of left<=right

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: