全部为自己学习手打整理,引用请标明出处
一、冒泡排序:
第一次从第一个数开始依次向后比较,如果比后边小则交换位置,每次保证最大的在最后方(倒数第一)。第二次次大的在倒数第二个位置。依次比较下去直到不用再比较。
def bubble_sort(alist):
n = len(alist)
for j in range(n-1):#每次都是第一个数走,走n-1次
count = 0
for i in range(n-1-j):#班长从头走到尾(尾变化),j=0时对比n-1次(n个数)
if alist[i] > alist[i+1]:
alist[i], alist[i+1] = alist[i+1], alist[i]
count += 1
# 优化:如果遍历一次之后发现没有任何可以交换的元素,则直接结束
#时间复杂度由O(n*n)变为O(n)
if count == 0:
return
if __name__ =="__main__":
lst = [54, 26, 93, 17]
print(lst)
bubble_sort(lst)
print(lst)
二、插入排序:把第一个数值默认看成有序(左侧看成有序),后面的序列看成无序,每次从无序序列中拿出第一个数依次向前比较(前面的序列循环),直到放到正确的位置上。(如果比前一个数小,则和前一个数交换位置)
如一个序列: 54 26 93 17 77
第一次: 54 26 93 17 77
26 54 93 17 77
第二次: 26 54 93 17 77
第三次: 26 54 17 93 77
26 17 54 93 77
17 26 54 93 77
第四次: 17 26 54 77 93
def insert_sort(alist):
n = len(alist)
for j in range(1, n):# 从右边的无序序列中取出1~n-1个元素进行这样的过程
# j:1,2,3,4,....,n-1
i = j # i是内层循环起始值,第一个数比较一次,第二个数比较两次......i=j
while i > 0:# 判断这个条件只要看第一个数只要比较一次即可
if alist[i] < alist[i-1]:# 起始alist[1]和alist[0]进行比较
alist[i], alist[i-1] = alist[i-1], alist[i]
i -= 1
# 不需要再进行比较时,前面本身有序,说明此时比前面都大了
# 退出当前循环,从右边再取比较下一个值
else:
break
if __name__ =="__main__":
lst=[54,26,94,17,77]
print(lst)
insert_sort(lst)
print(lst)
三、希尔排序:
将列表按照间隔看成几个子组,每个子组都进行插入排序,每按一个间隔排序后的算依次。再将间隔减半或其他处理,直至间隔为1结束。
如一个序列:54 26 44 17 77 31 93 55 20
第一次gap=4
再依次gap=2,gap=1 结束
def shell_sort(alist):
n=len(alist)
gap = n // 2
while gap > 0: #或gap>=1,插入算法执行的次数
for j in range(gap, n):#j=[gap,gap+1,gap+2,...n-1],for和下面的while执行一次gap
i = j
while i > 0:
if alist[i] < alist[i-gap]:
alist[i], alist[i-gap] = alist[i-gap], alist[i]
i -= gap#这里相当于插入排序每次交换后再往前跟前一个比,只不过前一个的间隔变成了gap
else:
break
gap = gap // 2#缩短gap步长
if __name__=='__main__':
lst = [54,26,94,17,77]
print(lst)
shell_sort(lst)
print(lst)
四、选择排序:
整个序列的最左侧看成有序(一开始是第一个元素看成有序),每次把除排好位置的元素外的后面的序列看成无序。从无序序列中一个一个判断找出最小值(后面的序列循环)放到对应的位置并交换相应位置的元素。
如一个序列: 54 226 93 17 77 31 44 55 20
0 1 2 3 4 5 6 7 8
第一次:右侧min=3
alist[0], alist[3] = alist[3], alist[0]
17 226 93 54 77 31 44 55 20
0 1 2 3 4 5 6 7 8
第二次:右侧min=8
alist[1], alist[8] = alist[8], alist[1]
17 20 93 54 77 31 44 55 226
0 1 2 3 4 5 6 7 8
第三次:右侧min=5
alist[2], alist[5] = alist[5], alist[2]
17 20 31 54 77 93 44 55 226
0 1 2 3 4 5 6 7 8
第四次:右侧min=6
alist[3], alist[6] = alist[6], alist[3]
17 20 31 44 77 93 54 55 226
依次往下…
def select_sort(alist):
n=len(alist)
for j in range(n-1):#j =0,1,....n-2(共n-1次)
min_index = j#左侧比较每一次都往后移动一个
for i in range(j+1, n):#循环选择出最小下标
if alist[min_index] > alist[i]:#每次记录小的下标
min_index = i
alist[min_index],alist[j]= alist[j], alist[min_index]#选出最小下标后和头的交换
if __name__=='__main__':
lst = [54,26,94,17,77]
print(lst)
select_sort(lst)
print(lst)
五、快速排序:
把alist[0]看成mid_val存储起来,有两个指针low和high, 最开始low=0,high=n-1。从high先开始判断,如果大于等于mid_value(这里等于保证相等的数始终在mid_val的一侧),向左移动一位;如果小于mid_value,将high处的值放到low指向的位置。
low小于mid_val(小于就放那),将low向右移动一位;low大于mid_val(等于时也换,保证等于的值都在右侧一侧),将low处的值放到high指向的位置。直至low和high相遇,此处即为mid_value的位置。接着mid_value将整个序列分成两部分,这两部分仍然把各自部分的第一个值看成mid_value,分别再进行上述的操作,直至每个部分只剩下一个值,即 first >= last 时退出。
def quick_sort(alist, first, last):
if first >= last:#递归终止条件,否则一直递归
return
mid_value = alist[first]
low = first #每一次的low都是0
high = last#first last保证左右边界动态传递
while low < high: #二者不相遇就一直循环,下面两个while交替执行,跳出循环即找到mid_value位置
while low < high and alist[high] >= mid_value:#high大于mid_value时移动,一直大于一直移
high -= 1
alist[low] = alist[high] #high小于mid_value时赋给low
#这时low处的值一定小于mid_value,low直接靠下面的while移动,如果这里移动会造成二者相遇再错开的情况
while low < high and alist[low] < mid_value:
low += 1
alist[high] = alist[low]
#这时low处的值一定大于mid_value,low直接靠上面的if移动
#跳出循环high=low指向的都是mid_value
alist[low] = mid_value
quick_sort(alist, first, low - 1)
#mid_value左侧的结尾是low - 1,每递归一次左侧的左右都会运行(递归进函数时有下一句),此句只管左侧
quick_sort(alist, low+1, last)
#mid_value右侧的开始是low + 1,每递归一次右侧的左右都会运行(递归进函数时有上一句),此句只管右侧
if __name__=='__main__':
lst = [54,26,94,17,77]
print(lst)
quick_sort(lst, 0, len(lst)-1)
print(lst)