BinarySearchTree
1、 struct
Node
代码
struct Node{
//节点的构造函数
Node(int& k, int& val): key(k), value(val), parent(NULL), left_child(NULL), right_child(NULL) { }
//成员变量声明
int key;
int value;
Node* parent;
Node* left_child;
Node* right_child;
};
内容
Node
结构体成员包括:
key
:key值value
: value值*parent
: 父节点*left_child
: 左子节点*right_child
: 右子节点
2、class
BinarySearchTree
(1) search_ptr()
函数:返回x的指针
代码
Node* BinarySearchTree::search_ptr(int k){ //返回 k 所在的指针
Node* ptr = root;
while(ptr){ //从根节点向下寻找
if(k == ptr->key) return ptr; //寻找到,返回指针
if(k < ptr->key) ptr = ptr->left_child;
if(k > ptr->key) ptr = ptr->right_child;
}
}
(2) swap()
函数:交换两个节点信息
代码
void BinarySearchTree::swap(Node*& a, Node*& b){ //交换两个节点
int temp;
temp = a->key; //交换key值
a->key = b->key;
b->key = temp;
temp = a->value; //交换value值
a->value = b->value;
b->value = temp;
}
(3) search_recursion()
函数:递归查找
代码
int BinarySearchTree::search_recursion(int& x, int k){ //递归查找
Node* xptr = search_ptr(x);
if(k == xptr->key) return xptr->value; //寻找到,返回对应的value值
else{
if(k < xptr->key && xptr->left_child != NULL){ //key值小,且仍有左子节点
x = xptr->left_child->key; //以左子节点为根向下寻找
search_recursion(x, k);
}
else if(k > xptr->key && xptr->right_child != NULL){ //key值大,且仍有右子节点
x = xptr->right_child->key; //以右子节点为根向下寻找
search_recursion(x, k);
}
else return -1; //若无对应的左右子节点,不在树中,返回-1
}
}
(4) search_iterative()
函数:迭代查找
代码
int BinarySearchTree::search_iterative(int x, int k){ //迭代查找
Node* xptr = search_ptr(x);
while(xptr){ //从x节点向下寻找
if(k == xptr->key) return xptr->value; //寻找到,返回对应的value值
if(k < xptr->key) xptr = xptr->left_child;
else if(k > xptr->key) xptr = xptr->right_child;
}
return -1; //未找到,返回-1
}
思路
两个查找的思路都是:比较key值,向下传递指针。
(5) minimum()
maximum()
函数:最小值/最大值
代码
int BinarySearchTree::minimum(int x){ //最小值
Node* xptr = search_ptr(x);
while(xptr->left_child) xptr = xptr->left_child; //不断寻找左子节点到底
return xptr->value;
}
int BinarySearchTree::maximum(int x){ //最大值
Node* xptr = search_ptr(x);
while(xptr->right_child) xptr = xptr->right_child; //不断寻找右子节点到底
return xptr->value;
}
思路
最小/最大值,从当前节点,不断向下寻找左/右子节点即可。
(6) predecessor()
successor()
函数:前驱/后继
代码
int BinarySearchTree::predecessor(int x){ //前驱
Node* xptr = search_ptr(x);
if(xptr->left_child){ //如果有左子节点
xptr = xptr->left_child; //以该点为根,寻找该点下的最大值
while(xptr->right_child) xptr = xptr->right_child; //不断寻找右子节点直至到底
}
else{ //如果没有左子节点
while(xptr->parent != NULL && xptr != xptr->parent->right_child){ //如果有父节点,且该点是其左子节点,继续往上寻找
xptr = xptr->parent;
}
xptr = xptr->parent; //前驱为当前指向点的父节点
if(!xptr) return -1; //如果为空,不存在前驱,返回-1
}
return xptr->value;
}
int BinarySearchTree::successor(int x){ //后继
Node* xptr = search_ptr(x);
if(xptr->right_child){ //如果有右子节点
xptr = xptr->right_child; //以该点为根,寻找该点下的最小值
while(xptr->left_child) xptr = xptr->left_child; //不断寻找左子节点直至到底
}
else{ //如果没有右子节点
while(xptr->parent != NULL && xptr != xptr->parent->left_child){ //如果有父节点,且该点是其右子节点,继续往上寻找
xptr = xptr->parent;
}
xptr = xptr->parent; //后继为当前指向点的父节点
if(!xptr) return -1; //如果为空,不存在后继,返回-1
}
return xptr->value;
}
思路
- 前驱:以左子节点为根,向下寻找最大值。
- 后继:以右子节点为根,向下寻找最小值。
(7) insert_x()
函数:插入
代码
void BinarySearchTree::insert_x(Node*& xptr, int k, int val){ //插入
if(!xptr){ //如果该点为空,将节点信息存入此处
xptr = new Node(k, val);
return;
}
if(k < xptr->key){ //如果小,从左子节点继续往下
if(xptr->left_child == NULL){
xptr->left_child = new Node(k, val);
xptr->left_child->parent = xptr;
return;
}
else insert_x(xptr->left_child, k, val);
}
else if(k > xptr->key){ //如果大,从右子节点继续往下
if(xptr->right_child == NULL){
xptr->right_child = new Node(k, val);
xptr->right_child->parent = xptr;
return;
}
else insert_x(xptr->right_child, k, val);
}
}
思路
从根节点开始,不断比较key值:
k
比当前点key值小,向下找左子节点k
比当前点key值大,向下找右子节点
直到找到最底,不存在对应子节点后,创建新的Node
,将信息key
value
*parent
存入。
(8) delete_x()
函数:删除
代码
void BinarySearchTree::delete_x(int k){ //删除
Node* ptr = search_ptr(k);
if(ptr->left_child && ptr->right_child){ //如果左右子节点均存在
Node* ptr1 = search_ptr(successor(k));
swap(ptr, ptr1);
ptr = ptr1;
}
else if(ptr->left_child == NULL && ptr->right_child == NULL){ //如果左右子节点都为空
Node* ptr2 = ptr->parent;
if(ptr2->left_child == ptr) ptr2->left_child = NULL;
else if(ptr2->right_child == ptr) ptr2->right_child = NULL;
delete ptr;
}
else if(!(ptr->left_child) && (ptr->right_child)){ //左为空,右非空
Node* ptr3 = ptr->parent;
ptr->right_child->parent = ptr3;
if(ptr3->left_child == ptr) ptr3->left_child = ptr->right_child;
else if(ptr3->right_child == ptr) ptr3->right_child = ptr->right_child;
delete ptr;
}
else if((ptr->left_child) && !(ptr->right_child)){ //左非空,右为空
Node* ptr4 = ptr->parent;
ptr->left_child->parent = ptr4;
if(ptr4->left_child == ptr) ptr4->left_child = ptr->left_child;
else if(ptr4->right_child == ptr) ptr4->right_child = ptr->left_child;
delete ptr;
}
return;
}
思路
讨论左右子节点空与非空共四种情况:
- 均非空: 找前驱或后继代替该点即可。
- 均为空: 只需要将父节点对应的子节点指针改为空即可。
- 左空,右非空: 将右子节点代替该点即可。
- 左非空,右空: 与上一种情况类似。
(9) traversal()
函数:遍历
代码
void BinarySearchTree::traversal_preorder(Node* ptr){ //先序:根左右
if(!ptr) return;
cout << ptr->value << " ";
traversal_preorder(ptr->left_child);
traversal_preorder(ptr->right_child);
return;
}
void BinarySearchTree::traversal_inorder(Node* ptr){ //中序:左根右
if(!ptr) return;
traversal_inorder(ptr->left_child);
cout << ptr->value << " ";
traversal_inorder(ptr->right_child);
return;
}
void BinarySearchTree::traversal_postorder(Node* ptr){ //后序:左右根
if(!ptr) return;
traversal_postorder(ptr->left_child);
traversal_postorder(ptr->right_child);
cout << ptr->value << " ";
return;
}
void BinarySearchTree::traversal(){ //遍历全树
traversal_preorder(root);
cout << endl;
traversal_inorder(root);
cout << endl;
traversal_postorder(root);
cout << endl;
}
思路
- 先序:根左右
- 中序:左根右
- 后序:左右根