二叉搜索树
注:通过单向指针构建的数据结构(单链表,二叉树等),在各种操作的时候,一般遵循下述模式:
1、寻找到待处理节点的前驱 以及该节点的指针
2、处理待处理节点(处理过程可能会比较复杂,譬如:二叉搜索树的删除操作)
注2:仅做记录之用,比较有意思的就是,该实现中,对二叉搜索树最复杂的节点删除操作,进行了分解。将其分解为了节点的卸载操作unstall,以及节点的安装操作install。这样虽然代码看上去很繁杂,但是理解这个删除构成会更加清晰的。
binarySearchTree.h
#ifndef BINARY_SEARCH_TREE
#define BINARY_SEARCH_TREE
#include<iostream>
using namespace std;
struct treeNode{
int key;
treeNode* left;
treeNode* right;
treeNode* parent;
};
class binarySearchTree{
public:
treeNode* root; //树根节点,该节点为空的时候,表示树为空
binarySearchTree() : root(0) {} //默认初始化
void inOrderTreeWalk(treeNode* node); //以node节点为根,开始中序遍历
void preOrderTreeWalk(treeNode* node);
void postOrderTreeWalk(treeNode* node);
//在以node为根的树上查找关键字为serachedKey的节点,如果不存在则返回nil指针。
treeNode* treeSearch(treeNode* node, int searchedKey);
treeNode* treeMinimum(treeNode* node); //返回以node为根的树上关键字最小的节点,如果是空树,则返回nil
treeNode* treeMaximum(treeNode* node);
treeNode* treeSuccessor(treeNode* node); //返回node节点的后继
treeNode* treePredecessor(treeNode* node);
void treeInsert(treeNode* node); //将node节点插入树中
void treeDelete(treeNode* node); //将node节点从树中删除
private:
//用于遍历操作中处理节点
void printNode(treeNode* node) { cout << node->key <<" ";}
//将child子树链接到parent节点,flag <= 0, 做为左孩子链接;
//falg > 0, 做为右孩子链接
void install(treeNode* child, treeNode* parent, int flag);
//将child孩子节点从parent上卸载下来
void uninstall(treeNode* child, treeNode* parent);
};
#endif
binarySearchTree.cpp
#include "binarySearchTree.h"
#include<iostream>
using namespace std;
void binarySearchTree::inOrderTreeWalk(treeNode* node)
{
if(node != 0)
{
inOrderTreeWalk(node->left);
printNode(node);
inOrderTreeWalk(node->right);
}
}
void binarySearchTree::preOrderTreeWalk(treeNode* node)
{
if(node != 0)
{
printNode(node);
preOrderTreeWalk(node->left);
preOrderTreeWalk(node->right);
}
}
void binarySearchTree::postOrderTreeWalk(treeNode* node)
{
if(node != 0)
{
postOrderTreeWalk(node->left);
postOrderTreeWalk(node->right);
printNode(node);
}
}
treeNode* binarySearchTree::treeSearch(treeNode* node, int searchedKey)
{
/*
在以node为根节点的树中,查找关键字为searchedKey的节点
如果存在,返回指向该节点的指针
否则返回空指针
*/
if(node == 0)
return 0;
if(node->key == searchedKey)
return node;
else if(searchedKey < node->key)
return treeSearch(node->left, searchedKey);
else
return treeSearch(node->right, searchedKey);
}
treeNode* binarySearchTree::treeMinimum(treeNode* node)
{
/*
返回以node为根节点的树上的最小节点的指针,
如果是空树,返回空指针
*/
if(node == 0)
return 0;
while(node->left != 0)
node = node->left;
return node;
}
treeNode* binarySearchTree::treeMaximum(treeNode* node)
{
if(node == 0)
return 0;
while(node -> right != 0)
node = node->right;
return node;
}
treeNode* binarySearchTree::treeSuccessor(treeNode* node)
{
/*
树根节点为binarySearchTree::root
输出节点node的后继节点指针,
如果没有的话,则输出空指针
如果node节点有右孩子,那么其后继就是其右子树上的最小节点
如果node节点没有右孩子,那么往回找,找到第一个往右走的节点。
如果找到根都没有遭遇的话,说明该节点没有后继,输出0
*/
if(node->right != 0)
return treeMaximum(node->right);
auto nodeP = node->parent;
while(nodeP != 0 && node == nodeP->right)
{
node = nodeP;
nodeP = node->parent;
}
return nodeP;
}
treeNode* binarySearchTree::treePredecessor(treeNode* node)
{
/*1、如果node有左孩子,那么其前驱就是其左孩子的最大节点
2、如果node没有做孩子,那么就往回找,找到第一个向左拐的位置
3、如果找到根都没有左拐的话,那么说明没有前驱,输出0
*/
if(node->left != 0)
return treeMinimum(node->left);
auto nodeP = node->parent;
while(nodeP != 0 && node == nodeP->left)
{
node = nodeP;
nodeP = node->parent;
}
return nodeP;
}
void binarySearchTree::treeInsert(treeNode* node)
{
/*
将node指向的节点插入二叉树中。
找到插入位置——————即找到插入位置的父节点
*/
if(root == 0)
{
root = node;
return;
}
auto prev = root;
auto cur = root;
if(node -> key < root->key)
{ cur = root->left; }
else
{ cur = root->right; }
while(cur != 0)
{
if(node -> key < cur->key)
{
prev = cur;
cur = prev->left;
}
else
{
prev = cur;
cur = prev->right;
}
}
if(node->key < prev->key)
{
prev->left = node;
node->parent = prev;
}
else
{
prev->right = node;
node->parent = prev;
}
}
void binarySearchTree::treeDelete(treeNode* node)
{
/*
下述代码还是太繁杂了,需要再次抽象,简化代码。
*/
if(node->left == 0 && node->right == 0)
{//node没有孩子节点
if(node->parent != 0) //node不是根节点
uninstall(node, node->parent);
else
root = 0;
}
else if(node->left != 0 && node->right == 0)
{//node只有左孩子节点
if(node->parent != 0)
{
auto p = node->parent;
auto l = node->left;
uninstall(node, node->parent);
uninstall(node->left, node);
install(l, p, 0);
}
else
root = node->left;
}
else if(node->left == 0 && node->right != 0)
{//node只有右孩子节点
if(node->parent != 0)
{
auto p = node->parent;
auto r = node->right;
uninstall(node, node->parent);
uninstall(node->right, node);
install(r, p, 1);
}
else
root = node->right;
}
else //node->left != 0 && node->right != 0
{//node有两个孩子节点:找后继节点,根据后继节点是不是node的孩子节点,有不同的卸载与安装步骤
auto succ = treeMinimum(node->right);
if(succ == node->right)
{ //后继节点是node的右孩子
if(node->parent != 0)
{
int flag;
if(node = node->parent->left)
flag = 0;
else
flag = 1;
auto p = node->parent;
auto l = node->left;
auto r = node->right;
uninstall(node, p);
uninstall(l, node);
uninstall(r, node);
install(l, r, 0);
install(r, p, flag);
}
else
{
auto l = node->left;
auto r = node->right;
uninstall(l, node);
uninstall(r, node);
install(l, r, 0);
root = r;
}
}
else
{
if(node->parent != 0)
{
int flag;
if(node = node->parent->left)
flag = 0;
else
flag = 1;
auto p = node->parent;
auto l = node->left;
auto r = node->right;
auto succR = succ->right;
auto succP = succ->parent;
uninstall(node, node->parent);
uninstall(l, node);
uninstall(r, node);
uninstall(succ, succ->parent);
uninstall(succR, succ);
install(succR, r, 0);
install(l, succ, 0);
install(r, succ, 1);
install(succ, p, flag);
}
else
{
auto l = node->left;
auto r = node->right;
auto succR = succ->right;
auto succP = succ->parent;
uninstall(l, node);
uninstall(r, node);
uninstall(succ, succ->parent);
uninstall(succR, succ);
install(succR, r, 0);
install(l, succ, 0);
install(r, succ, 1);
root = succ;
}
}
}
}
void binarySearchTree::install(treeNode* child, treeNode* p, int flag)
{
/*
将child子树链接到p节点上,flag <= 0, 左孩子;
flag > 0, 右孩子。
p不会为空节点
child可能是空节点
将child安装到p节点后,其原先的孩子节点信息丢失
*/
if(flag <= 0)
{
p->left = child;
if(child != 0) child->parent = p;
}
else
{
p->right = child;
if(child != 0) child->parent = p;
}
}
void binarySearchTree::uninstall(treeNode* child, treeNode* p)
{
//child一定是p的孩子节点
if(child == p->left)
p->left = 0;
else
p->right = 0;
}