**
排序算法(python)
冒泡排序
思想:从第一个数开始,与后面一个数进行两两比较交换,直到最后最大的数被交换到最后一个位置,冒泡排序是一个稳定的排序算法;
时间复杂度:需要从头到尾遍历n的平方次,所以冒泡排序的时间复杂度是
O(n2),但是它的最优的时间复杂度是O(n),当一个数组完全有序时,设置一个flag的指针,当flag为false时,就可以直接返回,不用遍历后面的;
空间复杂度:O(1)
稳定性:稳定
一般的冒泡排序的代码:
def bubble_sort(arr):
n=len(arr)
for i in range(0,n-1):
for j in range(0,n-i-1):
if arr[j]>arr[j+1]:
arr[j+1],arr[j]=arr[j],arr[j+1]
return arr
时间复杂度为O(n)的冒泡排序的代码:
def bubble_sort(arr):
n=len(arr)
for i in range(0,n-1):
flag=False
for j in range(0,n-i-1):
if arr[j]>arr[j+1]:
flag=True
arr[j+1],arr[j]=arr[j],arr[j+1]
if flag==False:
return
return arr
选择排序
思想:在一堆数中选择最小的一个数放在第一个位置,然后再在剩下的数中选择第二小的数放在第二个位置,这样依次遍历下去
时间复杂度:O(n2),最优的时间复杂度和最优的时间复杂度都是O(n2),不管是有多少个数,都是n个数进行n次比较
空间复杂度:只用到有限的几个变量,所以空间复杂度是O(1)
稳定性:不稳定,因为是第一个数与后面的数进行交换,会改变数之间的相对位置,所以是不稳定
代码:
def select_sort(arr):
n=len(arr)
for i in range(0,n-1):
min_index=i
for j in range(i,n):
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
插入排序
思想:从第二个数开始,插入到前面已经排好序的数,要插入的前i个数已经排好序了
时间复杂度:时间复杂度为O(n2),因为要遍历后面的n个数,与前面已经排好序的n个数进行比较,然后选择插入一个位置;最好的时间复杂度是O(n),当数组是完全有序的时候,不用与前面进行比较,所以最好情况下的时间复杂度是O(n)
空间复杂度:O(1)
稳定性:稳定的(可以决定换不换位置)
代码块:
def insert_sort(arr):
n=len(arr)
for i in range(1,n):
pre_index=i-1
cur=arr[i]
while pre_index>=0 and arr[pre_index]>cur:
arr[pre_index+1]=arr[pre_index]
pre_index-=1
arr[pre_index+1]=cur
return arr
归并排序
思想:先左边一个有序排列,再右边一个有序排列,然后再把这两部分合并,利用一个递归结构把列表中的数一分为2,然后再进行合并
时间复杂度:O(nlogn)
空间复杂度:O(n)
稳定性:稳定的,归并排序是具有稳定性的,在归并的过程中是稳定的
代码:
def merge_sort(arr):
if len(arr)==1:
return arr
n=len(arr)
mid=n//2
left=merge_sort(arr[:mid])
right=merge_sort(arr[mid:])
merge(left,right)
return arr
def merge(left,right):
result=[]
if left[0]<=right[0]:
result.append(left[0])
else:
result.append(right[0])
result+=left
result+right
return result
快速排序
思想:从一个序列中随机选择一个数作为基准(一般选择最后一个数),然后再遍历这个数组,比这个数小的放在左边,比这个数大的放在右边,然后再进行左右两边序列的递归操作
时间复杂度:遍历一遍序列,时间复杂度是n,然后再对左右两边进行递归操作,所以时间复杂度是logn,所以整个快排总的时间复杂度是O(nlogn)
空间复杂度:只用到了有限的几个变量,所以空间复杂度是O(1)
稳定性:快排有进行数字的交换,所以是不稳定的
代码:
def quick_sort(arr,low,high):
if low<high:
p=pat(arr,low,high)
quick_sort(arr,low,p-1)
quick_sort(arr,p+1,high)
return arr
def pat(arr,low,high):
pivot=arr[high]
i=low-1
for j in range(low,high):
if arr[j]<=pivot:
i+=1
arr[i],arr[j]=arr[j],arr[i]
arr[i+1],pivot=pivot,arr[i+1]
return i+1
希尔排序
思想:希尔排序也称缩小增量排序,是插入排序的一种优化,将一个序列按照若干个间隔分成若干个子序列,然后再对子序列进行插入排序,这个是在序列基本有序的情况下进行插入排序的,所以希尔排序的效率比直接插入排序要高一些
时间复杂度:希尔排序的时间复杂度的下限为O(nlogn),但是希尔排序没有快排快,因此对中等规模的数据表现良好,但对于规模非常大的数据,希尔排序不是最优的选择
空间复杂度:只用到了有限的几个变量,因此希尔排序的空间复杂度为O(1)
稳定性:有进行数据的交换,所以希尔排序是不稳定的
def shell_sort(arr):
n=len(arr)
gap=n//2
while gap>=1:
for j in range(gap,n):
tempindex=j
while tempindex>=gap and arr[tempindex-gap]>arr[tempindex]:
arr[tempindex-gap],arr[tempindex]=arr[tempindex],arr[tempindex-gap]
tempindex-=gap
gap=gap//2
return arr
堆排序
思想:先建立一个大顶堆,然后再把第一个数与最后一个数进行交换,再建立一个大顶堆
时间复杂度:建立一个大顶堆的时间复杂度是O(n),调整大顶堆的时间复杂度是O(logn),需要遍历整个序列,所以整个的时间复杂度是O(nlogn)
空间复杂度:只用到了少数的几个变量,所以空间复杂度为O(1)
稳定性:堆排序有进行数的交换,所以堆排序是不稳定的
代码:
def heapify(arr,n,i):
if i>n:
return
c1=2*i+1
c2=2*i+2
max_index=i
if c1<n and arr[c1]>arr[max_index]:
max_index=c1
if c2<n and arr[c2]>arr[max_index]:
max_index=c2
if max_index!=i:
arr[max_index],arr[i]=arr[i],arr[max_index]
heapify(arr,n,max_index)
return arr
def build_sort(arr):
n=len(arr)
last_node=n-1
parent_node=last_node//2
for i in range(parent_node,-1,-1):
heapify(arr,n,i)
return arr
def heap_sort(arr):
n=len(arr)
build_sort(arr)
for i in range(n-1,-1,-1):
arr[0],arr[i]=arr[i],arr[0]
heapify(arr,i,0)
return arr
桶排序
思想:桶排序是先找出一个最大元素和一个最小元素,假设这两个元素之间的间隔为k,初始化一个有k个元素的桶,将桶里面都初始化为0,然后再遍历这个序列,最终以排序的形式进行输出
时间复杂度:O(n)
空间复杂度:O(n),桶排序是一种以空间换时间的一种排序
稳定性:桶排序算法是一种稳定的算法
代码:
def bucket_sort(arr):
n=len(arr)
max_number=max(arr)
bucket=[0]*(max_number+1)
for i in arr:
bucket[i]+=1
sort_nums=[]
for j in range(len(bucket)):
if bucket[j]!=0:
for y in range(bucket[j]):
sort_nums.append(j)
return sort_nums