排序是比较常见的算法了,针对实际数据的特点选择合适的排序算法可以使程序获得更高的效率,今天来总结一下用Python来实现各种排序。
一、冒泡排序
冒泡排序是一种很简单的排序了,名字也很形象
思想:相邻节点进行两两比较,如果左边的比右边的大就交换两个元素的位置,第一轮排序结束后,最大的元素跑到了最右面;接下来对没排好序的n-1个元素再进行排序,这样,每次排序都有一个最大的往后面冒
时间复杂度:O(n2),假设排序的数有n个,遍历一趟的复杂度是O(n),需要遍历n-1趟,所以是O(n2)
空间复杂度:O(1),因为不需要额外的存储空间
稳定性:稳定,因为相邻两个元素之间交换,没有改变元素的相对位置,满足稳定性
实现:
def bubble_sort(aList):
n = len(aList)
for i in range(0, n - 1):
for j in range(0, n - i - 1):
if aList[j] > aList[j + 1]:
aList[j], aList[j + 1] = aList[j + 1], aList[j]
if __name__ == "__main__":
li = [54, 26, 93, 17, 77, 31, 44, 55, 20]
print(li)
bubble_sort(li)
print(li)
二、选择排序
思想:首先在未排序的序列中找出最小元素,放在排序序列的起始位置
然后继续在未排序序列中选择最小的,将其放在已排序序列的末尾
以此类推,直到所有元素都排好序
时间复杂度:O(n2),因为每次遍历的复杂度是O(n),一共遍历n-1次,所以复杂度是O(n2)
空间复杂度:O(1)
稳定性:稳定,因为无论什么数据进去都是O(n2)的时间复杂度,所以用到它的时候,数据规模越小越好
实现:
def SelectSort(lst):
n=len(lst)
if n<=1:
return lst
for i in range(0,n-1):
minIndex=i
for j in range(i+1,n): #比较一遍,记录索引不交换
if lst[j]<lst[minIndex]:
minIndex=j
if minIndex!=i: #按索引交换
(lst[minIndex],lst[i])=(lst[i],lst[minIndex])
return lst
if __name__ == "__main__":
li = [54, 26, 93, 17, 77, 31, 44, 55, 20]
print(li)
SelectSort(li)
print(li)
三、快速排序
思想:在数列中选择一个基准,所有比基准小的元素放在基准前面,所有比基准大的元素放在基准后面,然后递归的把左边和右边的子序列再进行此方法的排序。
快速排序之所以比较快,是因为与冒泡排序相比,每次的交换是跳跃式的,不会像冒泡排序一样每次只能在相邻的数之间进行交换,交换的距离大了,所以总的交换次数就少了,速度就提高了。
时间复杂度:在最坏的情况下,仍然可能是相邻的两个数进行交换,所以最差时间复杂度和冒泡排序一样是O(n2),平均时间复杂度是O(nlog2n)
实现:
def quick_sort(alist, start, end):
if start >= end: # 递归的退出条件
return
key = alist[start] # 设定起始的基准元素
low = start # low为序列左边在开始位置的由左向右移动的游标
high = end # high为序列右边末尾位置的由右向左移动的游标
while low < high:
# 如果low与high未重合,high(右边)指向的元素大于等于基准元素,则high向左移动
while low < high and alist[high] >= key:
high -= 1
alist[low] = alist[high] # 走到此位置时high指向一个比基准元素小的元素,将high指向的元素放到low的位置上,此时high指向的位置空着,接下来移动low找到符合条件的元素放在此处
# 如果low与high未重合,low指向的元素比基准元素小,则low向右移动
while low < high and alist[low] < key:
low += 1
alist[high] = alist[low] # 此时low指向一个比基准元素大的元素,将low指向的元素放到high空着的位置上,此时low指向的位置空着,之后进行下一次循环,将high找到符合条件的元素填到此处
# 退出循环后,low与high重合,此时所指位置为基准元素的正确位置,左边的元素都比基准元素小,右边的元素都比基准元素大
alist[low] = key # 将基准元素放到该位置
# 对基准元素左边的子序列进行快速排序
quick_sort(alist, start, low - 1
# 对基准元素右边的子序列进行快速排序
quick_sort(alist, low + 1, end)
if __name__ == '__main__':
alist = [54, 26, 93, 17, 77, 31, 44, 55, 20]
quick_sort(alist, 0, len(alist) - 1)
print(alist)
四、插入排序
思想:从第一个元素开始,该元素可以认为已经被排序,取出下一个元素,在已排序的元素序列中从后向前扫描,如果该元素(已排序)大于新元素,将该元素往后挪一个。插入排序在实现上,在从后向前扫描过程中,需要反复把已排序元素逐步向后挪位,为最新元素腾位置。
实现:
def insert_sort(list):
for i in range(1,len(list)):#外层循环
for j in range(i,0,-1):#内层循环决定试探位置
if list[j]<list[j-1]:
list[j],list[j-1]=list[j-1],list[j]
else:
break
list=[1,4,5,2,1,9,7,4,3,1,6]
insert_sort(list)
print(list)
- 第一层循环从1开始,到列表的长度终止。第二层循环主要是确定试探位置,从i的位置开始,到0终止。倒着进行循环
- 如果被试探位置的元素比插入元素大,那么试探元素后移一位,插入元素前进一位,直到被试探元素小于插入元素或者插入元素位于第一位。