zoukankan      html  css  js  c++  java
  • 排序NB三人组

    排序NB三人组

    快速排序,堆排序,归并排序

    1、快速排序

    方法其实很简单:分别从初始序列“6  1  2 7  9  3  4  5 10  8”两端开始“探测”。先从右往左找一个小于6的数,再从左往右找一个大于6的数,然后交换他们。

    这里可以用两个变量i和j,分别指向序列最左边和最右边。我们为这两个变量起个好听的名字“哨兵i”和“哨兵j”。刚开始的时候让哨兵i指向序列的最左边(即i=1)

    指向数字6。让哨兵j指向序列的最右边(即j=10),指向数字8。

    首先哨兵j开始出动。因为此处设置的基准数是最左边的数,所以需要让哨兵j先出动,这一点非常重要(请自己想一想为什么)。

    哨兵j一步一步地向左挪动(即j--),直到找到一个小于6的数停下来。接下来哨兵i再一步一步向右挪动(即i++),直到找到一个数大于6的数停下来。

    最后哨兵j停在了数字5面前,哨兵i停在了数字7面前。

    再继续:

    第二次交换结束,“探测”继续。哨兵j继续向左挪动,他发现了3(比基准数6要小,满足要求)之后又停了下来。

    哨兵i继续向右移动,糟啦!此时哨兵i和哨兵j相遇了,哨兵i和哨兵j都走到3面前。说明此时“探测”结束。我们将基准数6和3进行交换。交换之后的序列如下。

    到此第一轮“探测”真正结束。此时以基准数6为分界点,6左边的数都小于等于6,6右边的数都大于等于6。回顾一下刚才的过程,

    其实哨兵j的使命就是要找小于基准数的数,而哨兵i的使命就是要找大于基准数的数,直到i和j碰头为止。

     OK,解释完毕。现在基准数6已经归位,它正好处在序列的第6位。此时我们已经将原来的序列,以6为分界点拆分成了两个序列,左边的序列是“3  1 2  5  4”,右边的序列是“9  7  10  8”。接下来还需要分别处理这两个序列。因为6左边和右边的序列目前都还是很混乱的。不过不要紧,我们已经掌握了方法,接下来只要模拟刚才的方法分别处理6左边和右边的序列即可。现在先来处理6左边的序列现吧。

     

    left right

    取一个数,从左边找一个数比该数大,从右边找比该

    def partition(li,left,right):
        tmp = li[left]
        while left<right:
            while left<right and li[right]>= tmp:# 从右边找比tmp小的数
                right -=1 # 往左走一步
            li[left] = li[right] # 把右边的值写到左边
            print(li,'right')
            while left<right and li[left] <= tmp:# 从右边找比tmp大的数
                left += 1
            li[right] = li[left] # 把左边的值写到右边空位上
            print(li,'left')
        li[left] = tmp # tmp 归位
        # 此时数组以 tmp为分界线,左边比tmp小,右边的比tmp大
        return left
    def quick_sort(li,left,right):
        if left<right:
            mid = partition(li,left,right)
            quick_sort(li,left,mid-1)
            quick_sort(li,mid+1,right)
    li = [5,7,4,6,3,1,2,9,8]
    quick_sort(li,0,len(li)-1)
    print(li)

     

    总共有logn层,每一层复杂度为n------>  时间复杂度O(nlogn)

     2、堆排序

    序比快速排序的时

    A是根节点

    叶子节点 是没有子节点的点  b c h i p q k l m n 

    树的深度,最深有几层,如图有4层

    树的度 就是这个树最多的节点数

     什么是二叉树

    满二叉树和完全二叉树

    二叉树的存储方式:

     

    9编号为0  左孩子节点8的编号为1;右孩子7的编号为2

     大根堆和小根堆

    堆的概念:

    堆是一个完全二叉树

    堆中每一个节点的值都必须大于等于(或小于等于)其子树中每一个节点的值

    ---------------

    其实我们的堆排序算法就是抓住了堆的这一特点,每次都取堆顶的元素,将其放在序列最后面,然后将剩余的元素重新调整为最大堆,依次类推,最终得到排序的序列。

    给定一个列表array=[16,7,3,20,17,8],对其进行堆排序。

    首先根据该数组元素构建一个完全二叉树,得到

    每次所有堆的最后一个放堆顶

     i  j hight都是索引值

    堆建完之后堆顶是最大的元素

    # 堆排序
    def sift(li, low, high):
        """
        :param li: 列表
        :param low: 堆的根节点位置
        :param high: 堆的最后一个元素的位置
        :return:
        """
        i = low # i最开始指向根节点     父节点
        j = 2 * i + 1 # j开始是左孩子
        tmp = li[low] # 把堆顶存起来
        while j <= high: # 只要j位置有数
            if j + 1 <= high and li[j+1] > li[j]: # 如果右孩子有并且比较大
                j = j + 1  # j指向右孩子
            if li[j] > tmp: # 如果左孩子或者右孩子大于tmp
                li[i] = li[j] # 大的放堆顶
                i = j           # 往下看一层 变成新的父节点
                j = 2 * i + 1   # 新的子节点
            else:       # tmp更大,把tmp放到i的位置上
                li[i] = tmp     # 把tmp放到某一级领导位置上
                break
        else:
            li[i] = tmp  # 把tmp放到叶子节点上
    
    def heap_sort(li):
        n = len(li)
        # //除法不管操作数为何种数值类型,总是会舍去小数部分,返回数字序列中比真正的商小的最接近的数字。
        # range(start, stop[, step])
        # 比如 range(5,-1,-1)  [5,4,3,2,1,0] 倒叙
    
        # 创建堆
        for i in range((n-2)//2, -1, -1):
            # i表示建堆的时候调整的部分的根的下标
            print(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(100)]
    import random
    
    random.shuffle(li)  # 打乱顺序
    print(li)
    
    heap_sort(li)
    print(li)

     -----------

    堆排序参考

    -------------------

     堆排序--python内置模块

    import heapq

    # python 堆排序内置模块
    import heapq  # q-->queue优先队列
    import random
    li = list(range(100))
    random.shuffle(li)
    print(li)
    heapq.heapify(li) # 建堆
    n = len(li)
    for i in range(n):
        print(heapq.heappop(li),end=',')

    堆排序-----topk问题 

    问题描述:有 N (N>1000000)个数,求出其中的前K个最小的数(又被称作topK问题)。

    思路3:大根堆

    大根堆维护一个大小为K的数组,目前该大根堆中的元素是排名前K的数,其中根是最大的数。此后,每次从原数组中取一个元素与根进行比较,如小于根的元素,则将根元素替换并进行堆调整(下沉),即保证大根堆中的元素仍然是排名前K的数,且根元素仍然最大;否则不予处理,取下一个数组元素继续该过程。该算法的时间复杂度是O(N*logK),一般来说企业中都采用该策略处理topK问题,因为该算法不需要一次将原数组中的内容全部加载到内存中,而这正是海量数据处理必然会面临的一个关卡。如果能写出代码,offer基本搞定。

    # 堆排序
    def sift(li, low, high):
        """
        :param li: 列表
        :param low: 堆的根节点位置
        :param high: 堆的最后一个元素的位置
        :return:
        """
        i = low # i最开始指向根节点
        j = 2 * i + 1 # j开始是左孩子
        tmp = li[low] # 把堆顶存起来
        while j <= high: # 只要j位置有数
            if j + 1 <= high and li[j+1] < li[j]: # 如果右孩子有并且比较大
                j = j + 1  # j指向右孩子
            if li[j] < tmp: # 如果左孩子或者右孩子大于tmp
                li[i] = li[j] # 大的放堆顶
                i = j           # 往下看一层
                j = 2 * i + 1
            else:       # tmp更大,把tmp放到i的位置上
                li[i] = tmp     # 把tmp放到某一级领导位置上
                break
        else:
            li[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)
        # 1.建堆
        for i in range(k,len(li)-1):
            if li[i]>heap[0]:
                heap[0] = li[i]
                sift(heap,0,k-1)
        # 2.遍历
        for i in range(k-1,-1,-1):
            heap[0],heap[i] = heap[i],heap[0]
            sift(heap,0,i-1)
    
        # 3.出数
        return heap
    
    li = [i for i in range(100)]
    import random
    
    random.shuffle(li)  # 打乱顺序
    # 取出前10个数
    print(topk(li,10))

    还有没有更简单的算法呢?答案是肯定的。

    思路4:快速排序

    利用快速排序的分划函数找到分划位置K,则其前面的内容即为所求。该算法是一种非常有效的处理方式,时间复杂度是O(N)(证明可以参考算法导论书籍)。对于能一次加载到内存中的数组,该策略非常优秀。如果能完整写出代码,那么相信面试官会对你刮目相看的。

    归并排序

    时间复杂度:O(nlogn)

    空间复杂度:O(n)

    假设两段有序的情况下

    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 执行完,肯定有一部分没数了
        while i<=mid:
            ltmp.append(li[i])
            i+=1
        while j<=high:
            ltmp.append(li[j])
            j+=1
        li[low:high+1]=ltmp
    
    # 归并操作,前提是列表分两段,两段分别有序
    li = [2,4,5,7,1,3,6,8]
    merge(li,0,3,7)
    print(li)

    首先弄清楚递归的概念

    # 递归的数据结构式栈先进后出
    def calc(n):
        v = int(n/2)
        print(v)
        if v > 0:
            calc(v)
        print(n)
    
    calc(10)
    
    5
    2
    1
    0
    1
    2
    5
    10

    当遇到递归结束即然后执行递归后面的程序

    print((0+1)//2) # 0
    print((1+2)//2) # 1

    归并排序代码:

    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 执行完,肯定有一部分没数了
        while i<=mid:
            ltmp.append(li[i])
            i+=1
        while j<=high:
            ltmp.append(li[j])
            j+=1
        li[low:high+1]=ltmp
        print(li)
    
    
    def merge_sort(li,low,high):
        if low<high:#至少有两个元素
            mid = (low+high)//2
            # 例如len(li)==10
            # mid==5
            # 第一个merge_sort(li,0,5)
            merge_sort(li,low,mid)     # 左边排好序
    
    
            # 第二个merge_sort(li,6,10)
            merge_sort(li,mid+1,high)  # 右边排好序
            #print(li[low:high + 1])
            # 当遇到low=high递归结束然后执行递归后面的程序
    
            print(low, mid, high)
            merge(li,low,mid,high)     # 做归并处理
    
    
    li = list(range(10))
    import random
    random.shuffle(li)
    print(li,'初始值')
    merge_sort(li,0,len(li)-1)
    print(li,'最终值')

    NB三人组小结

  • 相关阅读:
    Notification的使用
    Spring面向切面之AOP深入探讨
    使用注解配置Spring框架自动代理通知
    回顾Spring框架
    Spring利器之包扫描器
    Spring 核心概念以及入门教程
    Struts 2之动态方法调用,不会的赶紧来
    Struts2之过滤器和拦截器的区别
    Struts 2开讲了!!!
    Mybatis开篇以及配置教程
  • 原文地址:https://www.cnblogs.com/foremostxl/p/10224964.html
Copyright © 2011-2022 走看看