《算法之美》---二叉搜索树

二叉排序树又叫二叉搜索树、二元查找树,它或者是一棵空树;或者是具有下列性质的二叉树:

1)每个节点有一个关键值,并且没有任意两个元素有相同的关键值;因此,所有关键值都是唯一的;

2)若它的左子树不空,则左子树上所有节点的值均小于它的根节点的值;

3)若它的右子树不空,则右子树上所有节点的值均大于它的根节点的值;

4 )它的左右子树也分别是二叉排序树。

二叉排序树是一种动态树表,其特点是:树的结构通常不是一次生成的,而是在查找过程中,当树中不存在关键字等于给定值的节点时再进行插入。新插入的节点一定是一个新添加的叶子节点,并且是查找不成功时查找路径上访问的最后一个节点的左孩子或右孩子节点。

中序遍历二叉排序树可得到一个关键字的有序序列,即一个无序序列可以通过构造一棵二叉排序树而变成一个有序序列,构造树的过程即为对无序序列进行排序的过程。而且每次插入的新节点都是二叉排序树上的新的叶子节点,则在进行插入操作时,不必移动其他节点,仅需改动某个节点的指针,由空变非空即可。这就相当于在一个有序序列上插入一个记录而不需要移动其他记录。这表明二叉排序树既拥有类似于折半查找的特性,又采用了链表做存储结构,因此是动态查找表的一种合适的表示。

这里重点说一下二叉排序树的删除操作,考虑包含要删除元素的节点p的三种情况:1p是树叶;2p只有一个非空子树;3p有两个非空子树。

1p是树叶:可以用丢弃树叶节点的方法来处理,即只有把其父节点指向它的指针域置空,然后删除该节点即可;

2p只有一个非空子树:如果p没有父节点(即p是根节点),则将p丢弃,p的唯一子树的根节点作为新的搜索树的根节点;如果p有父节点pp,则修改pp的指针,使pp指向p的唯一孩子,然后删除节点p

3p有两个非空子树:只需将要删除的元素替换成它的左子树中的最大元素或右子树中的最小元素。

注意:必须保证右子树的最小元素和左子树的最大元素既不会在没有子树的节点中,也不会在只有一个子树的节点中。可以按下述方法来查找到左子树中的最大元素:首先移动到子树的根,然后沿着各节点的右孩子指针移动,直到右孩子指针为0为止。

二叉排序树的一种实现代码如下:

二叉排序树的定义和实现都放在头文件BSTree.h中,因为C++编译器不支持对模板的分离式编译:

========================BSTree.h==========================

template<typename T> class BSTree;

template<typename T> struct TNode

{

private:

TNode<T> *left; //左子树指针

TNode<T> *right; //右子树指针

public:

friend class BSTree<T>;

T data; //数据域

//构造函数

TNode():left(NULL),right(NULL){}

TNode(T item, TNode<T> *left1, TNode<T> *right1)

: data(item), left(left1), right(right1)

{}

};

template<typename T> class BSTree //二叉搜索树类类模板定义

{

private:

int size;

public:

//构造函数,把树根指针置空

BSTree(TNode<T> *&root){root = NULL; size = 0;}

//ClearBST()所调用的函数

void DeleteTree(TNode<T> *&root);

//释放空间

void FreeBST(TNode<T> *&root);

//求二叉搜索树中所有节点数

int BSTSize();

//判断二叉搜索树是否为空

int BSTEmpty(TNode<T> *&root);

//取根指针

TNode<T> *GetRoot(TNode<T> *&root);

//从二叉搜索树中查找元素

TNode<T> *BSTLocate(TNode<T> *&root, T item);

//向二叉搜索树中插入元素

void BSTInsert(TNode<T> *&root, T item);

//从二叉搜索树中删除元素

void BSTDelete(TNode<T> *&root, T item);

//中序遍历输出二叉搜索树中的所有节点

void InOrder(TNode<T> *&root);

//求二叉搜索树的深度

int BSTreeDepth(TNode<T> *&root);

//求二叉搜索树中所有节点数

int BSTreeCount(TNode<T> *&root);

//求二叉搜索树中所有叶子节点数

int BSTreeLeafCount(TNode<T> *&root);

//清除二叉搜索树,使之变成一棵空树

void ClearBSTree(TNode<T> *&root);

};

template<typename T>

void BSTree<T>::DeleteTree(TNode<T> *&root)

{

if(root == NULL)

return;

if(root->left != NULL)

DeleteTree(root->left);

if(root->right != NULL)

DeleteTree(root->right);

free(root); //注意要释放root

}

template<typename T>

void BSTree<T>::FreeBST(TNode<T> *&root)

{

DeleteTree(root);

}

template<typename T>

int BSTree<T>::BSTSize()

{

return size;

}

template<typename T>

int BSTree<T>::BSTEmpty(TNode<T> *&root)

{

if(root == NULL)

return 1;

else

return 0;

}

template<typename T>

TNode<T>* BSTree<T>::GetRoot(TNode<T> *&root)

{

return root;

}

template<typename T>

TNode<T>* BSTree<T>::BSTLocate(TNode<T> *&root, T item)

{

TNode<T>* tmp;

tmp = root;

while(tmp != NULL)

{

if(item == tmp->data)

break;

else

{

if(item < tmp->data)

tmp = tmp->left;

else

tmp = tmp->right;

}

}

return tmp;

}

template<typename T>

void BSTree<T>::BSTInsert(TNode<T> *&root, T item)

{

TNode<T> *tmp, *p, *newNode;

newNode = new TNode<T>;

newNode->data = item;

if(root == NULL) //树是空的

{

root = newNode;

size++;

return;

}

tmp = root;

p = NULL;

while(tmp != NULL)

{

p = tmp;

if(item < tmp->data)

tmp = tmp->left;

else

tmp = tmp->right;

}

if(item < p->data)

p->left = newNode;

else

p->right = newNode;

size++;

}

template<typename T>

void BSTree<T>::BSTDelete(TNode<T> *&root, T item)

{

TNode<T> *tmp, *p, *r, *pr;

tmp = root;

p = NULL;

while(tmp != NULL) //查找要删除元素所在节点

{

if(item == tmp->data)

break;

else

{

p = tmp;

if(item < tmp->data)

tmp = tmp->left;

else

tmp = tmp->right;

}

}

if(tmp == NULL)

return;

if(tmp->left == NULL) //左子树为空,注意tmp是要删除的元素所在节点

{

if(p == NULL) //tmp的父节点p为空,即tmp是根节点

root = tmp->right;

else if(p->left == tmp) //tmp是父节点p的左子树

p->left = tmp->right; //tmp的父节点p指向tmp的指针改为指向tmp唯一的右子树

else //tmp是父节点的右子树

p->right = tmp->right; //tmp父节点p指向tmp的指针改为指向tmp唯一的右子树

free(tmp); //删除tmp节点

}

else //tmp左子树不为空,这里使用左子树的最大元素来替换tmp

{

pr = tmp;

r = tmp->left; //rtmp的右子树的根

while(r->right != NULL) //查找tmp左子树最大元素,放在r中,prr的父节点

{

pr = r;

r = r->right;

}

tmp->data = r->data; //tmp中的值替换为右子树最大值

if(pr == tmp)

pr->left = r->left;

else

pr->right = r->left;

free(r);

}

size--;

}

template<typename T>

void BSTree<T>::InOrder(TNode<T> *&root)

{

if(root != NULL)

{

InOrder(root->left);

std::cout<<root->data<<" ";

InOrder(root->right);

}

}

template<typename T>

int BSTree<T>::BSTreeDepth(TNode<T> *&root)

{

if(root == NULL)

return 0;

//计算左子树深度

int dpt1 = BSTreeDepth(root->left);

//计算右子树深度

int dpt2 = BSTreeDepth(root->right);

//返回树的深度

if(dpt1 > dpt2)

return dpt1+1;

else

return dpt2+1;

}

template<typename T>

int BSTree<T>::BSTreeCount(TNode<T> *&root)

{

if(root == NULL)

return 0;

else

return (BSTreeCount(root->left) + BSTreeCount(root->right) + 1);

}

template<typename T>

int BSTree<T>::BSTreeLeafCount(TNode<T> *&root)

{

if(root == NULL)

return 0;

else

{

if(root->left == NULL && root->right == NULL)

return 1;

else

{

BSTreeLeafCount(root->left) + BSTreeLeafCount(root->right);

}

}

}

template<typename T>

void BSTree<T>::ClearBSTree(TNode<T> *&root)

{

DeleteTree(root);

root = NULL;

size = 0;

}

=======================测试代码TestCase.cpp====================

#include <iostream>

#include <iomanip.h>

#include <stdlib.h>

#include <conio.h>

#include "BSTree.h"

int main()

{

TNode<char> *q;

std::cout<<"运行结果:"<<std::endl;

char data[50] = "abxycdMNefgzkl";

BSTree<char> tree(q);

for(int i=0; data[i] != '/0'; i++)

{

tree.BSTInsert(q, data[i]);

}

std::cout<<"中序遍历二叉搜索树:"<<std::endl;

tree.InOrder(q);

std::cout<<"二叉搜索树的节点数=="<<tree.BSTSize()<<std::endl;

std::cout<<"二叉搜索树的节点数=="<<tree.BSTreeCount(q)<<std::endl;

std::cout<<"二叉搜索树的深度=="<<tree.BSTreeDepth(q)<<std::endl;

std::cout<<"二叉搜索树的叶子节点数=="<<tree.BSTreeLeafCount(q)<<std::endl;

std::cout<<"Press any key and delete 'd'"<<std::endl;

getch();

tree.BSTDelete(q, 'd');

std::cout<<"中序遍历二叉搜索树:"<<std::endl;

tree.InOrder(q);

std::cout<<"二叉搜索树的节点数=="<<tree.BSTSize()<<std::endl;

std::cout<<"二叉搜索树的节点数=="<<tree.BSTreeCount(q)<<std::endl;

std::cout<<"二叉搜索树的深度=="<<tree.BSTreeDepth(q)<<std::endl;

std::cout<<"二叉搜索树的叶子节点数=="<<tree.BSTreeLeafCount(q)<<std::endl;

getch();

tree.FreeBST(q);

system("pause");

return 0;

}

你可能感兴趣的:(算法)