笛卡尔树

笛卡尔树是一种同时满足二叉搜索树和堆的性质的数据结构。 可在一个数组上构造出来(时间复杂度可以达到O(n))。树中节点有几个属性, key(节点元素的大小)、index(节点在原数组中的索引)、left(左子节点)、right(右子节点)、parent(父节点)。

性质

  1. 树中的元素满足二叉搜索树性质,要求按照中序遍历得到的序列为原数组序列
  2. 树中节点满足堆性质,节点的key值要大于其左右子节点的key值

构造

要求在给定的数组的基础上构造一棵笛卡尔树,这可以在O(n)的时间内完成。 其具体思路为:

当按照index从1到n(或者从0到n-1)的顺序将数组中的每个元素插入到笛卡尔树中时,当前要被插入的元素的index值最大,因此根据二叉搜索的性质需要沿着当前已经完成的笛卡尔树的根的右子树链搜索。 
    由于笛卡尔树要满足堆的性质(以最大堆为例),父节点的key值要大于子节点的key值,所以沿着树根的右子树链往下走,直到搜索到的节点的key值小于等于当前要插入节点的key值。 
    此时,便找到了当前结点需要插入的位置,记为P。此时P下方的节点的key值肯定小于当前被插入节点的key,但是index也小于当前插入节点的index(即需要在二叉搜索树中当前结点之前的位置),所以将当前节点插入到P的位置,同时将以P为根的子树挂载到新插入的节点的左子树(为了保证P及其子树在新插入节点之前被二叉搜索)

实际实现的时候,可以采用栈的数据结构。栈中保存当前树中的从树根开始的右子节点链,根在栈底部。 
    插入新元素的时候,从树的右子链的最末尾从下往上查找,直到找到第一个满足堆性质的节点(即找到的节点的key值大于当前需要插入的节点)。用栈来实现就是从栈顶不断弹出元素,直到栈顶的元素的key大于当前结点的key,然后将该节点入栈,同时将最后被弹出的节点的parent指向该节点,以及该节点的左子节点指向最后被弹出的节点。

复杂度分析: 每个节点最多入栈一次,出栈一次,因此时间复杂度为 O(n)

实现(c++)

struct DTreeNode{
    int index;            //在原来数组中的索引
    int key;            //节点的key,即原数组中 Array[index]值
    DTreeNode* left;    //左子节点
    DTreeNode* right;    //右子节点
    DTreeNode* parent;    //父节点
    DTreeNode(int i, int k) :
        index(i), key(k), left(NULL), right(NULL), parent(NULL){};
};

DTreeNode* BuildTree(int* arr, int n){
    stack<DTreeNode*> node_stack;
    DTreeNode* node = NULL, *new_node;
    for (int i = 0; i < n; i++){
        new_node = new DTreeNode(i, arr[i]);

        while (!node_stack.empty()){
            node = node_stack.top();
            if (node->key > new_node->key){ //直到栈顶的元素的key大于当前结点的key

                if (node->right){                //将原来的右子链挂载到new_node的左子树
                    node->right->parent = new_node;
                    new_node->left = node->right;
                }
                node->right = new_node;        //将新插入的节点插入,作为右链的最后
                new_node->parent = node;
                break;
            }
            node_stack.pop();
        }
        node_stack.push(new_node);
    }

    //找出栈顶元素,就是笛卡尔树的根
    while (!node_stack.empty()){
        node = node_stack.top();
        node_stack.pop();
    }
    return node;
}

void InorderTravel(DTreeNode* root){ //非递归进行中序遍历
    stack<DTreeNode*> node_stack;
    DTreeNode* node = root;

    while (!node_stack.empty() || node){
        if (node){
            node_stack.push(node);
            node = node->left;
        }
        else{
            node = node_stack.top();
            node_stack.pop(); 

            cout << "travel node, index = " << node->index << ", value = " << node->key << endl;

            node = node->right;
        }

    }
}

时间: 2024-08-10 17:20:10

笛卡尔树的相关文章

hdu 5412 CRB and Queries(线段树套笛卡尔树 - 动态区间第k大)

题目链接:hdu 5412 CRB and Queries 首先对所有出现过的值排序,建立线段树,每个线段树的节点是一棵笛卡尔树,笛卡尔树记录区间下标值. #include <cstdio> #include <cstring> #include <cstdlib> #include <algorithm> using namespace std; #define lson(x) (x<<1) #define rson(x) ((x<<

笛卡尔树cartesian tree

笛卡尔树cartesian tree 笛卡尔树是一种特定的二叉树数据结构,可由数列构造,在范围最值查询.范围top k查询(range top k queries)等问题上有广泛应用.它具有堆的有序性,中序遍历可以输出原数列.笛卡尔树结构由Vuillmin(1980)[1]在解决范围搜索的几何数据结构问题时提出.从数列中构造一棵笛卡尔树可以线性时间完成,需要采用基于栈的算法来找到在该数列中的所有最近小数. 定义 无相同元素的数列构造出的笛卡尔树具有下列性质: 结点一一对应于数列元素.即数列中的每

POJ-2201-Cartesian Tree(笛卡尔树)

Description Let us consider a special type of a binary search tree, called a cartesian tree. Recall that a binary search tree is a rooted ordered binary tree, such that for its every node x the following condition is satisfied: each node in its left

[COGS 2421] [HZOI 2016] 简单的Treap 笛卡尔树

笛卡尔树就是你给两维限制,一维堆R,一维二叉搜索树K,平地拔起一棵Treap,最广范的应用:用LCA求区间最值,建Treap,还有个什么范围top k我表示并不会查都查不到.它最妙最高的地方在于用栈来建树:我们可以先排序K然后一个个插入,那么我们都是最右端,横容易被卡,那么我们不从上到下,我们从下到上,用栈维护,那就把时间复杂度从O(n^2)降到O(n),具体过程见下图从图一到图二就是这么一个过程,我们在把K为13的点插入时要找到一个合适的位置,上比他大,下比他小(假设大根堆) 下面见代码 #i

POJ 2559 Largest Rectangle in a Histogram ——笛卡尔树

[题目分析] 本来是单调栈的题目,用笛卡尔树可以快速的水过去. 把每一个矩阵看成一个二元组(出现的顺序,高度). 然后建造笛卡尔树. 神奇的发现,每一个节点的高度*该子树的大小,就是这一块最大的子矩阵的可能解. 用二元组的第一个下标来限制,使它们在一块儿,然后堆的性质又限制了宽度以及高度. 计算,取最值即可. [代码] #include <cstdio> #include <cstring> #include <cstdlib> #include <cmath&g

POJ-1785-Binary Search Heap Construction(笛卡尔树)

Description Read the statement of problem G for the definitions concerning trees. In the following we define the basic terminology of heaps. A heap is a tree whose internal nodes have each assigned a priority (a number) such that the priority of each

NOIP2011pj表达式的值[树形DP 笛卡尔树]

题目描述 对于1 位二进制变量定义两种运算: 运算的优先级是: 先计算括号内的,再计算括号外的. “× ”运算优先于“⊕”运算,即计算表达式时,先计算× 运算,再计算⊕运算.例如:计算表达式A⊕B × C时,先计算 B × C,其结果再与 A 做⊕运算. 现给定一个未完成的表达式,例如+(*_),请你在横线处填入数字0 或者1 ,请问有多少种填法可以使得表达式的值为0 . 输入输出格式 输入格式: 输入文件名为exp.in ,共 2 行. 第1 行为一个整数 L,表示给定的表达式中除去横线外的运

4-09. 笛卡尔树(25)(ZJU_PAT)

题目链接:http://www.patest.cn/contests/ds/4-09 笛卡尔树是一种特殊的二叉树,其结点包含两个关键字K1和K2.首先笛卡尔树是关于K1的二叉搜索树,即结点左子树的所有K1值都比该结点的K1值小,右子树则大.其次所有结点的K2关键字满足优先队列(不妨设为最小堆)的顺序要求,即该结点的K2值比其子树中所有结点的K2值小.给定一棵二叉树,请判断该树是否笛卡尔树. 输入格式说明: 输入首先给出正整数N(<=1000),为树中结点的个数.随后N行,每行给出一个结点的信息,

笛卡尔树 POJ ——1785 Binary Search Heap Construction

相应POJ 题目:点击打开链接 Binary Search Heap Construction Time Limit: 2000MS   Memory Limit: 30000K Total Submissions: 9075   Accepted: 2566 Description Read the statement of problem G for the definitions concerning trees. In the following we define the basic

[poj2201]Cartesian Tree(笛卡尔树)

题目链接:http://poj.org/problem?id=2201 就是给你key和value,建出笛卡尔树.感觉笛卡尔树的建树过程真的优美,按key排序后,每次插入一个点,相当于从根一直向右走的路径上,找到value小于当前点value,并且value最大的点,插入即可,具体看代码吧. 区分笛卡尔式和treap:两者都有key和value,都既满足二叉搜索树的性质,也满足堆的性质,但treap是用value去维护树的平衡,而笛卡尔树的value是我们已知的(好像是吧). #include<