快速排序
一把辛酸泪,在面试某翻译软件公司的时候。
面试官:同学啊,知道快排吗?
我:嗯嗯
面试官:你能口诉一下快排原理吗
我:额,这个,那个,巴拉巴拉一堆(奈何语言表达能力比较差,后面详细描述)
面试官:你这也不行啊,太拉跨了吧,你直接说一趟快排结果是什么吧
我:一趟快排的结果就是选定的基准元素呆在它应该待的位置,并且在这个数组中它前面的数比它小,它后面的数比它不小(大于等于)
面试官:有道理,那你写一下吧
于是乎我掏出我的键盘,写下了下面的代码
def quickSort(a,left,right):
if right - left < 1:
return a
else:
pre = a[left]
l = left
r = right
while l < r:
while l < r and a[r] >= pre:
r -= 1
a[l] = a[r]
while l < r and a[l] <= pre:
l += 1
a[r] = a[l]
a[l] = pre
a = quickSort(a,left,l - 1)
a = quickSort(a,l + 1,right)
return a
跑了一下,没问题,以为稳了呀,这不搞定了吗?
结果面试官:你这写的什么玩意,能不能别写递归,给咱表演个循环版本的
当时心里一紧,确实不会写循环版本的,咋整,赶紧下来学吧。
快排
快速排序,是先通过划分(partition)算法,将数组两分,划分的过程中,比主元(pivot)小的数字全部被划分到了左侧,比主元大的数字全部被划分到了右侧。然后对两分的数组进行递归。当数组两侧的长度均小于等于1,那么数组就自然有序了。
快速排序非递归的执行过程中,只需要一个堆栈空间,其运行过程如下:
1. 对原数组进行一次划分,分别将左边的索引、主元固定的位置和右边的索引入栈。
2. 判断 stack 是否为空,若是;直接结束;若不是,出栈,进行一次划分。
3. 通过左边索引、主元固定的位置,判断左边的长度大于 1,将左边进行2的划分并入栈;同理,进行右边操作。
4. 循环步骤 2、3。
代码
def quickOne(a,left,right):
if left > right:
return a,[right,right,right]
pre = a[left]
l = left
r = right
while l < r:
while l < r and a[r] >= pre:
r -= 1
a[l] = a[r]
while l < r and a[l] <= pre:
l += 1
a[r] = a[l]
a[l] = pre
return a,[left,l,right]
def quickSort(a):
pointers = []
l = 0
r = len(a) - 1
a,poi = quickOne(a,l,r)
pointers.append(poi)
while len(pointers) > 0:
poi = pointers[-1]
pointers.pop()
[l,mid,r] = poi
a,poi = quickOne(a,l,mid - 1)
if poi[2] - poi[0] > 1:
pointers.append(poi)
a,poi = quickOne(a,mid + 1,r)
if poi[2] - poi[0] > 1:
pointers.append(poi)
return a
PS:好好写基础的算法