几个排序算法(未完)

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下二叉树的知识去……)

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值