zoukankan      html  css  js  c++  java
  • 大小顶堆的堆排序及堆的代码实现 Marathon

    1.大顶堆/大根堆-排序

    python

    # 堆排序-大顶堆-升序排列
    
    def bigHeapify(arr: [int], start: int, end: int) -> None:
        """向下调整,堆化,父节点与子节点大的比较并交换"""
        root = start
        # left child index
        child = root*2 + 1
        while child <= end:
            # 比较左右子节点的大值
            if child+1 <= end and arr[child] < arr[child+1]:
                child += 1
            if arr[root] < arr[child]:
                # 子节点更大,交换节点与子节点的值
                arr[root], arr[child] = arr[child], arr[root]
                # 更新节点到子节点位置,继续下一轮交换
                root = child
                child = root*2 + 1
            else:
                break
    
    # 递归法
    def bigHeapify_(arr, start, end):
        pos = start
        child = pos*2 + 1
        if child < end:
            right = child + 1
            if right < end and arr[right] > arr[child]:
                child = right
            if arr[child] > arr[pos]:
                arr[pos], arr[child] = arr[child], arr[pos]
                bigHeapify_(arr, pos, end)
    
    def heapSort(arr: [int]) -> [int]:
        """大顶堆排序"""
        # 初始化非叶子节点
        first = (len(arr) >> 1) - 1
        for start in range(first, -1, -1):
            # 从下往上,从右至左对每个非叶子节点进行向下调整,循环构成大顶堆
            bigHeapify(arr, start, len(arr)-1)
        # 交换堆顶尾数据,堆数量--,重新堆化
        for end in range(len(arr)-1, 0, -1):
            # 交换堆顶堆尾数据, 构造大顶堆
            arr[0],arr[end] = arr[end], arr[0]
            # 重新调整堆,构造大顶堆
            bigHeapify(arr, 0, end-1)
        return arr
    
    
    if __name__ == "__main__":
        import random
        nums = list(range(20))
        random.shuffle(nums)
        nums = [19, 1, 11, 4, 12, 8]
        orderNums = heapSort(nums)
        print(orderNums)
    

    golang

    func maxHeapSort(nums []int) []int {
    	// max heap sort
    	end := len(nums)-1
    	// 从最后一个非叶子节点开始堆化
    	for i:=end>>1;i>=0;i-- {
    		maxHeapify(nums, i, end)
    	}
    	// 依次弹出堆顶元素,然后堆化,相当于依次把最大的放尾部
    	for i:=end;i>=0;i-- {
    		nums[0], nums[i] = nums[i], nums[0]
    		end--
    		maxHeapify(nums, 0, end)
    	}
    	return nums
    }
    
    func maxHeapify(nums []int, root, end int)  {
    	// 大顶堆堆化,堆顶值小就一直下沉
    	for {
    		// 获取做左孩子
    		child := root*2 + 1
    		// 越界跳出
    		if child > end {
    			return
    		}
    		// 比较左右孩子节点,如果右孩子大则取右孩子与root比较,否则左右孩子左孩子大, child不用++
    		if child < end && nums[child] <= nums[child+1] {
    			child++
    		}
    		// 如果父节点值大于左右孩子的大值,说明,已经堆化
    		if nums[root] > nums[child] {
    			return
    		}
    		// 交换父节点与较大的子节点
    		nums[root], nums[child] = nums[child], nums[root]
    		// 更新父节点为孩子节点,继续与孙节点比较,不断往下沉
    		root = child
    	}
    }
    

    2.小顶堆/小根堆-排序

    python

    # 小顶堆-降序排列
    
    def minHeapify(arr: [int], start: int, end: int):
        """大的节点往下沉,小的往上冒-小顶堆化,父节点与小的子节点比较并交换"""
        root = start
        child = root*2 + 1
        tmpVal = arr[start]
        while child <= end:
            if child + 1 <= end and arr[child+1] < arr[child]:
                child += 1
            if arr[child] < tmpVal:
                arr[root] = arr[child]
                root = child
                child = 2*root + 1
            else:
                arr[root] = tmpVal
                break
        else:
            arr[root] = tmpVal
    
    def minHeapSort(arr: [int], k: int) -> [int]:
        """小顶堆,升序排列, topK"""
        # 以arr切片作为heap的初始序列
        heap = arr[:k]
        # 初始化topK的小顶堆的非叶子节点
        first = (k-2) >> 1
        # 小顶堆,堆化
        for i in range(first, -1, -1):
            minHeapify(heap, i, k-1)
        # 依次遍历arr的第k+1及以后的元素,入小顶堆顶,小顶堆化
        for i in range(k, len(arr)-1):
            if arr[i] > heap[0]:
                heap[0] = arr[i]
                minHeapify(heap, 0, k-1)
        # 排序heap, 小顶堆数量--
        for i in range(k-1, -1, -1):
            heap[0], heap[i] = heap[i], heap[0]
            minHeapify(heap, 0, i-1)
        return heap
    
    def minHeapSort_(arr: [int]) -> [int]:
        """小顶堆,降序输出"""
        length = len(arr)
        # 初始化非叶子结点
        first = (length-2) >> 1
        # 遍历非叶子节点,小堆化
        for i in range(first, -1, -1):
            minHeapify(arr, i, length-1)
        # 排序数组, 小顶堆数量--
        for i in range(length-1, -1, -1):
            arr[0], arr[i] = arr[i], arr[0]
            minHeapify(arr, 0, i-1)
        return arr
    
    if __name__ == "__main__":
        nums = [0, 8, 9, 12, 13, 15, 21, 23]
        # print(minHeapSort(nums, 5)) # top5, 前5的数
        # print(minHeapSort(nums, 8)) # k == len(nums), topK即为原数组的降序排列, copy
        print(minHeapSort_(nums))
    

    golang

    func minHeapify(arr []int, root, end int)  {
    	// 小顶堆,堆化,非叶子节点大的下沉
    	for {
    		child := root*2 + 1
    		// 越界跳出
    		if child > end {
    			return
    		}
    		// root的值和子节点的小值比较
    		if child < end && arr[child] >= arr[child+1] {
    			child++
    		}
    		// root节点已经小于子节点,跳出
    		if arr[root] < arr[child] {
    			return
    		}
    		// root节点大于等于子节点,交换
    		arr[root], arr[child] = arr[child], arr[root]
    		root = child
    	}
    }
    
    func minHeapSort(arr []int) []int  {
    	// 小顶堆,降序输出
    	length := len(arr)
    	// 非叶子节点初始化, int(n/2)
    	first := (length-2) >> 1
    	// 遍历所有非叶子节点,大的下沉
    	for i:=first;i>=0;i-- {
    		minHeapify(arr, i, length-1)
    	}
    	// 依次弹出堆尾节点,交换后继续堆化
    	for i:=length-1;i>=0;i-- {
    		arr[0], arr[i] = arr[i], arr[0]
    		minHeapify(arr, 0, i-1)
    	}
    	return arr
    }
    
    func minHeapSort_(arr []int, k int) []int {
    	// 小顶堆, top K
    	heap := arr[:k]
    	// 初始化非叶子节点
    	first := (k-2) >> 1
    	// 形成一个数量为k的小顶堆
    	for i:=first;i>=0;i-- {
    		minHeapify(heap, i, k-1)
    	}
    	// 遍历后续节点,只有大于堆顶的元素,放入堆顶,堆化
    	for i:=k;i<len(arr)-1;i++ {
    		if arr[i] > heap[0] {
    			heap[0] = arr[i]
    			minHeapify(heap, 0, k-1)
    		}
    	}
    	// 依次弹出heap堆中的堆顶元素,弹出的元素就是topK
    	for i:=k-1;i>=0;i-- {
    		heap[0], heap[i] = heap[i], heap[0]
    		minHeapify(heap, 0, i-1)
    	}
    	return heap
    }
    

    3.大顶堆功能实现

    参考小顶堆的功能实现

    4.小顶堆功能实现

    实现功能:

    • 堆化,从n//2节点开始,和子节点比较,节点小则交换父节点与子节点,然后继续与孙节点比较,一直到叶子节点,总之遇到更小的子节点则下沉
    • 堆的插入,先加入到尾部,然后堆化
    • 堆的弹出或删除,弹出堆尾节点,保存堆顶节点,交换堆顶堆尾元素,重新堆化,让新堆顶元素下沉,堆化
    • 获取堆顶元素
    • 获取前k大元素,新建容器heap,获取到原数组的前k个元素切片,堆化heap,从k开始遍历arr,只要比heap[0]大,就令heap[0]等于该值,重新堆化,最后依次倒序弹出堆顶元素,每弹出一个,重新堆化(end--)

    python

    # -*- coding: utf-8 -*-
    
    
    基于小顶堆的实现
    实现功能:
    -1.push(), 堆的插入
    -2.pop(), 堆顶弹出/删除
    -3.peak(), 获取堆顶元素
    -4.kLargest(), 获取k个最大, 降序
    -5.heapify(), 建堆
    
    
    class MinHeap:
        def __init__(self, arr=None):
            self.heap = arr or []
    
        def _heapify(self, arr):
            """from the last non-leaf node, heapify"""
            if len(arr) > 0:
                end = len(arr) - 1
                first = end >> 1
                for i in range(first, -1, -1):
                    self._siftdown(arr, i, end)
    
        def _siftdown(self, arr: [int], start: int, end: int):
            """cur root sink, compare with sub_node, if cur > sub_node, swap them, repeat, until to the leaf node"""
            root = start
            child = root*2 + 1
            while child <= end:
                if child+1 <= end and arr[child] > arr[child+1]:
                    child += 1
                if arr[root] > arr[child]:
                    arr[root], arr[child] = self._swap(arr[root], arr[child])
                    root = child
                    child = root*2 + 1
                else:
                    break
    
        def _swap(self, a, b):
            a, b = b, a
            return a, b
    
        def heapify(self, arr):
            """transform arr to heap"""
            self._heapify(arr)
    
        def push(self, heap, item):
            """insert new item to heap's tail, heapify"""
            heap.append(item)
            self._heapify(heap)
    
        def pop(self, heap):
            """pop the last item of arr, and heapify itself"""
            if len(heap) == 0:
                raise Exception("IndexError, heap is empty")
            lastItem = heap.pop()
            if heap:
                peakItem = heap[0]
                heap[0] = lastItem
                self._heapify(heap)
                return peakItem
            return lastItem
    
        def peak(self, heap):
            """return peak of heap"""
            if len(heap) == 0:
                raise Exception("IndexError, heap is empty")
            return heap[0]
    
        def kLasrgest(self, arr, k):
            """arr -> heap, use minHeapSort to return k largest items"""
            if len(arr) == 0:
                return []
            if k == 1:
                result = max(arr)
                return [result]
            heap = arr[:k]
            self._heapify(heap)
            for i in range(k, len(arr)-1):
                if arr[i] > heap[0]:
                    heap[0] = arr[i]
                    self._siftdown(heap, 0, k-1)
            for i in range(k-1, -1, -1):
                heap[0], heap[i] = heap[i], heap[0]
                self._siftdown(heap, 0, i-1)
            return heap
    
    
    if __name__ == "__main__":
        import heapq
        import random
        nums = list(range(100))
        random.shuffle(nums)
        randomNums = nums[:10]
        print(randomNums)
    
        heap = MinHeap()
        # heap.heapify(randomNums)
        # heap.push(randomNums, 1200)
        # print(randomNums)
        print(heap.kLasrgest(randomNums, 5))
    

    参考:

  • 相关阅读:
    JavaScript中的ActiveXObject控制Excel的方法
    事务的作用
    SQL2005关于quotename的用法
    简易办公系统的设计与实现 文献收集
    《UML建模在办公自动化(OA)系统设计中的应用 》论文笔记(四)
    《基于 UML 与 J2EE 的高校 OA 系统的分析与设计》论文笔记(三)
    《浅谈企业办公管理OA系统的设计与实现 》论文笔记(二)
    《基于UML连锁超市OA系统公文流转的设计》论文笔记(五)
    《暗时间》读书笔记
    《无纸化办公管理系统的设计与实现》论文笔记(一)
  • 原文地址:https://www.cnblogs.com/davis12/p/15665446.html
Copyright © 2011-2022 走看看