Левосторонние красно-чёрные деревья — различия между версиями
(→Удаление) |
(→Вращения) |
||
Строка 4: | Строка 4: | ||
==Вращения== | ==Вращения== | ||
One way to view red-black BST algorithms is as maintaining the following invariant properties under insertion and deletion: | One way to view red-black BST algorithms is as maintaining the following invariant properties under insertion and deletion: | ||
− | + | Чтобы поддерживать красно-черные двоичное деревья поиска необходимо соблюдать следующие инвариантные свойства при вставке и удалении: | |
− | + | * Ни один путь от корня до листьев не содержит двух последовательных красных узлов. | |
− | + | * Количество черных узлов на каждом таком пути одинаково. | |
− | + | Из этих инвариантов следует, что длина каждого пути от корня до листьев в красно-черном дереве с <tex>N</tex> узлами не превышает <tex>2 \cdot log(N)</tex> . | |
− | + | Основные операции, используемые алгоритмами сбалансированного дерева для поддержания баланса при вставке и удалении, называются вращениями. Эти операции трансформируют <tex>3</tex>-узел,левый потомок которого окрашен в красный, в <tex>3</tex>-узел, правый потомок которого окрашен в красный и наоборот. Вращения сохраняют два указанных выше инварианта, не изменяют поддеревья узла. | |
− | |||
− | |||
− | |||
<code> | <code> | ||
'''Node''' rotateRight(h : '''Node'''): | '''Node''' rotateRight(h : '''Node'''): | ||
Строка 31: | Строка 28: | ||
'''return''' x | '''return''' x | ||
</code> | </code> | ||
+ | |||
+ | В красно-черных деревьях используется такая операция как <tex>color flip</tex>, которая инвертирует цвет данного узла и двух его детей. Она не изменяет количество черых узлов на любом пути от корня до листьев, но может привести к появлению двух последовательных красных узлов. | ||
<code> | <code> |
Версия 03:20, 9 декабря 2017
Определение: |
Left-leaning Red-Black Trees— . |
Вращения
One way to view red-black BST algorithms is as maintaining the following invariant properties under insertion and deletion: Чтобы поддерживать красно-черные двоичное деревья поиска необходимо соблюдать следующие инвариантные свойства при вставке и удалении:
- Ни один путь от корня до листьев не содержит двух последовательных красных узлов.
- Количество черных узлов на каждом таком пути одинаково.
Из этих инвариантов следует, что длина каждого пути от корня до листьев в красно-черном дереве с
Node rotateRight(h : Node): x = h.left h.left= x.right x.right= h x.color = h.color h.color = RED return x
Node rotateLeft(h : Node): x = h.right h.right = x.left x.left = h x.color = h.color h.color = RED return x
В красно-черных деревьях используется такая операция как
, которая инвертирует цвет данного узла и двух его детей. Она не изменяет количество черых узлов на любом пути от корня до листьев, но может привести к появлению двух последовательных красных узлов.
void flipColors(h : Node h): h.color = !h.color h.left.color = !h.left.color h.right.color = !h.right.color
Методы
void insert( key : Key, value : Value ): root = insert(root, key, value) root.color = BLACK
Node insert( h : Node, key : Key, value : Value): if h == null return new Node(key, value) if isRed(h.left) && isRed(h.right) colorFlip(h) int cmp = key.compareTo(h.key) if cmp == 0 h.val = value else if cmp < 0 h.left = insert(h.left, key, value) else h.right = insert(h.right, key, value) if isRed(h.right) && !isRed(h.left) h = rotateLeft(h) if isRed(h.left) && isRed(h.left.left) h = rotateRight(h) return h
Value search(key : Key): Node x = root while x != null int cmp = key.compareTo(x.key) if cmp == 0 return x.val else if cmp < 0 x = x.left else if cmp > 0 x = x.right return null
Удаление
f cient implementation of the delete operation is a challenge in many symbol-table implementa- tions, and red-black trees are no exception. Industrial-strength implementations run to over 100 lines of code, and text books generally describe the operation in terms of detailed case studies, eschewing full implementations. Guibas and Sedgewick presented a delete implementation in [7], but it is not fully speci ed and depends on a call-by-reference approach not commonly found in modern code. The most popular method in common use is based on a parent pointers (see [6]), which adds substantial overhead and does not reduce the number of cases to be handled.
The code on the next page is a full implementation of
void deleteMin() root = deleteMin(root); root.color = BLACK;
Node deleteMin(h : Node) if (h.left == null) return null; if !isRed(h.left) && !isRed(h.left.left) h = moveRedLeft(h); h.left = deleteMin(h.left); return fixUp(h);
Delete-the-minimum code for LLRB 2-3 trees
void deleteMin(): root = deleteMin(root) root.color = BLACK
Node deleteMin( h : Node): if h.left == null return null if !isRed(h.left) && !isRed(h.left.left) h = moveRedLeft(h) h.left = deleteMin(h.left) return fixUp(h)
Node moveRedLeft(Node : h): colorFlip(h): if isRed(h.right.left) h.right = rotateRight(h.right) h = rotateLeft(h) colorFlip(h) return h
Node moveRedRight(h :Node ): colorFlip(h) if isRed(h.left.left)) h = rotateRight(h) colorFlip(h) return h
void delete(key : Key): root = delete(root, key) root.color = BLACK
Node delete(Node : h, Key : key): if key.compareTo(h.key) < 0) if !isRed(h.left) && !isRed(h.left.left) h = moveRedLeft(h) h.left = delete(h.left, key) else if isRed(h.left) h = rotateRight(h) if key.compareTo(h.key) == 0 && (h.right == null) return null if !isRed(h.right) && !isRed(h.right.left) h = moveRedRight(h) if key.compareTo(h.key) == 0 h.val = get(h.right, min(h.right).key) h.key = min(h.right).key h.right = deleteMin(h.right) else h.right = delete(h.right, key) return fixUp(h)