今天看到一句话分享一下,所谓优势只不过比别人深入思考一点而已。
多看书,多思考。
二叉排序树(二叉搜索树,二叉查找树)
基本性质:
1.若它的左子树不空,则左子树上所有节点的值均小于它的根结点的值
2.若它的右子树不空,则右子树上所有结点的值均大于它的根节点的值
3.它的左右子树也是二叉排序树
应用目的:并不是为了排序,而是为了提高查找和插入删除关键字的速度。
二叉排序树的查找算法:
(1)若根节点不为空
如果根节点key==查找key,返回true
如果根节点key>查找key,在其左子树查找
如果根节点key<查找key,在其右子树查找
否则,返回false;
操作:
二叉排序树的插入算法:
(1)先检测这个元素是否在树中已经存在。
(2)如果存在,则不进行插入,如果不存在,则进行插入
操作:
删除操作:
删除操作比较查找和插入都复杂一些。
分这么几种情况:
(1)删除节点为叶子节点
(2)删除节点仅有左子树或者右子树
(3)删除节点左右子树都有。
1.如果删除的节点是叶子节点的话,我们可以直接删除,对树的结构基本没有影响
2.如果删除的节点仅有左子树或右子树,那么可以将左子树或者右子树移动到删除节点的位置即可。
3.删除节点左右子树都有的情况。
我们可以从它的左子树或者右子树里面找个节点来替代它,找哪个节点呢?我们分析一下二叉排序树的特点可知,它的中序遍历是有序的,所以可以找到它的前一个节点或者后一个节点。
举个栗子:
以0 1 2 3 4 5 6 7 8 9
以5作为根节点,我们现在要删除5的话,可以找4或者6来替代它也就是它的直接前驱和直接后继,那4和6在二叉排序树应该在什么位置呢?
在它的左子树的最右节点和右子树的最左节点上。
然后替换。
下面是代码实例:
#include<iostream>
#include<cstdio>
using namespace std;
typedef struct tree
{
int data;
struct tree *lChild;
struct tree *rChild;
}BiTode,*BiTree;
typedef bool Status;
typedef int KeyType;
//在根指针T所指二叉排序树中递归地查找其关键字等于Key的数据元素,若查找成功,
//则指针p指向该数据元素节点,并返回true;否则指针p查找路径上访问的最后一个节点并返回FALSE;
//指针f指向T的双亲,其初始调用值为NULL
Status SearchBST(BiTree T, KeyType key,BiTree f,BiTree *p)
{
//如果根指针为空则返回false;
if (T==NULL)
{
*p = f;
return false;
}
//如果查找的节点正好是根节点
else if (T->data == key)
{
*p = T;
return true;
}
else if (key > T->data)
{
return SearchBST(T->rChild,key,T,p);
}
else
{
f = T;
return SearchBST(T->lChild,key,T,p);
}
}
//插入操作
Status InsertBST(BiTree *T,KeyType key)
{
BiTree p, s;
//查找这个值在节点中是否存在,如果存在,则不插入,不存在,则插入
if (!SearchBST(*T, key,NULL,&p))
{
//创建一个节点并赋值
s = (BiTree)malloc(sizeof(BiTode));
s->data = key;
s->lChild = s->rChild = NULL;
//如果p指向空,则直接插入
if (!p)
{
*T = s;
}
else if (key > p->data)
{
p->rChild = s;
}
else
{
p->lChild = s;
}
return true;
}
else
return false;
}
Status DeleteNode(BiTree *p)
{
BiTree q, s;
//只有右子树
if ((*p)->lChild == NULL)
{
q = *p;
*p = (*p)->rChild;
free(q);
}
//只有左子树
else if ((*p)->rChild == NULL)
{
q = *p;
*p = (*p)->lChild;
free(q);
}
//左右子树皆不为空,从左子树中找到最右节点即为删除节点的直接前驱,进行替换
else
{
q = *p; s = (*p)->lChild;
while (s->rChild != NULL)
{
q = s;
s = s->rChild;
}
//找到直接前驱,将s的值赋予删除节点,释放s。
(*p)->data = s->data;
if (q != *p)
{
q->rChild = s->lChild;
}
else
{
q->lChild = s->lChild;
}
free(s);
}
return true;
}
//删除操作
Status DeleteBST(BiTree *T,KeyType key)
{
//若二叉排序树T中存在关键字等于key的节点,则删除
//如果不存在,则直接返回false;
if (!*T) return false;//一直遍历,知道*T为空难,则不存在关键字等于key的元素
else
{
if (key == (*T)->data)
{
return DeleteNode(T);
}
else if (key > (*T)->data)
{
return DeleteBST(&(*T)->rChild,key);
}
else
{
return DeleteBST(&(*T)->lChild,key);
}
}
}
//创建一颗二叉排序树
void CreateBST(KeyType array[], BiTree *p,int len)
{
int i;
BiTree T = *p;
for (i = 0; i < len; i++)
{
if (InsertBST(&T, array[i]))
{
cout << "创建了一个值为" << array[i] << "的节点" << endl;
}
}
*p = T;
}
void Delete(BiTree root,KeyType *array,int len)
{
int i;
for (i = 0; i < len; i++)
{
if (DeleteBST(&root, array[i]))
{
cout << "删除了一个值为" <<array[i]<<"的节点"<< endl;
}
}
if (root == NULL)
{
cout << "销毁成功!" << endl;
}
}
int main(void)
{
int arr[] = {35,62,37,64,84,96,12,4,75,61};
int len = sizeof(arr) / sizeof(arr[0]);
BiTree proot = NULL;
BiTree p;//用于指向查找元素的节点
int searchdata;
CreateBST(arr,&proot,len);
if (proot != NULL)
{
cout << "创建成功!" << endl;
}
//查找元素
cin >> searchdata;
if (SearchBST(proot, searchdata, NULL, &p))
{
printf("元素%d已找到!\n",p->data);
}
else
{
printf("没有找到此元素!\n");
}
Delete(proot,arr,len);
return 0;
}