树的应用——二叉堆实现优先队列

柔情痞子 提交于 2020-08-12 04:54:04

之前的队列(queue)都是先进先出的数据结构。然而在优先队列中,在队列里的数据都有一个优先级标签。 在优先级队列中,队列的项的逻辑顺序由他们的优先级决定。最高优先级在队列的前面,最低优先级在项的后面。

实现优先级队列的经典方法是使用成为二叉堆的数据结构,它可以在O(log(n))时间中排队和取出队列

什么是二叉堆

二叉堆(binary heap),这个堆(heap)在结构上是一棵完全二叉树,在实现上使用的数组list,采用数组的index值表示父结点及子结点。二叉堆有两个常见的变体:最小堆(其中最小的键总是在前面)和最大堆。

由于二叉堆要是一个完全二叉树,所以为了保证log(n)的时间量,必须保证树是平衡的。

如图是一个二叉堆,堆的结构类似树,实现方式由list实现。list的第一个元素是0,至于为什么要这样呢?因为树上的每一个元素都有对应的index,要满足左右结点分别是2*p & 2*p+1,如果索引index是从0开始,则不满足。

二叉堆的属性是一个很重要的东西,二叉堆的所有操作基本都基于它的属性:每个结点的父结点都比它本身要小 (最小堆)

二叉堆的构造


class BinaryHeap:
    def __init__(self):
        self.__heap_list = [0]
        self.__size = 0

二叉堆的插入

在二叉堆中插入一个项,过程是:将这个要插入的项置于二叉堆list的最后一项,由于二叉堆要保持它的属性(每个结点的父结点都比它本身要小),这个项与其父结点进行比较,小的在上,大的在下进行可能的交换,这种比较要一直持续到根结点

这种交换由于是将待插入的项从下往上交换,所以叫做go_up


    def go_up(self, index):
        while index // 2 > 0:
            if self.__heap_list[index] < self.__heap_list[index // 2]:
                self.__heap_list[index], self.__heap_list[index // 2] = self.__heap_list[index // 2], self.__heap_list[index]

            index = index // 2

    def insert(self, data):
        self.__heap_list.append(data)
        self.__size = self.__size + 1
        self.go_up(self.__size)

二叉堆的删除

由于我们研究的是最小堆,所以出队操作是移出值最小的那个结点,即根结点。

具体操作:移除根结点后,将list的最后一个项放置在根结点的位置上,然后根据二叉堆的属性进行go_down操作(即根结点的项依次向下进行比较)


    def go_down(self, index):
        while index * 2 <= self.__size:
            mc = self.find_min(index)

            if self.__heap_list[index] > self.__heap_list[mc]:
                self.__heap_list[index], self.__heap_list[mc] = self.__heap_list[mc], self.__heap_list[index]

            index = mc

    def find_min(self, index):
        if index * 2 + 1 > self.__size:
            return index * 2
        else:
            if self.__heap_list[index * 2] < self.__heap_list[index * 2 + 1]:
                return index * 2
            else:
                return index * 2 + 1

    def delete(self, data):
        ret_val = self.__heap_list[1]
        self.__heap_list[1] = self.__heap_list[self.__size]
        self.__size = self.__size - 1
        self.__heap_list.pop()
        self.go_down(1)

        return ret_val

建立二叉堆

两种想法:

1.可以将list直接进行排序,最低花费O(nlogn),得出的list肯定是个二叉堆

2.对于一个list的每一个项从左往右进行go_down操作,时间复杂度O(n)


    def delete(self, data):
        ret_val = self.__heap_list[1]
        self.__heap_list[1] = self.__heap_list[self.__size]
        self.__size = self.__size - 1
        self.__heap_list.pop()
        self.go_down(1)

        return ret_val

二叉堆完整实现


class BinaryHeap:

    def __init__(self):
        self.__heap_list = [0]
        self.__size = 0

    def go_up(self, index):
        while index // 2 > 0:
            if self.__heap_list[index] < self.__heap_list[index // 2]:
                self.__heap_list[index], self.__heap_list[index // 2] = self.__heap_list[index // 2], self.__heap_list[index]

            index = index // 2

    def insert(self, data):
        self.__heap_list.append(data)
        self.__size = self.__size + 1
        self.go_up(self.__size)

    def go_down(self, index):
        while index * 2 <= self.__size:
            mc = self.find_min(index)

            if self.__heap_list[index] > self.__heap_list[mc]:
                self.__heap_list[index], self.__heap_list[mc] = self.__heap_list[mc], self.__heap_list[index]

            index = mc

    def find_min(self, index):
        if index * 2 + 1 > self.__size:
            return index * 2
        else:
            if self.__heap_list[index * 2] < self.__heap_list[index * 2 + 1]:
                return index * 2
            else:
                return index * 2 + 1

    def delete(self, data):
        ret_val = self.__heap_list[1]
        self.__heap_list[1] = self.__heap_list[self.__size]
        self.__size = self.__size - 1
        self.__heap_list.pop()
        self.go_down(1)

        return ret_val

    def build_heap(self, alist):
        index = len(alist) // 2
        self.__size = len(alist)
        self.__heap_list = [0] + alist[:]

        while index > 0:
            self.go_down(index)
            index = index - 1

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!