【数据结构】二叉查找树

查找树
  • 定义

    定义1:查找树T是一棵二叉树T,它或空,或满足下面三个条件:

    (1)如果树T的根节点的左子树非空,那么左子树中的所有结 点的键值都小于T的根结点的键值。

    (2)如果树T的根节点的右子树非空,那么右子树中的所有结 点的键值都大于T的根结点的键值。
    (3)树T的根结点的左、右子树也都是查找树。

    定义2:

    对于一棵给定的二叉树T,如果树T中的结点的中序是排好序的,那么我们称树T是一棵查找树。

  • 查找

    NODE* search(NODE* sub_root, char target) {
    	if sub_root == NULL || subroot->data == target)
        	return sub_root;
    	else if (sub_root->data > target)
            return search (sub_root->lchild, target);
        else return search (sub_root->rchild, target);
    }
    NODE* search (NODE* sub_root, char target) {
    	while (sub_root != NULL && subroot->data != target)
            if (sub_root->data < target)
                sub_root=sub_root->rchild;
    		else
                sub_root=sub_root->lchild;
        return sub_root;
    }
    
    //查找的同时获取父结点——为了插入和删除
    void search(NODE *t,char target,NODE **p_p,NODE **p_q) //p_p,p_q指向指针变量的指针。 *p_q是指针,指向当前结点; *p_p指向当前结点 的父结点
    {
        *p_p=NULL;
        *p_q=t;
        while (*p_q != NULL){
            if (*p_q)->data == target) return; //找到结点 
            *p_p= * p_q; //准备“下移” 
            if (target<(*p_q)->data) *p_q=(*p_q)->lchild;
    		else * p_q=(*p_q)->rchild; }// 算法执行到结束,若*p_q不空,则*p_q所指的结点就是要查找的结点
    }
    /*
    算法执行到结束,若*p_q不空,则*p_q所指的结点就是要查找的结点 (找到了),而*p_p指向它的父结点。若此时*p_p为空,则根结点键值符合。
    假若*p_q为空,则表示找不到target结点。此时*p_p有两种情况:
    (1)若为空,则查找树t为空树;
    (2) *p_p不为空,*p_p指向查找路径的最后一个结点。
    */
    

在这里插入图片描述

  • 插入

    (1)已有键值为target的结点,不执行插入操作;

    (2)树空,插入的结点成为树根;
    (3)树不空, 寻找合适的位置插入

    int search_and_insert (NODE **sub_root, char new_data) {
    	if (( *sub_root )== NULL)
        {*sub_root = ……; return (0);//构造结点成为树根 }
    	else if (new_data <(*sub_root)->data)
            return search_and_insert(&(*sub_root)->lchild,new_data);
    	else if (new_data >(*sub_root)->data)
            return search_and_insert(&(*sub_root)->rchild,new_data);
        else return(1);// 要插入的节点值重复,则插入失败
    }
        
    int insert (NODE **p_t, char a) {
    	NODE *p,*q,*r;
        Search (*p_t,a,&p;&q);
        if (q!=NULL) return (1); r=………… //构造结点r 
        if (p==NULL) *p_t=r;
        else if (p->data>a) p->lchild=r;
        else p-rchild=r;
    	return (0);
    }
    
  • 构建

    int main() {
    	BSTNODE *root;
        root=NULL;
        int n;
        char a;
        cin>>n;
        while (n--) {
    		cin>>a;
            insert (&root,a);
    	}
    	return 0;
    }
    
  • 删除

    找到要删除的结点,将它删去,要求删除后的二叉树仍是一棵查找树。

    用中序序列检验

    在这里插入图片描述
    在这里插入图片描述

    在这里插入图片描述

    在这里插入图片描述

    在这里插入图片描述

    int delete (NODE **p_t, char to_delete) {
    	NODE *p,*q,*r;
        search (*p_t, to_delete,&p;&q); //执行后q如果不空,指向找到的结点 //待删除结点如果不是根,p指向q的父结点
    	If (q==NULL) return (1); //结点“to_delete” 不在树中
        If (p==NULL) //p为NULL,找到的结点为根,被删结点为根结点
            if (q->lchild==NULL) *p_t=q->rchild;
            else { r=q->lchild;
                  while (r->rchid!=NULL) r=r->rchild; //找“最右” 
                  r->rchild=q->rchild; *p_t =q->lchild;
            }
        //将要被删除的结点q不是根,作为子树的根来处理,同时完成父结点p的指针变化 
        else if (q->lchild == NULL ) 
            if(q==p->lchild) p->lchild=q->rchild;
        	else p->rchild = q->rchild;
    	else{ 
            r=q->lchild;
            while (r->rchid!=NULL) r=r->rchild;
    		r->rchild=q->rchild;
            if (q==p->lchild) p->lchild=q->lchild;
            else p->rchild = q->lchild; }
        free (q);
        return (0);
    }
    
  • 效率分析

    在这里插入图片描述

    在这里插入图片描述

    当树中结点尽量靠近树根时,AVG(二叉查找法)的值达 到最小。当查找树退化成链接表时,AVG的值达到最大

  • 满树,拟满树,丰满树

    设二叉树T有n个结点,i=[ l o g 2 ( n + 1 ) log_2(n+1) log2(n+1)](向下取整),r=n-( 2 i − 1 2^i-1 2i1

    如果其中( 2 i − 1 2^i-1 2i1)放满第0至第(i-1)层。

    (1)若r=0,则称树T是一棵满二叉树,简称满树。

    (2)若r>0,且剩下的r个结点尽量靠左地排列在第i层上,则称树T是一棵拟 满二叉树(完全二叉树)。
    (3)若r>0,且剩下的r个结点随意分布在第i层,则称树T是一棵丰满二叉树。

    如果树T是满树,那么树T一定是拟满树(完全二叉树)和丰满树。 如果树T是拟满树(完全二叉树) ,那么树T一定是丰满树。

    在这里插入图片描述

    拟满树和丰满树在查找效率上没有差别

    构造丰满树

    若丰满树T中有n个结点,则树T有[ l o g 2 n log_2n log2n]+1层(向下取整)。当n=2t-1时,丰
    满树刚好是一棵满树。

    在这里插入图片描述

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值