二叉搜索树
设x是二叉搜索树的一个结点,如果y是x左子树的一个结点,那么y.key≤x.key,如果y是x有字数的一个结点,那么y.key≥x.key。
二叉树有三种遍历的方法:
先序遍历:输出根的关键字在其左右子树的关键字之前。
中序遍历:输出根的关键字在其左右子树的关键字之间。
后序遍历:输出根的关键字在其左右子树的关键字之后。
主要的操作包括查找,遍历,最大最小关键字寻找,前驱后继结点查找,插入和删除。代码如下:
class Node
{
private:
int key;//值
public:
Node *left;//左子树
Node *right;//右子树
Node *parent;//父结点
int getkey();
void setkey(int k);
Node(int k = 0);
bool operator == (Node &z);
Node& operator = (Node &z);
};
//二叉搜索树
class BSTree
{
public:
Node *root;
BSTree(){
root = NULL;
}
void treeinsert(Node &root, Node &z);//插入结点
Node treesearch(Node *root, int k);//查询结点
void treewalk(Node *root);//遍历
Node treemin(Node *root);//寻找结点root下最小值结点
Node treemax(Node *root);//寻找结点root下最大值结点
Node treesuccessor(Node *x);//寻找结点x的后继结点
Node treeprodecessor(Node *x);//寻找结点x的前驱结点
void treetransplant(Node &root, Node *u, Node *v);//在根结点root下移动子树v到u
void treedelete(Node &root, Node *z);//删除结点
};
#include<iostream>
#include"BinarySearchTree.h"
using namespace std;
Node::Node(int k):key(k)
{
left = NULL;
right = NULL;
parent = NULL;
}
bool Node::operator == (Node &z)
{
if ((key == z.key)&&(left == z.left)&&(right == z.right)&&(parent == z.parent))
{
return true;
}
else{
return false;
}
}
Node& Node::operator = (Node &z)
{
delete left;
delete right;
delete parent;
left = z.left;
right = z.right;
parent = z.parent;
key = z.key;
z.left = NULL;
z.right = NULL;
z.parent = NULL;
return *this;
}
int Node::getkey()
{
return key;
}
void Node::setkey(int k)
{
key = k;
}
//查询、最大值、最小值、前驱、后继函数均可以在O(h)时间内完成,h为树的高度
Node BSTree::treesearch(Node *root, int k)//查询结点
{
//递归版本
if (k == root->getkey())
{
return *root;
}
if (k < root->getkey())
{
return treesearch(root->left, k);
}
else
{
return treesearch(root->right, k);
}
return 0;
}
void BSTree::treewalk(Node *root)//中序遍历
{
if (root != NULL)
{
treewalk(root->left);
cout << root->getkey() << " ";
treewalk(root->right);
}
}
Node BSTree::treemin(Node *root)//寻找结点root下最小值结点
{
//最左边最小
Node *x;
x = root;
while (x->left != NULL)
{
x = x->left;
}
return *x;
}
Node BSTree::treemax(Node *root)//寻找结点root下最大值结点
{
//最右边最大
Node *x;
x = root;
if (x->right != NULL)
{
return treemax(x->right);
}
return *x;
}
Node BSTree::treesuccessor(Node *x)//寻找结点x的后继结点
{
Node *y;
//如果右孩子不空,则右子树中的最小值即为后继
if (x->right != NULL){
return treemin(x->right);
}
y = x->parent;
//如果父结点也为空,无后继结点
//父结点存在时,后继结点为它的最底层祖先,并且后继结点的左结点也是它的祖先
//因此循环的终止条件为x == y->right,当x是一个左孩子时终止,x的父结点为后继结点
while (y != NULL && x == y->right)
{
x = y;
y = y->parent;
}
//y=NULL时,返回y会出错
if (y != NULL)
{
return *y;
}
return 0;
}
Node BSTree::treeprodecessor(Node *x)//寻找结点x的前驱结点
{
Node *y;
//如果左孩子存在,前驱结点为左子树中最大值
if (x->left != NULL){
return treemax(x->left);
}
y = x->parent;
//与后继结点类似,当x为右孩子时终止,x父结点为前驱结点
while (y != NULL && x == y->left)
{
x = y;
y = y->parent;
}
if (y != NULL)
{
return *y;
}
return 0;
}
void BSTree::treeinsert(Node &root, Node &z)//插入结点
{
Node *x, *y = NULL;
x = &root;
//向下寻找位置
while (x != NULL)
{
y = x;
if (z.getkey() < x->getkey())
{
x = x->left;
}
else{
x = x->right;
}
}
z.parent = y;
//判断树是否为空
if (y == NULL)
{
root = z;
}
else if (z.getkey() < y->getkey())
{
y->left = &z;
}
else{
y->right = &z;
}
}
void BSTree::treetransplant(Node &root, Node *u, Node *v)//在根结点root下移动子树v到u
{
//u为根结点
if (u->parent == NULL)
{
root = *v;
}
else if (u == u->parent->left)
{
u->parent->left = v;
}
else{
u->parent->right = v;
}
if (v != NULL)
{
v->parent = u->parent;
}
}
void BSTree::treedelete(Node &root, Node *z)//删除结点
{
Node *y=new Node;
if (z->left == NULL){
//如果左孩子为空,利用右孩子替换,右孩子为空时,相当于直接删除
treetransplant(root, z, z->right);
}
else if (z->right == NULL){
//执行此步时,一定只有左孩子,拿左孩子替换即可
treetransplant(root, z, z->left);
}
else{
//左右孩子都存在,首先需要寻找它的后继结点
y= &treemin(z->right);
if (!(*y == *z->right)){
//如果后继结点不是它的右孩子,后继结点没有左孩子,否则不是后继结点
//先拿后继结点右孩子替换后继结点,再拿后继结点替换要删除的结点
treetransplant(root, y, y->right);
//将z的右孩子换到y上,if外的语句把z的左孩子换到y上
y->right = z->right;
y->right->parent = y;
}
//如果后继结点就是它的右孩子,并且这个右孩子没有左孩子,否则不可能是后继结点,因此直接拿后继结点替换
treetransplant(root, z, y);
y->left = z->left;
y->left->parent = y;
}
}
结构上,指针、引用的应用都比较乱,只做参考。