牛客网_算法初级班_Lesson2_Part II_完全二叉树转为大根堆heapinsert_原先大根堆经过变化再回到大根堆heapify_堆排序_比较器的实现_相邻两数的最大差值--python语言

一、heapinsert

1.问题描述
数组本质就是完全二叉树,因此完全二叉树只是一种逻辑结构,实际结构其实是数组。那么给定一个数组,如何将其变成大根堆?这就是一个heapinsert过程。
方法:
父结点----(i-1)/2
左孩子-----2i+1
右孩子------2i+2

每从数组里拿出一个元素,就找该元素下标对应的父结点。比较大小,如果大于父结点,则和父结点互换,否则不动。

2.python实现

def turnBigHeap(arr):
    '''
    问题一:将一个完全二叉树(实际结构是数组)转换成大根堆
    '''
    for i in range(0,len(arr)):
        arr = heapInsert(arr, i)
    return arr

def heapInsert(arr, index):
    while arr[index] > arr[int((index-1)/2)]:
        arr[index], arr[int ((index-1)/2)] = arr[int((index-1)/2)], arr[index]
        index = int((index-1)/2)
    return arr

arr = [1,21515,3,1255]
fianlArr = turBigHeap(arr)
print(fianlArr)    

二、heapipy

1.问题描述
一个之前是大根堆的完全二叉树,因为某种变化导致第一个结点的变小了,那么要对这样一个完全二叉树重新变成大根堆,这个过程我们称之为heapipy。

2.python实现

def heapipy(arr, index, heapsize):
    '''
    heapipy过程:将一个原本是大根堆的完全二叉树重新变成大根堆的过程。
    方法:index和它的左右孩子比较,如果小于它的左右孩子那么就往下沉;否则不动
    '''
    left = 2 * index + 1
    right = 2 * index + 2 #其实可以用left + 1表示右孩子,但是这里为了方便以后复习就引入一个右孩子变量
    while left <= heapsize: #这里用heapsize是因为增加程序的鲁棒性;heapsize小于等于数组的大小(也就是表示0~heapsize区间是个大根堆);
        large = right if (arr[right] > arr[left] and right < heapsize) else left
        large = large if (arr[large] > arr[index]) else index  #python的三目运算符,说白了就是从三者中取一个最大的,然后返回对应的索引
        if large == index:
            break
        
        arr[large], arr[index] = arr[index], arr[large]
        index = large
        left = 2 * index + 1
    
    return arr

arr = [2,6,3,2,1]
fianlArr = heapipy(arr,0,4)
print(fianlArr)    

三、堆排序

1.问题描述
利用堆排序将一个数组按照从小到大的顺序排列。

2.思想

  1. 先将数组变成大根堆 (heapinsert)
  2. 大根堆堆顶(全局最大值)与最后一个数交换,然后heapsize-1(0到heapsize范围表示待排序的堆结构,heapsize以外的表示排好的),再对新的0~heapsize作heapipy过程,再次得到新的大根堆
  3. 以此反复,最后得到从小到大的数组

3.python实现

def heapSort(arr, R):
    '''
    问题三:堆排序
    step1:先将数组变成大根堆
    step2:堆顶的数与最后一个数交换;然后heapsize减1(也就是把最大的放在最后位置不再动)
    step3:对新的堆调用heapipy 将其再变成一个大根堆
    step4:以此反复,最后得到一个从小到大的数组
    '''
    for i in range(0,len(arr)):
        arr = heapInsert(arr, i)
        
    heapsize = R
    while heapsize > 0:
        
        arr[heapsize], arr[0] = arr[0], arr[heapsize]
        heapsize -= 1
        heapipy(arr, 0, heapsize)
    return arr

def heapInsert(arr, index):
    '''
    step1 函数
    '''
    while arr[index] > arr[int((index-1)/2)]:
        arr[index], arr[int ((index-1)/2)] = arr[int((index-1)/2)], arr[index]
        index = int((index-1)/2)
    return arr

def heapipy(arr, index, heapsize):
    '''
    step3 函数 
    将原先是大根堆的再次变成大根堆(改变的只有堆的第一个结点)
    '''
    left = 2 * index + 1
    right = 2 * index + 2 #其实可以用left + 1表示右孩子,但是这里为了方便以后复习就引入一个右孩子变量
    while left <= heapsize: #这里用heapsize是因为增加程序的鲁棒性;heapsize小于等于数组的大小(也就是表示0~heapsize区间是个大根堆);
        large = right if (arr[right] > arr[left] and right < heapsize) else left
        large = large if (arr[large] > arr[index]) else index  #python的三目运算符,说白了就是从三者中取一个最大的,然后返回对应的索引
        if large == index:
            break
        
        arr[large], arr[index] = arr[index], arr[large]
        index = large
        left = 2 * index + 1
    
    return arr


arr = [1000,2,6,3,2,1,888,4]
fianlArr = heapSort(arr,len(arr) - 1)
print(fianlArr)

四、比较器

比较器的实现部分在博客的上一篇文章详细的解释了实现过程,这里不再赘述。

五、求相邻两数的最大差值

1.问题描述
给定一个数组,求如果排序之后,相邻两数的最大差值,要求时间复杂度O(N),且要求不能用非基于比较的排序。

2.思想
题目要求时间复杂度O(N),我们借用桶的思想,但不用桶排序。

  1. 遍历数组,数组的最小值放在第0号桶,数组的最大值放在第N号桶
  2. 将N个数按照一定规则等分在N+1个桶中
  3. 相邻两数的最大差值一定出现在两个相邻的非空桶之间

3.python实现

import sys
def MaxGap(arr):
    '''
     问题五:求相邻两数的最大差值(要求时间复杂度O(N))
     给定一个数组,求如果排序之后,相邻两数的最大差值,要求时 间复杂度O(N),且要求不能用非基于比较的排序。
     借用桶的思想,但是没有用桶排序
     '''
    length = len(arr)
    minNum = sys.maxsize    #因为要取最小值,故这里赋值要赋值为系统最大值,这样才不会因为赋值不好导致取不出来数组最小值
    maxNum = -sys.maxsize - 1  #因为要取最大值,故这里赋值要赋值为系统最小值,这样才不会因为赋值不好导致取不出来数组最大值
    for i in range(0, len(arr)):
        minNum = min(minNum, arr[i])
        maxNum = max(maxNum, arr[i])    #17行-21行是遍历列表,取出全局最小值和最大值分别放到0号桶和N+1号桶
        
    if minNum == maxNum:
        return 0
    
    boolList = [0 for i in range(length+1)]
    maxList = [-sys.maxsize - 1 for i in range(length+1)]
    minList = [sys.maxsize for i in range(length+1)]
    
    for i in range(0, len(arr)):
        bit = bucket(arr[i], length, minNum, maxNum)
        boolList[bit] = 1
        maxList[bit] = max(maxList[bit], arr[i])
        minList[bit] = min(minList[bit], arr[i])   #上下两种写法都对
        
#        maxList[bit] = max(maxList[bit], arr[i]) if (boolList[bit]) else arr[i]
#        minList[bit] = min(minList[bit], arr[i]) if (boolList[bit]) else arr[i]
#        boolList[bit] = 1
        
    print('maxList', maxList, 'minList', minList, 'boolList',boolList)
    
    res = maxList[1] - minList[0]
#    for i in range(1, len(maxList)):
#        if boolList[i] and not boolList[i-1]:    #这种错误写法在于:并不是说一定只有一个空桶,因为可能会有很多重复的,那么就会有很多空桶;如果这么去找最近的非空桶,则仅对 只有一个空桶的情况有效
#            res = max(res, maxList[i] - minList[i-2])
#        else:
#            res = max(res, maxList[i] - minList[i-1])
    res = 0
    lastMax = maxList[0]
    for i in range(1, length + 1):
        if boolList[i]:
            res = max(res, minList[i] - lastMax)
            lastMax = maxList[i]   #lastMax代表着上一次(最近一次)的最大值,时刻更新着,作为一个临时变量存在
        
    return res


def bucket(num, length, minNum, maxNum):
    '''
    分桶函数:
    功能是把所有的数按照一定数理逻辑分到不同范围的桶内
    '''
    bid = ((num - minNum)*length)//(maxNum - minNum)   #函数目的是把当前数组中的第i个数放在对应的范围桶中
    print ('bucket', bid)
    return bid

array = [1,3,6,3,7,9,15,1,5]
print (MaxGap(array)) 

注意

  1. 导入sys库,为了获取系统最大值和系统最小值;
  2. 要注意如何实现第i个桶可以找到最近的第i-1个非空的桶,方法就是定义一个临时变量,随时随地被赋值即可。
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值