数据结构-二叉搜索树
二叉查找树(Binary Search Tree),(又:二叉搜索树,二叉排序树)它或者是一棵空树,或者是具有下列性质的二叉树: 若它的左子树不空,则左子树上所有结点的值均小于它的根结点的值; 若它的右子树不空,则右子树上所有结点的值均大于它的根结点的值; 它的左、右子树也分别为二叉排序树。
原理
二叉排序树的查找过程和次优
二叉树类似,通常采取
二叉链表作为
二叉排序树的
存储结构。
中序遍历二叉排序树可得到一个
关键字的有序序列,一个无序序列可以通过构造一棵二叉排序树变成一个有序序列,构造树的过程即为对无序序列进行排序的过程。每次插入的新的结点都是二叉排序树上新的
叶子结点,在进行插入操作时,不必移动其它结点,只需改动某个结点的
指针,由空变为非空即可。搜索,插入,删除的复杂度等于树高,O(log(n)).
算法实现
1 二叉排序树的查找算法
2 在
二叉排序树插入结点的算法
3 在
二叉排序树删除结点的算法
查找算法
在二叉排序树b中查找x的过程为:
若b是空树,则搜索失败,否则:
若x等于b的根结点的数据域之值,则查找成功;否则:
若x小于b的根结点的数据域之值,则搜索左子树;否则:
查找右子树。
#include <iostream>
#include <string>
using namespace std;
template <typename T>
struct binaryTreeNode
{
T element;// pair<const K,E> element;
binaryTreeNode<T>* leftChild;
binaryTreeNode<T>* rightChild;
//没有初始化数据域
binaryTreeNode()
{
leftChild = rightChild = nullptr;
}
//都初始化
binaryTreeNode(const T& element) :element(element)
{
leftChild = rightChild = nullptr;
}
//构造函数--->初始化参数列表的方式
binaryTreeNode(const T& element, binaryTreeNode<T>* leftChild, binaryTreeNode<T>* rightChild) :element(element)
{
this->leftChild = leftChild;
this->rightChild = rightChild;
}
};
template <class K,class E>
class binarySearchTree
{
public:
//构造函数
binarySearchTree()
{
treeSize = 0;
root = nullptr;
}
//两个万金油函数
int size()const
{
return treeSize;
}
bool empty()const
{
return treeSize == 0;
}
//查找
pair<const K, E>* find(const K& theKey)const;
//构建--->插入结点的过程
//插入--->数对 + 也可以用指针
void insert(const pair<const K, E>& thePair)
{
//插入-->找到指定位置
//1:树为空
//2.键已经存在, 选择 可以覆盖,选择放那一边都可以
//键:比较准则, 值:存放数据
binaryTreeNode<pair<const K, E>>* p = root; //移动指针
binaryTreeNode<pair<const K, E>>* pp = nullptr; //表示p的父节点
//找到合适的位置
while (p != nullptr)
{
pp = p; //记录p的父节点
if (thePair.first < p->element.first)
{
p = p->leftChild;
}
else if (thePair.first>p->element.first)
{
p = p->rightChild;
}
else
{
//first 已经存在树中,直接修改second
p->element.second = thePair.second;
return;
}
}
//创建插入的结点--调用构造函数
binaryTreeNode<pair<const K, E>>* newNode = new binaryTreeNode<pair<const K, E>>(thePair);
//插入的位置插在pp下面
if (root != nullptr)
if (thePair.first < pp->element.first)
pp->leftChild = newNode;
else
pp->rightChild = newNode;
else //树为空 ,新的结点就要成为根结点
root = newNode;
treeSize++;
}
//打印当前节点中的值
void visit(binaryTreeNode<pair<const K, E>>* Node)
{
//map中讲过
cout << Node->element.first << ":" << Node->element.second << "\t";
}
//中序遍历打印树
void printNode(binaryTreeNode<pair<const K, E>>* root)
{
if (root != nullptr)
{
printNode(root->leftChild);
visit(root);
printNode(root->rightChild);
}
}
void printTree()
{
printNode(root);
}
//通过键(first)去删除
void erase(const K& theKey);
protected:
//T -->pair<const K,E>
binaryTreeNode<pair<const K, E>>* root;//指向树根结点
int treeSize; //树的结点个数
};
//查找: 通过数对中键去查找
template<typename K,typename E>
pair<const K, E>* binarySearchTree<K, E>::find(const K& theKey)const
{
//定义一个移动的指针去查找
binaryTreeNode<pair<const K, E>>* p = root;
while (p != nullptr)
{
//如果当前节点比他大 往左边找
if (theKey < p->element.first)
p = p->leftChild;
//如果当前节点比他小,往右边找
else if (theKey>p->element.first)
p = p->rightChild;
else//相等
return &p->element; //return 的类型要和函数的返回值类型(pair<const K,E>*)一致
}
}
template <typename K,typename E>
void binarySearchTree<K, E>::erase(const K& theKey)
{
binaryTreeNode<pair<const K, E>>* p = root; //从根开始找
binaryTreeNode<pair<const K, E>>* pp = nullptr; //p的父节点
//找到要删除的位置
while (p != nullptr&&p->element.first != theKey)
{
pp = p;
if (theKey < p->element.first)
p = p->leftChild;
else if (theKey>p->element.first)
p = p->rightChild;
}
if (p == nullptr)
{
cout << "未找到指定位置,无法删除" << endl;
system("pause");
return; //未找到,无法删除
}
//有两个孩子的时候
if (p->leftChild != nullptr&&p->rightChild != nullptr)
{
//找到调整位置的那个结点
binaryTreeNode<pair<const K, E>>* s = p->leftChild; //从删除结点左边去找
binaryTreeNode<pair<const K, E>>* ps = p; //s的父节点
//左边找最右边,并记录要调整的结点的父节点
while (s->rightChild != nullptr)
{
ps = s;
s = s->rightChild;
}
//不能直接赋值的方式做--->const 的存在 所以要使用构造的方式
binaryTreeNode<pair<const K, E>>* q = new binaryTreeNode<pair<const K, E>>
(s->element, p->leftChild, p->rightChild);
if (pp == nullptr) //p就是根结点
root = q; //拿上来的那个结点要成为根结点
//删除p结点上面还有结点
//p不是根结点,存在父节点pp
//确定q结点放在pp左边还是右边
else if (p == pp->leftChild)//删除结点p在父节点的左边 ,q放在pp的左边
pp->leftChild = q;
else//删除结点p在父节点的右边 ,q放在pp的右边
pp->rightChild = q;
if (ps == p) //q=ps
pp = q;
else //同样的方法删除多余的结点
pp = ps;
delete p;
p = s;
}
//p只有一个孩子的,把孩子结点指针存放c
binaryTreeNode<pair<const K, E>>* c;
if (p->leftChild != nullptr)
c = p->leftChild;
else
c = p->rightChild;
//删除s也就 就是p
if (root == p)
root =c;
else
{
if (p == pp->leftChild)
//让删除p的父节点的指针指向p的下一个结点
pp->leftChild = c;
else
pp->rightChild = c;
}
treeSize--;
delete p;
}
int main()
{
binarySearchTree<int, string> myBST;
myBST.insert(pair<int, string>(1, "初心"));
myBST.insert(pair<int, string>(7, "Mingle"));
myBST.insert(pair<int, string>(2, "Honey"));
myBST.insert(pair<int, string>(5, "村雨"));
myBST.insert(pair<int, string>(6, "圆圆"));
myBST.insert(pair<int, string>(4, "柠檬"));
myBST.printTree();
cout << endl;
myBST.erase(1);
cout << endl;
myBST.printTree();
myBST.erase(5);
cout << endl;
myBST.printTree();
system("pause");
return 0;
}