数据结构之快速排序
快速排序,又称划分交换排序,通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都比另外一部分的所有数据都要小,然后再按照此方法将这两部分数据分别进行快速排序,整个排序过程可以递归进行,依次达到整个数据变成有序序列。
步骤为:
- 从数列中挑出一个元素,称为“基准”。
- 重新排序数列,所有元素比基准值小的摆放在基准前面,所有元素比基准元素大的放在基准元素后面(相同的数可以放在任意一边),在这个分区结束以后,该基准就处于数列的中间位置。这个称为分区操作。
- 递归地把小于基准值元素的子数列和大于基准值元素的子数列排序。
递归的最底部形式,是数列的大小是0或1,也就是永远都可以被排序好了,虽然一直递归下去,但是这个算法总会结束,因为在每次迭代中,它至少会把一个元素摆到它最后的位置去。
快速排序算法分析
简述:先从数列中取出一个数作为基准数。分区过程,将比这个数大的数全放到它的右边,小于或等于它的数全放到它的左边。再对左右区间重复第二步,直到各区间只有一个数。
其原理是通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都比另外一部分的所有数据都要小,然后再按此方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,以此达到整个数据变成有序序列。
简单点理解就是:以序列中的任意一个元素为基准(一般以第一个元素),通过逐个比较后,找到这个基准元素的合适位置(即在基准元素的左边元素都比它小,右边都比它大),这时在将序列分成左右两个部分,在继续上述的操作,直到不能再分为止(只有一个元素),此时排序也就完成。
快速排序算法实现
方法一:
def quick_sort(li, first, last):
"""快速排序"""
# 参数first,last:指定序列排序的位置起始和终止下标
# 只有当first小于last时才退出排序,此时元素只有一个
if first >= last:
return li
else:
mid_value = li[first]
low = first
high = last
while low < high:
# high 左移
while low < high and mid_value <= li[high]:
high -= 1
li[low] = li[high]
# 此时li[low]的值已经小于或等于mid_value
# low 右移
while low < high and mid_value > li[low]:
low += 1
li[high] = li[low]
# 从循环退出时,low等于high
li[low] = mid_value
# 对low左边的列表进行快速排序
quick_sort(li, first, low - 1)
# 对low右边的列表进行快速排序
quick_sort(li, low + 1, last)
if __name__ == '__main__':
li = [54, 26, 93, 17, 77, 31, 44, 50, 20]
print('排序前:', li)
quick_sort(li, 0, len(li) - 1)
print('排序后:', li)
运行结果:
方法二:
def quick_sort(li):
"""快速排序"""
# 必须return 否则right和left 都是Nonetype(当数组长度为2时候除去基准len=1,for时候会找不到执行list)
if len(li) <= 1:
return li
mid_value = li[0]
# 定义两个列表用于存放大于或小于基准的值
left = list()
right = list()
for i in li[1:]:
if mid_value <= i:
right.append(i)
else:
left.append(i)
# 对right left分别快速排序后与 li[0]拼接为一个排序后的list
# 合并时,需要都是list类型,所以需将基准元素变成list类型
return quick_sort(left) + [mid_value] + quick_sort(right)
if __name__ == '__main__':
li = [54, 26, 93, 17, 77, 31, 44, 50, 20]
print('排序前:', li)
new_li = quick_sort(li)
print('排序后:', new_li)
运行结果:
对比两种方法的运算速度:
示例代码:
from timeit import Timer
def quick_sort(li, first, last):
"""快速排序"""
# 参数first,last:指定序列排序的位置起始和终止下标
# 只有当first小于last时才退出排序,此时元素只有一个
if first >= last:
return li
else:
mid_value = li[first]
low = first
high = last
while low < high:
# high 左移
while low < high and mid_value <= li[high]:
high -= 1
li[low] = li[high]
# 此时li[low]的值已经小于或等于mid_value
# low 右移
while low < high and mid_value > li[low]:
low += 1
li[high] = li[low]
# 从循环退出时,low等于high
li[low] = mid_value
# 对low左边的列表进行快速排序
quick_sort(li, first, low - 1)
# 对low右边的列表进行快速排序
quick_sort(li, low + 1, last)
def quick_sort2(li):
"""快速排序"""
# 必须return 否则right和left 都是Nonetype(当数组长度为2时候除去基准len=1,for时候会找不到执行list)
if len(li) <= 1:
return li
mid_value = li[0]
# 定义两个列表用于存放大于或小于基准的值
left = list()
right = list()
for i in li[1:]:
if mid_value <= i:
right.append(i)
else:
left.append(i)
# 对right left分别快速排序后与 li[0]拼接为一个排序后的list
# 合并时,需要都是list类型,所以需将基准元素变成list类型
return quick_sort2(left) + [mid_value] + quick_sort2(right)
if __name__ == '__main__':
li = [54, 26, 93, 17, 77, 31, 44, 50, 20]
li2 = [54, 26, 93, 17, 77, 31, 44, 50, 20]
print('排序前:', li)
time1 = Timer('quick_sort([54, 26, 93, 17, 77, 31, 44, 50, 20], 0, 8)', 'from __main__ import quick_sort')
quick_sort(li, 0, len(li) - 1)
print('方法1排序后:', li)
print('running time is :', time1.timeit(10))
time2 = Timer('quick_sort2([54, 26, 93, 17, 77, 31, 44, 50, 20])', 'from __main__ import quick_sort2')
new_li = quick_sort2(li2)
print('方法2排序后:', new_li)
print('running time is :', time2.timeit(10))
运行结果: