经过一段时间的学习,python的语法已经学了七七八八,又学习了数据结构相关知识,编写两种不同的排序算法验证一下这段时间学习的成果。
一、冒泡排序
作为最基础的排序算法,上次接触应该是在2011年 o !!
用python实现一下:
def bubble_sort(alist):
length = len(alist)
for loopout in range(length):
for loopin in range(0, length - loopout - 1):
if alist[loopin] > alist[loopin + 1]:
alist[loopin], alist[loopin + 1] = alist[loopin + 1], alist[loopin]
Python确实很简洁!!
二、快速排序
2.1 快速排序的原理
快速排序的总体思想:确定每一个元素的位置
具体的实现过程分成两步:
- Step1: 确定序列中第一个元素应该处于的位置,然后把他放到那个位置,并将比它大的放到右边,比它小的放到左边(默认是升序排列,降序就反一下)。以刚刚定位完的那个点为分界,分成前后两个序列。
- Step2:将分好的两个序列再分别执行第一步。直到排完序。
在用程序实现的时候,我先将“Step1”用一个函数实现并封装起来,再在另一个函数中实现整个排序过程。
2.2 div_list()函数:实现“Step1” ——序列的分割
div_list()函数的功能如下图所示
div_list()函数的具体实现过程如下:
记我们待处理的序列为a,长度为n,a=[a[0], a[1], …, a[n-1]]
-
Step 1: 设置
头游标
指向除了第一个元素(记为a[0])之外的序列的头(即序列中的第二个元素a[1])和尾游标
指向序列的尾(即序列最后一个元素a[n-1]) -
Step 2: 分别比较a[0]和
头游标
、尾游标
所指向元素(a[头]和a[尾])的大小,在不考虑“=” 的情况下,存在如下情况,进行相应的处理。
如果a[0]>a[头] ,就将头游标
后移一位,a[0]<a[尾]将尾游标
前移一位。
如果a[0]<a[头] ,就停止头游标
,a[0]>a[尾],就停止尾游标
如果头游标
和尾游标
都停止了,就交换a[头] 和a[尾],再继续。直到两个游标相遇。 -
Step 3: 两个游标相遇的地方就是a[0]的位置。
专门做了动图来展示一下这个过程。
Step1和Step2 的实现过程
在头尾游标相遇后,会存在下面两种情况:
-
头游标
停止(变红),尾游标
未停止。此时a[0]应该插在游标相遇处的前面
-
头游标
未停止,尾游标
停止。此时a[0]应该插在游标相遇处的后面
完成以上步骤后,会获得一个新的序列,该序列原来的a[0]位于正确的位置,左边的都比它小,右边都比他大。而原序列也将分为两个新的序列,即:比原a[0]小的序列,比原a[0]大的序列。
所编写的代码如下
def div_list(alist, start, end):
"""
函数div_list(),实现功能:确定序列alist[start, end]中第一个元素的位置并返回之
同时将该元素放到相应位置,并保证左边都比他小,右边都比他大
"""
length = len(alist) # 获得整个列表的长度
cur_begin = start + 1 # 初始化头游标
cur_end = end # 初始化尾游标
if end-start+1 > length: # 长度判断,此处还应加入是否是数字,是否是超出什么的,偷个懒
print("length wrong")
return -1
begin_finished = False # 初始化游标停止标志位
end_finished = False
while cur_begin < cur_end: # 只要头尾没有相遇就继续
if not begin_finished and alist[start] >= alist[cur_begin]: # 如果a[0]>a[头],将`头游标`后移一位
cur_begin += 1 # 否则判定头游标停止
else: # 为了应付等于的情况,此处将a[0]=a[头]
if not begin_finished: # 视为a[0]>a[头],而下面的a[0]=a[尾],
begin_finished = True # 则视为a[0]>a[尾]
if not end_finished and alist[start] < alist[cur_end]: # 如果a[0]<a[尾],将`尾游标`前移一位
cur_end += -1 # 否则判定尾游标停止
else:
if not end_finished:
end_finished = True
if begin_finished and end_finished: # 如果头、尾游标都停止,交换元素
alist[cur_begin], alist[cur_end] = alist[cur_end], alist[cur_begin]
begin_finished = False
end_finished = False
if alist[start] <= alist[cur_end]: # 此处是为了应付一种特殊情况
begin_finished = True
else:
end_finished = True
if not begin_finished and end_finished: # 实现a[0]插入
alist[start], alist[cur_end] = alist[cur_end], alist[start]
return cur_end
else:
alist[start], alist[cur_end-1] = alist[cur_end-1], alist[start]
return cur_end-1
实现的效果如下
测试程序:
import fastsort
import random
if __name__ == "__main__":
testlist = []
for loop in range(0, 10):
testlist.append(random.randint(0, 100))
print(testlist)
position = fastsort.div_list(testlist, 0, len(testlist) - 1)
print(testlist)
print(position)
输出
2.3 fast_sort() 函数:利用div_list()实现排序
实现了找一个序列第一个元素所处于的位置后,需要将其分开在继续后面的排序工作。具体实现过程如下图
代码如下:
def fast_sort(alist):
istart_last = [0] #初始化一个列表用于保存前一次的结果
iend_last = [len(alist)-1]
while istart_last:
istart_temp = istart_last
iend_temp = iend_last
istart_last = []
iend_last = []
for i in range(0, len(istart_temp)):
position_ok = div_list(alist, istart_temp[i], iend_temp[i])
if position_ok - istart_temp[i] <= 1 and iend_temp[i] - position_ok <= 1:
pass
elif position_ok - istart_temp[i] <= 1 and iend_temp[i] - position_ok > 1:
istart_temp[i] = istart_temp[i] + 1
istart_last.append(position_ok + 1)
iend_last.append(iend_temp[i])
elif position_ok - istart_temp[i] > 1 and iend_temp[i] - position_ok <= 1:
iend_temp[i] = iend_temp[i] - 1
istart_last.append(istart_temp[i])
iend_last.append(position_ok - 1)
else:
istart_last.append(istart_temp[i])
iend_last.append(position_ok - 1)
istart_last.append(position_ok + 1)
iend_last.append(iend_temp[i])
运行结果:
2.4 与冒泡法的对比
对比程序:
import fastsort
import bubble
import random
import time
if __name__ == "__main__":
begintime = time.time()
for loopout in range(0, 100):
testlist = []
for loop in range(0, 1000):
testlist.append(random.randint(0, 100))
fastsort.fast_sort(testlist)
endtime = time.time()
print("快速排序用时:", endtime - begintime)
begintime1 = time.time()
for loopout in range(0, 100):
testlist = []
for loop in range(0, 1000):
testlist.append(random.randint(0, 100))
bubble.bubbleSort(testlist)
endtime1 = time.time()
print("冒泡排序用时:", endtime1 - begintime1)
结果如下:
测试样本是100组,每组1000个0~100的随机数。
可以看出快速排序确实很快