一、基本概念
1、二叉搜索树概念
二叉搜索树:又称二叉排序树,它或者是一棵空树,或者是具有以下性质的二叉树
(1)若它的左子树不为空,则左子树上所有节点的值都小于根节点的值
(2)若它的右子树不为空,则右子树上所有节点的值都大于根节点的值
(3)它的左右子树也分别为二叉搜索树
2、形式
二、操作
(一)插入
1、若二叉树为空——>直接插入
2、不为空
(1)找插入结点的位置
(2)插入结点
注:新插入的结点为叶子结点,若插入的结点在树中已经存在,则插入失败
程序算法如下所示:
bool Insert(const K& key, const V& value)
{
pNode pCur = _pRoot;
pNode pParent = NULL;
pNode pNewNode = new Node(key, value);
//空树--直接插入
if (pCur == NULL)
{
_pRoot = pNewNode;
return true;
}
//找插入的位置
while (pCur)
{
if (key == pCur->_key)
return false;
else if (key < pCur->_key)
{
pParent = pCur;
pCur = pCur->_pLeft;
}
else
{
pParent = pCur;
pCur = pCur->_pRight;
}
}
//插入元素
if (key < pParent->_key)
pParent->_pLeft = pNewNode;
else
pParent->_pRight = pNewNode;
return true;
}
递归实现
bool _Insert1(pNode& pRoot, const K&key, const V&value)
{
pNode pNewNode = new Node(key, value);
if (pRoot == NULL)
{
pRoot = pNewNode;
return true;
}
if (pRoot == NULL)
return false;
if (pNewNode->_key == pRoot->_key)
return false;
if (pRoot->_key > pNewNode->_key)
_Insert1(pRoot->_pLeft, key, value);
else
_Insert1(pRoot->_pRight, key, value);
}
(二)查找
1、空树—–则此结点不存在
2、非空树
(1)用当前结点与所需比较的结点比较,如果大于,则走右子树,反之,查找成功。
程序算法如下所示
bool Find(const K&key)
{
//空树
if (_pRoot == NULL)
return false;
//非空树
pNode pCur = _pRoot;
while (pCur)
{
if (key == pCur->_key)
return true;
else if (key > pCur->_key)
pCur = pCur->_pRight;
else
pCur = pCur->_pLeft;
}
return false;
}
递归实现
bool _Find1(pNode pRoot, const K&key)
{
if (pRoot == NULL)
return false;
if (key == pRoot->_key)
return true;
//左子树
else if (key < pRoot->_pLeft->_key)
_Find1(pRoot->_pLeft, key);
//右子树
else
_Find1(pRoot->_pRight,key);
}
(三)获取最小的元素
二叉搜索树是一个有序树,最小的结点位于树中的最左边,因此,直到最左边没有元素,则找到最小的一个结点。
程序算法如下所示:
K LastMost()const
{
assert(_pRoot);//判断是否为空树
pNode pCur = _pRoot;
while (pCur->_pLeft)
{
pCur = pCur->_pLeft;
}
return pCur->_key;
}
(四)获取最大的元素
二叉搜索树是一个有序树,最大的结点位于树中的最右边,因此,直到最右边没有元素,则找到最大的一个结点。
程序算法如下所示:
K RightMost()const
{
assert(_pRoot);//判断是否为空树
pNode pCur = _pRoot;
while (pCur->_pRight)
{
pCur = pCur->_pRight;
}
return pCur->_key;
}
(五)删除树中的元素
树存在,主要分四种情况,其中,情况一与二或三可以合并在一起
1、删除叶子结点——>直接删
2、待删的结点只有左孩子
3、待删的结点只有右孩子
4、待删的结点左右孩子均有
删除情况具体如上面所示,根据上面的情况,便可完成所有的情况,具体代码如下所示:
void Pop(const K&key)
{
//空树
if (_pRoot == NULL)
return;
//非空树
pNode pDel = _pRoot;
pNode pDParent = NULL;
//找待删除的结点
while (pDel)
{
if (key == pDel->_key)
break;
else if (key > pDel->_key)
{
pDParent = pDel;
pDel = pDel->_pRight;
}
else
{
pDParent = pDel;
pDel = pDel->_pLeft;
}
}
//删除的结点不在树中
if (pDel == NULL)
{
return;
}
//删除结点
//只有左孩子,此种情况包含两个孩子都没有
if (NULL == pDel->_pRight)
{
//判断待删结点是否为根节点
if (pDel == _pRoot)//左单支
{
_pRoot = pDel->_pLeft;
}
else
{
//待删结点在双亲结点的左孩子上
if (pDParent->_pLeft == pDel)
{
pDParent->_pLeft = pDel->_pLeft;
}
//待删结点在双亲结点的右孩子上
else
{
pDParent->_pRight = pDel->_pLeft;
}
}
}
//只有右孩子,此种情况包含两个孩子都没有
else if (NULL == pDel->_pLeft)
{
if (pDel == _pRoot)//右单支
{
_pRoot = pDel->_pRight;
}
else
{
if (pDParent->_pLeft == pDel)
{
pDParent->_pLeft = pDel->_pRight;
}
else
{
pDParent->_pRight = pDel->_pRight;
}
}
}
//两个孩子都有
else
{
//找替代结点,在右子树中,找待删除结点的中序遍历下的第一个结点,右子树中序遍历下的第一个结点
pNode pReplaceNode = pDel->_pRight;
pDParent = pDel;
//找出替代结点
while (pReplaceNode->_pLeft)
{
pDParent = pReplaceNode;
pReplaceNode = pReplaceNode->_pLeft;
}
//交换待删结点与替代结点,一般的替代结点为只有右子树或者叶子结点
pDel->_key = pReplaceNode->_key;
pDel->_value = pReplaceNode->_value;
pDel = pReplaceNode;
//删除结点
if (pDParent->_pLeft == pDel)
{
pDParent->_pLeft = pDel->_pRight;
}
else
{
pDParent->_pRight = pDel->_pRight;
}
}
delete pDel;
}
二叉搜索树最大的特点就是,其中序遍历的结果是一个有序的结果。
对于二叉搜索树,有关的操作就是在上面了,希望大家一起进步!!
所有的代码如下所示:
#pragma once
#include<iostream>
using namespace std;
#include<assert.h>
template<class K,class V>
struct BSTreeNode
{
BSTreeNode(const K& key, const V& value)
:_pLeft(NULL)
, _pRight(NULL)
, _key(key)
, _value(value)
{}
BSTreeNode<K, V>* _pLeft;
BSTreeNode<K, V>* _pRight;
K _key;
V _value;
};
template<class K,class V>
class BSTree
{
typedef BSTreeNode<K, V> Node;
typedef BSTreeNode<K, V>* pNode;
public:
BSTree()
:_pRoot(NULL)
{}
bool Insert(const K& key, const V& value)
{
pNode pCur = _pRoot;
pNode pParent = NULL;
pNode pNewNode = new Node(key, value);
//空树--直接插入
if (pCur == NULL)
{
_pRoot = pNewNode;
return true;
}
//找插入的位置
while (pCur)
{
if (key == pCur->_key)
return false;
else if (key < pCur->_key)
{
pParent = pCur;
pCur = pCur->_pLeft;
}
else
{
pParent = pCur;
pCur = pCur->_pRight;
}
}
//插入元素
if (key < pParent->_key)
pParent->_pLeft = pNewNode;
else
pParent->_pRight = pNewNode;
return true;
}
//递归
void Insert1(const K& key, const V& value)
{
_Insert1(_pRoot, key, value);
}
//查找某一个元素
bool Find(const K&key)
{
//空树
if (_pRoot == NULL)
return false;
//非空树
pNode pCur = _pRoot;
while (pCur)
{
if (key == pCur->_key)
return true;
else if (key > pCur->_key)
pCur = pCur->_pRight;
else
pCur = pCur->_pLeft;
}
return false;
}
//递归
bool Find1(const K&key)
{
//空树
if (_pRoot == NULL)
return true;
//非空树
_Find1(_pRoot, key);
}
//获取最小的元素,一直往其左边走
K LastMost()const
{
assert(_pRoot);//判断是否为空树
pNode pCur = _pRoot;
while (pCur->_pLeft)
{
pCur = pCur->_pLeft;
}
return pCur->_key;
}
//获取最大的元素
K RightMost()const
{
assert(_pRoot);//判断是否为空树
pNode pCur = _pRoot;
while (pCur->_pRight)
{
pCur = pCur->_pRight;
}
return pCur->_key;
}
void Pop(const K&key)
{
//空树
if (_pRoot == NULL)
return;
//非空树
pNode pDel = _pRoot;
pNode pDParent = NULL;
//找待删除的结点
while (pDel)
{
if (key == pDel->_key)
break;
else if (key > pDel->_key)
{
pDParent = pDel;
pDel = pDel->_pRight;
}
else
{
pDParent = pDel;
pDel = pDel->_pLeft;
}
}
//删除的结点不在树中
if (pDel == NULL)
return;
//删除结点
//只有左孩子,此种情况包含两个孩子都没有
if (NULL == pDel->_pRight)
{
//判断待删结点是否为根节点
if (pDel == _pRoot)//左单支
{
_pRoot = pDel->_pLeft;
}
else
{
//待删结点在双亲结点的左孩子上
if (pDParent->_pLeft == pDel)
{
pDParent->_pLeft = pDel->_pLeft;
}
//待删结点在双亲结点的右孩子上
else
{
pDParent->_pRight = pDel->_pLeft;
}
}
}
//只有右孩子,此种情况包含两个孩子都没有
else if (NULL == pDel->_pLeft)
{
if (pDel == _pRoot)//右单支
{
_pRoot = pDel->_pRight;
}
else
{
if (pDParent->_pLeft == pDel)
{
pDParent->_pLeft = pDel->_pRight;
}
else
{
pDParent->_pRight = pDel->_pRight;
}
}
}
//两个孩子都有
else
{
//找替代结点,在右子树中,找待删除结点的中序遍历下的第一个结点,右子树中序遍历下的第一个结点
pNode pReplaceNode = pDel->_pRight;
pDParent = pDel;
//找出替代结点
while (pReplaceNode->_pLeft)
{
pDParent = pReplaceNode;
pReplaceNode = pReplaceNode->_pLeft;
}
//交换待删结点与替代结点,一般的替代结点为只有右子树或者叶子结点
pDel->_key = pReplaceNode->_key;
pDel->_value = pReplaceNode->_value;
pDel = pReplaceNode;
//删除结点
if (pDParent->_pLeft == pDel)
{
pDParent->_pLeft = pDel->_pRight;
}
else
{
pDParent->_pRight = pDel->_pRight;
}
}
delete pDel;
}
void InOrder()
{
cout << "InOrder:" << endl;
_InOrder(_pRoot);
}
//递归
private:
bool _Find1(pNode pRoot, const K&key)
{
if (pRoot == NULL)
return false;
if (key == pRoot->_key)
return true;
//左子树
else if (key < pRoot->_pLeft->_key)
_Find1(pRoot->_pLeft, key);
//右子树
else
_Find1(pRoot->_pRight,key);
}
bool _Insert1(pNode& pRoot, const K&key, const V&value)
{
pNode pNewNode = new Node(key, value);
if (pRoot == NULL)
{
pRoot = pNewNode;
return true;
}
if (pRoot == NULL)
return false;
if (pNewNode->_key == pRoot->_key)
return false;
if (pRoot->_key > pNewNode->_key)
_Insert1(pRoot->_pLeft, key, value);
else
_Insert1(pRoot->_pRight, key, value);
}
private:
void _InOrder(pNode pRoot)
{
if (pRoot)
{
_InOrder(pRoot->_pLeft);
cout << "<" << pRoot->_key << "," << pRoot->_value << ">" << endl;;
_InOrder(pRoot->_pRight);
}
}
主要测试代码如下所示:
#define _CRT_SECURE_NO_WARNINGS 1
#include"BinarySearchTree.hpp"
int main()
{
int a[] = { 5, 7, 2, 1, 9, 4, 8, 3, 6, 0 };
BSTree<int,int> bst1;
for (int i = 0; i < sizeof(a) / sizeof(*a); ++i)
{
bst1.Insert(a[i], a[i]);
}
bst1.InOrder();
for (int i = 0; i < sizeof(a) / sizeof(*a); ++i)
{
bst1.Insert1(a[i], a[i]);
}
bst1.InOrder();
if (bst1.Find(10))
cout << "存在" << endl;
else
cout << "不存在" << endl;
if (bst1.Find(5))
cout << "存在" << endl;
else
cout << "不存在" << endl;
if (bst1.Find1(10))
cout << "存在" << endl;
else
cout << "不存在" << endl;
if (bst1.Find1(5))
cout << "存在" << endl;
else
cout << "不存在" << endl;
cout << bst1.LastMost() << " ";//最小
cout << bst1.RightMost();//最大
//删除根结点
bst1.Pop(5);
bst1.InOrder();
//删除结点只有右子树
bst1.Pop(7);
bst1.InOrder();
//删除叶子结点
bst1.Pop(0);
bst1.InOrder();
//删除结点只有左子树
bst1.Pop(4);
bst1.InOrder();
//待删结点的左右孩子均存在
bst1.Pop(2);
bst1.InOrder();
//删除结点不存在
bst1.Pop(2);
bst1.InOrder();
//bst1.Pop(9);
//bst1.InOrder();
//bst1.Pop(2);
//bst1.InOrder();
//bst1.Pop(3);
//bst1.InOrder();
//bst1.Pop(6);
//bst1.InOrder();
//bst1.Pop(1);
//bst1.InOrder();
////空树
//bst1.Pop(2);
//bst1.InOrder();
//判断空树的情况
//BSTree<int, int> bst2;
//cout << bst2.LastMost() << " ";//最小
//cout << bst2.RightMost();//最大
system("pause");
return 0;
}
只有不停的奔跑,才能不停留在原地。