常见的7种比较类排序算法(python详解)

常见的7种比较类排序算法(python详解)

常见的7种比较类的排序算法

冒泡排序、插入排序、选择排序、快速排序、希尔排序、归并排序、堆排序详解以及python实现
算法稳定:对于序列中元素相等的值,若排序后前后顺序不变,则算法稳定

1. 冒泡排序

时间复杂度O(n2)
稳定

主要思想:

每次排序时,从头开始两两进行比较,较小的数向前“冒”,较大的数向后“沉”

python实现:
def bubble_sort(arr):
	for i in range(0,len(arr)):
	#每排序一次,经过两两比较最大值“沉”到最后
		for j in range(1,len(arr)-i):
		#将第一个元素到未排序好的元素进行两两比较,大数靠后
			if arr[j]<arr[j-1]:
				arr[j-1],arr[j]=arr[j],arr[j-1]
	return arr

2.插入排序

时间复杂度O(n2)
稳定

主要思想:将元素插入到排好序序列的合适的位置(在排好序的序列中从后向前依次两两比较)
python实现:
def insert_sort(arr):
	for i in range(1,len(arr)):
	#i为当前要插入元素下标,与已经排好序的arr[:i]从后向前依次两两比较
		pre_index=i-1
		current=arr[i]
		#如果待插入的值小,则比他大的值后移,直到找到插入点
		while pre_index>=0 and arr[pre_index]>current:
			arr[pre_index+1]=arr[pre_index]
			pre_index-=1
		arr[pre_index+1]=current
	return arr

3.选择排序

时间复杂度O(n2)
不稳定

主要思想:从未排好序的选择最小的元素放在最前面(交换)
python实现:
def select_sort(arr):
	for i in range(0,len(arr)):
	#每一次排序后将最小的值放到最前面:从后面未排序的序列中找到最小值的索引,与当前arr[i]交换
		min_index=i
		for j in range(i+1,len(arr)):
			if arr[j]<arr[min_index]:
				min_index=j
		if min_index!=i:
			arr[i],arr[min_index]=arr[min_index],arr[i]
	return arr
			

4.快速排序

时间复杂度O(nlogn)
不稳定

主要思想:选择一个基准元素(一般情况选第一个或最后一个),根据小于基准元素和大于基准元素将原序列分为两个子序列,再分别对子序列进行快排
python实现:
def quick_sort(arr):
#递归实现,先找到终止条件
	if len(arr)<2:
		return arr
	#选择arr[0]为基准元素,将arr[1:]与其进行比较
	left,right=[],[]
	for i in range(1,len(arr)):
		if arr[i] <=arr[0]:
			left.append(arr[i])
		else:
			right.append(arr[i])
	#每进行一次排序,基准元素的位置已经确定,分别将小于和大于基准元素的子序列进行快排
	return quick_sort(left)+[arr[0]]+quick(right)

5.归并排序

时间复杂度O(nlogn)
稳定

主要思想:先两两合并成有序序列,再四四合并…
python实现:

递归方法:将大问题逐步分解成一个个小问题,先解决小问题(调用本身函数),再解决大问题

def recursion_merge_sort(arr):
   #分割成不同子序列,各子序列分别再分割
	mid=len(arr)//2
	arr1=arr[:mid]
	arr2=arr[mid:]
	if len(arr1)>1:
		arr1=recursion_merge_sort(arr1)
	if len(arr2)>1:
		arr2=recursion_merge_sort(arr2)
	result=[]
	#合并两个已经排好顺序的子序列
	while arr1 and arr2:
		 if arr1[0]<arr2[0]:
		 	result.append(arr1.pop(0))
		 else:
		 	result.append(arr2.pop(0))
	if arr1:
		result=result+arr1
	if arr2:
		result=result+arr2
	return result

非递归方法:先解决小问题,将得到的结果替换自己本身的值(迭代),将小问题一步步合并

def non_recursion_merge_sort(arr):
	#分割未排序序列,步长i,逐渐增大步长
	i=1
	while i<len(arr):
		low=0
		while low<len(arr):
			mid=low+i
			high=min(mid+i,len(arr))
			if mid<hight:
				left,right=arr[low:mid],arr[mid:high]
				#将每个子序列进行两两比较,合并成一个有序序列
				result=[]
				while left and right:
					if left[0]<right[0]:
						result.append(left.pop(0))
					else:
						result.append(right.pop(0))
				if left:
					result+=left
				if right:
					result+=right
				#用新得到的结果替换自己的值
				arr[low:high]=result
			low+=2*i
		i*=2
	return arr	

6.希尔排序

时间复杂度O(n1.3)
不稳定

主要思想:根据一定的增量(分组的跨度)分割序列,各子序列使用插入排序,再逐渐减小增量
python实现:
def shell_sort(arr):
	grap=len(arr)//2
	while grap>0:
	#相当于跨度为grap的插入排序
		for i in range(grap,len(arr)):
			current=arr[i]
			pre_index=i-grap
			#两两比较,大的后移,找到插入点,插入当前元素
			while pre_index>=0 and arr[pre_index]>current:
				arr[pre_index+grap]=arr[pre_index]
				pre_index-=grap
			arr[pre_index+grap]=current
		#逐渐减小跨度(跨度为1时为插入排序)
		grap//=2
	return arr

7.堆排序

时间复杂度O(nlogn)
不稳定

主要思想:若升序排列,根据大顶堆(根节点值大于等于所有左右子树的值的完全二叉树),每次排序将堆顶元素与最后一个值交换,调整大顶堆,交换…
python实现:
def heap_sort(arr):
	#以start为根节点调整大顶堆(比较根节点与所有子树的值大小,最大值放在堆顶),end为堆的最后一个值对应的下标
	def adjust_heap(start,end):
		root=start
		#若根节点下标为i,则左孩子下标为2*i+1,右孩子为2*i+2
		while True:
			child=2*root+1
			#没有左子树
			if child>end:
				break
			#找到各子树中的最大值
			if child+1<end and arr[child+1]>arr[child]:
				child+=1
			if arr[root]<arr[child]:
				arr[root],arr[child]=arr[child],arr[root]
				root=child
			#最大值已经在堆顶,结束调整
			else:
				break
	#创建大顶堆
	#完全二叉树中,最后一个非叶子节点的下标
	last_no_leave=len(arr)//2-1
	while last_no_leave>=0:
		#调整每一个带有孩子的子树
		adjust_heap(last_no_leave,len(arr)-1)
		last_no_leave-=1
	#将堆顶元素与最后一个元素交换,调整堆,再交换...
	end=len(arr)-1
	while end>0:
		arr[0],arr[end]=arr[end],arr[0]
		#除去最后一个元素,将剩余元素调整为大顶堆
		adjust_heap(0,end-1)
		end-=1
	return arr
总结:比较类排序中
稳定的排序算法有(3个):冒泡排序、插入排序、归并排序;不稳定的排序(4个):选择排序、快速排序、希尔排序、堆排序
  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值