二叉搜索树

来源:互联网 发布:caffe matlab可视化 编辑:程序博客网 时间:2024/06/05 04:12

概述:

二叉搜索树中的关键词总是以满足二叉搜索树性质的方式来存储:
设x是二叉搜索树中的一个结点。如果y是x左子树中的一个结点,那么y.key<=x.key。如果y是x右子树中的一个结点,那么y.key>=x.key。

Notes:不同于一般二叉树,二叉搜索树的顺序与结点内容即key值有关,而一般二叉树对相应结点的key值没有要求,故若要对一般二叉树进行遍历,则要排序,因此才有常见的先序,中序,后序三种遍历方式

这样一棵树可以使用一个链表数据结构来表示。
对二叉搜索树的基本操作有:
查找(基于关键词、最小值、最大值、后继、前驱)、插入(考虑空树情况)、删除
(时间复杂度均为O(h), h为树的高度)

代码实现

#include<stdio.h>#include<stdlib.h>typedef int ElemType;typedef struct BiTree{//也即三叉链表 二叉链表少了双亲域    ElemType key;//结点值    struct BiTree *left;//左孩子    struct BiTree *right;//右孩子    struct BiTree *p;//双亲}BiTNode,*BiTree;/*基于关键词的查找*///递归表示BiTree Search_BST(BiTree T, ElemType k){    if (T != NULL&&T->key != k)    {        if (k < T->key)            return Search_BST(T->left,k);        else            return Search_BST(T->right,k);    }    return T;}//迭代表示BiTree Interative_Search_BST(BiTree T, ElemType k){    while (T != NULL&&T->key != k)    {        if (k < T->key)            T = T->left;    else            T = T->right;    }    return T;}/*最大关键字元素和最小关键字元素的查找*/BiTree Tree_Minimum(BiTree T){    while (T->left != NULL)//找到最左下的元素        T = T->left;    return T;}BiTree Tree_Maximum(BiTree T){    while (T->right != NULL)//找到最右下的元素        T = T->right;    return T;}/*对某结点的后继和前驱的查找*/BiTree  Tree_Successor(BiTree T)//查找后继{    if (T->right != NULL)//T有右孩子,返回右子树的最小值        return Tree_Minimum(T->right);    BiTree y;    y = T->p;//y为T的双亲    while (y != NULL&&T == y->right)//直到找到一个结点是这个结点的双亲的左孩子 返回这个双亲    {        T = y;        y = y->p;    }    return y;}BiTree Tree_Predecessor(BiTree T)//查找前驱{    if (T->left != NULL)        return Tree_Maximum(T->left);    BiTree y;    y = T->p;    while (y != NULL&&T == y->left)    {        T = y;        y = y->p;    }        return y;}/*二叉搜索树的插入*///note:要对搜索树结构进行修改void InsertBST(BiTree &T, ElemType e)//传入二叉树的根结点地址  note:《算法导论》传的是T.root 说明定义了另一个结构体存树的相关信息 如根结点地址 结点数等{    BiTree z, x, y=NULL;    //对新增结点进行初始化,现在要修改的是它的双亲和它双亲的left或right    z = (BiTree)malloc(sizeof(BiTNode));    if (z != NULL)//空间申请成功    {        z->key = e;        z->left = z->right=NULL;    }    x = T;    while(x != NULL)    {        y = x;        if (z->key < x->key)//z应该插入到左半部分            x = x->left;        else            x = x->right;    }//循环跳出后 x=NULL, x的位置即z要插入的位置 y的位置为z的双亲的位置    //下面处理z和y的关系    z->p = y;    if (y = NULL)//说明是空树        T = z;//新插入的z即为根结点    else if (z->key < y->key)//z为y左孩子        y->left = z;    else        y->right = z;}/*这个函数用一个以v为根的子树来替换一个以u为根的子树,二叉树的删除操作要用到*/void Transplant(BiTree &T, BiTree u, BiTree v){    if (u->p == NULL)//u没有双亲,说明u为根结点        T = v;    else if (u->p->left == u)//若u是其双亲的左子树        u->p->left = v;    else        u->p->right = v;    if (v != NULL)//要考虑v是否为空        v->p = u->p;}/*对二叉树的删除操作*/void DeleteBST(BiTree &T, BiTree z)//以T为根结点的二叉搜索树中删除结点z{    if (z->left == NULL)//第一种情况:要删除的结点没有左孩子 包含了z只有右孩子和右孩子为NULL即z没有孩子的情况 ,z右孩子代替z        Transplant(T, z, z->right);    else if (z->right == NULL)//第二种情况:z有且仅有非NULL左孩子(因为左孩子为NULL则说明没有孩子,这种情况上面已经包含了)z左孩子代替z        Transplant(T, z, z->left);    else    {        BiTree y = Tree_Minimum(z->right);        if (y != z->right)//若z的右孩子不是z的后继 说明以右孩子为根的子树最小的那个结点才是z的后继  这个时候这个结点一定没有左孩子!!!        {            Transplant(T, y, y->right);//用y自己的右孩子来替代y         //  y->p = z->p;//???这一步不用吗???不用  因为后面还要将y Transplant到z 故只用处理好p的子树部分即可            y->right = z->right;//并置y为z的右孩子的双亲            y->right->p = y;        }//处理完以后继结点y为根的子树后(包含本来y就是z的右孩子的情况)        Transplant(T, z, y);        y->left = z->left;        y->left->p = y;    }}

notes:

1.查询二叉搜索树,对于大多数计算机,用迭代方式比用递归效率要高得多。
2.《算法导论》中函数传入的是T.root 应该有个类似下面形式的结构体定义,T是Tree类型的变量,我的函数中传入的T默认是根结点地址。

typedef struct{    BiTree root;//根结点地址    int nodenum;//结点数量    //其他信息,如树的类型(二叉搜索树,红黑树,AVL树,B-/B+树)blablabla}Tree;
0 0
原创粉丝点击