二叉查找树:是支持动态查询的查询算法,即可以插入和删除
查询:遵循二叉树的规则,关键字的值大于左子树的值,小于右子树的值
插入:通过查询操作,如果存在,当然不用再插入咯,如果失败,则返回应该插入位置(NULL)的父结点,如果父结点为NULL,只有一种情况,那么要插入的关键字为第一个结点,连父结点也不存在;如果父结点不为NULL,那很容易,比对下父结点的数据,就可以知道关键字得插入在左子树,还是右子树了.
删除:删除其实有两种办法:
第一种,就是下面程序用到的方法,即先找到要【删除结点】,然后找【删除结点】的【左子树】的【最大孩子】,用该【最大孩子】的数据和要【删除的结点】的数据 进行交换,然后删除【最大孩子】,当然不能直接就把最大孩子给删掉,必须先保存【最大孩子】的【左孩子】(最大孩子不可能有右孩子,不然它就不左子树的最大孩子了)。
第二种就是将指向【删除结点】的指针指向【删除结点】的【左子树】,然后将【删除结点】的【右子树】并到【左子树】的最大孩子哪里去
二叉树的性能最好可以达到O(logn),它是二叉树,性能最好也跟【满二插树】一样咯,但是,它也有糟糕的时候,当如果插入数据是有序的话,如 [1,2,3,4...],可想而知,整棵树偏向了右边,那时性能就为O(n)了╮(╯_╰)╭,不过它的改进版,平衡二叉树AVL就解决了这个糟糕的问题。
#include <iostream>
using namespace std;
typedef struct BiNode
{
int m_data;
BiNode* m_lchild;
BiNode* m_rchild;
}BiNode, *BiTree;
// last_node:在查找不到结点的时候,保存父结点
bool searchBST(BiTree tree, int key, BiTree parent, BiTree& last_node)
{
// 如果当前结点为NULL
if (!tree)
{
// 保存父结点返回
last_node = parent;
return false;
}
if (key < tree->m_data)
{
return searchBST(tree->m_lchild, key, tree, last_node);
}
else if (key == tree->m_data)
{
last_node = tree;
return true;
}
else
{
return searchBST(tree->m_rchild, key, tree, last_node);
}
return false;
}
// 插入结点
bool insertBST(BiTree& tree, int key)
{
BiTree last_node = 0;
// 如果找不到才插入【关键字】
if (!searchBST(tree, key, 0, last_node))
{
BiNode* node = new BiNode;
node->m_data = key;
node->m_lchild = 0;
node->m_rchild = 0;
// 如果最后的结点不存在,说明刚才插入的结点将会是根结点
if (!last_node)
{
tree = node;
}
else if (key < last_node->m_data)
{
last_node->m_lchild = node;
}
else
{
last_node->m_rchild = node;
}
return true;
}
return false;
}
// 中序遍历下
void orderTraverse(BiTree tree)
{
if (tree)
{
orderTraverse(tree->m_lchild);
cout<<tree->m_data<<" ";
orderTraverse(tree->m_rchild);
}
}
// 删除结点
void deleteNodes(BiTree& delete_node)
{
// 如果不存在右子树或者不存在孩子
if (!delete_node->m_rchild)
{
// 先用temp保存该结点,因为它有左孩子(如果为空,把NULL看成左孩子也可以的),得先处理下
BiNode* temp = delete_node;
// 将指向该【删除结点】的指针指向【删除结点的孩子】
delete_node = delete_node->m_lchild;
// 现在,可以删除要删除的结点了
delete temp;
temp = 0;
}
// 如果不存在左子树
else if (!delete_node->m_lchild)
{
// 先用temp保存该结点,因为它有右孩子
BiNode* temp = delete_node;
// 将指向该【删除结点】的指针指向【删除结点的孩子】
delete_node = delete_node->m_rchild;
// 现在,可以删除要删除的结点了
delete temp;
temp = 0;
}
// 如果存在左右孩子
// 只是把要删除结点的左子树的最大孩子的数据跟起对换,然后删掉最大孩子(当然需要保存最大孩子的左子树)
else
{
// 保存【左子树】中【最大孩子】的【双亲结点】
BiNode* parent = delete_node;
// 因为【删除结点】存在左右子树,所以,初始化【左子树】的最大孩子为【左子树】的根结点
BiNode* max_child = delete_node->m_lchild;
// 如果当前【最大孩子】存在【右孩子】(右孩子肯定比父节点大,所以得更新下最大孩子的值)
while(max_child->m_rchild)
{
// 因为要下面要更新【最大孩子】,所以最大孩子的【父节点】也是需要更新的
parent = max_child;
// 更新【最大孩子】
max_child = max_child->m_rchild;
}
// 将【最大孩子】的数据交给要【删除的结点】
delete_node->m_data = max_child->m_data;
// 如果【删除结点】的左子树存在【右孩子】,所以最大孩子为保存的parent的【右孩子】
if (parent != delete_node)
{
// 最大结点即将代替【删除结点】被删除,要保存下它的【左孩子】
parent->m_rchild = max_child->m_lchild;
}
// 如果【删除结点】的左子树不存在【右孩子】,所以最大孩子为【左子树】的【根结点】
else
{
parent->m_lchild = max_child->m_lchild;
}
delete max_child;
max_child = 0;
}
}
void deleteBST(BiTree& tree, int key)
{
if (tree)
{
if (key < tree->m_data)
{
deleteBST(tree->m_lchild, key);
}
// 找到关键字
else if (key == tree->m_data)
{
// 删除结点
deleteNodes(tree);
}
else
{
deleteBST(tree->m_rchild, key);
}
}
}
int main()
{
BiTree tree = 0;
insertBST(tree, 1);
insertBST(tree, 2);
insertBST(tree, 3);
insertBST(tree, 4);
insertBST(tree, 5);
insertBST(tree, 6);
insertBST(tree, 7);
orderTraverse(tree);
deleteBST(tree, 5);
deleteBST(tree, 4);
cout<<endl;
orderTraverse(tree);
return 0;
}