快速排序(荷兰国旗法)

 快排是经典的二分法思想的排序方法, 它是不稳定的(即a0, a1的值均为1, 但是排序后可能a1在a0前面, 不保证相对顺序不变).

  • 输入: 数组A, 长度为L.

  • 输出: 排序后的数组A.

  • 基本思想:

    1. 选择"基准元": 从输入数组中随机取一个数字作为基准(pivot);
    2. 划分: 将所有小于pivot的数字放到pivot左边, 记为子数组A_left,
      所有大于pivot的数字放到pivot右边, 记为A_right;
    3. 递归: 对子数组A_left和A_right递归的调用步骤①和步骤②.

    经典的快速排序划分方法和荷兰国旗法的区别在于:

    • 经典方法是返回一个位置索引position, 将数组划分为两个部分:
      A [ p o s i t i o n ] = = p i v o t ; A l e f t = { A [ i ] ∣ A [ i ] < = p i v o t } ; A r i g h t = { A [ j ] ∣ A [ j ] > p i v o t } ; A[position] == pivot; \\ A_{left} = \{ A[i] | A[i] <= pivot \}; \\ A_{right} = \{ A[j] | A[j] > pivot \}; A[position]==pivot;Aleft={A[i]A[i]<=pivot};Aright={A[j]A[j]>pivot};
    • 而荷兰国旗法返回的是一个开区间(left, right), 将数组划分为三个部分:
      A l e f t = { A [ i ] ∣ A [ i ] < p i v o t } ; A m i d = { A [ k ] ∣ A [ k ] = = p i v o t } ; A r i g h t = { A [ j ] ∣ A [ j ] > p i v o t } ; A_{left} = \{A[i] | A[i] < pivot \}; \\ A_{mid} = \{A[k] | A[k] == pivot\}; \\ A_{right} = \{A[j] | A[j] > pivot\}; Aleft={A[i]A[i]<pivot};Amid={A[k]A[k]==pivot};Aright={A[j]A[j]>pivot};

 由此可以看出, 荷兰国旗法的效率更高, 每一次划分, 如果选择的基准元有重复值的话, 会一次性将重复值放到中间, 不会再参与下一次划分.
 荷兰国旗法的关键在于使用两个标记left, 和right, 在遍历元素的过程中, 保证left左边的元素都小于pivot, right右边的元素都大于pivot.

代码实现(python, 荷兰国旗法)

def swap(A, i, j):
	tmp = A[i]
	A[i] = A[j]
	A[j] = tmp

def partition(A, start, end):
    left = start - 1
    right = end
    pivot = A[end-1]
    k = start
    while k < right:
        if A[k] == pivot:
            k += 1
        elif A[k] < pivot:		# 将碰到的<pivot的值放到left控制的左半部分
            left += 1
            swap(A, k, left)
            k += 1
        else:					# 将碰到的>pivot的值放到right控制的右半部分
            right -= 1
            swap(A, k, right) 
    return left, right
    
def QSort(A, start, end):
	if start < end:
		left, right = partition(A, start, end) 
		QSort(A, start, left+1)
		QSort(A, right, end)```
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值