排序算法

#coding=utf-8
#具有稳定性的算法:冒泡排序、插入排序、基数排序、归并排序
#堆排序、归并排序:平均、最好、最坏均为O(nlogn);选择排序:平均、最好、最坏均为O(n^2)
#快排:平均、最好为O(nlogn),最坏为O(n^2)
#冒泡、插入排序:最好O(n),最坏和平均为O(n^2)
#希尔排序:最坏O(n^1.3),最好O(n^2)
#基数排序:O(d(n+k)),其中d为数字位数,n为排序数字个数,k为基数


#冒泡排序,具有稳定性,O(n^2)
def bubble_sort(num):
	for i in range(len(num)):
		# print(i)
		change = False
		for j in range(len(num)-1,i,-1): #从后往前,每次最小的冒到最前面(也可以从前往后,每次最大的冒到最后面)
			if num[j]<num[j-1]:
				num[j],num[j-1] = num[j-1],num[j]
				change = True
		if not change:
			break			#最好情况为轮询一遍不需要交换,O(n)
	return num

#插入排序,具有稳定性,O(n^2)
def insert_sort(num):
	for i in range(len(num)):
		for j in range(i,0,-1):
			if num[j]<num[j-1]:
				num[j],num[j-1] = num[j-1],num[j]
			else:
				break  #最好情况为都break不需要操作,O(n)
	return num

#选择排序,不具有稳定性,O(n^2)
def select_sort(num):
	for i in range(len(num)):
		min_index = i
		for j in range(i+1,len(num)):   #找出最小值,与num[i]交换
			if num[min_index]>num[j]:
				min_index = j
		num[i],num[min_index] = num[min_index],num[i]   #交换导致不稳定
	return num

#---------------------------------------------------------------------------------------
#归并排序,具有稳定性,O(nlogn),其中n为排序耗时,logn为二分耗时
def merge(num,left,mid,right):
	temp = []
	i,j = left,mid+1
	while (i<=mid and j<=right):
		if (num[i]<=num[j]):
			temp.append(num[i])
			i+=1
		else:
			temp.append(num[j])
			j+=1
	while (i<=mid):   #长度不等时剩下的,不是左边剩就是右边剩
		temp.append(num[i])
		i += 1
	while (j<=right):
		temp.append(num[j])
		j += 1
	num[left:right+1] = temp

#index[0,1,2,3,4,5]->[0,1,2][3,4,5]->[0,1][2,2][3,4,5]->[0,0][1,1][2,2][3,4,5]
#->merge([0,0][1,1])->merge([0,1][2,2])->(0,1,2)[3,4][5,5]->(0,1,2)[3,3][4,4][5,5]
#->merge([3,3][4,4])->merge([3,4][5,5])->merge([0,1,2][3,4,5])
def merge_recursion_sort(num,left,right):  #递归归并排序,自顶向下
	if left==right:
		return
	mid = (left+right)//2
	merge_recursion_sort(num,left,mid)   #左区间不断对半分
	merge_recursion_sort(num,mid+1,right)   #右区间不断对半分
	merge(num,left,mid,right)  #左右
	# print('merge',num,left,mid,right)
	return num

#merge([0,0][1,1])([2,2][3,3])([4,4][5,5])->[0,1][2,3][4,5]->merge([0,1][2,3])
#->[0,3][4,5]->merge([0,3][4,5])->[0,5]
def merge_iteration_sort(num):  #非递归归并排序,自底向上
	n = len(num)-1
	i = 1
	while (i<=n): #子序列的长度初始为1,每轮merge后长度乘2
		left = 0
		while (left+i<=n):  #如果后面还有子序列,就再加i个长度之后
			mid = left+i-1  #每个子区间长度为i,merge([left,left+i-1][left+i,right])
			if (mid+i)>n:  #如果right超过数组长度,就将right设置为len-1
				right = n
			else:
				right = mid + i
			merge(num,left,mid,right)
			# print('merge',num,left,mid,right)
			left = right + 1
		i *= 2
	return num

#-------------------------------------------------------------------------------------------
#堆排序,不具有稳定性,O(nlogn),其中新堆顶向下调整为logn,有n个元素
def heap_sort(num):
	n = len(num)
	build_heap(num,n-1)
	while (n>1): #堆元素还有两个或两个以上就还需要交换位置然后调整堆
		# print('顶点放最末前:',num)
		num[0],num[n-1] = num[n-1],num[0]
		# print('顶点放最末后:',num)
		heapify(num,0,n-2)
		n -= 1
	return num
	
#堆顶从0开始,和树结构类存储不一样,用数组存储堆是层次存储。父节点为i,则左孩子为2i+1,右孩子为2i+2
#最末尾的非叶子节点为(n-1)//2,其中n=堆元素个数-1
#数组建堆
def build_heap(num,n):
	i = (n-1)//2   #最末尾的非叶节点
	while (i>=0):
		heapify(num,i,n)
		i -= 1

#堆自顶向下调整
def heapify(num,i,n):
	maxx = i  #根和左右子树中的最大值的index
	if (2*i+1<=n) and (num[2*i+1]>num[maxx]):   #存在左孩子且左孩子更大
		maxx = 2*i+1
	if (2*i+2<=n) and (num[2*i+2]>num[maxx]):   #存在右孩子且右孩子更大
		maxx = 2*i+2
	if (maxx != i):   #此处根若最大没有继续往下是因为build_heap的时候是从最末尾非叶开始调
		num[maxx],num[i] = num[i],num[maxx]   #把最大放到i节点位置
		heapify(num,maxx,n)   #交换位置后,再去调整因交换而可能改变的下面的堆结构

#---------------------------------------------------------------------------------------
def heap_sort2(array):
    def heap_adjust(parent):
        child = 2 * parent + 1  # left child
        while child < len(heap):
            if child + 1 < len(heap):
                if heap[child + 1] > heap[child]:
                    child += 1  # right child
            if heap[parent] >= heap[child]:
                break
            heap[parent], heap[child] = \
                heap[child], heap[parent]
            parent, child = child, 2 * child + 1

    heap, array = array.copy(), []
    for i in range(len(heap) // 2, -1, -1):
        heap_adjust(i)
    while len(heap) != 0:
        heap[0], heap[-1] = heap[-1], heap[0]
        array.insert(0, heap.pop())
        heap_adjust(0)
    return array


#---------------------------------------------------------------------------------------
#快速排序,不具有稳定性,O(nlogn)
def quick_sort(num,left,right):
	if left>=right:
		# print('left>=right')
		return
	pivot_index = partition(num,left,right)
	# print(pivot_index)
	quick_sort(num, left, pivot_index-1)
	# print(num)
	quick_sort(num, pivot_index+1, right)
	# print(num)
	return num

def partition(num, left, right):
	pivot = num[right]  #每次选最右边的元素为基准元素
	tail = left - 1 #左边均小于基准,右边均大于基准,tail记录左边区间最后一位的下标
	for i in range(left,right): #最后一位是pivot单独处理
		if num[i]<pivot:
			tail += 1
			num[tail],num[i] = num[i],num[tail]
	num[tail+1],num[right] = num[right],num[tail+1]
	return tail+1

#-------------------------------------------------------------------------------
def quick_sort2(array):
    def recursive(begin, end):
        if begin > end:
            return
        l, r = begin, end
        pivot = array[l]
        while l < r:
            while l < r and array[r] > pivot:
                r -= 1
            while l < r and array[l] <= pivot:
                l += 1
            array[l], array[r] = array[r], array[l]
        array[l], array[begin] = pivot, array[l]
        recursive(begin, l - 1)
        recursive(r + 1, end)

    recursive(0, len(array) - 1)
    return array

#--------------------------------------------------------------------
#基数排序,具有稳定性,O(d*(n+r)),其中d为位数,n为数组元素个数,r为基数(如十进制则为10)
#首先是遍历各个位将数字放入桶中(共d*n次操作,n个数,d次遍历),再是遍历桶,得到最终排列(共r*d次操作,r个桶,d次遍历)
def radix_sort(num):
	n = len(num)
	digit = 0  #用来得到各个位的数
	bucket = [[]]  
	while len(bucket[0])!=n:   #最后最高位均为0,都跑到标号为0的桶中
		bucket = [[] for i in range(10)]   #每次循环初始就清空桶
		for i in num:
			number = i//(10**digit)%10  #获取各个位上的数
			bucket[number].append(i)
		# print('bucket',bucket)
		num.clear()          #用完num之后清空,获取新排序的num
		for i in bucket:     #此处为从小到大排列,若从大到小则为bucket[::-1]
			num += i
		# print('num',num)
		digit += 1    #下一位需要多除以一位10
	return num

#-----------------------------------------------------------------------
#希尔排序,不具有稳定性,O(n^1.3-n^2),改进版插入排序
def shell_sort2(num):  #自己写的,循环太多
	n = len(num)
	gap = n//2
	while gap>0:
		for i in range(gap):
			for ii in range(i,n,gap):   #从此处开始就是插入排序
				for jj in range(ii,0,-1):
					if num[jj]<num[jj-1]:
						num[jj],num[jj-1] = num[jj-1],num[jj]
					else:
						break
		gap = gap//2
	return num

#第一次要比的区间们gap=5:[0,5][1,6][2,7][3,8][4,9]
#第二次要比的区间们gap=2:[0,2,4,6,8][1,3,5,7,9]
def shell_sort(num):
	n = len(num)
	gap = n//2
	while gap>0:
		for i in range(gap,n):
			ii = i
			while (ii>=gap and num[ii]<num[ii-gap]):   #几个区间同时比
				num[ii],num[ii-gap] = num[ii-gap],num[ii]
				ii -= gap
		gap = gap//2
	return num




a = [4,3,2,1,0]
# a = [5,4,10,3,8,3,2,2,1]
# print(bubble_sort(a))
# print(insert_sort(a))
# print(select_sort(a))
# print(merge_recursion_sort(a,0,len(a)-1))
# print(merge_iteration_sort(a))
# print(heap_sort(a))
# print(heap_sort2(a))
# print(quick_sort(a,0,len(a)-1))
# print(quick_sort2(a))
# print(radix_sort(a))
# print(shell_sort(a))

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值