Двоичные деревья поиска. Декартово дерево

Декартово дерево — это двоичное дерево, в узлах которого хранятся: ссылки на правое и левое поддерево, ссылка на родительский узел (необязательно), ключи x и y, которые являются двоичным деревом поиска по ключу x и двоичной кучей по ключу y. А именно, для любого узла дерева n ключи x узлов правого (левого) поддерева больше (меньше либо равны) ключа x узла n, ключи y узлов правого и левого детей меньше либо равны ключу y узла n.

Ссылка на родительский узел не обязательна, она желательна только для линейного алгоритма построения дерева.

Декартово дерево - это структура данных, объединяющая в себе бинарное дерево поиска и бинарную кучу (отсюда и второе её название: treap (tree+heap) и дерамида (дерево+пирамида).

type
  Treap = ^TNode;
  TNode = record
    x,y : Integer; { x - ключ, y - приоритет (произвольные сравнимые типы данных) }
    Left,Right : Treap; { Левое и правое поддерево }
  end;

Merge (склеивание)

{ Слияние декартовых деревьев }
function Merge( L,R : Treap ):Treap;
begin
  if L = nil then { Левого поддерева нет }
    Result := R     { => результат - правое поддерево }
  else if R = nil then { Правого поддерева нет }
    Result := L     { => результат - левое поддерево }
  else if L.y > R.y then begin { У левого приоритет выше }
    { => левое становится корнем }
    { Левое поддерево у него сохраняется }
    L.Right := Merge(L.Right,R);
    Result := L;
  end else begin { У правого приоритет выше или равен }
    { Правое поддерево сохраняется }
    { Левое поддерево = результат слияния левого с
      левым сыном правого поддерева }
    R.Left := Merge(L,R.Left);
    Result := R;
  end;
end;

Реализация на Python

# Склеивание декартовых деревьев (merge): O(log n) в среднем, где n - число вершин.
class Node:
    def __init__(self, key, prio):
        self.key = key
        self.prio = prio  # приоритет: у родителя он не меньше, чем у детей (куча)
        self.left = None
        self.right = None


def merge(left, right):
    # Все ключи left не больше ключей right; корнем становится вершина с большим приоритетом
    if left is None:
        return right
    if right is None:
        return left
    if left.prio > right.prio:
        left.right = merge(left.right, right)
        return left
    right.left = merge(left, right.left)
    return right


def keys_in_order(node, keys):
    # Обход по возрастанию ключей
    if node is None:
        return
    keys_in_order(node.left, keys)
    keys.append(node.key)
    keys_in_order(node.right, keys)


def main():
    # Склеиваем одиночные вершины в порядке возрастания ключей
    root = None
    for key, prio in [(1, 30), (2, 50), (3, 10), (4, 40)]:
        root = merge(root, Node(key, prio))
    keys = []
    keys_in_order(root, keys)
    print(keys, root.key)  # [1, 2, 3, 4] 2


if __name__ == "__main__":
    main()

Реализация на Rust

// Склеивание декартовых деревьев (merge): O(log n) в среднем, где n - число вершин.
pub struct Node {
    pub key: i32,
    pub prio: i32, // приоритет: у родителя он не меньше, чем у детей (куча)
    pub left: Tree,
    pub right: Tree,
}

pub type Tree = Option<Box<Node>>;

// Все ключи left не больше ключей right; корнем становится вершина с большим приоритетом.
pub fn merge(left: Tree, right: Tree) -> Tree {
    match (left, right) {
        (None, right) => right,
        (left, None) => left,
        (Some(mut l), Some(mut r)) => {
            if l.prio > r.prio {
                l.right = merge(l.right.take(), Some(r));
                Some(l)
            } else {
                r.left = merge(Some(l), r.left.take());
                Some(r)
            }
        }
    }
}

// Обход по возрастанию ключей.
pub fn keys_in_order(node: &Tree, keys: &mut Vec<i32>) {
    if let Some(current) = node {
        keys_in_order(&current.left, keys);
        keys.push(current.key);
        keys_in_order(&current.right, keys);
    }
}

fn main() {
    // Склеиваем одиночные вершины в порядке возрастания ключей
    let mut root: Tree = None;
    for (key, prio) in [(1, 30), (2, 50), (3, 10), (4, 40)] {
        root = merge(root, Some(Box::new(Node { key, prio, left: None, right: None })));
    }
    let mut keys = Vec::new();
    keys_in_order(&root, &mut keys);
    println!("{:?} {}", keys, root.as_ref().map_or(0, |n| n.key)); // [1, 2, 3, 4] 2
}

Реализация на C++

// Склеивание декартовых деревьев (merge): O(log n) в среднем, где n - число вершин.
#include <iostream>
#include <memory>
#include <utility>
#include <vector>

struct Node {
    int key;
    int prio;  // приоритет: у родителя он не меньше, чем у детей (куча)
    std::unique_ptr<Node> left;
    std::unique_ptr<Node> right;
    Node(int k, int p) : key(k), prio(p) {}
};

using Tree = std::unique_ptr<Node>;

// Все ключи left не больше ключей right; корнем становится вершина с большим приоритетом.
Tree merge(Tree left, Tree right) {
    if (!left) return right;
    if (!right) return left;
    if (left->prio > right->prio) {
        left->right = merge(std::move(left->right), std::move(right));
        return left;
    }
    right->left = merge(std::move(left), std::move(right->left));
    return right;
}

// Обход по возрастанию ключей.
void keys_in_order(const Node* node, std::vector<int>& keys) {
    if (!node) return;
    keys_in_order(node->left.get(), keys);
    keys.push_back(node->key);
    keys_in_order(node->right.get(), keys);
}

int main() {
    // Склеиваем одиночные вершины в порядке возрастания ключей
    Tree root;
    for (auto [key, prio] : {std::pair{1, 30}, std::pair{2, 50}, std::pair{3, 10}, std::pair{4, 40}}) {
        root = merge(std::move(root), std::make_unique<Node>(key, prio));
    }
    std::vector<int> keys;
    keys_in_order(root.get(), keys);
    for (int key : keys) std::cout << key << ' ';
    std::cout << "корень " << root->key << '\n';  // 1 2 3 4 корень 2
    return 0;
}

Split (разрезание)

{ Операция разрезания дерева T по ключу x на 2 поддерева L и R }
procedure Split( T:Treap; x:Integer; var L,R:Treap);
var Temp : Treap; { Временное дерево }
begin
  Temp := nil;
  if T = nil then begin { Если дерево пустое }
    L := nil; { то результат разрезания пустой }
    R := nil;
  end else
  if T.x <= x then begin
    if T.Right = nil then
      R := nil
    else
      Split(T.Right,x,Temp,R);
    L := T;
    L.Right := Temp;
  end else begin
    if T.Left = nil then
      L := nil
    else
      Split(T.Left,x,L,Temp);
    R := T;
    R.Left := Temp;
  end;
end;

Реализация на Python

# Разрезание декартова дерева по ключу (split): O(log n) в среднем, где n - число вершин.
class Node:
    def __init__(self, key, prio):
        self.key = key
        self.prio = prio  # приоритет: у родителя он не меньше, чем у детей (куча)
        self.left = None
        self.right = None


def merge(left, right):
    if left is None:
        return right
    if right is None:
        return left
    if left.prio > right.prio:
        left.right = merge(left.right, right)
        return left
    right.left = merge(left, right.left)
    return right


def split(node, split_key):
    # Возвращает (left, right): в left ключи <= split_key, в right - остальные
    if node is None:
        return None, None
    if node.key <= split_key:
        left, right = split(node.right, split_key)
        node.right = left
        return node, right
    left, right = split(node.left, split_key)
    node.left = right
    return left, node


def keys_in_order(node, keys):
    if node is None:
        return
    keys_in_order(node.left, keys)
    keys.append(node.key)
    keys_in_order(node.right, keys)


def main():
    root = None
    for key, prio in [(1, 30), (2, 50), (3, 10), (4, 40), (5, 20)]:
        root = merge(root, Node(key, prio))
    left, right = split(root, 3)
    left_keys, right_keys = [], []
    keys_in_order(left, left_keys)
    keys_in_order(right, right_keys)
    print(left_keys, right_keys)  # [1, 2, 3] [4, 5]


if __name__ == "__main__":
    main()

Реализация на Rust

// Разрезание декартова дерева по ключу (split): O(log n) в среднем, где n - число вершин.
pub struct Node {
    pub key: i32,
    pub prio: i32, // приоритет: у родителя он не меньше, чем у детей (куча)
    pub left: Tree,
    pub right: Tree,
}

pub type Tree = Option<Box<Node>>;

pub fn merge(left: Tree, right: Tree) -> Tree {
    match (left, right) {
        (None, right) => right,
        (left, None) => left,
        (Some(mut l), Some(mut r)) => {
            if l.prio > r.prio {
                l.right = merge(l.right.take(), Some(r));
                Some(l)
            } else {
                r.left = merge(Some(l), r.left.take());
                Some(r)
            }
        }
    }
}

// Возвращает (left, right): в left ключи <= split_key, в right - остальные.
pub fn split(node: Tree, split_key: i32) -> (Tree, Tree) {
    let Some(mut current) = node else { return (None, None) };
    if current.key <= split_key {
        let (left, right) = split(current.right.take(), split_key);
        current.right = left;
        (Some(current), right)
    } else {
        let (left, right) = split(current.left.take(), split_key);
        current.left = right;
        (left, Some(current))
    }
}

pub fn keys_in_order(node: &Tree, keys: &mut Vec<i32>) {
    if let Some(current) = node {
        keys_in_order(&current.left, keys);
        keys.push(current.key);
        keys_in_order(&current.right, keys);
    }
}

fn main() {
    let mut root: Tree = None;
    for (key, prio) in [(1, 30), (2, 50), (3, 10), (4, 40), (5, 20)] {
        root = merge(root, Some(Box::new(Node { key, prio, left: None, right: None })));
    }
    let (left, right) = split(root, 3);
    let mut left_keys = Vec::new();
    keys_in_order(&left, &mut left_keys);
    let mut right_keys = Vec::new();
    keys_in_order(&right, &mut right_keys);
    println!("{:?} {:?}", left_keys, right_keys); // [1, 2, 3] [4, 5]
}

Реализация на C++

// Разрезание декартова дерева по ключу (split): O(log n) в среднем, где n - число вершин.
#include <iostream>
#include <memory>
#include <utility>
#include <vector>
struct Node {
    int key;
    int prio;  // приоритет: у родителя он не меньше, чем у детей (куча)
    std::unique_ptr<Node> left;
    std::unique_ptr<Node> right;
    Node(int k, int p) : key(k), prio(p) {}
};

using Tree = std::unique_ptr<Node>;

Tree merge(Tree left, Tree right) {
    if (!left) return right;
    if (!right) return left;
    if (left->prio > right->prio) {
        left->right = merge(std::move(left->right), std::move(right));
        return left;
    }
    right->left = merge(std::move(left), std::move(right->left));
    return right;
}

// Возвращает пару (left, right): в left ключи <= split_key, в right - остальные.
std::pair<Tree, Tree> split(Tree node, int split_key) {
    if (!node) return {nullptr, nullptr};
    if (node->key <= split_key) {
        auto [left, right] = split(std::move(node->right), split_key);
        node->right = std::move(left);
        return {std::move(node), std::move(right)};
    }
    auto [left, right] = split(std::move(node->left), split_key);
    node->left = std::move(right);
    return {std::move(left), std::move(node)};
}

void keys_in_order(const Node* node, std::vector<int>& keys) {
    if (!node) return;
    keys_in_order(node->left.get(), keys);
    keys.push_back(node->key);
    keys_in_order(node->right.get(), keys);
}

int main() {
    Tree root;
    for (auto [key, prio] : {std::pair{1, 30}, std::pair{2, 50}, std::pair{3, 10}, std::pair{4, 40}, std::pair{5, 20}}) {
        root = merge(std::move(root), std::make_unique<Node>(key, prio));
    }
    auto [left, right] = split(std::move(root), 3);
    std::vector<int> left_keys, right_keys;
    keys_in_order(left.get(), left_keys);
    keys_in_order(right.get(), right_keys);
    for (int key : left_keys) std::cout << key << ' ';
    std::cout << "| ";
    for (int key : right_keys) std::cout << key << ' ';
    std::cout << '\n';  // 1 2 3 | 4 5
    return 0;
}

Добавление новой вершины

{ Добавление вершины с ключём x в дерево T }
procedure Add( var T:Treap; x:integer );
var NV,L,R : Treap;
begin
  new(NV); { Создаём новый узел }
  NV.x := x; { У него ключ x }
  NV.y := Random(High(Integer)); { И случайный приоритет }
  NV.Left := nil; { Нет поддеревьев }
  NV.Right := nil;
  Split(T,x,L,R); { Разрезаем исходное дерево по ключу x }
  { Склеиваем 3 получившихся дерева }
  T := Merge(Merge(L,NV),R);
end;

Реализация на Python

# Вставка в декартово дерево через разрезание и склеивание: O(log n) в среднем.
class Node:
    def __init__(self, key, prio):
        self.key = key
        self.prio = prio  # приоритет: у родителя он не меньше, чем у детей (куча)
        self.left = None
        self.right = None


def merge(left, right):
    if left is None:
        return right
    if right is None:
        return left
    if left.prio > right.prio:
        left.right = merge(left.right, right)
        return left
    right.left = merge(left, right.left)
    return right


def split(node, split_key):
    # Возвращает (left, right): в left ключи <= split_key, в right - остальные
    if node is None:
        return None, None
    if node.key <= split_key:
        left, right = split(node.right, split_key)
        node.right = left
        return node, right
    left, right = split(node.left, split_key)
    node.left = right
    return left, node


def insert(root, key, prio):
    # Разрезаем дерево по ключу и склеиваем: левая часть, новая вершина, правая часть
    left, right = split(root, key)
    return merge(merge(left, Node(key, prio)), right)


def keys_in_order(node, keys):
    if node is None:
        return
    keys_in_order(node.left, keys)
    keys.append(node.key)
    keys_in_order(node.right, keys)


def main():
    root = None
    for key, prio in [(5, 50), (3, 80), (8, 20), (1, 90), (4, 10)]:
        root = insert(root, key, prio)
    keys = []
    keys_in_order(root, keys)
    print(keys, root.key)  # [1, 3, 4, 5, 8] 1


if __name__ == "__main__":
    main()

Реализация на Rust

// Вставка в декартово дерево через разрезание и склеивание: O(log n) в среднем.
pub struct Node {
    pub key: i32,
    pub prio: i32, // приоритет: у родителя он не меньше, чем у детей (куча)
    pub left: Tree,
    pub right: Tree,
}

pub type Tree = Option<Box<Node>>;

pub fn merge(left: Tree, right: Tree) -> Tree {
    match (left, right) {
        (None, right) => right,
        (left, None) => left,
        (Some(mut l), Some(mut r)) => {
            if l.prio > r.prio {
                l.right = merge(l.right.take(), Some(r));
                Some(l)
            } else {
                r.left = merge(Some(l), r.left.take());
                Some(r)
            }
        }
    }
}

// Возвращает (left, right): в left ключи <= split_key, в right - остальные.
pub fn split(node: Tree, split_key: i32) -> (Tree, Tree) {
    let Some(mut current) = node else { return (None, None) };
    if current.key <= split_key {
        let (left, right) = split(current.right.take(), split_key);
        current.right = left;
        (Some(current), right)
    } else {
        let (left, right) = split(current.left.take(), split_key);
        current.left = right;
        (left, Some(current))
    }
}

// Разрезаем дерево по ключу и склеиваем: левая часть, новая вершина, правая часть.
pub fn insert(root: Tree, key: i32, prio: i32) -> Tree {
    let (left, right) = split(root, key);
    merge(merge(left, Some(Box::new(Node { key, prio, left: None, right: None }))), right)
}

pub fn keys_in_order(node: &Tree, keys: &mut Vec<i32>) {
    if let Some(current) = node {
        keys_in_order(&current.left, keys);
        keys.push(current.key);
        keys_in_order(&current.right, keys);
    }
}

fn main() {
    let mut root: Tree = None;
    for (key, prio) in [(5, 50), (3, 80), (8, 20), (1, 90), (4, 10)] {
        root = insert(root, key, prio);
    }
    let mut keys = Vec::new();
    keys_in_order(&root, &mut keys);
    println!("{:?} {}", keys, root.as_ref().map_or(0, |n| n.key)); // [1, 3, 4, 5, 8] 1
}

Реализация на C++

// Вставка в декартово дерево через разрезание и склеивание: O(log n) в среднем.
#include <iostream>
#include <memory>
#include <utility>
#include <vector>
struct Node {
    int key;
    int prio;  // приоритет: у родителя он не меньше, чем у детей (куча)
    std::unique_ptr<Node> left;
    std::unique_ptr<Node> right;
    Node(int k, int p) : key(k), prio(p) {}
};

using Tree = std::unique_ptr<Node>;

Tree merge(Tree left, Tree right) {
    if (!left) return right;
    if (!right) return left;
    if (left->prio > right->prio) {
        left->right = merge(std::move(left->right), std::move(right));
        return left;
    }
    right->left = merge(std::move(left), std::move(right->left));
    return right;
}

// Возвращает пару (left, right): в left ключи <= split_key, в right - остальные.
std::pair<Tree, Tree> split(Tree node, int split_key) {
    if (!node) return {nullptr, nullptr};
    if (node->key <= split_key) {
        auto [left, right] = split(std::move(node->right), split_key);
        node->right = std::move(left);
        return {std::move(node), std::move(right)};
    }
    auto [left, right] = split(std::move(node->left), split_key);
    node->left = std::move(right);
    return {std::move(left), std::move(node)};
}

// Разрезаем дерево по ключу и склеиваем: левая часть, новая вершина, правая часть.
Tree insert(Tree root, int key, int prio) {
    auto [left, right] = split(std::move(root), key);
    return merge(merge(std::move(left), std::make_unique<Node>(key, prio)), std::move(right));
}

void keys_in_order(const Node* node, std::vector<int>& keys) {
    if (!node) return;
    keys_in_order(node->left.get(), keys);
    keys.push_back(node->key);
    keys_in_order(node->right.get(), keys);
}

int main() {
    Tree root;
    for (auto [key, prio] : {std::pair{5, 50}, std::pair{3, 80}, std::pair{8, 20}, std::pair{1, 90}, std::pair{4, 10}}) {
        root = insert(std::move(root), key, prio);
    }
    std::vector<int> keys;
    keys_in_order(root.get(), keys);
    for (int key : keys) std::cout << key << ' ';
    std::cout << "корень " << root->key << '\n';  // 1 3 4 5 8 корень 1
    return 0;
}

Удаление вершины с заданным ключом x

{ Удаление вершины }
procedure Delete( var T:Treap; x:integer );
var L,R,M,Rs : Treap;
begin
  Split(T,x-1,L,R);
  Split(R,x,M,Rs);
  { Удаляем одну верхнюю вершину в M }
  if M <> nil then begin
    if M.Left = nil then
      M := M.Right
    else
      M := M.Left;
  end;
  { Сливаем вместе оставшиеся куски }
  T := Merge(L,Merge(M,Rs));
end;

Реализация на Python

# Удаление ключа из декартова дерева (split + merge): O(log n) в среднем, где n - число вершин
class Node:
    def __init__(self, key, prio, left=None, right=None):
        self.key = key
        self.prio = prio  # у родителя приоритет не меньше, чем у детей (куча)
        self.left = left
        self.right = right


def merge(left, right):
    """Все ключи left не больше ключей right; корнем становится вершина с большим приоритетом."""
    if left is None:
        return right
    if right is None:
        return left
    if left.prio > right.prio:
        left.right = merge(left.right, right)
        return left
    right.left = merge(left, right.left)
    return right


def split(node, key):
    """Возвращает два дерева: с ключами <= key и с ключами > key."""
    if node is None:
        return None, None
    if node.key <= key:
        left, right = split(node.right, key)
        node.right = left
        return node, right
    left, right = split(node.left, key)
    node.left = right
    return left, node


def erase(root, key):
    """Удаляет одну вершину с ключом key: режем на части, у средней убираем корень, склеиваем."""
    left, rest = split(root, key - 1)  # целые ключи
    middle, right = split(rest, key)
    if middle is not None:
        middle = merge(middle.left, middle.right)
    return merge(left, merge(middle, right))


def keys(node):
    """Ключи дерева в порядке возрастания."""
    if node is None:
        return []
    return keys(node.left) + [node.key] + keys(node.right)


if __name__ == "__main__":
    root = None
    for key, prio in [(1, 5), (2, 3), (3, 8), (4, 1), (5, 6)]:  # ключи по возрастанию
        root = merge(root, Node(key, prio))
    print("до:", keys(root))
    print("после:", keys(erase(root, 3)))

Реализация на Rust


// Удаление ключа из декартова дерева (split + merge): O(log n) в среднем, где n - число вершин
pub type Link = Option<Box<Node>>;
pub struct Node { pub key: i64, pub prio: u64, pub left: Link, pub right: Link } // приоритет родителя не меньше детского

// Все ключи a не больше ключей b; корнем становится вершина с большим приоритетом
pub fn merge(a: Link, b: Link) -> Link {
    match (a, b) {
        (None, b) => b,
        (a, None) => a,
        (Some(mut a), Some(b)) if a.prio > b.prio => {
            a.right = merge(a.right.take(), Some(b));
            Some(a)
        }
        (Some(a), Some(mut b)) => {
            b.left = merge(Some(a), b.left.take());
            Some(b)
        }
    }
}

// Разрезание: в первом дереве ключи <= key, во втором - больше key
pub fn split(link: Link, key: i64) -> (Link, Link) {
    let Some(mut node) = link else { return (None, None) };
    if node.key <= key {
        let (left, right) = split(node.right.take(), key);
        node.right = left;
        (Some(node), right)
    } else {
        let (left, right) = split(node.left.take(), key);
        node.left = right;
        (left, Some(node))
    }
}

// Удаляем одну вершину с ключом key: режем на части, у средней убираем корень, склеиваем
pub fn erase(root: Link, key: i64) -> Link {
    let (left, rest) = split(root, key - 1);
    let (middle, right) = split(rest, key);
    let middle = middle.and_then(|node| merge(node.left, node.right));
    merge(left, merge(middle, right))
}

// Ключи дерева в порядке возрастания
pub fn keys(link: &Link) -> Vec<i64> {
    match link {
        None => vec![],
        Some(n) => [keys(&n.left), vec![n.key], keys(&n.right)].concat(),
    }
}

fn main() {
    // Ключи добавляем по возрастанию: (ключ, приоритет)
    let mut root: Link = None;
    for (key, prio) in [(1, 5), (2, 3), (3, 8), (4, 1), (5, 6)] {
        root = merge(root, Some(Box::new(Node { key, prio, left: None, right: None })));
    }
    println!("до:    {:?}", keys(&root));
    root = erase(root, 3);
    println!("после: {:?}", keys(&root));
}

Реализация на C++

// Удаление ключа из декартова дерева (split + merge): O(log n) в среднем, где n - число вершин
#include <cstdio>
#include <memory>
#include <utility>
struct Node { int key, prio; std::unique_ptr<Node> left, right; };  // у родителя приоритет не меньше, чем у детей
using Tree = std::unique_ptr<Node>;

// Все ключи a не больше ключей b; корнем становится вершина с большим приоритетом
Tree merge(Tree a, Tree b) {
    if (!a) return b;
    if (!b) return a;
    if (a->prio > b->prio) {
        a->right = merge(std::move(a->right), std::move(b));
        return a;
    }
    b->left = merge(std::move(a), std::move(b->left));
    return b;
}

// Разрезание: в первом дереве ключи <= key, во втором - больше key
std::pair<Tree, Tree> split(Tree t, int key) {
    if (!t) return {nullptr, nullptr};
    if (t->key <= key) {
        auto [left, right] = split(std::move(t->right), key);
        t->right = std::move(left);
        return {std::move(t), std::move(right)};
    }
    auto [left, right] = split(std::move(t->left), key);
    t->left = std::move(right);
    return {std::move(left), std::move(t)};
}

// Удаляем одну вершину с ключом key: режем на части, у средней убираем корень, склеиваем
Tree erase(Tree root, int key) {
    auto [left, rest] = split(std::move(root), key - 1);
    auto [middle, right] = split(std::move(rest), key);
    if (middle) middle = merge(std::move(middle->left), std::move(middle->right));
    return merge(std::move(left), merge(std::move(middle), std::move(right)));
}

void printKeys(const Node* t) {  // ключи в порядке возрастания
    if (!t) return;
    printKeys(t->left.get());
    std::printf(" %d", t->key);
    printKeys(t->right.get());
}

int main() {
    // Ключи добавляем по возрастанию: (ключ, приоритет)
    const std::pair<int, int> items[] = {{1, 5}, {2, 3}, {3, 8}, {4, 1}, {5, 6}};
    Tree root;
    for (const auto& [key, prio] : items) {
        root = merge(std::move(root), std::make_unique<Node>(Node{key, prio, nullptr, nullptr}));
    }
    root = erase(std::move(root), 3);
    std::printf("после удаления 3:");
    printKeys(root.get());
    std::printf("\n");
    return 0;
}

Поиск минимума и максимума

{ Поиск минимума в дереве }
function MinT( T:Treap ):integer;
begin
  if T = nil then { Если дерево пустое, то минимума нет }
    MinT := High(integer)
  else if T.Left = nil then { Левого поддерева нет => текущий элемент - минимум }
    MinT := T.x
  else
    MinT := MinT(T.Left); { Минимум в левом поддереве }
end;

{ Поиск максимума в дереве - аналогично минимуму, только идём вправо }
function MaxT( T:Treap ):integer;
begin
  if T = nil then
    MaxT := Low(Integer)
  else if T.Right = nil then
    MaxT := T.x
  else
    MaxT := MaxT(T.Right);
end;

Реализация на Python

# Минимум и максимум в декартовом дереве: O(h) по времени, где h - высота дерева
class Node:
    def __init__(self, key, left=None, right=None):
        self.key = key
        self.left = left
        self.right = right


def min_key(root):
    """Минимум - самая левая вершина дерева; для пустого дерева возвращаем None."""
    if root is None:
        return None
    while root.left is not None:
        root = root.left
    return root.key


def max_key(root):
    """Максимум - самая правая вершина дерева; для пустого дерева возвращаем None."""
    if root is None:
        return None
    while root.right is not None:
        root = root.right
    return root.key


if __name__ == "__main__":
    # Дерево: корень 4, слева 2 (с сыновьями 1 и 3), справа 6 (с сыном 7)
    root = Node(4, Node(2, Node(1), Node(3)), Node(6, None, Node(7)))
    print("Минимум:", min_key(root), "Максимум:", max_key(root))

Реализация на Rust


// Минимум и максимум в декартовом дереве: O(h) по времени, где h - высота дерева
pub type Link = Option<Box<Node>>;

pub struct Node {
    pub key: i64,
    pub left: Link,
    pub right: Link,
}

pub fn node(key: i64, left: Link, right: Link) -> Link {
    Some(Box::new(Node { key, left, right }))
}

/// Минимум - самая левая вершина дерева; для пустого дерева возвращаем None.
pub fn min_key(mut link: &Link) -> Option<i64> {
    let mut best = None;
    while let Some(n) = link {
        best = Some(n.key);
        link = &n.left;
    }
    best
}

/// Максимум - самая правая вершина дерева; для пустого дерева возвращаем None.
pub fn max_key(mut link: &Link) -> Option<i64> {
    let mut best = None;
    while let Some(n) = link {
        best = Some(n.key);
        link = &n.right;
    }
    best
}

fn main() {
    // Дерево: корень 4, слева 2 (с сыновьями 1 и 3), справа 6 (с сыном 7)
    let root = node(4, node(2, node(1, None, None), node(3, None, None)), node(6, None, node(7, None, None)));
    println!("Минимум: {}, максимум: {}", min_key(&root).unwrap(), max_key(&root).unwrap());
}

Реализация на C++

// Минимум и максимум в декартовом дереве: O(h) по времени, где h - высота дерева
#include <cstdio>
#include <memory>
#include <optional>
#include <utility>

struct Node {
    int key;
    std::unique_ptr<Node> left, right;
};

std::unique_ptr<Node> makeNode(int key, std::unique_ptr<Node> left = nullptr,
                               std::unique_ptr<Node> right = nullptr) {
    return std::make_unique<Node>(Node{key, std::move(left), std::move(right)});
}

// Минимум - самая левая вершина дерева; для пустого дерева результат пуст
std::optional<int> minKey(const Node* node) {
    std::optional<int> best;
    for (; node != nullptr; node = node->left.get()) best = node->key;
    return best;
}

// Максимум - самая правая вершина дерева; для пустого дерева результат пуст
std::optional<int> maxKey(const Node* node) {
    std::optional<int> best;
    for (; node != nullptr; node = node->right.get()) best = node->key;
    return best;
}

int main() {
    // Дерево: корень 4, слева 2 (с сыновьями 1 и 3), справа 6 (с сыном 7)
    auto root = makeNode(4, makeNode(2, makeNode(1), makeNode(3)), makeNode(6, nullptr, makeNode(7)));
    std::printf("Минимум: %d, максимум: %d\n", minKey(root.get()).value(), maxKey(root.get()).value());
    return 0;
}

Поиск значения в дереве

{ Поиск значения в дереве }
function Find( T:Treap; x:integer ):boolean;
begin
  if T = nil then
    Find := false { Не найдено }
  else if T.x = x then begin
    Find := true; { x найдено в текущей вершине }
  end else if x < T.x then
    Find := Find(T.Left,x) { Поищем слева }
  else
    Find := Find(T.Right,x); { Поищем справа }
end;

Реализация на Python

# Поиск ключа в декартовом дереве (как в двоичном дереве поиска): O(h) по времени, где h - высота дерева
class Node:
    def __init__(self, key, left=None, right=None):
        self.key = key
        self.left = left
        self.right = right


def find_key(root, key) -> bool:
    """Сравниваем с ключом вершины: равен - нашли, меньше - идем влево, больше - вправо."""
    node = root
    while node is not None:
        if node.key == key:
            return True
        node = node.left if key < node.key else node.right
    return False


if __name__ == "__main__":
    # Дерево: корень 4, слева 2 (с сыновьями 1 и 3), справа 6 (с сыном 7)
    root = Node(4, Node(2, Node(1), Node(3)), Node(6, None, Node(7)))
    print("Ключ 3:", find_key(root, 3), "Ключ 5:", find_key(root, 5))

Реализация на Rust


// Поиск ключа в декартовом дереве (как в двоичном дереве поиска): O(h) по времени, где h - высота дерева
pub type Link = Option<Box<Node>>;

pub struct Node {
    pub key: i64,
    pub left: Link,
    pub right: Link,
}

pub fn node(key: i64, left: Link, right: Link) -> Link {
    Some(Box::new(Node { key, left, right }))
}

/// Сравниваем с ключом вершины: равен - нашли, меньше - идем влево, больше - вправо.
pub fn find_key(mut link: &Link, key: i64) -> bool {
    while let Some(n) = link {
        if n.key == key {
            return true;
        }
        link = if key < n.key { &n.left } else { &n.right };
    }
    false
}

fn main() {
    // Дерево: корень 4, слева 2 (с сыновьями 1 и 3), справа 6 (с сыном 7)
    let root = node(4, node(2, node(1, None, None), node(3, None, None)), node(6, None, node(7, None, None)));
    println!("Ключ 3: {}, ключ 5: {}", find_key(&root, 3), find_key(&root, 5));
}

Реализация на C++

// Поиск ключа в декартовом дереве (как в двоичном дереве поиска): O(h) по времени, где h - высота дерева
#include <cstdio>
#include <memory>
#include <utility>

struct Node {
    int key;
    std::unique_ptr<Node> left, right;
};

std::unique_ptr<Node> makeNode(int key, std::unique_ptr<Node> left = nullptr,
                               std::unique_ptr<Node> right = nullptr) {
    return std::make_unique<Node>(Node{key, std::move(left), std::move(right)});
}

// Сравниваем с ключом вершины: равен - нашли, меньше - идем влево, больше - вправо
bool findKey(const Node* node, int key) {
    while (node != nullptr) {
        if (node->key == key) return true;
        node = key < node->key ? node->left.get() : node->right.get();
    }
    return false;
}

int main() {
    // Дерево: корень 4, слева 2 (с сыновьями 1 и 3), справа 6 (с сыном 7)
    auto root = makeNode(4, makeNode(2, makeNode(1), makeNode(3)), makeNode(6, nullptr, makeNode(7)));
    std::printf("Ключ 3: %s, ключ 5: %s\n", findKey(root.get(), 3) ? "да" : "нет",
                findKey(root.get(), 5) ? "да" : "нет");
    return 0;
}

Вычисление высоты дерева

{ Высота дерева }
function Height( T:Treap ):integer;
begin
  if T = nil then
    Result := 0
  else
    Result := max(Height(T.Left),Height(T.Right))+1;
end;

Реализация на Python

# Высота декартова дерева (рекурсивно): O(n) по времени, O(h) по памяти стека рекурсии
class Node:
    def __init__(self, key, left=None, right=None):
        self.key = key
        self.left = left
        self.right = right


def height(node) -> int:
    """Высота пустого дерева равна 0, иначе 1 + максимум из высот поддеревьев."""
    if node is None:
        return 0
    return 1 + max(height(node.left), height(node.right))


if __name__ == "__main__":
    # Дерево: корень 4, слева 2 (с сыновьями 1 и 3), справа 6 (с сыном 7)
    root = Node(4, Node(2, Node(1), Node(3)), Node(6, None, Node(7)))
    print("Высота:", height(root))

Реализация на Rust


// Высота декартова дерева (рекурсивно): O(n) по времени, O(h) по памяти стека рекурсии
pub type Link = Option<Box<Node>>;

pub struct Node {
    pub key: i64,
    pub left: Link,
    pub right: Link,
}

pub fn node(key: i64, left: Link, right: Link) -> Link {
    Some(Box::new(Node { key, left, right }))
}

/// Высота пустого дерева равна 0, иначе 1 + максимум из высот поддеревьев.
pub fn height(link: &Link) -> usize {
    match link {
        None => 0,
        Some(n) => 1 + height(&n.left).max(height(&n.right)),
    }
}

fn main() {
    // Дерево: корень 4, слева 2 (с сыновьями 1 и 3), справа 6 (с сыном 7)
    let root = node(4, node(2, node(1, None, None), node(3, None, None)), node(6, None, node(7, None, None)));
    println!("Корень {}, высота {}", root.as_ref().map_or(0, |n| n.key), height(&root));
}

Реализация на C++

// Высота декартова дерева (рекурсивно): O(n) по времени, O(h) по памяти стека рекурсии
#include <algorithm>
#include <cstdio>
#include <memory>
#include <utility>

struct Node {
    int key;
    std::unique_ptr<Node> left, right;
};

std::unique_ptr<Node> makeNode(int key, std::unique_ptr<Node> left = nullptr,
                               std::unique_ptr<Node> right = nullptr) {
    return std::make_unique<Node>(Node{key, std::move(left), std::move(right)});
}

// Высота пустого дерева равна 0, иначе 1 + максимум из высот поддеревьев
int height(const Node* node) {
    if (node == nullptr) return 0;
    return 1 + std::max(height(node->left.get()), height(node->right.get()));
}

int main() {
    // Дерево: корень 4, слева 2 (с сыновьями 1 и 3), справа 6 (с сыном 7)
    auto root = makeNode(4, makeNode(2, makeNode(1), makeNode(3)), makeNode(6, nullptr, makeNode(7)));
    std::printf("Высота: %d\n", height(root.get()));
    return 0;
}

Тестирование всех операций

var
  T : Treap = nil;
  i,j : Integer;
begin
  Randomize;
  { Проверяем что сейчас ничего в дереве нет }
  for i := -10 to 10 do
    assert( not Find(T,i) );
  { Добавляем вершины }
  for i := 1 to 1000000 do begin
    Add(T,i);
    assert( not Find(T,-1) ); { Вершины -1 по-прежнему нет }
    for j := 1 to min(10,i) do { Добавленные вершины есть }
      assert( Find(T,j) );
    assert( not Find(T,i+1) ); { Вершин с большим номером нет }
  end;  
  Writeln('Высота дерева (оценка: 4*log(N)): ',Height(T));
  assert( Find(T,10) );
  Delete(T,10);
  assert( not Find(T,10) );
end.

Решение задачи поиска чисел в массиве

var
  T : Treap = nil;
  N,M,x,i : Integer;
begin
  Reset(Input,'find.in');
  Rewrite(Output,'find.out');

  Randomize;
  Read(N,M);
  for i := 1 to N do begin
    Read(x);
    Add(T,x);
  end;
  for i := 1 to M do begin
    Read(x);
    if Find(T,x) then
      Writeln('YES')
    else
      Writeln('NO');
  end;
end.

Ссылки