排序算法
一,冒泡排序
1.思想
冒泡排序,从左往右依次比较,将大的轮换到最右边,然后循环,已经排位的大 的不用参加新一轮的轮换。
内层循环负责把左边的数依次与右边的轮换。外层循环负责控制轮换的终止位置。
2.注意:
循环range(列表长度),还是list[]切片,一定要搞清楚,不能写错。对于列表都是从0开始标号,所以结束位置是n-1
比较轮换的时候,i到n-2就可以了,也就是说i的终止位置,【n-2,n-3,n-4....1】
def bubble_sort(alist): n = len(alist) for j in range(n - 1, 0, -1):#-1是步长,放在后面,不能放中间 count=0 for i in range(0, j): if alist[i] > alist[i + 1]: alist[i], alist[i + 1] = alist[i + 1], alist[i] count+=1 if count==0: break if __name__=="__main__": alist=[54,26,93,17,77,31,44,55,20] print(alist) bubble_sort(alist) print(alist)
- 最优时间复杂度:O(n) (表示遍历一次发现没有任何可以交换的元素,排序结束。)
- 最坏时间复杂度:O(n2)
- 稳定性:稳定
二,选择排序
选择排序,找出序列里面最小值,往左放。一般循环是找找最小值的位置,最后在这个循环外面跟最左边未排序的进行交换,不能轮换。
内循环:找最小值的位置,外循环。控制未排列的序列和最小值和最左位置的交换。
def select_sort(alist): n = len(alist) for j in range(0, n - 1): min_index = j for i in range(j, n): if alist[i] < alist[min_index]: min_index = i#这里只能给坐标转换值,不能动列表里面的值。
if min_index != j:#循环结束找到最小值位置,才动列表的值 alist[min_index], alist[j] = alist[j], alist[min_index] if __name__ == "__main__": alist = [54, 26, 93, 17, 77, 31, 44, 55, 20] select_sort(alist) print(alist)
三,插入排序
插入排序,是依次将序列从右边与左边已经排好的轮换。但是和冒泡不同的是,不需要一个个比较,当比较到相应位置就停止。
内循环控制插入过程,和冒泡类似,用i和i+1相比较。
def insert_sort(alist): n = len(alist) for j in range(1, n): for i in range(j, 0, -1): if alist[i] < alist[i - 1]: alist[i], alist[i - 1] = alist[i - 1], alist[i] else:#当直接找到了比这个待排序大的就停止排序 break
注意:range(i-1,-1,-1):中间不能放-1,最小放0
- 最优时间复杂度:O(n) (升序排列,序列已经处于升序状态)
- 最坏时间复杂度:O(n2)
- 稳定性:稳定。。一般跟冒泡类似的,轮换性质的都是稳定的
四。希尔排序
五,快速排序(划分交换排序)
1. 思想:(选择一个中间值作为一个分割线,分开序列)
通过第一个值作为中值(注意这里中值并不意味着最后位置是最中间)对整个数列进行划分,然后从右开始做判断,交换进行排序,最后要求:规则:这个中值的左边都小于它,右边都大于它。
将list[0]提出来,0位空缺
low游标初始指向0,和high游标指向尾部,在指向空值时不能挪动。high游标先动,直到有不满足规则的,交换空缺和high的值。然后让low游标移动
以中值左右划分之后的序列再迭代进行快速排序。
2.注意:
迭代的时候再函数里面进行,不是定义之后。在其他函数里面反复调用,那样不是迭代。
迭代的输入要始终都是要处理的列表,只是不能传入切片,因为切片是取列表的一部分
if 语句是判断并不能当循环用。
想用两段代码交替进行,就在外部加一个while,这样循环起来。
递归的终止一定要写,而且写在函数内部,列表的两边只剩下一个元素时,就可以停止了。
空位=值a,这样就可以把a赋给空位,a为为空。
3.代码。思路
def quick_sort(alist, first, last): #递归的结束条件千万不能忘记 if first >= last: return mid_value = alist[first] low = first high = last while low < high: while low < high and alist[high] >= mid_value: high -= 1 alist[low] = alist[high] while(low < high and alist[low] < mid_value): low += 1 alist[high] = alist[low]#赋值的时候,不用交替赋值,因为这里high的值是0,直接这样赋值,就能让low得到high的空值。 alist[low] = mid_value quick_sort(alist, 0, low-1)#左边序列的左边子序列开始始终是0,结束是需要low控制 quick_sort(alist, low + 1, last)#右边序列的之后的子序列的右边子序列始终是last。 #关于迭代要清楚 if __name__ == "__main__": alist = [54, 26, 93, 17, 77, 31, 44, 55, 20] print(alist) n = len(alist) quick_sort(alist, 0, n-1)#传入的last一定要是n-1,因为这里是直接对n-1位置进行对比。 print(alist)

其中wid2左,是第二次快排的时候,中间值。
每一次迭代的两次划分都是用相同的输入变量。左边都是【0,wid-1】,右边都是【wid+1,last】
4.时间复杂度
最优排序时间复杂度:当wid正好可以把序列一分为二,迭代会依次把n/2/2/2/2/...,.一直到1停止,这里进行了x次的除2:x=log(n)
每次迭代函数内部要n次,需要O(nlog(n))
最差时间复杂度:每次wid只能把序列分成自己和其他:O(n的平方)
不稳定:因为交换有可能造成相同值的顺序被打乱。
浙公网安备 33010602011771号