数据结构——优先级队列(堆)

一、堆

0、预备知识
①使用数组保存二叉树结构,方式即将二叉树用层序遍历方式放入数组中。这种方式的主要用法就是堆的表示。
②在数组中:左孩子(left)下标 = 2 * parent + 1;
右孩子(right)下标 = 2 * parent + 2;
双亲(parent)下标 = (child - 1) / 2;

1、堆的概念
① 堆在逻辑上是一个完全二叉树。
②堆在物理实现上是保存在数组中的。
③大堆和小堆:满足任意结点的值都大于其子树中结点的值,叫做大堆,反之叫小堆。
④ ※堆的基本作用是,快速找集合中的最值

2、堆的操作——向下调整
前提: 要调整的结点左右子树必须已经是一个堆。
说明:
1.array 代表存储堆的数组
2.size 代表数组中被视为堆数据的个数
3.index 代表要调整位置的下标
4.left 代表 index 左孩子下标
5.right 代表 index 右孩子下标
6. min 代表 index 的最小值孩子的下标
7. 向下调整一次的时间复杂度为log2n

public static void shiftDown(int[] array,int size,int index){
        int left = 2 * index + 1;
        while (left < size){   //判断 index 位置有没有孩子因为堆的存储结构是数组,
                              // 所以判断是否有左孩子即判断左孩子下标是否越界,
            int min = left;
            int  right = 2 * index + 2;
            if(right < size){
                if(array[right] < array[left]){//确定 left 或 right,谁是 index 的最
                                               // 小孩子 min
                    min = right;
                }
            }
            if (array[index] <= array[min]){ //比较 array[index] 的值 和
                                            // array[min] 的值
                break;
            }
            int t = array[index];           // 否则,交换 array[index] 和 array[min] 的值
            array[index] = array[min];
            array[min] = t;
            index = min;                  //然后因为 min 位置的堆的性质可能被破坏,
                                         // 所以把 min 视作 index,向下重复以上过程
            left = 2 * index + 1;
        }
    }

3、堆的操作——建堆
使用向下调整把一个不是堆的数组变成堆。

时间复杂度为nlog2n

思路:从倒数的第一个非叶子节点的子树开始调整,一直调整到根节点的树,就可以调整成堆。

public static void createHeap(int[] array, int size) {
 	for (int i = (size - 1) / 2; i >= 0; i--) {
 	 	shiftDown(array, size, i);
 	 }
 }

4、堆的应用——优先级队列
是一种不同于先进先出队列的队列。每次从队列中取出的是有最高优先权的元素,有两个操作 入队列出队列(出优先级最高的) 常使用堆来构建。
① 入队(大堆):

过程: 以大堆为例
1. 首先按尾插方式放入数组
2. 比较其和其双亲的值的大小,如果双亲的值大,则满足堆的性质, 插入结束
3. 否则,交换其和双亲位置的值,重新进行 2、3 步骤
4. 直到根结点

public static void shiftUp(int[] array, int index) { 
	while (index > 0) { //3.直到根结点
		int parent = (index - 1) / 2; 
		if (array[parent] >= array[index]) { 
			break; //1.比较其和其双亲的值的大小,如果双亲的值大,则满足堆的性质,	插入结束
		}
		int t = array[parent];//2.否则,交换其和双亲位置的值,重新进行 2、3 步骤
		 array[parent] = array[index]; 
		 array[index] = t;
		 index = parent; 
	} 
}

②出队(优先级最高的)
过程: 为了防止破坏堆的结构,删除时并不是直接将堆顶元素删除,而是用数组的最后一个元素替换堆顶元素,然后通过向下调整方式重新调整成堆。

5、TopK问题
①问题: 从大量的数据中找出K个最大(最小)的值。
②思路: 将待找的元素序列的前K个元素建立一个小堆,每次和堆顶元素进行比较。如果数组当中的当前元素,大于堆顶元素,进行替换,并向下调整。先出堆顶元素,然后进行入堆。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值