常用排序算法总结

冒泡排序:

两层循环,第一层冒泡次数,第二层比较次数

def bubblesort(L):
    n = len(L)
    for i in range(n):
        for j in range(n-i-1):
            if L[j] > L[j+1]:
                L[j+1], L[j] = L[j], L[j+1]
                
   #return L
   
#测试
if __name__ == '__main__':
 
    array = [96,14,10,9,6,99,16,5,1,3,2,4,1,13,26,18,2,45,34,23,1,7,3,22,19,2]
    #array = [8,4,1, 14, 6, 2, 3, 9,5, 13, 7,1, 8,10, 12]
    print("before sort:", array)
    bubblesort(array)
 
    print("-------final -------")
    print(array)

选择排序

关键在于两层循环,第一层是选择次数,第二层是找出最小值的比较次数

def choosesort(L):
    n = len(L)
    for i in range(n):
        min_index = i
        for j in range(i,n):
            if L[min_index] > L[j]:
                min_index = j
        L[i],L[min_index] = L[min_index],L[i]
#测试
if __name__ == '__main__':
 
    array = [96,14,10,9,6,99,16,5,1,3,2,4,1,13,26,18,2,45,34,23,1,7,3,22,19,2]
    #array = [8,4,1, 14, 6, 2, 3, 9,5, 13, 7,1, 8,10, 12]
    print("before sort:", array)
    choosesort(array)
 
    print("-------final -------")
    print(array)

插入排序

第一层循环,需要插入的次数;第二层循环,需要插入数据的比较次数,一直比较到它的前一个数比它小或者它是第一个数结束;第二层循环是重点,要求索引不能超出,同时当发现前一个数小于它时要停止当前插入数字的循环(指的第二层)

def insertsort(L):
    n = len(L)
    for i in range(1,n):
        for j in range(i,0,-1):
            if L[j] > L[j-1]:
                break
            L[j-1],L[j] = L[j],L[j-1]
#测试
if __name__ == '__main__':
 
    array = [96,14,10,9,6,99,16,5,1,3,2,4,1,13,26,18,2,45,34,23,1,7,3,22,19,2]
    #array = [8,4,1, 14, 6, 2, 3, 9,5, 13, 7,1, 8,10, 12]
    print("before sort:", array)
    insertsort(array)
 
    print("-------final -------")
    print(array)

快速排序

法1:常规的算法是使用两个指针的移动来实现

对一串数字进行排序,在python中就是对列表中的数据排序
基本思路是:首先在列表中选取一个数据作为元,将比元小的数放在左边,比元大的数放在元的右边,递归的进行排序
其实思想是蛮简单的,就是通过第一遍的遍历(让left和right指针重合)来找到数组的切割点。
其实思想是蛮简单的,就是通过第一遍的遍历(让left和right指针重合)来找到数组的切割点。

第一步:首先我们从数组的left位置取出该数(20)作为基准(base)参照物。
第二步:从数组的right位置向前找,一直找到比(base)小的数,
如果找到,将此数赋给left位置(也就是将10赋给20),
此时数组为:10,40,50,10,60,
left和right指针分别为前后的10。
第三步:从数组的left位置向后找,一直找到比(base)大的数,
如果找到,将此数赋给right的位置(也就是40赋给10),
此时数组为:10,40,50,40,60,
left和right指针分别为前后的40。
第四步:重复“第二,第三“步骤,直到left和right指针重合,
最后将(base)插入到40的位置,
此时数组值为: 10,20,50,40,60,至此完成一次排序。
第五步:此时20已经潜入到数组的内部,20的左侧一组数都比20小,20的右侧作为一组数都比20大,
以20为切入点对左右两边数按照"第一,第二,第三,第四"步骤进行,最终快排大功告成。

快速排序是原址排序,基本思想是:选择一个标准元,将比它小的放在它的左边,比它大的放在它的右边;递归的进行这个操作就排序好了。难点在于如何将将比它小的放在它的左边,比它大的放在它的右边
快速排序是空间复杂度为O(1)的原址排序,原址排序:要注意开始就要出地址序列,从而方便将元素填入对应的地址;
快速排序是通过选择一个标准元,将比它小的放在左边,比它大的放在右边,递归进行操作.算法有两个关键点:1、通过双指针来指向小于标准元和大于标准元的元素;2、终止条件,大小指针对应的索引:low >= high;

#解决难点有两个思路:
#1、算法导论上的方法:找出标准元在有序情况下的位置,然后将其左边分为一个序列,都比标准元小;右边分为一个子序列,都比标准元大;
#通过两个指针来实现对选定标准元的二分
#一般情况下是直接选择最右边的作为标准元
def partition(L,left,right):
    #设定标准元
    key = L[right]
    i = left - 1
    for j in range(left,right):
        if L[j] < key:
            i +=1
            L[i],L[j] = L[j],L[i]
    L[i+1],L[right] = L[right],L[i+1]
    return i+1
def quicksort(L,left,right):
    if left < right:
        q = partition(L,left,right)
        quicksort(L,left,q-1)
        quicksort(L,q+1,right)

#2、常规的思路,通过循环来找出两个子序列,直接在递归中实现序列的二分
def quicksort(L,left,right):
    if left >= right
        return #递归终止条件子序列不存在或者大小为1
    #应用两个指针来找出子序列
    low = left 
    high = rigt
    key = L[low]
    while low < high:
        while low < high and key < L[high]:
            high -=1
        L[low] = L[high]
        while low < high and key >=L[low]
            low +=1
        L[high] = L[low]
    L[low] = key
    quicksort(L,left,low-1)
    quicksort(L,low+1,right)
        
#测试
if __name__ == '__main__':
 
    array = [96,14,10,9,6,99,16,5,1,3,2,4,1,13,26,18,2,45,34,23,1,7,3,22,19,2]
    #array = [8,4,1, 14, 6, 2, 3, 9,5, 13, 7,1, 8,10, 12]
    print("before sort:", array)
    quicksort(array,0,len(array)-1)
 
    print("-------final -------")
    print(array)  

归并排序

归并排序的关键思想是:分治。分指:将序列二分为连个序列;治指:将拍好序的序列合并层一个序列; 其空间复杂度为O(n);
其基本思想是:将序列递归的分为两个子序列,直到子序列的大小不大于1,然后合并两个排好序的子序列。

def merge(L1,L2):
    m = len(L1)
    n = len(L2)
    i = 0
    j= 0
    temp = []
    while i < m and j < n:
        if L1[i] < L2[j]:
            temp.append(L1[i])
            i +=1
        else:
            temp.append(L2[j])
            j +=1
    while( i < m):
        temp.append(L1[i])
        i +=1
    while(j < n):
        temp.append(L2[j])
        j +=1
    return temp
def mergesort(L):
    if len(L) <2:
        return L
    middle = len(L)//2
    L1 = mergesort(L[:middle])
    L2 = mergesort(L[middle:])
    temp = merge(L1,L2)
    return temp      
        
    
#测试
if __name__ == '__main__':
 
    array = [96,14,10,9,6,99,16,5,1,3,2,4,1,13,26,18,2,45,34,23,1,7,3,22,19,2]
    #array = [8,4,1, 14, 6, 2, 3, 9,5, 13, 7,1, 8,10, 12]
    print("before sort:", array)
    array=mergesort(array)
 
    print("-------final -------")
    print(array)
    
    
# 
    以上的方法空间复杂度比较高,可以实现O(n)的空间复杂度;
    通过传入一个序列大小的temp来实现:
def merge(L,left,middle,right,temp):
    i = left
    j= middle + 1 
    k = 0 # temp 的索引
    while i <= middle and j <= right:
        if L[i] < L[j]:
            temp[k] = L[i]
            k +=1
            i +=1
        else:
            temp[k]=L[j]
            k +=1
            j +=1
    while(i<=middle):
        temp[k] = L[i]
        k +=1
        i +=1
    while(j<=right):
        temp[k]=L[j]
        k +=1
        j +=1
    #将temp传回元数组array
    t = 0
    while(left<=right):
        L[left] = temp[t]
        left +=1
        t +=1
def mergesort(L,left,right,temp):
    if left < right:
        middle = (left + right)//2
        mergesort(L,left,middle,temp)
        mergesort(L,middle+1,right,temp)
        merge(L,left,middle,right,temp)   
        
    
#测试
if __name__ == '__main__':
 
    array = [96,14,10,9,6,99,16,5,1,3,2,4,1,13,26,18,2,45,34,23,1,7,3,22,19,2]
    #array = [8,4,1, 14, 6, 2, 3, 9,5, 13, 7,1, 8,10, 12]
    print("before sort:", array)
    temp = [0]*len(array)
    mergesort(array,0,len(array)-1,temp)
 
    print("-------final -------")
    print(array)  
    
##备注:为了减少空间存储,需要传入一个temp空间,每次需要的额外空间就调用这个temp,
而不用再次分配空间,同时为了在递归时及时的释放空间,需要将处理好的数据,传回原数组。
同时要在对应的原数组的索引范围之内,因此在定义函数时需要传入原数组的索引范围。
必须要传入索引范围,才能做原址排序或者O(n)空间复杂度的排序

堆排序

完全二叉树

完全二叉树是效率很高的数据结构,完全二叉树是由满二叉树而引出来的。对于深度为K的,
有n个结点的二叉树,当且仅当其每一个结点都与深度为K的满二叉树中编号从1至n的结点
一一对应时称之为完全二叉树。
完全二叉树 是 一种除了最后一层之外的其他每一层都被完全填充,并且所有结点都保持向左对齐的树,
即优先填充左子节点。

最大堆最小堆

堆分为最大堆和最小堆,其实就是完全二叉树。最大堆要求节点的元素都要不小于其孩子,
最小堆要求节点元素都不大于其左右孩子,两者对左右孩子的大小关系不做任何要求,其实很好理解。
最大堆:每个结点的值都大于或等于左右孩子结点
最小堆:每个结点的值都小于或等于左右孩子结点

基本思想

首先构建完全二叉树
然后构建最大堆
交换
维护最大堆
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值