排序算法
排序算法稳定性
- 在满足排序规则的前提下,保持原有顺序即具备稳定性,不保持原有顺序即不具稳定性
冒泡排序
源代码
具备稳定性,最坏时间复杂度=O(n^2)
def bubble_list(list):
for i in range(len(list)):
for k in range(len(list)-1-i):
if list[k] > list[k+1]:
list[k],list[k+1] = list[k+1],list[k]
print(list,end="\n\n") #看下每个泡泡的上升情况
return list
print(bubble_list([232,1,54,3463,22,121232,-8,99]))
选择排序
源代码
不具备稳定性(不具备吗?应该具备吧?)
def select (list):
select_list =[]
for j in range(len(list)):
min = list[j] #如果min用作下标,不用重新构建一个select_list素组,这样可以少一次迭代
for i in range(j+1,len(list)):
if list[i] < min:
min,list[i] = list[i],min
select_list.append(min)
print(select_list) #还是看看过程
return select_list
select([-101,232,1,22,54,3463,22,121232,-8,99])
插入排序
源代码
源代码包含在下面希尔排序中
具备稳定性,最坏时间复杂度=O(n^2)
希尔排序
不具备稳定性,最坏时间复杂度=O(n^2)。它的好处就是平均时间复杂度较小(它的最好情况甚至也不如插入排序)
源代码
def insert(list):
for i in range(len(list)-1):
for j in range(i,-1,-1):
if list[j+1] < list[j]:
list[j+1],list[j] = list[j],list[j+1]
else:
break
print(list) #仍然看过程
return list
def shell(list): #在插入排序基础上建立希尔排序
gap = len(list)
while gap//2 != 1 :
gap = gap//2
gap_list = [list[k] for k in range(0,len(list),gap) ] #构建基于每个gap的小列表
insert(gap_list)
return list
print(insert([-101, 232, 1, 22, 54, 3463, 22, 121232, -8, 99,-1234]))
print(shell([-101, 232, 1, 22, 54, 3463, 22, 121232, -8, 99,344543,-2123,12]))
快速排序
基本思路:使用两个游标(low和high),从列表的两端进行逼近(或者叫遍历)。从列表第一个元素开始查找正确位置,游标low(high)遇到比当前要确认位置的元素小(大)的元素,则继续遍历,否则停止,并交换low和high两个游标所指元素。这个过程一直进行,进行到low和high指向的元素一样的时候,则这个位置就是当前要确认位置的元素的正确位置,原有列表也被这个元素分割成两个列表,后面再按这个思路一直进行下去
思路改进:先用high(或者low)进行遍历,遇到小于待确认位置元素的元素的时候,把这个元素赋值给low,然后low游标开始遍历,直到找到比待确认位置元素大的元素,把这个值赋值给high,循此往复
不具备稳定性,最好时间复杂度O(n*log n) (log以2为底),最坏时间复杂度O(n^2)
难点:理解函数嵌套的递归思路;注意列表中下标+1,-1的情况
源代码
def fast(list, first, last): #为了后面递归能继续操作list中的元素,引入first和last
if first-1 == last: #这个判断只能写在前面,因为后面的嵌套内部要用, 思考:这里为什么first要-1?当分割到列表仅剩一个元素的时候,low= first , last = low-1,所以last比low还小1
return list
mid_value = list[first] #mid_value就是待确认位置的元素, high与low游标都和它进行对比
low = first
high = last
while high > low:
while list[high] >= mid_value:
high -= 1
if high == low: #防止中间有过多一样的元素,导致high一直减少,导致high与low游标错过
break
list[low] = list[high] #刚开始的时候list[low]=mid_value=list[0],所以第一个list[low]的值不会丢
while list[low] < mid_value: #这里和上面while list[high] >= mid_value只有一个地方能加=,否则有可能在上面break后下面再操作一遍(这里比较抽象)
low += 1
if high == low: #防止中间有过多一样的元素,导致low一直增多,导致high与low游标错过
break
list[high] = list[low]
list[low] = mid_value
print(list,end="\n\n") #仍然要看过程
fast(list,first,low-1)
# print("---------------------------------------")
fast(list,low+1,last)
li = [-8,1,23,5,5,43,-9,100,4,6,7,2,4,-100]
li2 = [121,434,23,2,0,3,0,444,0]
fast(li, 0, len(li) - 1)
fast(li2,0,len(li2)-1)
print(li)
print(li2)
输出(注意看过程)
"C:\Users\Lenovo\Desktop\Python coding\venv\Scripts\python.exe" "C:/Users/Lenovo/Desktop/Python coding/05_fast.py"
[-100, -9, -8, 5, 5, 43, 23, 100, 4, 6, 7, 2, 4, 1]
[-100, -9, -8, 5, 5, 43, 23, 100, 4, 6, 7, 2, 4, 1]
[-100, -9, -8, 5, 5, 43, 23, 100, 4, 6, 7, 2, 4, 1]
[-100, -9, -8, 1, 4, 2, 4, 5, 100, 6, 7, 23, 43, 5]
[-100, -9, -8, 1, 4, 2, 4, 5, 100, 6, 7, 23, 43, 5]
[-100, -9, -8, 1, 2, 4, 4, 5, 100, 6, 7, 23, 43, 5]
[-100, -9, -8, 1, 2, 4, 4, 5, 100, 6, 7, 23, 43, 5]
[-100, -9, -8, 1, 2, 4, 4, 5, 100, 6, 7, 23, 43, 5]
[-100, -9, -8, 1, 2, 4, 4, 5, 5, 6, 7, 23, 43, 100]
[-100, -9, -8, 1, 2, 4, 4, 5, 5, 6, 7, 23, 43, 100]
[-100, -9, -8, 1, 2, 4, 4, 5, 5, 6, 7, 23, 43, 100]
[-100, -9, -8, 1, 2, 4, 4, 5, 5, 6, 7, 23, 43, 100]
[-100, -9, -8, 1, 2, 4, 4, 5, 5, 6, 7, 23, 43, 100]
[-100, -9, -8, 1, 2, 4, 4, 5, 5, 6, 7, 23, 43, 100]
[0, 0, 23, 2, 0, 3, 121, 444, 434]
[0, 0, 23, 2, 0, 3, 121, 444, 434]
[0, 0, 23, 2, 0, 3, 121, 444, 434]
[0, 0, 3, 2, 0, 23, 121, 444, 434]
[0, 0, 0, 2, 3, 23, 121, 444, 434]
[0, 0, 0, 2, 3, 23, 121, 444, 434]
[0, 0, 0, 2, 3, 23, 121, 444, 434]
[0, 0, 0, 2, 3, 23, 121, 434, 444]
[0, 0, 0, 2, 3, 23, 121, 434, 444]
[-100, -9, -8, 1, 2, 4, 4, 5, 5, 6, 7, 23, 43, 100]
[0, 0, 0, 2, 3, 23, 121, 434, 444]
Process finished with exit code 0
归并排序
在这个排序中,嵌套的理解仍是难点
最有时间复杂度和最坏时间复杂度都是O(n*log n),具备稳定性
源代码
def merge(list):
if len(list) == 1:
return list
mid = len(list) //2
left_list = merge(list[:mid]) #难点:理解这个嵌套
right_list = merge(list[mid:])
left_point = 0
right_point = 0
result_list = []
print(left_list)#这里仍然用于看过程
print(right_list)
print(result_list,end="\n\n")
while left_point < mid and right_point < mid:
if left_list[left_point] <= right_list[right_point]:
result_list.append(left_list[left_point])
left_point +=1
else:
result_list.append(right_list[right_point])
right_point +=1
result_list= result_list +left_list[left_point:] #把剩余元素补上,注意,这里不能用append
result_list= result_list +right_list[right_point:]
return result_list
li = [12,53,1]
merge(li)
二分法查找
只能作用于排序后的顺序表
最坏时间复杂度O(log n)
难点仍在于对嵌套递归的理解
源代码
def binary_search(in_list, target): #in_list是有序列表
n = len(in_list)
if n == 0:
return "Nogo"
# print(n,end="****")
else:
n = n // 2
print(n)
if target == in_list[n]:
return "bingo"
else:
if target > in_list[n]:
in_list = in_list[n+1:]
print(in_list, end= "\n")
return binary_search(in_list, target) #层层return最终结果
else:
in_list = in_list[:n]
print(in_list,end= "\n")
return binary_search(in_list, target)
print(binary_search([5,6,7,66,77,88,99,100,1000,10000],5))