我建议的数据结构需要更多的工作来实现,但它确实达到了预期的结果;
具有{insert, delete, findMin, search} 操作的数据结构可以使用 AVL 树来实现,该树确保每个操作在 O(logn) 中完成,findMin 在 O(1) 中完成。
我将深入了解一下实现:
树将包含一个指向最小节点的指针,该指针在每次插入和删除时都会更新,因此findMin 需要O(1)。
insert 在每个采用O(logn) 的 AVL 树中实现(使用平衡因子和旋转/交换来平衡树)。插入元素后,您需要从树根一直到左侧来更新最小节点指针,这也需要O(logn),因为树高是O(logn)。
同样,在使用delete 之后,您需要以同样的方式更新最小指针,因此它需要O(logn)。
最后,search 还需要O(logn)。
如果给出更多假设,例如插入的元素在最小值的一定范围内,那么你也可以给树中的每个节点successor和predecessor指针,在插入和删除时也可以在O(logn)中更新,从而可以访问在O(1) 中,无需遍历整个树。并且可以更快地搜索插入的元素。
插入节点的后继节点可以通过先到右子节点然后一直到左边来更新。但是,如果不存在右孩子,那么只要当前节点不是其父母的左孩子,您就需要爬上父母。
前身以完全相反的方式更新。
在 C++ 中,节点看起来像这样
template <class Key,class Value>
class AvlNode{
private:
Key key;
Value value;
int Height;
int BF; //balance factor
AvlNode* Left;
AvlNode* Right;
AvlNode* Parent;
AvlNode* Succ;
AvlNode* Pred;
public:
...
}
虽然树看起来像这样:
template <class Key,class Value>
class AVL {
private:
int NumOfKeys;
int Height;
AvlNode<Key, Value> *Minimum;
AvlNode<Key, Value> *Root;
static void swapLL(AVL<Key, Value> *avl, AvlNode<Key, Value> *root);
static void swapLR(AVL<Key, Value> *avl, AvlNode<Key, Value> *root);
static void swapRL(AVL<Key, Value> *avl, AvlNode<Key, Value> *root);
static void swapRR(AVL<Key, Value> *avl, AvlNode<Key, Value> *root);
public:
...
}