目录
高级搜索树:
用于数据的存储和查找的树
分类:
BST AVL 红黑树 B树 B+树
二叉搜索树:
定义:
在二叉树的基础上增加一些规则:
1.如果某节点的左子树不空 ,左子树上所有的节点的值都要小于该节点的值
2.如果某节点的右子树不空,右子树上所有的节点的值都要大于该节点的值
3.所有节点都要满足以上约束。
性质:
中序遍历序列有序(从小到大,由规则可知)注意:如果变成从大到小,也是二叉排序树
特点:
优点:提高查找效率(如果是完全二叉树,高度为log2(n+1)向下取整)
缺点:如果用于建树的初始序列有序,建立的BST是一个斜树,高度为n
操作:
插入操作
在空树插入数据x时,将数据k作为根节点即可,左右指针为空
//二叉链表存树
typedef struct BSTnode {
int data;
struct BSTnode* left;
struct BSTnode* right;
}BSTNode, * BSTree;
BSTree initBST(int k)
{
BSTree r = (BSTNode*)malloc(sizeof(BSTNode));
//if(r==NULL)
r->data = k;
r->left = r->right = NULL;
return r;
}
递归方法插入
在非空树上插入数据时,假设此时树的根节点是r,判断插入数据k和根节点数据的大小关系:
如果k<r,k插入左子树中,再以r的左孩子作为根节点,让k与其比较,直到找到空结点
如果k>r,k插入右子树中,再以r的右孩子作为根节点,让k与其比较,直到找到空结点
递归出口:结点位置为空
代码:
BSTree insert(BSTree r, int k)
{
if (r == NULL)
{
BSTree s = (BSTNode*)malloc(sizeof(BSTNode));
//if(s==NULL)
s->data = k;
s->left = s->right = NULL;
return s;
}
if (k < r->data)
{
r->left = insert(r->left, k);
}
if (k > r->data)
{
r->right = insert(r->right, k);
}
return r;
}
非递归方法插入
在上面的递归方法中,插入位置是在递归的过程中找到的,而在非递归方法中,要是想要插入数据,就需要我们先找到要插入的位置,将给位置的空结点换成要插入的数据结点
查找函数:
void find(BSTree r, int x)
{
BSTNode* p = r;
while (p != NULL)
{
if (x == p->data)
{
cout << "存在" << endl;
break;
}
if (x < p->data)
{
p = p->left;
}
if (x > p->data)
{
p = p->right;
}
}
if (p == NULL)
{
cout << "不存在" << endl;
}
}
BSTree insert_1(BSTree r, int k)
{
BSTree s = (BSTNode*)malloc(sizeof(BSTNode));
//if(s==NULL)
s->data = k;
s->left = s->right = NULL;
//空树插入
if (r == NULL)
{
return s;
}
//非空树插入
BSTNode* p = r;//遍历
BSTNode* pre = NULL;//p的父亲
//遍历找插入位置
while (p != NULL)
{
if (k < p->data)
{
pre = p;
p = p->left;
}
else {
pre = p;
p = p->right;
}
}
//插入
if (k < pre->data)
{
pre->left = s;
}
else {
pre->right = s;
}
return r;
}
整体代码
#include <iostream>
using namespace std;
//二叉链表存树
typedef struct BSTnode {
int data;
struct BSTnode* left;
struct BSTnode* right;
}BSTNode, * BSTree;
BSTree initBST(int k)
{
BSTree r = (BSTNode*)malloc(sizeof(BSTNode));
//if(r==NULL)
r->data = k;
r->left = r->right = NULL;
return r;
}
BSTree insert(BSTree r, int k)
{
if (r == NULL)
{
BSTree s = (BSTNode*)malloc(sizeof(BSTNode));
//if(s==NULL)
s->data = k;
s->left = s->right = NULL;
return s;
}
if (k < r->data)
{
r->left = insert(r->left, k);
}
if (k > r->data)
{
r->right = insert(r->right, k);
}
return r;
}
//-----------非递归-------
BSTree insert_1(BSTree r, int k)
{
BSTree s = (BSTNode*)malloc(sizeof(BSTNode));
//if(s==NULL)
s->data = k;
s->left = s->right = NULL;
//空树插入
if (r == NULL)
{
return s;
}
//非空树插入
BSTNode* p = r;//遍历
BSTNode* pre = NULL;//p的父亲
//遍历找插入位置
while (p != NULL)
{
if (k < p->data)
{
pre = p;
p = p->left;
}
else {
pre = p;
p = p->right;
}
}
//插入
if (k < pre->data)
{
pre->left = s;
}
else {
pre->right = s;
}
return r;
}
void inOrder(BSTree r)
{
if (r == NULL)
{
return;
}
inOrder(r->left);
cout << r->data << endl;
inOrder(r->right);
}
void find(BSTree r, int x)
{
BSTNode* p = r;
while (p != NULL)
{
if (x == p->data)
{
cout << "存在" << endl;
break;
}
if (x < p->data)
{
p = p->left;
}
if (x > p->data)
{
p = p->right;
}
}
if (p == NULL)
{
cout << "不存在" << endl;
}
}
int main()
{
int n;
int a[105];
cin >> n;
for (int i = 1; i <= n; i++)
{
cin >> a[i];
}
BSTree r = NULL;
//-----递归版 不单独初始化根节点------------
/*
for(int i=1;i<=n;i++)
{
r=insert(r,a[i]);
}
*/
//-----递归版 单独初始化根节点-------------
/*
r=initBST(a[1]);
for(int i=2;i<=n;i++)
{
r=insert(r,a[i]);
}
*/
//------非递归版 ------------------
for (int i = 1; i <= n; i++)
{
r = insert_1(r, a[i]);
}
//---------------------------
inOrder(r);//中序遍历输出验证
cout << endl;
//查找
int x;
cin >> x;
find(r, x);
return 0;
}
/*
9
8 3 10 1 6 14 4 7 13
*/
删除操作
首先要找到要删除的结点p,同时找p的父亲结点pre
在删除的过程,分为三种情况
1)如果p的度为2:在删掉p后,将p的左子树的最靠右的结点m或者是右子树最靠左的结点n移动到删除位置(相当于p的前驱或者是后继),而左子树的最靠右的结点m或者是右子树最靠左的结点n一定是度为0或1的结点。
这样的话我们就可以把问题转化为将m或n的数据复制到要删除的数据位置来代替,在将m或n的原来位置的结点删除
2)如果p的度为1:直接让pre指向p的指针指向p的孩子(即将p删除后,让p唯一的孩子顶替p的位置)
3)如果p的度为0:直接删除
注意:这里度为0的情况我们也可以看作度为1的情况去处理,认为他也右一个孩子,只不过一个孩子是NULL孩子
递归查找的思路:在以r为根节点的树中,删除数据x----->递归
(1)x<r->data:问题转化为在以r->left为根的子树上删除x
(2)x>r->data :问题转化为在以r->right为根的子树上删除x
(3)x==r->data:r就是要被删除的节点,去根据r的度 判断如何删除
BSTNode* find_leftmaxx(BSTree p)
{
while (p->right != NULL)
{
p = p->right;
}
return p;
}
BSTree delet(BSTree r, int k)
{
if (k < r->data)
{
r->left = delet(r->left, k);
}
if (k > r->data)
{
r->right = delet(r->right, k);
}
if (k == r->data)
{//r就是要被删除的节点
if (r->left != NULL && r->right != NULL)
{//r的度为2
//找到r的左子树中最靠右的节点
BSTNode* lmaxx = find_leftmaxx(r->left);
r->data = lmaxx->data;
r->left = delet(r->left, lmaxx->data);//删掉顶替的节点
}
else
{//r的度为1/0(0也看成1)
BSTNode* p = r;
if (r->left != NULL)
{
r = r->left;
}
else
{
r = r->right;
}
free(p);
p = NULL;
}
}
return r;//返回删除后的新树
}
整体代码:
#include <iostream>
using namespace std;
//二叉链表存树
typedef struct BSTnode {
int data;
struct BSTnode* left;
struct BSTnode* right;
}BSTNode, * BSTree;
BSTree initBST(int k)
{
BSTree r = (BSTNode*)malloc(sizeof(BSTNode));
//if(r==NULL)
r->data = k;
r->left = r->right = NULL;
return r;
}
BSTree insert(BSTree r, int k)
{
if (r == NULL)
{
BSTree s = (BSTNode*)malloc(sizeof(BSTNode));
//if(s==NULL)
s->data = k;
s->left = s->right = NULL;
return s;
}
if (k < r->data)
{
r->left = insert(r->left, k);
}
if (k > r->data)
{
r->right = insert(r->right, k);
}
return r;
}
//-----------非递归-------
BSTree insert_1(BSTree r, int k)
{
BSTree s = (BSTNode*)malloc(sizeof(BSTNode));
//if(s==NULL)
s->data = k;
s->left = s->right = NULL;
//空树插入
if (r == NULL)
{
return s;
}
//非空树插入
BSTNode* p = r;//遍历
BSTNode* pre = NULL;//p的父亲
//遍历找插入位置
while (p != NULL)
{
if (k < p->data)
{
pre = p;
p = p->left;
}
else {
pre = p;
p = p->right;
}
}
//插入
if (k < pre->data)
{
pre->left = s;
}
else {
pre->right = s;
}
return r;
}
void inOrder(BSTree r)
{
if (r == NULL)
{
return;
}
inOrder(r->left);
cout << r->data << endl;
inOrder(r->right);
}
void find(BSTree r, int x)
{
BSTNode* p = r;
while (p != NULL)
{
if (x == p->data)
{
cout << "存在" << endl;
break;
}
if (x < p->data)
{
p = p->left;
}
if (x > p->data)
{
p = p->right;
}
}
if (p == NULL)
{
cout << "不存在" << endl;
}
}
//-------删除-------------------
BSTNode* find_leftmaxx(BSTree p)
{
while (p->right != NULL)
{
p = p->right;
}
return p;
}
BSTree delet(BSTree r, int k)
{
if (k < r->data)
{
r->left = delet(r->left, k);
}
if (k > r->data)
{
r->right = delet(r->right, k);
}
if (k == r->data)
{//r就是要被删除的节点
if (r->left != NULL && r->right != NULL)
{//r的度为2
//找到r的左子树中最靠右的节点
BSTNode* lmaxx = find_leftmaxx(r->left);
r->data = lmaxx->data;
r->left = delet(r->left, lmaxx->data);//删掉顶替的节点
}
else
{//r的度为1/0(0也看成1)
BSTNode* p = r;
if (r->left != NULL)
{
r = r->left;
}
else
{
r = r->right;
}
free(p);
p = NULL;
}
}
return r;//返回删除后的新树
}
int main()
{
int n;
int a[105];
cin >> n;
for (int i = 1; i <= n; i++)
{
cin >> a[i];
}
BSTree r = NULL;
//-----递归版 不单独初始化根节点------------
/*
for(int i=1;i<=n;i++)
{
r=insert(r,a[i]);
}
*/
//-----递归版 单独初始化根节点-------------
/*
r=initBST(a[1]);
for(int i=2;i<=n;i++)
{
r=insert(r,a[i]);
}
*/
//------非递归版 ------------------
for (int i = 1; i <= n; i++)
{
r = insert_1(r, a[i]);
}
//---------------------------
inOrder(r);//中序遍历输出验证
cout << endl;
//删除
int x;
cin >> x;
r = delet(r, x);
inOrder(r);//中序遍历输出验证
printf("\n");
return 0;
}
/*
14
8 6 13 5 7 9 14 1 12 3 11 2 4 10
*/