mirror of
https://github.com/JakeHillion/drgn.git
synced 2024-12-23 09:43:06 +00:00
8b264f8823
drgn was originally my side project, but for awhile now it's also been my work project. Update the copyright headers to reflect this, and add a copyright header to various files that were missing it.
189 lines
5.0 KiB
C
189 lines
5.0 KiB
C
// Copyright (c) Facebook, Inc. and its affiliates.
|
|
// SPDX-License-Identifier: GPL-3.0+
|
|
|
|
#include "binary_search_tree.h"
|
|
|
|
/*
|
|
* Binary search tree splay operation based on the original paper [1]. Rotations
|
|
* are inlined to avoid redundant pointer assignments. We still do redundant
|
|
* assignments to great_grandparent->{left,right} and node->{left,right}; this
|
|
* was faster in microbenchmarks than doing the extra tracking to avoid the
|
|
* reassignments.
|
|
*
|
|
* This assumes that the node is not already the root.
|
|
*
|
|
* 1: "Self-Adjusting Binary Search Trees" (Sleator & Tarjan, 1985):
|
|
* http://www.cs.cmu.edu/~sleator/papers/self-adjusting.pdf
|
|
*/
|
|
void splay_tree_splay(struct binary_tree_node **root,
|
|
struct binary_tree_node *node,
|
|
struct binary_tree_node *parent)
|
|
{
|
|
for (;;) {
|
|
struct binary_tree_node *grandparent, *great_grandparent;
|
|
|
|
grandparent = parent->parent;
|
|
if (node == parent->left) {
|
|
if (!grandparent) {
|
|
/*
|
|
* Zig step: rotate_right(parent). The node
|
|
* takes the place of its parent, which is the
|
|
* root.
|
|
*/
|
|
parent->left = node->right;
|
|
node->right = parent;
|
|
|
|
if (parent->left)
|
|
parent->left->parent = parent;
|
|
parent->parent = node;
|
|
break;
|
|
} else {
|
|
great_grandparent = grandparent->parent;
|
|
if (parent == grandparent->left) {
|
|
/*
|
|
* Zig-zig step:
|
|
* rotate_right(grandparent),
|
|
* rotate_right(parent).
|
|
*/
|
|
grandparent->left = parent->right;
|
|
parent->left = node->right;
|
|
parent->right = grandparent;
|
|
node->right = parent;
|
|
|
|
if (grandparent->left)
|
|
grandparent->left->parent = grandparent;
|
|
grandparent->parent = parent;
|
|
if (parent->left)
|
|
parent->left->parent = parent;
|
|
parent->parent = node;
|
|
} else {
|
|
/*
|
|
* Zig-zag step: rotate_right(parent),
|
|
* rotate_left(grandparent).
|
|
*/
|
|
grandparent->right = node->left;
|
|
parent->left = node->right;
|
|
node->left = grandparent;
|
|
node->right = parent;
|
|
|
|
if (grandparent->right)
|
|
grandparent->right->parent = grandparent;
|
|
if (parent->left)
|
|
parent->left->parent = parent;
|
|
grandparent->parent = node;
|
|
parent->parent = node;
|
|
}
|
|
}
|
|
} else {
|
|
if (!grandparent) {
|
|
/*
|
|
* Zig step: rotate_left(parent). The node
|
|
* takes the place of its parent, which is the
|
|
* root.
|
|
*/
|
|
parent->right = node->left;
|
|
node->left = parent;
|
|
|
|
if (parent->right)
|
|
parent->right->parent = parent;
|
|
parent->parent = node;
|
|
break;
|
|
} else {
|
|
great_grandparent = grandparent->parent;
|
|
if (parent == grandparent->right) {
|
|
/*
|
|
* Zig-zig step:
|
|
* rotate_left(grandparent),
|
|
* rotate_left(parent).
|
|
*/
|
|
grandparent->right = parent->left;
|
|
parent->right = node->left;
|
|
parent->left = grandparent;
|
|
node->left = parent;
|
|
|
|
if (grandparent->right)
|
|
grandparent->right->parent = grandparent;
|
|
grandparent->parent = parent;
|
|
if (parent->right)
|
|
parent->right->parent = parent;
|
|
parent->parent = node;
|
|
} else {
|
|
/*
|
|
* Zig-zag step: rotate_left(parent),
|
|
* rotate_right(grandparent).
|
|
*/
|
|
grandparent->left = node->right;
|
|
parent->right = node->left;
|
|
node->right = grandparent;
|
|
node->left = parent;
|
|
|
|
if (grandparent->left)
|
|
grandparent->left->parent = grandparent;
|
|
if (parent->right)
|
|
parent->right->parent = parent;
|
|
grandparent->parent = node;
|
|
parent->parent = node;
|
|
}
|
|
}
|
|
}
|
|
/*
|
|
* Common code for zig-zig and zig-zag steps, both left and
|
|
* right. The node took the place of its grandparent, which may
|
|
* have been the root. We don't need to update the node's parent
|
|
* pointer because it is always NULL in the end.
|
|
*/
|
|
if (!great_grandparent)
|
|
break;
|
|
if (grandparent == great_grandparent->left)
|
|
great_grandparent->left = node;
|
|
else
|
|
great_grandparent->right = node;
|
|
parent = great_grandparent;
|
|
}
|
|
|
|
/* The node reached the root. */
|
|
*root = node;
|
|
node->parent = NULL;
|
|
}
|
|
|
|
static inline void transplant(struct binary_tree_node **root,
|
|
struct binary_tree_node *old,
|
|
struct binary_tree_node *new)
|
|
{
|
|
if (!old->parent)
|
|
*root = new;
|
|
else if (old == old->parent->left)
|
|
old->parent->left = new;
|
|
else
|
|
old->parent->right = new;
|
|
if (new)
|
|
new->parent = old->parent;
|
|
}
|
|
|
|
void splay_tree_delete(struct binary_tree_node **root,
|
|
struct binary_tree_node *node)
|
|
{
|
|
if (node->left == NULL) {
|
|
transplant(root, node, node->right);
|
|
} else if (node->right == NULL) {
|
|
transplant(root, node, node->left);
|
|
} else {
|
|
struct binary_tree_node *successor;
|
|
|
|
successor = node->right;
|
|
if (successor->left) {
|
|
do {
|
|
successor = successor->left;
|
|
} while (successor->left);
|
|
transplant(root, successor, successor->right);
|
|
successor->right = node->right;
|
|
successor->right->parent = successor;
|
|
}
|
|
transplant(root, node, successor);
|
|
successor->left = node->left;
|
|
successor->left->parent = successor;
|
|
}
|
|
if (node->parent && node->parent->parent)
|
|
splay_tree_splay(root, node->parent, node->parent->parent);
|
|
}
|