NB 三人组

NB  三人组

1.三人行

  快排

  堆排

  归并

快排

思路:

#快速排序法
'''
    思路分析:
        1.取一个元素p,使元素p归位。
        2.列表被p分成两部分,左边都比p小,右边都比p大,
        3.递归完成排序。
            递归:第一个归位只是归为一位,所以需要递归把列表里的每一位数都归位了才能完成排序。

        关键点:
            1.归位
            2.递归

        partition函数里的逻辑:
            1.拿去左边第一个值假如是5,做比较,现在第一个位置为空
            2.从右边开始找比5小的数,放到那个空的位置。找到后移过去,自己的位置又位空,
            3.从左边找,比5大的数,移过去空的位置,以此类推。
            4.最后叠加,重合。

            5 1 7

            _ 1 7

            1 _ 7

        时间的复杂度: n*logn
        最坏情况:n*    如:987654321
        预防:随机找一个元素,就不找第一个元素,跟第一个元素对调一下。
'''

简单代码实现:

def partition(li,left,right): #无序列表,最小值,最大值
    tmp =li[left]   #拿去左边第一个值
    while left < right:  #左边小于右边,就一直循环
        while left < right and li[right] >= tmp:
            right -= 1
        li[left] = li[right]    #把小于5的数,移到左边空的位置
        while left < right and li[left] <= tmp:
            left += 1
        li[right] = li[left]    #把大于的5的数,移到右边空的位置
    li[left] = tmp  #最后还需要归位。

    return left

def _quick_sort(data,left,right):    #data=列表,左边,右边
    if left < right:    #至少两个元素,才会递归
        mid =partition(data,left,right)
        _quick_sort(data,left,mid-1)
        _quick_sort(data,mid+1,right)

list = [2,3,4,1,5,6,8,9,7]
_quick_sort(list,0,8)
print(list)

和系统排序比较时间效率:

import random
import copy
import sys
import time


sys.setrecursionlimit(100000) #更改最大递归深度

def cal_time(func):
    def wrapper(*args, **kwargs):
        t1 = time.time()
        result = func(*args, **kwargs)
        t2 = time.time()
        print("%s running time: %s secs." % (func.__name__, t2-t1))
        return result
    return wrapper


def partition(li,left,right): #无序列表,最小值,最大值
    tmp =li[left]   #拿去左边第一个值
    while left < right:  #左边小于右边,就一直循环
        while left < right and li[right] >= tmp:
            right -= 1
        li[left] = li[right]    #把小于5的数,移到左边空的位置
        while left < right and li[left] <= tmp:
            left += 1
        li[right] = li[left]    #把大于的5的数,移到右边空的位置
    li[left] = tmp  #最后还需要归位。

    return left

def _quick_sort(data,left,right):    #data=列表,左边,右边
    if left < right:    #至少两个元素,才会递归
        mid =partition(data,left,right)
        _quick_sort(data,left,mid-1)
        _quick_sort(data,mid+1,right)

list = [2,3,4,1,5,6,8,9,7]
_quick_sort(list,0,8)
print(list)

#加壳处理
@cal_time
def quick_sort(li):
    return _quick_sort(li,0,len(li)-1)

#系统排序
@cal_time
def sys_sort(li):
    li.sort()

li = list(range(100000))
random.shuffle(li)
li1 = copy.deepcopy(li)
li2 = copy.deepcopy(li)


sys_sort(li1)   #系统排序
_quick_sort(li) #快排排序
View Code

堆排

思路:

#堆排序
'''
大根堆:一颗完全二叉树,任意节点都比其孩子节点大
小根堆:一颗完全二叉树,任意节点都比其孩子节点少

堆的性质: 
    -向下调整性质
        意思就是,左右子树都是堆,自身不是堆。
        (划分身份: 省长,市长,村站,村民)若级别构不成省长,那么就会被下调,直到形成一个堆。
        
堆排序的过程:
    1.建立堆
    2.堆顶为最大元素
    3.去掉堆顶,将堆最后一个元素放到堆顶,通过调整,让堆有序(让省长退休,找个傀儡,进行调整)
    4.堆顶又有新值为:当前最大元素。
    5.重复以上,完成排序。

详细讲解:
    1.建立堆
        一句话:农村包围城市,从叶子开始,从后往前调整。 (从村民到村长到市长到省长)
    2.后面就是挨个出数的意思。
    
代码实现分析:
    1.i指向父亲,j指向孩子。
    
    
'''

代码实现:

def sift(li,low,high):
    '''
    :param li:列表
    :param low: 堆根节点的位置
    :param high:堆最后一个节点的位置
    :return: 这是一个调整堆的过程
    '''
    i = low       #父亲的位置
    j = 2*i +1    #左孩子: 2*i +1
    tmp = li[low] #存一下省长的位置。(纪委办)
    while j <= high:  #只要有孩子就一直循环。
        if j +1 <= high and li[j+1] > li[j]: #有右孩子存在的情况下:li[j]为左孩子,li[j+1]为右孩子,若右孩子大于左孩子。
            j +=1
        if tmp < li[j]: #原省长的级别比孩子的级别小。
            li[i] = li[j]  #把孩子向上调整1级
            i = j
            j = 2*i +1
        else:
            li[i] = tmp #若纪委办的原省长级别比孩子的级别大,复职对应的省份(干部)。
            break
    else:
        li[i] =tmp   #一撸到底,回归到村民

li =[2,9,7,8,5,0,1,6,4,3]
sift(li,0,len(li)-1)
print(li)


def heap_sort(li):
    n = len(li)
    #1.建堆
    for i in range(n//2-1,-1,-1):
        sift(li,i,n-1)
    #2.挨个出数
    for j in range(n-1,-1,-1):
        li[0],li[j] = li[j],li[0]
        #堆的大小少了一个元素(j-1)
        sift(li,0,j-1)

heap_sort(li)
print(li)

# 打印如下:
# [9, 8, 7, 6, 5, 0, 1, 2, 4, 3]
# [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

归并

思路:

#归并排序法
'''
根节点:头一个节点称为:'根节点'
叶子节点: 没有孩子节点的称为:'叶子节点'
树的深度: 从根开始往下走了几层就是: 树的深度
节点的度: 不算节点上面的叉,只算下面的叉。
树的度: 树包含的节点中,最大的度。
孩子节点: 如: A分出了B   A为B的父节点   B为A的子节点
子树: 树里面包含的子树


归并排序分为:
    1.一次归并:
        把列表分为2段,这两段数组都是有序的,都有个指针,
        把两段数组的指针比较大小,小的移到孤儿院,小的指针交给下一位挑战者。以此类推
        
    2.归并是nb三人组里唯一不需要递归的。
        
'''

代码实现:

def merge(li,low,mid,high):
    '''
    :param li: 列表
    :param low: 开头的值
    :param mid: 中间划分的值
    :param high: 结尾的值
    :return:
    '''
    i =low  #第1个有序的头值
    j =mid+1 #第2个有序的头值
    tmp=[]   #孤儿院
    while i <= mid and j <= high:
        if li[i]<li[j]:
            tmp.append(li[i])
            i +=1
        else:
            tmp.append(li[j])
            j +=1
    while  i <=mid:
        tmp.append(li[i])
        i +=1
    while  j <=high:
        tmp.append(li[j])
        j +=1
    li[low:high+1] = tmp
    # print(li[low:high+1])

#递归
def _merge_sort(li,low,high):
    if low < high:  #至少两个元素
        mid = (low+high) // 2  #两边切一半
        _merge_sort(li,low,mid)  #递归左边
        _merge_sort(li,mid+1,high) #递归右边
        merge(li,low,mid,high)  #然后merge
        # print(li[low:high + 1])

def merge_sort(li):
    return _merge_sort(li,0,len(li)-1)

import random
li = list(range(10))
random.shuffle(li)
print(li)
merge_sort(li)
print(li)
原文地址:https://www.cnblogs.com/zhongbokun/p/8690990.html