使用STL来模拟Treap的功能

问题描述

我们知道,Treap可以完成节点的动态插入、删除、查询,其每个操作的时间复杂度是O(log n),因为其实现较红黑树更为简单,因此常常用于某些场合,以替换红黑树的实现。

Treap的每个节点维护了key, priority。

struct Node {
    int key;
    int priority;
    Node (int k, int p): key(k), priority(p) {}
}

key是作为BST的键值,用于支持快速的插入、删除和查询操作,而priority则是用于维护最小堆的性质。即从key层面上看,整个树是一个BST;从priority层面上看,则整个树是一个最小堆。

关于priority为何物?每当插入一个key值时,也会为它对应生成一个随机的priority。这个节点的插入操作分为两步:

  • 按BST树的性质插入节点(key, priority)
  • 插入完成后,按priority的值去zig-zap,以调整树的平衡性,这样最终生成的树是趋于平衡二叉树的

Treap除去支持insert, find, remove等,还支持快速地查找到最小的priority。于是我们又可以通过STL中的map,set等模拟之。

问题要求

  • insert(string key, int value),插入一个pair,时间复杂度要求为 O(log n)
  • lookup(string key), 查询,时间复杂度要求为O(log n)
  • remove(string key),删除一个节点,时间复杂度要求为O(log n)
  • max(),获得当前所有节点中最大的value,时间复杂度要求为O(1)

问题分析

显然,insert, find, remove 等方法就可以用BST搞定,比如直接使用STL的map(时间复杂度为O(log n),而STL的unordered_map时间复杂度为O(1)),但是max如何搞定呢?STL的map不支持对所有的value进行维护,比如取得最大值。

那么可以使用两个map+set来搞定,思路如下:

  • unordered_map<string, int> mp,用于O(1)的时间来对key进行查找
  • map<int, unordered_set<string> > mp_reverse,mp_reverse用O(log n)的时间可以取得当前value的最大值,最小值,并且针对每个value,都可以查询到对应的所有的key值。

代码如下:

#include <iostream>
#include <map>
#include <map>
#include <unordered_map>
#include <unordered_set>
#include <cstdio>
#include <cstdlib>

using namespace std;

// using map and set to simulate a Treap

class Solution {
public:
    unordered_map<string, int> mp;
    map<int, unordered_set<string> > mp_reverse;

    void test() {
        insert("a", 3);
        insert("b", 6);
        cout << "a: " << lookup("a") << endl;
        cout << "max: " << max() << endl;
        insert("a", 7);
        cout << "a: " << lookup("a") << endl;
        cout << "max: " << max() << endl;
        remove("a");
        cout << "max: " << max() << endl;
    }

    // insert a pair(key, value), if the key exists, then override the previous entry
    // time complexity: O(log n)
    void insert(string key, int value) {
        // first check whether key exists
        int pre_value = lookup(key);
        if (pre_value != -1) remove(key);
        // first step of inserting
        mp.insert(make_pair(key, value));
        // second step of inserting
        map<int, unordered_set<string> >::iterator iter = mp_reverse.find(value);
        if (iter == mp_reverse.end()) {
            unordered_set<string> s;
            s.insert(key);
            mp_reverse.insert(make_pair(value, s));
        } else {
            iter->second.insert(key);
        }
    }

    // remove a pair(key, value)
    // time complexity: O(log n)
    void remove(string key) {
        int value;
        if ((value=lookup(key)) == -1) return;
        mp.erase(key);  // first step of erasing
        map<int, unordered_set<string> >::iterator iter = mp_reverse.find(value);
        if (iter != mp_reverse.end()) iter->second.erase(key); // second step of erasing
        if (iter->second.empty()) mp_reverse.erase(value); // third step of eraing
    }

    // lookup an entry with key
    // time complexity: O(log n)
    int lookup(string key) {
        unordered_map<string, int>::iterator iter = mp.find(key);
        if (iter == mp.end()) return -1; // cannot find the key
        return iter->second;
    }

    // return the maximun value
    // time complexity: O(1)
    string max() {
        map<int, unordered_set<string> >::iterator iter = mp_reverse.end();
        iter--;
        if (!iter->second.empty())
            return *(iter->second.begin());
    }

};

int main() {
    Solution solution;
    solution.test();
}
// output
a: 3
max: b
a: 7
max: a
max: b
时间: 2024-10-29 19:13:50

使用STL来模拟Treap的功能的相关文章

ListView模拟微信好友功能

ListView模拟微信好友功能 效果图: 分析: 1.创建listView 2.创建数据 3.创建适配器 将数据放到呈现数据的容器里面. 将这个容器(带数据)连接适配器. 4.ListView设置适配器 代码: 1 package fry; 2 3 import java.util.ArrayList; 4 import java.util.List; 5 6 import com.example.weChatFriends.R; 7 8 import android.app.Activity

hdu 4941 STL HASH 模拟

http://acm.hdu.edu.cn/showproblem.php?pid=4941 比赛的时候现学的map的find...以前都是用下标做的,但是map用下标查询的话,如果查询的元素不存在,会插入一个新的元素. 贴一个map查找元素找到和找不到的模板 map<pair<int,int>,int>::iterator it=poshash.find(tmppos);//pair<int,int>poshash; int pp; if(it == poshash.

Python 操作文件模拟SQL语句功能

Python操作文件模拟SQL语句功能 一.需求 当然此表你在文件存储时可以这样表示 1,Alex Li,22,13651054608,IT,2013-04-01 现需要对这个员工信息文件,实现增删改查操作 1. 可进行模糊查询,语法至少支持下面3种: 1. select name,age from staff_table where age > 22 2. select * from staff_table where dept = "IT" 3. select * from

标准IO的简单应用,动静态库,读取系统时间并打印,模拟ls -l功能

2015.2.27星期五,小雨 标准IO实现的复制功能: #include <stdio.h>#include <errno.h> #define N 64 int main(int argc, char *argv[]){ int n; char buf[N]; FILE *fps, *fpd; if(argc < 3) { printf("usage : %s <src_file><dst_file>\n",argv[0]);

js模拟实现继承功能

<!DOCTYPE html> <html> <head lang="en"> <meta charset="UTF-8"> <title></title> <script type="text/javascript"> //js中模拟继承效果的案例 //函数对象中的三种“继承” 方式 汇总 //方式一 //****************************

Android模拟键盘输入功能的实现

在做关于输入框的操作指引时,用动态的输入效果比用静态的图片指示效果会好很多,本文结合最近需要实现的一个搜索输入操作指引的功能介绍一下android平台模拟键盘输入的实现. 在android上不知道怎么录制gif的动态图,直接截图看一下效果吧,具体看demo就行啦. 实现起来很简单,开一个线程,通过sleep控制输入字符的间隔时间,封装一个模拟键盘输入的方法,最终代码是这样子的: public class TypeInActivity extends BaseActivity { @Overrid

模拟ATM机功能(C语言)

/* fuction:模拟ATM机存取功能 date:2014/8/20 by:zhouhaiou*/ #include <stdio.h>#include <string.h>#include <math.h>int money=100000; void query();void transf(); void welcome()//欢迎界面 { printf("\t\t*********************************************

洛谷 P1739 表达式括号匹配【STL/stack/模拟】

题目描述 假设一个表达式有英文字母(小写).运算符(+,-,*,/)和左右小(圆)括号构成,以"@"作为表达式的结束符.请编写一个程序检查表达式中的左右圆括号是否匹配,若匹配,则返回"YES":否则返回"NO".表达式长度小于255,左圆括号少于20个. 输入输出格式 输入格式: 一行:表达式 输出格式: 一行:"YES" 或"NO" 输入输出样例 输入样例#1: 2*(x+y)/(1-x)@ 输出样例#1

&lt;泛&gt; STL - stack 模拟实现

今天,看C++Template的时候看到那人写了一个Stack,于是乎,手痒,自己也写了一个,在拜读了STD文件和C++模板元编程某些小节之后,你们就看到了这篇代码. 经过上述一番经历之后,我重新写了myVector,使之更完善,更加服务于顶层结构,如:myStack myVector实现 栈没什么写的,大部分精力都放在了重新构建底层容器上,STL里面的功能函数基本都实现了,除了std的各种相关的构造函数实在整不来那么多 测试效果: #include "E:\数据结构\myStack.h&quo