1.快速排序(基准,哨兵ij,交换)
内层while中至少有一个带=的判断!!!
空间复杂度:O(log2(n))
时间复杂度:最好的情况是O(n),最差的情况是O(n2),所以平时说的O(nlogn),为其平均时间复杂度。
基本思想:随机取一个数(最左或最右)作为基准,比基准小的放左边,比基准大的放右边,方法是和基准进行交换,然后再从左右2部分重新选择基准,直至不能分解位置。
例子:
对于序列(6,1,2,7,9,3,4,5,10,8),以6位基准,左右各设置一个哨兵i(指向6)和j(指向8)
第一次,哨兵j左移,找到一个小于6的数;哨兵i右移,找到一个大于6的数。(注,必须是 j 先移动)
i,j所指的数交换
此时序列变为(6,1,2,5,9,3,4,7,10,8),此时 i 指向5,j 指向7
第二次,j 左移,指向4停止,i 右移,指向9停止,作交换,得到新数列
(6,1,2,5,4,3,9,7,10,8)
第三次,j左移,指向3停止,i 右移,与j相应,说明探测结束,将6和j交换,得到数列
(3,1,2,5,4,6,9,7,10,8)
至此,第一轮排序完成。
然后以6位分解,数列分为两部分,对这两部分重复刚才的步骤即可。
代码:
def quick_sort(arr,start,end):
if not(start<end):
return
# 基准,哨兵
base=arr[start]
low=start
high=end
#交换过程
while(low<high):
while(low<high)and(arr[high]>base):
high -= 1
# 由于一开始的base和low是同一个值,而base已经单独保存了,所以arr[low]看成是一个“空位”,可以直接覆盖
arr[low]=arr[high]
while(low<high) and (arr[low]<=base):
low += 1
arr[high]=arr[low]
# 交换基准
arr[low]=base
#对子序列快排
quick_sort(arr,start,low-1)
quick_sort(arr,low+1,end)
if __name__=='__main__':
arr=[3,1,2,5,4,6,9,7,10,8]
quick_sort(arr,0,len(arr)-1)
print(arr)
2.冒泡排序(每次交换2个元素,每次排序都将最小的沉到底)
算法描述:
1)比较相邻元素,如果第一个比第二个大,则交换;
2)对每一对相邻元素做排序,从第一对到最后一对,然后最大值会沉底
3)对所有元素(最后一个除外),重复执行1)2),直到结束
时间复杂度:
最佳情况:T(n) = O(n)
最差情况:T(n) = O(n2)
平均情况:T(n) = O(n2)
代码:
def bubbleSort(arr):
temp=0
if len(arr)<2:
return arr
for i in range((len(arr)-1),0,-1):
for j in range(i):
if(arr[j]<arr[j+1]):
temp=arr[j]
arr[j]=arr[j+1]
arr[j+1]=temp
return arr
3.选择排序(一个个找最值放在最后)
最稳定的排序算法,不占用额外空间。
算法描述:
1)初始全部是无序区
2)每次遍历无无序区,选出最大(小)值,并与无序区最后一个元素交换。
此时,无序区长度-1,有序区长度+1
3)重复1)2)直到无序区为0,共执行n-1次无序区的遍历
时间复杂度:
恒为 O(n2)
代码:
def SSort(arr):
if len(arr)<2: return arr
temp=0
for i in range(len(arr)-1,0,-1):
ind=arr.index(min(arr[:i+1]))
print(ind,i)
temp=arr[ind]
arr[ind]=arr[i]
arr[i]=temp
return arr
arr=[1,3,5,6,7,2,4,8,0,3,5]
print(SSort(arr)
4.插入排序
从前到后,构建有序序列,类似于从无序区取一个元素,然后插入到有序序列的正确位置。
算法描述:
1) 从第一个元素开始,该元素可以认为已经被排序;
2) 取出下一个元素,在已经排序的元素序列中从后向前扫描;
3)如果该元素(已排序)大于新元素,将该元素移到下一位置;
4)重复步骤3,直到找到已排序的元素小于或者等于新元素的位置;
5) 将新元素插入到该位置后;
6) 重复步骤2~5。
时间复杂度:
最佳情况:T(n) = O(n)
最坏情况:T(n) = O(n2)
平均情况:T(n) = O(n2)
代码:
# 插入排序InsertionSort
def insertSort(arr):
if len(arr)<2: return arr
for i in range(1,len(arr)):
k=0
temp=arr[i]
while(arr[k]<arr[i]): # 找插入位置
k+=1
for j in range(i,k,-1): # 后边的全部向后移动一格,把插入位让出来
arr[j]=arr[j-1]
arr[k]=temp
return arr
arr=[1,3,5,6,7,2,4,8,0,3,5]
print(insertSort(arr))
5.希尔排序
是插入排序的改进版本,又叫缩小增量排序。与插入排序的不同在于,会优先比较距离较远的元素。
希尔排序是把记录按下表的一定增量分组,对每组使用直接插入排序算法排序;随着增量逐渐减少,每组包含的关键词越来越多,当增量减至1时,整个文件恰被分成一组,算法便终止。
增量,指的是划分子序列时,选择元素时的间隔。
算法描述:
1)选择增量序列{t1,t2,…,tk},tk=1,一般是依次取1/2
2)按照增量序列的个数k,对序列进行 k 趟排序
3)每趟排序,根据对应的增量ti,将待排序列分割成若干长度为m 的子序列,分别对各子表进行直接插入排序。仅增量因子为1 时,整个序列作为一个表来处理,表长度即为整个序列的长度。
时间复杂度:
最佳情况:T(n) = O(nlog2 n)
最坏情况:T(n) = O(nlog2 n)
平均情况:T(n) =O(nlog2n)
代码:
# 不能把子序列提取出来,插入排序,再放回去。因为放回去的过程很麻烦
# 考虑把子序列的下标提取出来,根据下标直接进行排序
def ShellSort(arr):
N=len(arr)
L1=[]
while(N>0):
L1.append(N//2)
N=N//2
#print(L1)
for k in L1: # 取增量
for i in range(k): # 增量=k,则会生成k个子序列,每个子序列的起点是i,i+1,...,i+k-1
s=i
L2=[]
while(s<len(arr)): # 根据增量k和起点s,构建子序列
L2.append(s)
s=s+k
#print(L2)
# 对子序列进行插入排序(其实就是把插入排序中的下标i用L2[i]替换(做映射)即可实现
# 直接在arr中对子序列做插入排序的操作
for j in range(1,len(L2)):
kk=0
temp=arr[L2[j]]
while(arr[L2[kk]]<arr[L2[j]]):
kk+=1
for m in range(j,kk,-1):
arr[L2[m]]=arr[L2[m-1]]
arr[L2[kk]]=temp
return arr
arr=[1,3,5,6,7,2,4,8,0,3,5]
print(ShellSort(arr))
6.归并排序(分治法,对子序列进行排序,然后归并)
归并排序需要额外内存空间。
归并排序 是建立在归并操作上的一种有效的排序算法。该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。归并排序是一种稳定的排序方法。将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表,称为2-路归并。
算法描述:
1)将给定序列分为2个子序列
2)对每个子序列采用归并排序
3)将2个排序好的子序列合并
注:两个子序列合并的方法,就是依次取值,比较大小并排序
时间复杂度:
最佳情况:T(n) = O(n)
最差情况:T(n) = O(nlogn)
平均情况:T(n) = O(nlogn)
代码:
def MergeSort(arr):
if len(arr)<2: return arr
N=len(arr)//2
print(N)
arr[:N]=MergeSort(arr[:N])
arr[N:]=MergeSort(arr[N:])
i=0
j=N
MergeArr=[]
while(i<N)and(j<len(arr)):
if(arr[i]<arr[j]):
MergeArr.append(arr[i])
i+=1
else:
MergeArr.append(arr[j])
j+=1
if i==N:
MergeArr+=arr[j:]
else:
MergeArr+=arr[:i+1] # !!特别注意这里,要写i+1,才能将arr[i]也合并进去!!!!!!!!!
print(arr[:N])
print(arr[N:])
print(MergeArr)
print()
return MergeArr
arr=[1,5,3,7,6,2,4,8,0,9]
print(MergeSort(arr))
7.堆排序
使用“堆”数据结构完成排序。
堆是一个近似完全二叉树的结构,并满足堆积性质:子节点值总小于(大于)其父节点
算法描述:
1)将待排序列构建成大根堆(R1,R2….Rn),即为初始无序区
2)将R[1]与R[n]交换,此时无序区变为(R1,R2….Rn-1),有序区是(Rn)
3)对无序区进行调整,使其为新的堆。
4)在对新的无序区重复1)2)3)
时间复杂度:
最佳情况:T(n) = O(nlogn)
最差情况:T(n) = O(nlogn)
平均情况:T(n) = O(nlogn)
代码:
(未完,先去补充一下python下二叉树的知识去……)