二叉查找树(Binary Search Tree),又被称为二叉搜索树。设x为二叉查找树中的一个结点,x节点包含关键字key,节点x的key值记为key[x]。如果y是x的左子树中的一个结点,则key[y] <= key[x];如果y是x的右子树的一个结点,则key[y] >= key[x]。
在二叉查找树中:
(01) 若任意节点的左子树不空,则左子树上所有结点的值均小于它的根结点的值;
(02) 任意节点的右子树不空,则右子树上所有结点的值均大于它的根结点的值;
(03) 任意节点的左、右子树也分别为二叉查找树。
(04) 没有键值相等的节点(no duplicate nodes)。
在实际应用中,二叉查找树的使用比较多。下面,用C语言实现二叉查找树。
我在网上查到的一位大神写的加上我自己总结的,一起分享给大家
*二叉搜索树中的节点类
*Node.h
*/
# ifndef _NODE_
#define _NODE_
class Node
{
private:
int value;/*节点中存放的元素值*/
Node *parentNode;/*所指向的父节点指针*/
Node *leftChildNode;/*左孩子节点指针*/
Node *rightChildNode;/*右孩子节点指针*/
public:
Node(int v);/*初始化函数*/
Node* getParentNode();/*返回父节点指针*/
Node* getLeftChildNode();/*返回左孩子节点指针*/
Node* getRightChildNode();/*返回右孩子节点指针*/
int getValue();/*返回节点元素值*/
void setParentNode(Node *p);/*设定父节点指针*/
void setLeftChildNode(Node *left);/*设定左孩子节点*/
void setRightChildNode(Node *right);/*设定右孩子结点*/
void setValue(int v);/*设定节点元素值*/
};
#endif
/*
*Node.cpp
*/
#include "Node.h"
#include <cstdio> //NULL
/*初始化函数*/
Node::Node(int r)
{
setValue(r);
setParentNode(NULL);
setLeftChildNode(NULL);
setRightChildNode(NULL);
}
/*返回父节点指针*/
Node* Node::getParentNode()
{
return parentNode;
}
/*返回右孩子节点指针*/
Node* Node::getRightChildNode()
{
return rightChildNode;
}
/*返回左孩子节点指针*/
Node* Node::getLeftChildNode()
{
return leftChildNode;
}
/*返回节点元素值*/
int Node::getValue()
{
return value;
}
/*设定左孩子节点*/
void Node::setLeftChildNode(Node *left)
{
leftChildNode = left;
}
/*设定父节点指针*/
void Node::setParentNode(Node *parent)
{
parentNode = parent;
}
/*设定右孩子结点*/
void Node::setRightChildNode(Node *right)
{
rightChildNode = right;
}
/*设定节点元素值*/
void Node::setValue(int v)
{
value = v;
}
/*二叉搜索树类:
*BinarySearchTree.h
*/
#ifndef _BINARYSEARCHTREE_
#define _BINARYSEARCHTREE_
#define MAXLENGTH 100 //二叉搜索树的最大节点总数
#include "Node.h"
class BinarySearchTree
{
private:
Node *rootNode;/*根节点指针*/
public:
BinarySearchTree();/*构造函数初始化*/
void setRootNode(Node *root);/*设置根节点*/
void treeInsert(int v);/*向搜索数中添加节点*/
void levelTreeWalk(Node *start);/*层次遍历*/
void inorderTreeWalk(Node *start);/*中序遍历*/
void preorderTreeWalk(Node *start);/*先序遍历*/
void postorderTreeWalk(Node *start);/*后序遍历*/
void transplant(Node *u,Node *v);/*将节点v替换到u的位置,并且相应子树进行转换*/
bool deleteNode(Node *point);/*从搜索树中删除节点point*/
bool max(int x,int y);/*比较两个整型元素值大小,x<y返回false*/
int getNodeNumber(Node *start);/*得到以start为根的树的节点总数*/
int getTreeHeight();/*计算二叉搜索树的高度*/
int getNodeHeight(Node *start);/*计算节点start的高度*/
Node* getRootNode();/*得到根节点指针*/
Node* getMinimum(Node *start);/*得到以start节点为根的搜索数中的具有最小元素值的节点*/
Node* treeMax(Node *start);//递归版本的得到具有最大元素值的节点
Node* getMaximum(Node *start);/*得到以start为根节点的搜索数中的具有最大元素值的节点*/
Node* getTreeSuccessor(Node *start);/*得到节点start的后继节点*/
Node* getTreePredessor(Node *start);/*得到start的前驱节点*/
Node* treeSearch2(Node *start,int k);/*迭代版本*/
Node* treeSearch1(Node *start,int k);/*搜索数的查找,如果k存在于搜索树中,
(从树根开始查找,)则返回给节点,否则返回null*/
};
#endif
/*
*BinarySearchTree.cpp
*/
#include "BinarySearchTree.h"
#include <cstdio>
#include <iostream>
using namespace std;
/*构造函数初始化*/
BinarySearchTree::BinarySearchTree()
{
setRootNode(NULL);
}
/*得到根节点指针*/
Node* BinarySearchTree::getRootNode()
{
return rootNode;
}
/*设置根节点*/
void BinarySearchTree::setRootNode(Node *root)
{
rootNode = root;
}
/*向搜索数中添加节点,输入是新的节点元素值*/
void BinarySearchTree::treeInsert(int v)
{
/*新的插入的节点*/
Node *newInsertNode = new Node(v);
Node *y = NULL;
Node *x = getRootNode();//得到根节点
/*通过while循环中元素比较得到新的节点的合适位置*/
while(x!=NULL)
{
y = x;
if(v < x->getValue()) /*二叉搜索树的性质:x.left.value<x.value;*/
x = x->getLeftChildNode();
else /*x.right.value>=x.values*/
x = x->getRightChildNode();
}
//y = newInsertNode;
if(y == NULL)//二叉搜索树为空的情况
setRootNode(newInsertNode);
else if(v < y->getValue())
{
y->setLeftChildNode(newInsertNode);
newInsertNode->setParentNode(y);
}
else
{
y->setRightChildNode(newInsertNode);
newInsertNode->setParentNode(y);
}
}
/*从搜索树中删除节点point,如果删除成功,返回true,
如果是空子树,返回false*/
/*1、point没有左右子孩子,直接删除point
*2、point没有左孩子的情况,直接删除point并把右孩子放到原来point位置
上面两种情况可以归为一类情况:没有左孩子,将右孩子放到point位置
3、只有左孩子情况,把左孩子放到point位置,删除point
4、左右孩子都有的情况:查找point节点的后继节点successor
1、如果successor为point右孩子(既然为point右孩子,则successsor没有左孩子)
将point左孩子作为successor左孩子,successor替换point,删除point节点
2、如果successor不是point的右孩子(是以point右孩子为根节点的子树最小值所在节点
且没有左孩子)将successor右节点sright作为successor所在子树根节点,并将point
右孩子节点pright作为successor右节点,successor左孩子节点pleft作为successor
左孩子节点,删除point,,,
*/
bool BinarySearchTree::deleteNode(Node *point)
{
/*搜索树为空或point为空时进行的操作*/
if(point == NULL || getRootNode() == NULL)
return false;
/*如果节点point不再搜索树中*/
if(treeSearch1(getRootNode(),point->getValue()) == NULL)
return false;
/*下面的就是讨论的三种情况:*************************/
/*1、point的左孩子节点为空*/
if(point->getLeftChildNode() == NULL)
transplant(point,point->getRightChildNode());
/*2、point的右孩子节点为空*/
else if(point->getRightChildNode() == NULL)
transplant(point,point->getLeftChildNode());
/*3、point的左右孩子节点均不为空*/
else
{
/*得到point的后继节点*/
Node *successor = getMinimum(point->getRightChildNode());
/*当successor不为point的右孩子节点时进行的操作*/
if(successor->getParentNode() != point)
{
transplant(successor,successor->getRightChildNode());
successor->setRightChildNode(point->getRightChildNode());
successor->getRightChildNode()->setParentNode(successor);
}
transplant(point,successor);
successor->setLeftChildNode(point->getLeftChildNode());
successor->getLeftChildNode()->setParentNode(successor);
}
delete point;
return true;
}
/*此时u节点右节点为空,v节点左孩子为空,将u的左孩子节点放到v的左孩子节点处
并把u的父节点作为v的父节点,即删除u节点
此函数的作用是将u的父节点作为v的父节点,v作为u的父节点的原u位置相应子节点
v可以为空节点,也可以不是,对于u的左孩子节点的处理,由这个函数的调用者进行
处理
*/
void BinarySearchTree::transplant(Node *u,Node *v)
{
if(u->getParentNode() == NULL)
setRootNode(v);
else if(u == u->getParentNode()->getLeftChildNode())
u->getParentNode()->setLeftChildNode(v);
else
u->getParentNode()->setRightChildNode(v);
if(v != NULL)
v->setParentNode(u->getParentNode());
}
/*得到以start节点为根的搜索数中的具有最小元素值的节点*/
/*while迭代版本:*/
Node* BinarySearchTree::getMinimum(Node *start)
{
Node *minNode = start;
if(minNode == NULL)//空树的情况
return minNode;
while(minNode->getLeftChildNode() != NULL)
{
minNode = minNode->getLeftChildNode();
}
return minNode;
}
/*得到以start为根节点的搜索数中的具有最大元素值的节点*/
/*递归版本:*/
Node* BinarySearchTree::getMaximum(Node *start)
{
return treeMax(start);
}
Node* BinarySearchTree::treeMax(Node *start)
{
if(start == NULL)
return NULL;
else if(start->getRightChildNode() == NULL)
return start;
else
return treeMax(start->getRightChildNode());
}
/*得到以start为根的树的节点总数*/
int BinarySearchTree::getNodeNumber(Node *start)
{
if(start == NULL)
return 0;
if(start->getLeftChildNode() ==NULL)
return getNodeNumber(start->getRightChildNode()) + 1;
if(start->getRightChildNode() == NULL)
return getNodeNumber(start->getLeftChildNode()) + 1;
return getNodeNumber(start->getLeftChildNode()) +
getNodeNumber(start->getRightChildNode()) + 1;
}
/*层次遍历*/
void BinarySearchTree::levelTreeWalk(Node *start)
{
if(start == NULL)
{
cout << "这是一个空子树," << endl;
return;
}
/*定义一个数组来存放层次遍历过程中的节点指针,最大为MAXLENGTH*/
Node *B[MAXLENGTH + 1];
B[1] = start;/*根节点放到B[1]处*/
int nodeNumber = getNodeNumber(start);/*树中节点个数*/
int counter = 1;//已经放到数组B中的节点个数
int k = 1;/*在之后的每次循环中,counter之前有k个节点需要得到子节点放入数组B*/
int m,i;//寄存器值
while(counter < nodeNumber)
{
m = 0;
/*循环得到counter之前的k个节点它们的子节点*/
for(i = 1;i <= k;i ++)//k其实就是每一层中的节点个数
{
if(B[counter-k+i]->getLeftChildNode() != NULL)
{
m ++;
B[counter + m] = B[counter-k+i]->getLeftChildNode();
}
if(B[counter-k+i]->getRightChildNode() != NULL)
{
m ++;
B[counter + m] = B[counter-k+i]->getRightChildNode();
}
}
k = m;
counter = counter + k;
}
for(i = 1;i <= nodeNumber;i++)
cout << B[i]->getValue() << " ";
}
/*中序遍历:<<<<左根右>>>>*/
void BinarySearchTree::inorderTreeWalk(Node *start)
{
if(start != NULL)
{
inorderTreeWalk(start->getLeftChildNode());
cout << start->getValue() << " ";
inorderTreeWalk(start->getRightChildNode());
}
}
/*先序遍历:<<<<根左右>>>>*/
void BinarySearchTree::preorderTreeWalk(Node *start)
{
if(start != NULL)
{
cout << start->getValue() << " ";
preorderTreeWalk(start->getLeftChildNode());
preorderTreeWalk(start->getRightChildNode());
}
}
/*后序遍历:<<<<左右根>>>>*/
void BinarySearchTree::postorderTreeWalk(Node *start)
{
if(start != NULL)
{
preorderTreeWalk(start->getLeftChildNode());
preorderTreeWalk(start->getRightChildNode());
cout << start->getValue() << " ";
}
}
/*计算二叉搜索树的高度*/
int BinarySearchTree::getTreeHeight()
{
return getNodeHeight(getRootNode()) - 1;
}
/*计算节点start的高度*/
int BinarySearchTree::getNodeHeight(Node *start)
{
if(start == NULL)
return 0;
int leftChildLength = getNodeHeight(start->getLeftChildNode());
int rightChildLength = getNodeHeight(start->getRightChildNode());
/*这两个判断语句是把递归进行到二叉树的叶子节点进行判断并把
叶子节点的高度(本来为0)加一*/
if(max(leftChildLength,rightChildLength))
return leftChildLength + 1;
else
return rightChildLength + 1;
}
/*比较两个整型元素值大小,x<y返回false,x>=y返回true*/
bool BinarySearchTree::max(int x,int y)
{
if(x >= y)
return true;
else
return false;
}
/*得到节点start的后继节点,如果后继节点存在,则返回,
如果后继节点为自身,则返回null*/
Node* BinarySearchTree::getTreeSuccessor(Node *start)
{
if(start->getRightChildNode() != NULL)
return getMinimum(start->getRightChildNode());
Node *y = start->getParentNode();//叶子节点的情况
/*仍是二叉搜索树的性质决定*/
while(y != NULL && start == y->getRightChildNode ())
{
start = y;
y = y->getParentNode();
}
return y;
}
/*得到start的前驱节点如果前驱节点存在,则返回,如果前驱节点
为自身,则返回null*/
Node* BinarySearchTree::getTreePredessor(Node *start)
{
if(start->getLeftChildNode() != NULL)
return getMaximum(start->getLeftChildNode());
Node *y = start->getParentNode();
while(y != NULL && start == y->getRightChildNode())
{
start = y;
y = y->getParentNode();
}
return y;
}
/*搜索数的查找,如果k存在于搜索树中,则返回给节点,否则返回null*/
Node* BinarySearchTree::treeSearch1(Node *start,int k)
{
Node *temp = start;
if(temp == NULL || k == temp->getValue())
return temp;
if(k < start->getValue())
return treeSearch1(temp->getLeftChildNode(),k);
else
return treeSearch1(temp->getRightChildNode(),k);
}
/*搜索的while迭代版本*/
Node* BinarySearchTree::treeSearch2(Node *start,int k)
{
Node *temp = start;
while(temp != NULL && k != temp->getValue())
{
if(k < temp->getValue())
temp = temp->getLeftChildNode();
else
temp = temp->getRightChildNode();
}
return temp;
}