新建一棵树 以#代替空树 上图树的输入值为 62 58 47 35 # 37 51 # # # # 88 73 # # 99 93 #
二叉搜索树的概念
对于一棵二叉搜索树,如果不为空,它应该满足以下三个特点:
1、树上的任一结点,该结点的值都大于它的非空左子树的值。
2、树上的任一结点,该结点的值都小于它的非空右子树的值。
3、任一结点的左右子树都是二叉搜索树。
查找
对于二叉搜索树的查找,思路方法为:
1、从根结点开始查找,如果树为空,就返回NULL。
2、如果树不空,就让数据X和根结点的数据Data作比较。
3、如果X的值大于根结点的Data,就往右子树中进行搜索;如果X的值小于根结点的Data,就往左子树中进行搜索。
4、如果X的值等于Data,就表示查找完成,返回该结点。
递归查找伪算法
- 首先判断树空不空,空就返回NULL。
- 如果不空,判断数据X和T—>Data;
- 如果X更大,就往右子树去递归查找;
- 如果X比Data小,就往左子树去递归查找;
- 如果X和Data相等,就retuen这个结点。
循环查找伪算法
- 判断树空不空,如果树空,就直接执行return NULL。
- 如果树不空就执行while里面的语句:
- 如果X大于Data,就让T=T—>Right,也就是往右边查找;
- 如果X小于Data,就让T=T—>Left,让左边查找;
- 当X等于Data,找到就return这个结点。
查找最值
如何查找最大值和最小值,根据二叉搜索树的特点,最大值一定是在树的最右边的结点上,而最小值就一定是在最左边的结点上,既可以用递归实现也可以循环实现。
递归查找最值伪算法
- 对于递归查找最大最小元素,都是一开始先判断结点是否为空,如果为空就返回NULL
- 否则就一直往左(或者往右)递归,直到找到最左(或最右的结点为止)
- 判断最左或最右结点的方法就是递归到结点为NULL,就证明找到最左或最右的叶结点了。
循环查找最值伪算法
- 判断树空不空,如果树空,就直接执行return NULL。
- 如果树不空就执行while里面的语句:
对于查找最小值,让T=T—>Left,直到T—>Left为空,证明找到了最左的叶结点,退出while循环
3. 最后return出去。
最大值方法一样,循环右子树直到找到最右结点,再return出去就可以了。
插入
对于二叉搜索树的插入,插入结点后应该仍然要保持树是二叉搜索树,也就是说插入的结点应该仍要保持该结点的左子树比它小,右子树比它大,可以参考递归查找函数的方法。
删除
第一种情况,要删除的结点是叶结点,也就是没有左右子树。这样的情况只要把该结点的父结点指向NULL即可。
第二种情况,要删除的结点有一个子树(左子树或右子树),这时删除该结点的方法就是让该结点的父结点指向该结点的子树即可。
第三种情况,要删除的结点有左右两个子树,两种方法,第一种:从左子树里找一个最大值来代替,或者从右子树里找一个最小值来代替,第二种,使用前驱(后继)节点替换删除节点的方法
#define _CRT_SECURE_NO_WARNINGS
# include <vector>
# include <iostream>
# include <string>
# include <sstream>
using namespace std;
struct BiTree {
int val;
BiTree* left;
BiTree* right;
BiTree(int x) : val(x), left(NULL), right(NULL) {}
};
void CreateTree(BiTree **T, vector<string> arr, int len, int index)
{
//scanf("%d", &val);
if ("#" == arr[index])
*T = NULL;
else
{
int val;
stringstream ss;
ss << arr[index];
ss >> val;
*T = new BiTree(val);
if (!(*T))
exit(-1);
int left = 2 * index + 1;
int right = 2 * index + 2;
if (left >= len)
(*T)->left = NULL;
else
CreateTree(&(*T)->left, arr, len, left);
if (right >= len)
(*T)->right = NULL;
else
CreateTree(&(*T)->right, arr, len, right);
}
}
void InTraversal(BiTree *T)
{
if (T != NULL)
{
if (T->left != NULL)
InTraversal(T->left);
cout << T->val << endl;
if (T->right != NULL)
InTraversal(T->right);
}
}
//递归查找1
//递归的查找二叉排序树T中是否存在key
//指针f指向T的双亲,当T指向根节点时,f的初值就为NULL
//若查找不成功,则指针p指向查找路径上访问的最后一个节点并返回False
//若查找成功,则指针p指向该数据元素节点,并返回True
bool SearchBST(BiTree *T, int key, BiTree *f, BiTree **p)
{
if (!T) //查找不成功
{
*p = f;
return false;
}
else if (key == T->val) //查找成功
{
*p = T;
return true;
}
else if (key < T->val)
{
return SearchBST(T->left, key, T, p); //左子树继续查找
}
else
{
return SearchBST(T->right, key, T, p); //右子树继续查找
}
}
//在二叉排序树插入一个元素
bool InsertBST(BiTree **T, int key)
{
BiTree *p, *s;
if (!SearchBST(*T, key, NULL, &p)) // 查找不成功
{
s = new BiTree(key);
if (!p)
*T = s;
else if (key < p->val)
p->left = s;
else
p->right = s;
return true;
}
else
return false;
}
// 在二叉排序树插入一个元素
BiTree* InsertBST2(int key, BiTree *T)
{
//若树为空,就生成并返回一个节点
if (!T)
T = new BiTree(key);
else if (key > T->val)
T->right = InsertBST2(key, T->right);
else if (key < T->val)
T->left = InsertBST2(key, T->left);
return T;
}
//递归查找2
BiTree* PosSearchBST(int key, BiTree *T)
{
if (!T)
return NULL;
if (key > T->val)
return PosSearchBST(key, T->right);
else if (key < T->val)
return PosSearchBST(key, T->left);
else
return T;
}
//循环查找
BiTree* PosSearchBST2(int key, BiTree *T)
{
if (!T)
return NULL;
while (T)
{
if (key > T->val)
T = T->right;
else if (key < T->val)
T = T->left;
else
return T;
}
}
//递归查找最大值得位置
BiTree* PosFindMax(BiTree* T)
{
if (!T) return NULL;
else if (!T->right) return T;
else PosFindMax(T->right);
}
//循环查找最小值
int FindMin(BiTree* T)
{
if (!T) return NULL;
while (T->left)
T = T->left;
return T->val;
}
BiTree* FindMin2(BiTree* T)
{
if (!T) return NULL;
while (T->left)
T = T->left;
return T;
}
//从二叉排序树中删除节点p,并重接他的左右子树
bool Delete(BiTree **p)
{
BiTree *q, *s;
if ((*p)->right == NULL) //右子树为空则只需重接他的左子树
{
q = *p;
*p = (*p)->left;
delete q;
}
else if ((*p)->left == NULL) //只需重接他的右子树
{
q = *p;
*p = (*p)->right;
delete q;
}
else //左右子树均不空
{
q = *p;
s = (*p)->left;
while (s->right) // 转左,然后向右到尽头(找待删节点的前驱)
{
q = s;
s = s->right;
}
(*p)->val = s->val; // s指向被删节点的直接前驱
if (q != *p)
q->right = s->left; //重接q的右子树
else
q->left = s->left; // 重接q的左子树
delete s;
}
return true;
}
//删除排序二叉树中的节点 第二种方法
bool DeleteBST(BiTree **T, int key)
{
if (!(*T)) //不存在关键字等于key的数据元素
return false;
else
{
if (key == (*T)->val) //找到关键字等于key的元素
return Delete(T);
else if (key < (*T)->val)
return DeleteBST(&(*T)->left, key);
else
return DeleteBST(&(*T)->right, key);
}
}
//删除排序二叉树中的节点,第一种方法
BiTree* DeleteBST2(int key, BiTree *T)
{
BiTree* p;
if (!T)
cout << "找不到删除的元素\n" << endl;
else if (key < T->val)
T->left = DeleteBST2(key, T->left);
else if (key > T->val)
T->right = DeleteBST2(key, T->right);
else
{
if (T->left && T->right)
{
p = FindMin2(T->right); //find函数要重新写 返回最小元素的位置
T->val = p->val;
T->right = DeleteBST2(T->val, T->right);
}
else
{
p = T;
if (!T->left)
T = T->right;
else if (!T->right)
T = T->left;
delete p;
}
}
return T;
}
int main(void)
{
BiTree*T = NULL;
BiTree*p = NULL;
vector<string> arr = { "62", "58", "88", "47", "#", "73", "99", "36", "51", "#", "#", "#", "#", "93", "#", "#", "37" };
/*
使用插入创建一棵树
vector<int> a = {62, 88, 58, 47, 35, 73, 51, 99, 37, 93 }
for (int i = 0; i < arr.size(); ++i)
InsertBST(&T, a[i]);
*/
cout << "广度优先输入一棵二叉树:\n" << endl;
for (int i = 0; i < arr.size(); ++i)
{
if (arr[i] == "#")
continue;
cout << arr[i] << endl;
}
CreateTree(&T, arr, arr.size(), 0);
printf("\n");
cout << "中序遍历输出的结果为:\n" << endl;
InTraversal(T);
bool status = SearchBST(T, 93, NULL, &p);
if (status)
cout << "查找成功\n" << endl;
else
cout << "查找失败\n" << endl;
BiTree * pos1 = PosSearchBST(99, T);
BiTree * pos2 = PosSearchBST2(99, T);
cout << "递归查找和循环查找到的位置分别为:\n" << pos1 << " & " << pos2 << endl;
BiTree* max = PosFindMax(T);
cout << "最大值的位置:" << max << "\n" << endl;
int min = FindMin(T);
cout << "最小值:" << min << "\n" << endl;
bool InsertFlag = InsertBST(&T, 44);
if (InsertFlag)
cout << "插入成功\n" << endl;
else
cout << "插入失败\n" << endl;
cout << "插入之后的中序遍历输出结果为:\n";
InTraversal(T);
bool DeleteFlag = DeleteBST(&T, 47);
if (DeleteFlag)
cout << "删除成功\n" << endl;
else
cout << "删除失败\n" << endl;
cout << "删除之后的中序遍历输出结果为:\n";
InTraversal(T);
system("PAUSE");
return 0;
}
参考
大话数据结构--程杰