n*logn

快速排序

# 复杂度   O(nlogn)
# 从小到大
1、取一个元素p(第一个元素),使元素p归位
2、列表被p分成两部分,左边都比p小,右边都比p大
3、递归完成排序
def partition(li,left,right):
    tmp = li[left]
    while left < right:
        while left < right and tmp <= li[right]:
            right -= 1
        li[left] = li[right]    # 找到右边第一个<=tmp的
        while left < right and tmp >= li[left]:
            left += 1
        li[right]=li[left]
    li[left] = tmp

def quick_sort(li,left,right):
    if len(li)>=2:
        mid = partition(li,left,right)
        quick_sort(li,mid+1,right)
        quick_sort(li,left,mid-1)
li = [5,7,4,6,3,1,2,9,8]    
quick_sort(li,0,len(li)-1)
print(li)
装饰器装饰递归函数,装饰器每次递归都会执行        
# 涉及到的问题
# 最坏情况:当列表正好是从大到小,复杂度升级为O(n^2)
# 递归:递归深度sys.setrecursionlimit(226)    # 设置深度
View Code

 

 

堆排序

树的深度
节点的度:(分了几个叉)
树的度:(最大的节点的度)
二叉树:节点的度不超过2
满二叉树:一个二叉树,如果每一个层的结点数都达到最大值,则这个二叉树就是满二叉树
完全二叉树:叶节点只能出现在最下层和次下层,并且最下面一层的结点都集中在该层最左边的若干位置的二叉树

二叉树的存储方式:
[9,8,7,6,5,0,1,2,4,3]
 0,1,2,3,4,5,6,7,8,9
父节点->左孩子        i-->2i+1
父节点->右孩子        i-->2i+2

堆:特殊的完全二叉树
    大根堆:一棵完全二叉树,满足任意节点都比其孩子结点大
    小根堆:一棵完全二叉树,满足任意节点都比其孩子结点小
堆的向下调整顺序
    当根节点的左右子树都是堆时,可以通过一次向下的调整来将其变换成一个堆

堆排序过程:
    1、建立堆
    2、得到堆顶元素,为最大元素
    3、去掉堆顶、将堆最后一个元素放到堆顶,此时可通过一次调整重新使堆有序
    4、堆顶元素为第二大元素
    5、重复步骤3、直到堆变空

    
    def sift(data,low,high):
        # low 堆的根节点位置;high堆得最后一个节点位置
        i = low    #  最开始指向根节点
        j = 2*i+1    # j开始是左孩子
        tmp = data[low]    # 把堆顶存起来
        while j <= high:    # 只要j位置有数
            if j+1 <=high and data[j+1] >data[j]:    # 如果右孩子有并且比较大
                j+=1    # j指向右孩子
            if data[j] > tmp:
                data[i] = data[j]
                i = j     # 往下看一层
                j = 2 * i + 1
            else:            # tmp更大,把tmp放到i位置上
                data[i] = tmp        #  把tmp放到某一级领导位置上
                break    
        else:
            data[i] = tmp        # 把tmp放到叶子节点上
        
    def heap_sort(li):
        n = len(li)
        for i in range((n-2)//2,-1,-1):
            # i表示建堆的时候调整的部分的根的下标
            sift(li,i,n-1)
        # 建堆完成后
        for i in range(n-1, -1, -1):
            # i指向当前堆得最后一个元素
            li[0],li[i] = li[i],li[0]
            sift(li,0,i-1)    # i-1是新的high
    
    li = [i for i in range(1000)]
    import random
    random.shuffle(li)
    print(li)
    heap_sort(li)
    print(li)

    内置模块----------heapq        实现堆排序
        常用函数    heapify(x)        # 建堆(小根堆)
                    heappush(heap,item)
                    heappop(heap)    # 弹出最小的元素
    应用场景:
        现有n个数,设计算法得到前k大的数
        解决思路:
            排序后切片:O(nlogn)    +    k
            冒泡排序,排k次,O(kn)就出来了,比上边快
            插入排序,维护一个长度为k的列表,O(kn)
            选择排序;和冒泡类似
            
            
            堆排序:    O(nlogk)
                1、取列表前k个元素建立一个小根堆,堆顶就是目前第k大的数
                2、依次向后遍历原列表,对于列表中的元素,如果小于堆顶,则忽略该元素;
                    如果大于堆顶,则将堆顶更换为该元素,并且对堆进行一次调整
                3、遍历列表所有元素后,倒序弹出堆顶
                    def sift(data,low,high):
                        # low 堆的根节点位置;high堆得最后一个节点位置
                        i = low    #  最开始指向根节点
                        j = 2*i+1    # j开始是左孩子
                        tmp = data[low]    # 把堆顶存起来
                        while j <= high:    # 只要j位置有数
                            if j+1 <=high and data[j+1] >data[j]:    # 如果右孩子有并且比较大
                                j+=1    # j指向右孩子
                            if data[j] > tmp:
                                data[i] = data[j]
                                i = j     # 往下看一层
                                j = 2 * i + 1
                            else:            # tmp更大,把tmp放到i位置上
                                data[i] = tmp        #  把tmp放到某一级领导位置上
                                break    
                        else:
                            data[i] = tmp        # 把tmp放到叶子节点上
                    
                    def topk(li,k):
                        heap = li[0:k]
                        for i in range((k-2)//2,-1,-1):
                            sift(heap,i,k-1)
                        for i in range(k,len(li)-1):
                            if li[i] > heap[0]:
                                heap[0]=li[i]
                                sift(heap,0,k-1)
                        for i in range(k-1,-1,-1):
                            heap[0],heap[i]=heap[i],heap[0]
                            sift(heap,0,i-1)
                        return heap
                    import random
                    li = list(range(1000))
                    random.shuffle(li)
                    print(topk(li,10))
View Code

 

 

归并排序

# 空间复杂度O(n)        ltmp = []
# 时间复杂度O(nlogn)
def merge(li,low,mid,high):
    i = low 
    j = mid + 1
    ltmp = []
    while i<=mid and j<=high:
        if li[i] < li[j]:
            ltmp.append(li[i])
            i+=1
        else:
            ltmp.append(li[j])
            j+=1
    while i<=mid:
        ltmp.append(li[i])
        i+=1
    while j<=high:
        ltmp.append(li[j])
        j+=1
    li[low:high+1]=ltmp

def merge_sort(li,low,high):
    if low<high:    # 至少有2元素,递归
        mid = (low + high)//2
        merge_sort(li,low,mid)
        merge_sort(li,mid+1,high)
        merge(li,low,mid,high)

li = list(range(1000))
import random
random.shuffle(li)
print(li)
merge_sort(li,0,len(li)-1)
print(li)



稳定性:当两个元素相同时,保证相对位置不变;(挨着换的都稳定)
View Code

 

posted @ 2018-12-16 20:16  慕沁  阅读(180)  评论(0)    收藏  举报