三向字符串快速排序——python实现
为啥写这个
因为yh老师布置了这个高算作业,可怜我的国庆假期就这么没了,不过能有所得总是好的,所以记录一下
三向字符串快速排序是什么
首先快速排序是什么?
快速排序是这么做的:
1、用一个字符作为基准值(一般默认第一个为基准值),比它大的移到它的右边,比它小的移到它左边。
2.这样就分成了三块,大于小于和等于三组
3.然后每一块再次重复步骤一,又分成小组,直到不能再分
那么三向字符串快速排序又是什么?
和快排一样,只是他需要先从首字母比较单词大小,如果遇到同字母,还要再次比较下一个字母,如图所示(图是用别人的哈)
所以你会发现:三向字符串快速排序==快排+从左向右依次比较单词字母大小排序
我做了什么
刚开始,我真的按照思路去走了,我这么走的:
从首字母开始不断快排,每次快排都会分出三个组,left,mid和right,那么mid那一组一定是首字母相同的呀,那就mid那一组下一个字母再次快排呀,这样不就行了
def quick_sort(list,start,end,num):#num表示第几个字母
value=list[start]
right=[]
left=[]
mid=[]
result=[]
for i in range(end):
if list[i]>value:
right.append(list[i])
elif list[i]<value:
left.append(list[i])
else:
mid.append(list[i])
if len(mid)>1:
quick_sort(mid,0,len(mid)-1,1)
result=left+mid+right
if len(left)>1:
quick_sort(left,0,len(left)-1,0)
if len(right)>1:
quick_sort(right,0,len(right)-1,0)
可是!!我这样写了之后,他给我报错了?!!当然我的代码坑定是有问题的,因为我没有交换啥的,一定还有解决办法
RecursionError: maximum recursion depth exceeded in comparison
然后我调试的时候,发现,机器自己就可以从左到右顺序比较字母排序呀!!那我还乱啥呀?直接快派它不香吗?
开玩笑,作业要认真做,原理也是要搞懂的
问了下同组计算机出身的sc大佬,明白了:计算机不明白除了数字外的东西怎么比较大小,那怎么办呢,那就字符串对应数字呗,这样比较字符串的时候就是在比较它们对应的数字,很多语言里面都是早就写有这种默认规则的,要么可以直接用,要么用个函数啥的。
顺带一提,python的列表中有个sort函数,直接用就可以排好顺序,但是他的排序原理是timsort。
list.sort(cmp=None, key=None, reverse=False)
'''
cmp -- 可选参数, 如果指定了该参数会使用该参数的方法进行排序。
python3.x中取消了cmp参数,也不支持直接往sort()里面传函数,但可以构造排序函数传递给key来实现。
key -- 主要是用来进行比较的元素,只有一个参数,具体的函数的参数就是取自于可迭代对象中,指定可迭代对象中的一个元素来进行排序。比如第几个字母等等
reverse -- 排序规则,reverse = True 降序, reverse = False 升序(默认)'''
所以,接下来的事情的思路就清晰了,在快排的基础上,揪出中间的部分,在中间的部分用下一个字母再次快排
Python的实现
先附上快速排序的代码:
def quick_sort(alist, start, end):
"""快速排序"""
if start >= end: # 递归的退出条件
return
mid = alist[start] # 默认第一个为基准值
low = start # low在最左边的开始位置,是个由左向右移动的游标
high = end # low在最右边的末尾位置,是个由右向左移动的游标
while low < high:
# 如果low与high未重合,high此时对应的值大于等于基准值,则high左移
while low < high and alist[high] >= mid:
high -= 1
alist[low] = alist[high]
# 如果low与high未重合,low指向的元素比基准元素小,则low向右移动
while low < high and alist[low] < mid:
low += 1
alist[high] = alist[low]
#low和high遇到为一次,一次有一个基准值,high和low互换就会有空位出现,方便移动元素
# 退出循环后,low与high重合,此时所指位置为基准元素的正确位置,左边的元素都比基准元素小,右边的元素都比基准元素大
alist[low] = mid # 将基准元素放到该位置,
# 对基准元素左边的子序列进行快速排序
quick_sort(alist, start, low - 1) # start :0 low -1 原基准元素靠左边一位
# 对基准元素右边的子序列进行快速排序
quick_sort(alist, low + 1, end) # low+1 : 原基准元素靠右一位 end: 最后
'''读取输入数据'''
input = []
with open("用的是txt文件里的三字母单词做数据,这里写的是txt地址", "r") as f:
linedata = f.readlines() # 读全部
for line in linedata:
words = line.split() # 空格消除
for i in words:
input.append(i)#变成单个单词
# print(input[5][0])
f.close
if __name__ == '__main__':
quick_sort(input, 0, len(input) - 1)
print(input)
然后是三向字符串快速排序的代码:当然这个就没办法去给数字排序了,因为写了限定字母的部分
#用来确定列表里面第几个单词的第几个字母在比较
def CharAt(str,num):
if num<len(str):
return str[num]
def Quick3String(alist,start,end,num):
#括号里的内容分别是输入的单词列表,开始单词的序号,结尾单词的序号,在比较的第几个字母
if end<=start:#边界条件
return
low=start#左边游标
high=end#右边游标
base = CharAt(alist[low], num)#默认第一个单词为基准值
i = low + 1 # 从基准之后一个开始比较
while i<=high:#不重叠的情况下
current = CharAt(alist[i], num)#一定要在循环里面,每次会变的
if current<base:#小了就换,排成从小到大的顺序
alist[low],alist[i]=alist[i],alist[low]
low = low + 1
i = i + 1
elif current>base:
alist[high],alist[i]=alist[i],alist[high]
high=high-1
else:#相等的只移动游标
i=i+1
Quick3String(alist, start, low-1, num)
if len(base)>0:
Quick3String(alist, low, high, num+1)
Quick3String(alist, high+1, end, num)
这是结果(部分)