排序算法总结
1、选择排序
选择排序的算法步骤是,从头到尾遍历数组找出最小的值,然后将其与前方未经过排序的第一个数进行交换。重复执行上述步骤直至结束
该算法需要两次循环,时间复杂度是 O(n2)
代码如下:
2、冒泡排序
该算法步骤是,循环比较当前数与下一个数的大小,将大的数放到后面小的数放到前面,这样依次交换,一直到未排序的最后一个数字。经此步骤最大的数字就会 “冒泡” 到最后面。重复持续上述步骤
该算法时间复杂度为O(n2)
代码如下:
3、插入排序
该算法步骤是,循环数组未排序部分,将未排序部分与排序部分比较,找到排序数组中小于等于当前数的位置,将当前数插入其中。
该算法时间复杂度是 O(n2)
代码如下:
def insertion_sort(arr): arr_length=len(arr) if arr_length<2: return arr for i in range (arr_length-1): pre_index=i-1 cur_index=i while pre_index>=0 and arr[cur_index]<pre_index: arr[pre_index],arr[cur_index]= arr[cur_index],arr[pre_index] cur_index=pre_index pre_index=cur_index-1 return arr
4、希尔排序
希尔排序可以认为是改进的插入排序,首先设置一个间隔值 gap (gap=3x+1 and gap<arr_length//3).通过间隔将数组分为指定的 m 个数组,依次对该 m 个数组进行插入排序,然后后递减 gap的值(gap=gap//3 ) 重复上述步骤直到gap 为0.
时间复杂度为 O(nLogn)
代码如下:
def shell_sort(arr): gap=1 arr_length=len(arr) if arr_length<2: return arr while gap<arr_length//3: gap=gap*3+1 while gap>0: for i in range(gap,arr_length): pre_index=i-gap cur_val=arr[i] while pre_index>=0 and arr[pre_index] >cur_val: arr[pre_index+gap]=arr[pre_index] pre_index-=gap arr[pre_index+gap]=cur_val gap=gap//3 return arr
5、归并排序
归并排序采用分治法,将大列表分为左右两个子列表,依次分下去,直到只剩下一个元素,然后将左右子列表合并。
时间复杂度 O(nLogn) 空间复杂度 O(n)
递归法
def merge(left,right): result=[] while left and right : if left[0] <=right[0]: result.append(left.pop(0)) else: result.append(right.pop(0)) while left: result.append(left.pop(0)) while right: result.append(right.pop(0)) return result def merge_sort(arr): arr_length=len(arr) if arr_length<2: return arr mid=arr_length//2 left=arr[:mid] right=arr[mid:] return merge(merge_sort(left),merge_sort(right))
分治法:
def merge_sort_iteration(arr): arr_length=len(arr) i=1 while i<arr_length: left_start=left_end=right_start=right_end=0 while left_start<=arr_length-i: merged=[] right_start=left_end=left_start+i right_end=left_end+i if right_end>arr_length: right_end=arr_length left=arr[left_start:left_end] right=arr[right_start:right_end] while left and right: if left[0]<=right[0]: merged.append(left.pop(0)) else: merged.append(right.pop(0)) merged.extend(left if left else right) arr[left_start:right_end]=merged left_start+=i*2 i*=2 return arr
6、快速排序
快速排序也是采用分治法,先选取一个数,默认选取第一个数,将小于该数的数字放入其左边,将大于该数的数字放入右边。在一次对左边和右边重复上述操作。
时间复杂度 O(nLogn) 空间复杂度 O(Logn)
代码如下:
def partion(arr,low,high): povit_num=arr[low] index=low+1 i=index while low<high: while low <high and arr[high]>=povit_num : high-=1 arr[low]=arr[high] while low<high and arr[low]<=povit_num: low+=1 arr[high]=arr[low] arr[low]=povit_num return low def quick_sort(arr,low=0,high=None): if high is None: high=len(arr)-1 if(low<high): pivot=partion(arr,low,high) quick_sort(arr,low,pivot-1) quick_sort(arr,pivot+1,high) return arr
7、堆排序
对于 一个序列 {a1,a2,...an} 如果 a[i] >=a[2i+1] a[i]>=a[2i+2] 则为大根堆,即完全二叉树中,非叶子节点的值均大于孩子节点的值,就叫大根堆.
根据定义可以知道,只要知道了大根堆,就可以直接获取根节点然后在动态调整。重复此步骤即可
堆排序时间复杂度O(nLogn) 空间复杂度O(1)
def heap_adjust(arr,start,end): firt_num=arr[start] index=start*2+1 while index<=end: if index<end and arr[index]<arr[index+1]: index+=1 if index<=end and arr[index]<=firt_num: break arr[start]=arr[index] start=index index=2*index+1 arr[start]=firt_num def build_max_heap(arr): arr_length=len(arr) index=arr_length//2-1 while index>=0: heap_adjust(arr,index,arr_length-1) index-=1 def heap_sort(arr): arr_length=len(arr) build_max_heap(arr) for i in range(arr_length-1,0,-1): arr[i],arr[0]=arr[0],arr[i] heap_adjust(arr,0,i-1) return arr
8、计数排序
计数排序适合数字处于较小区间内,建立一个整数数组作为计数,然后后循环该整数数组,依次将数字放回原始数组中
计数排序的时间复杂都为:O(n+k),空间复杂度为:O(k)
def counting_sort(arr,maxVal): bucketLen=maxVal+1 bucket=[0]*bucketLen arr_length=len(arr) for i in range(arr_length): bucket[arr[i]]+=1 index=0 for i in range(bucketLen): while bucket[i]>0: arr[index]=bucket[i] index+=1 bucket[i]-=1 return arr
9、桶排序
桶排序是一种优化的计数排序,需要设计一种函数关系,将给定的数据映射到一定范围内。需要做到尽可能增大桶的数量,并且保证均匀分布
桶排序的时间复杂度是O(n+k),空间复杂度是 O(n+k)
代码如下:
def bucket_sort_2(arr): arr_length=len(arr) if(arr_length<2): return arr min_num=min(arr) max_num=max(arr) bucket_range=(max_num-min_num)/arr_length if bucket_range==0: return arr buckets=[[] for _ in range(arr_length+1)] for item in arr: buckets[int((item-min_num)//bucket_range)].append(item) arr.clear() for bucket in buckets: arr.extend(sorted(bucket)) return arr
10、基数排序
基数排序实际上和桶排序类似,只不过利用了每位数字作为桶。
基数排序的时间复杂度为:O(n*K) 空间复杂度为O(n+k)
代码如下:
def radix_sort(arr): radix=0 arr_len=len(arr) if arr_len<2: return arr max_num=max(arr) max_radix=len(str(max_num)) while radix<max_radix: buckets=[[] for _ in range(10)] for item in arr: buckets[(item//10**max_radix)%10].append(item) arr.clear() for bucket in buckets: if bucket: arr.extend(sorted(bucket)) max_radix+=1 return arr