码迷,mamicode.com
首页 > 其他好文 > 详细

映射二叉堆

时间:2017-05-01 18:21:17      阅读:227      评论:0      收藏:0      [点我收藏+]

标签:hit   mic   namespace   简易   thml   padding   队列   方法   containe   

定义

具有映射功能的堆称为双向映射堆。堆又名二叉堆,所以也常常称其为映射二叉堆。

映射二叉堆相比普通的堆,核心功能是支持元素的快速查找,可以在O(logn) 的时间复杂度内找到索引为 id 的元素

(没有重复索引,索引并非堆中用来比较大小的关键字),并进行后续的修改或删除等操作。

映射二叉堆与普通堆的不同之处是它不存储数值,而是存储数据对应的索引。

当需要比较父子结点的大小时,我们需要对两个索引对应的关键字进行比较;当需要交换父子结点时,我们要交换堆中父子结点的索引。

在堆的外部还需要存储一个从索引到堆中元素的反向映射,用来在堆中检索指定索引的元素,进行后续的修改或删除操作。

 

性质

映射堆元素内储存的索引本身是无序的,但它存放的索引对应的关键字是有序的,并且满足堆的性质。

存储堆的数组 H[i] = j 表示 H[i] 存放的是索引为 j 的数据,反向映射 G[j]=i 表示索引为 j 的元素存储在 H[i] 中,这样就可以实现映射二叉堆的双向映射。

 

常用操作的复杂度

插入

将插入的元素放在堆尾,自底向上调整(与父亲比较)。时间复杂度是 O(logn)。

删除堆顶元素

把堆顶元素与堆尾元素对调,调整堆容量,再自顶向下调整(与儿子比较)。时间复杂度是 O(logn)。

删除

通过映射到堆的地址 G[],找到指定索引在堆中存放的位置,然后将该位置与堆尾元素对调,再自底向上调整,或者自顶向下调整。

在调整时我们不需要修改索引对应的关键字,只需分别交换 H[] 和 G[] 两个数组的值即可。时间复杂度也是 O(logn)。

 

技术分享简易实现

我们可以用 STL 中的set来近似地实现映射二叉堆的功能。set内部是通过红黑树来实现的,而非堆,不过这并不妨碍我们用set来实现堆的功能。

 

堆的存储

我们可以用如下的结构来存储一个关键字为int类型堆:

#define PII pair<int, int>
set<PII, greater<PII>> gheap;  // 定义了一个大根堆
set<PII, less<PII>> lheap;  // 定义了一个小根堆
int keys[MAX_INDEX];  // 存储每个索引对应的关键字,如果索引的范围很大,可以用 map<int, int> 来储存

其中pair<int, int>first储存关键字,second储存原始的索引(或下标)。

接下来,我们都用大根堆来举例说明其他的用法。

 

堆的插入

使用如下的方法将关键字为value、索引为id的元素插入堆中。

 

gheap.insert(make_pair(value, id));

获取及删除堆顶元素

我们可以在 O(logn) 的时间复杂度内获取对应元素的关键字和索引。

 

set<PII, greater<PII>>::iterator iter = gheap.begin();
cout << iter->first << " " << iter->second << endl;  // 第一个数是堆顶元素的关键字,第二个数是堆顶元素的索引
 

并在 O(logn) 的时间复杂度内删除堆顶元素。

gheap.erase(*(gheap.begin()));

删除指定索引

我们可以在 O(logn) 的时间复杂度内将堆中指定索引idx的元素删除。

gheap.erase(make_pair(keys[idx], idx));

技术分享

技术分享

技术分享

#include<iostream>
#include<vector>
#include<queue>
#include<algorithm>
#include<memory.h>
#include<cmath>
#include<map>
#include<set>
#define INF 0x3f3f3f3f
#define PII pair<int,int>
using namespace std;

set<PII,greater<PII> > gheap;  //大根堆  注意这里和优先队列不太一样
set<PII,less<PII> > lheap;     //小根堆
int main()
{
    int choose,k,p;
    cin>>choose;
    while(choose)
    {
        if(choose==1)
        {
            cin>>k>>p;
            gheap.insert(make_pair(p,k));
            lheap.insert(make_pair(p,k));
        }
        else if(choose==2)
        {
            PII p=*(gheap.begin());
            cout<<p.second<<endl;
            gheap.erase(*(gheap.begin()));
            lheap.erase(p);
        }
        else if(choose==3)
        {
            PII p=*(lheap.begin());
            cout<<p.second<<endl;
            lheap.erase(*(lheap.begin()));
            gheap.erase(p);
        }
        /*
        set<PII, greater<PII> >::iterator iter1 = gheap.begin();
        for(;iter1!=gheap.end();iter1++)
            cout << iter1->first << " " << iter1->second << endl;
        set<PII, less<PII> >::iterator iter2 = lheap.begin();
        for(;iter2!=lheap.end();iter2++)
            cout << iter2->first << " " << iter2->second << endl;
        */
        cin>>choose;
    }

    return 0;
}

 

 

映射二叉堆

标签:hit   mic   namespace   简易   thml   padding   队列   方法   containe   

原文地址:http://www.cnblogs.com/wangkaipeng/p/6792319.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!