Yellowpython 2019-06-26
二叉查找树或者是一棵空树,或者是具有下列性质的二叉树: 若它的左子树不空,则左子树上所有结点的值均小于它的根结点的值; 若它的右子树不空,则右子树上所有结点的值均大于它的根结点的值; 它的左、右子树也分别为二叉排序树。
二叉搜索树不一定是完全二叉树,因此不能像堆一样可以数组表示。
定义一个TNode类来实例化节点,有key,value,l_child,r_child属性。其中key,value通过构造函数传入,l_child,r_child初始化为None。
再定义一个BSTree类,根节点初始化为None。
然后给BSTree添加以下方法:
insert(key,value) 插入一个节点
update(key,value) 更新节点的值
search(key) 通过key来找相应节点的value
remove(key) 通过key来删除树中相应节点
以及深度优先和广度优先的遍历方法。
insert:
传入参数key,value,插入一个新的节点。但是如果树中已经存在key为key的节点,就将插入操作转变为更新操作。
def __insert(self, key, value, curr_node): if curr_node is None: return TNode(key, value) if key < curr_node.key: curr_node.l_child = self.__insert(key, value, curr_node.l_child) elif key > curr_node.key: curr_node.r_child = self.__insert(key, value, curr_node.r_child) else: curr_node.value = value return curr_node
当当前的节点为None时,根据参数中的key和value建立新的节点,并返回这个节点。当key值小于当前节点的key时,将新节点插入到当前节点的左子树的相应位置,然后返回当前节点。同理key值大于当前节点的key时,将新节点插入到当前节点的右子树的相应位置,返回当前节点。如果key等于当前节点key,将插入操作改变为更新操作。
search:
def __search(self, node, key): if node: if node.key == key: return node elif node.key > key: return self.__search(node.l_child, key) else: return self.__search(node.r_child, key) return False
在当前node为根节点的子树中,查找key为key的子节点,如果当前node的key值与参数相同,返回当前节点。否则递归地到左右子树中找key为key的节点,如果没有找到,最终返回False。
update:
def __update(self, key, value, node): if node: if node.key == key: node.value = value elif node.key > key: self.__update(key, value, node.l_child) else: self.__update(key, value, node.r_child)
在当前node为根节点的子树中,查找key为key的节点。如果当前node的key值与参数相同,更新当前节点的value。否则递归地到左右子树中找到key为key的节点,并更新value。
remove:
执行remove操作时,分为两种情况。
1.当前要删除的节点没有右子节点,此时将左子节点作为当前节点,返回。
2.当前要删除的节点(node_to_delete)有右子节点(r_child),找到右子节点下,最小的节点(r_child_smallest_child),将该节点与要删除的节点换位置。具体操作为:先拿到r_child_smallest_child,再将该节点从以r_child为根的子树中删除。再将node_to_delete的左孩子作为r_child_smallest_child的左孩子,node_to_delete的右孩子作为r_child_smallest_child的右孩子。最终将r_child_smallest_child赋给node_to_delete,并返回。
代码如下:
def __remove(self, node, key): if node: if node.key < key: node.r_child = self.__remove(node.r_child, key) elif node.key > key: node.l_child = self.__remove(node.l_child, key) else: if node.r_child is None: node = node.l_child else: node_r_child_smallest_child = self.__get_smallest_child(node.r_child) self.__remove_smallest(node.r_child) node_r_child_smallest_child.r_child = node.r_child node_r_child_smallest_child.l_child = node.l_child node = node_r_child_smallest_child return node return False
其中__remove_smallest和__get_smallest_child含义分别是:删除当前节点下,最小的节点,以及获得当前节点下最小的节点。
代码如下:
def __remove_smallest(self, node): if node.l_child: node.l_child = self.__remove_smallest(node.l_child) return node return node.r_child
当当前节点有左孩子时,删除左子树中最小的节点,并且返回当前节点。没有左孩子时,返回右孩子。
def __get_smallest_child(self, node): if node.l_child: return self.__get_smallest_child(node.l_child) return node
当当前节点有左孩子时,获得左子树中最小的节点。没有左孩子时,返回当前节点。
深度优先遍历,可以选择先序遍历,中序遍历,后续遍历,以其中之一为例:
def __l_m_r(self, node): if node: self.__l_m_r(node.l_child) print(node) self.__l_m_r(node.r_child)
当进行广度优先遍历时,需要用到队列。
def bfs(self): queue = deque() queue.append(self.root) while queue: node = queue.popleft() if node: l_child = node.l_child r_child = node.r_child print(node.value) queue.append(l_child) queue.append(r_child)
以上是我所了解的二叉搜索树的基本功能