堆 续4

--------------------siwuxie095

索引堆

这里介绍一个比普通堆更加高级的数据结构:索引堆(Index Heap)

首先来看一下普通堆有什么问题 或 缺点:

将一个数组通过 Heapify 构建成一个堆,对于这个数组而言,

在堆构建前和堆构建后,它的元素位置发生了改变,正是因为

元素位置的改变,才使得它被看做是一个堆

但在构建堆的过程中,改变元素的位置将会有一些局限性:

(1)如果元素是非常复杂的结构,如:元素是字符串,那么交换这些元素

本身,消耗就是巨大的

比如说:如果每一个元素都是一篇有十万字的文章,那么对于这些巨型的字

符串,让它们来回交换会产生大量的性能上的消耗

不过这种性能上的消耗,还可以使用技术手段来解决,另一个问题可能相对

就更加致命

(2)由于元素在数组中的位置发生了改变,使得堆建成以后很难索引到它,

当难以索引到元素时,就很难去改变它


0


1


2


3


4


5


6


7


8


9


10


-


15


17


19


13


22


16


28


30


41


62

比如说:这个数组里的元素表示一个一个的系统任务,可能在初始的

时候,索引表示进程的 ID 号(从 1 开始),元素表示的是优先级

(每一个进程都表示一个系统任务)

可是当把这个表示系统任务的数组构建成堆之后,这些元素的索引和

系统任务之间就不再产生关联了

如果现在想提升原来进程的 ID 号为 6 的那个系统任务的优先级,应

该怎么做?

这个操作就变的非常难,在以前的数组中,可以用 O(1) 的性能效率

直接将这个任务提取出来,但当把它组建成堆以后,元素的位置发生

了改变,索引不到了

有人可能会说,在这个元素里再添加一个属性,来表示 ID 号就好了

这样的确可以解决,但要将整个数组遍历一遍,才能够找到相应的进

程,这个性能也是低效的

为此,就需要引入索引堆来解决这个问题

什么是索引堆?

其实非常简单,对于索引堆来说:

数据 data 和索引 index 这两部分内容分开存储,而真正表征

堆的数组是由索引 index 构建成的

以最大索引堆为例(索引从 1 开始):

数组在初始情况下:


0


1


2


3


4


5


6


7


8


9


10


index


1


2


3


4


5


6


7


8


9


10


data


15


17


19


13


22


16


28


30


41


62

当将数组构建成堆以后:


0


1


2


3


4


5


6


7


8


9


10


index


10


9


5


7


8


6


2


4


3


1


data


15


17


19


13


22


16


28


30


41


62

对于 data 域来说,它们没有发生任何改变,真正改变的是 index 域,

这个 index 数组发生了改变,形成了一个堆

这个堆怎么解读呢?堆顶的元素为 10,实际指向的是 10 这个 index

所指向的 data,也就是 62,相应的堆顶元素有左孩子和右孩子,左

孩子的元素为 9,实际指向的是 41,右孩子的元素是 7,实际指向的

是 28 … 依此类推

这样一来,可以观察到索引堆的两个好处:

(1)构建堆的过程只是索引 index 的位置发生交换

索引 index 就是一个简单的 int 型,如果数据 data 是非常复杂的结构,

只交换 int 型的索引 index,交换效率非常高

(2)如果现在想对堆中的数据进行一个操作,如:修改 index 为 7 的

data,也就是 28,修改完后,相应的还要做一些维护的操作来维持堆

的性质,那么维持堆的性质只是根据新的 data 数组来改变 index 数组

即可

简而言之:索引堆比较的是 data,交换的是 index

索引堆的优化

在修改数据 data 时是从外部传入进来一个索引来修改 data 数组,

而在维护索引堆的过程中,要先用 O(n) 的时间来遍历 index 数组

找到传入进来的索引的位置

如果要修改 n 个 data,算法的时间复杂度就是 O(n^2) 级别的

所以可以通过 反向查找 的方式来进行优化,在查找时就可以直接

用 O(1) 的时间找到传入进来的索引在 index 数组中的位置

如果要修改 n 个 data,算法的时间复杂度就是 O(n*lgn) 级别的

以最大索引堆为例(索引从 1 开始):


0


1


2


3


4


5


6


7


8


9


10


index


10


9


5


7


8


6


2


4


3


1


data


15


17


19


13


22


16


28


30


41


62


reverse


10


7


9


8


3


6


4


5


2


1

其中:reverse[i] 表示 index 为 i 的值在堆中的位置

另,有公式如下:

(1)index[i]=j

(2)reverse[j]=i

(3)index[reverse[i]]=i

(4)reverse[index[i]]=i

【made by siwuxie095】

时间: 2024-11-07 12:29:12

堆 续4的相关文章

堆 续2

---------------------siwuxie095 索引从 1 开始 程序 1:最大堆的实现 MaxHeap.h: #ifndef MAXHEAP_H #define MAXHEAP_H #include <iostream> #include <algorithm> #include <string> #include <cmath> #include <cassert> using namespace std; //最大堆:索引从

堆 续1

--------------------siwuxie095 堆的基本存储 在堆中实现的插入操作和删除操作,都是 logN 级别的, 显然,堆一定相应的是一个树形结构,最为经典的一种 堆的实现叫做 二叉堆(Binary Heap) 二叉堆对应的是二叉树,所谓二叉树,就是每一个节点, 最多有两个子节点 那么这个二叉树有什么特点呢? 分为两种情况: (一)最大堆 1)它的任何一个节点都不大于它的父节点 2)它必须是一棵完全二叉树 满足上面两个性质的二叉树,称为 最大堆 也即 1)堆中某个节点的值总是

堆 续8

----------------------siwuxie095 索引从 0 开始 程序 1:最小索引堆的实现 MinIndexHeap.h: #ifndef MININDEXHEAP_H #define MININDEXHEAP_H #include <iostream> #include <string> #include <cassert> #include <algorithm> using namespace std; //最小索引堆:索引从0开始

数据结构-各类排序算法总结[续]

各类排序算法总结 三.交换类排序[接上] 2.快速排序 快速排序是通过比较关键码.交换记录,以某个记录为界(该记录称为支点),将待排序列分成两部分.其中,一部分所有记录的关键码大于等于支点记录的关键码,另一部分所有记录的关键码小于支点记录的关键码.我们将待排序列按关键码以支点记录分成两部分的过程,称为一次划分.对各部分不断划分,直到整个序列按关键码有序. 如果每次划分对一个元素定位后,该元素的左侧子序列与右侧子序列的长度相同,则下一步将是对两个长度减半的子序列进行排序,这是最理想的情况! [算法

栈内存和堆内存的区别

总结: 1 栈:为编译器自动分配和释放,如函数参数.局部变量.临时变量等等 2 堆:为成员分配和释放,由程序员自己申请.自己释放.否则发生内存泄露.典型为使用new申请的堆内容. 除了这两部分,还有一部分是: 3 静态存储区:内存在程序编译的时候就已经分配好,这块内存在程序的整个运行期间都存在.它主要存放静态数据.全局数据和常量. 转自: 栈内存和堆内存的区别(一个笔试题的一部分)http://blog.csdn.net/richerg85/article/details/19175133 笔试

【裸单源最短路:Dijkstra算法两种版本】hdu 1874 畅通工程续

Source : hdu 1874 畅通工程续 http://acm.hdu.edu.cn/showproblem.php?pid=1874 Problem Description 某省自从实行了很多年的畅通工程计划后,终于修建了很多路.不过路多了也不好,每次要从一个城镇到另一个城镇时,都有许多种道路方案可以选择,而某些方案要比另一些方案行走的距离要短很多.这让行人很困扰. 现在,已知起点和终点,请你计算出要从起点到终点,最短需要行走多少距离. Input 本题目包含多组数据,请处理到文件结束.

浅谈数据结构-堆

在数据结构的世界中有一个叫堆的玩意,这玩意有什么用呢?无用,都去pq了 堆,其实就是一棵完全二叉树. “若设二叉树的深度为h,除第 h 层外,其它各层 (1-h-1) 的结点数都达到最大个数,第 h 层所有的结点都连续集中在最左边,这就是完全二叉树”  by 谋财害命公司 百度 ↑清真的 完全二叉树 ↓ 啊那么为什么会闲的无聊出现这种奇怪的数据结构呢? 因为我们的某些算法可能需要堆来进行优化,如dj,prim. 堆可以在O(1)的时间取出最优值,但是需要O(logn)的时间修改和O(nlogn)

1续hdu1009

上网查了资料,看了其他人写的代码,学到了一下一些: c++头文件:algorithm.h 这个头文件可以对范围内的数据做任何处理 #include<algorithm> 里面包含的函数有:   非修改性序列操作(12个)   循环 对序列中的每个元素执行某操作 for_each()   查找 在序列中找出某个值的第一次出现的位置 find()   在序列中找出符合某谓词的第一个元素 find_if()   在序列中找出一子序列的最后一次出现的位置 find_end()   在序列中找出第一次出

设计模式一(续)

本篇是接着设计模一:观察者模式的续写. 为什么要写这一篇呢: java在main函数里new出的对象都是局部变量,而用C++ 在main函数里new出来的都是 动态分配到堆区的. 那么可不可以按照java的思路来写呢. 这就是写本篇的原因了:C++完全可以按照java的思路来实现(使用引用) 附上代码: #include "stdafx.h" #include<iostream> #include<string> #include<vector> u