Deletion in Binary Search Tree
方針
二分探索木からあるノードを削除したい場合、下記の3つのパターンに分けて考えます。
- 削除対象のノードが子を持たない
- 削除対象のノードが1つの子を持つ
- 削除対象のノードが2つの子を持つ
1の場合は単純に削除対象のノードをnullで置き換えればよく、2の場合は削除対象のノードをその子で置き換えてやればよいです。3の場合は処理がやや複雑になり、削除対象のノードを中間順配列(in-order)で次に来るノード(successor)の値で上書きした上で、元のsuccessorを削除する必要があります。具体的な実装例を下記に示します。
実装例
# 二分木のノードを表すクラス
class TreeNode:
def __init__(self, x):
self.val = x
self.left = None
self.right = None
# 二分探索木rootからkeyの値を持つノードを削除する
def deleteNode(self, root, key):
if root is None:
return None
if key < root.val:
# 削除対象が自身より小さければ、左部分木から削除する
root.left = self.deleteNode(root.left, key)
elif key > root.val:
# 削除対象が自身より大きければ、右部分木から削除する
root.right = self.deleteNode(root.right, key)
# 削除対象が自身と等しければ、自身を削除する
else:
# 子を持たない場合、自身をnullで置き換える
if root.left is None and root.right is None:
root = None
# 1つの子を持つ場合、自身をその子で置き換える
elif root.left is None or root.right is None:
root = root.left or root.right
else:
# 2つの子を持つ場合、自身をそのsuccessorの値で上書きし、元のsuccessorを削除する
root.val = self.successor(root)
root.right = self.deleteNode(root.right, root.val)
return root
# nodeの右部分木からsuccessorの値を返す
def successor(self, node):
node = node.right
while node.left:
node = node.left
return node.val
補足
中間順配列(in-order)における自身のsuccessorは、自身が右部分木を持つ場合は必ずその右部分木内に存在します。実装例内のsuccessorメソッドは、引数のnodeが右部分木を持つ場合にのみ使われることを想定しています。
参考