查找-之二叉排序树(查找、插入、删除)

简介: 有序的线性表采用:折半/二分、插值、斐波那契查找相比顺序查找效率得到提高,但是在插入和删除时效率低(为维持数据的有序性) 在高效实现查找操作时,如何提高插入和删除的效率?在一些应用场景:在查找时需要插入和删除

问题:

有序的线性表采用:折半/二分、插值、斐波那契查找相比顺序查找效率得到提高,但是在插入和删除时效率低(为维持数据的有序性)

在高效实现查找操作时,如何提高插入和删除的效率?

在一些应用场景:在查找时需要插入和删除

解决方法:

二叉排序树


二叉排序树特点

1)若左子树不为空,左子树上所有结点的值均小于或等于它的根节点的值

2)若右子树不为空,右子树上所有结点的值均大于或等于它的根节点的值

3)左右子树也分别为二叉排序树

二叉排序算法的复杂度:

时间复杂度:二分查找的思想,查找次数为二叉查找树的高度,若树为平衡二叉树则为O(logn),否则最坏的情况为右斜树O(n)

二叉排序算法的缺点是:

二叉树的构建类型多种,不同的二叉树形状会导致查找的性能差异很大,例如普通的二叉树和一棵右斜树。

二叉排序树的查找:

1)查找数据key,判断key是否等于树的根节点数据

2)若待查数据key小于根结点数据则递归的在左子树查找

3)若待查数据key大于根结点数据则递归的在右子树查找

C伪代码:

//定义结点结构
typedef struct BiTNode
{
   int data;  //结点数据
   struct BiTNode *lchild, *rchild;//左右孩子指针
}BiTNode,*BiTree


/递归查找二叉排序树T中是否存在key
//f指向T的双亲 
//p获得查找到的结点位置
Status SearchBST(BiTree T,int key,BiTree f,BiTree *p)
{
   //查找不成功
    if(!T)//判断当前二叉树是否到叶子结点
     {
        *p=f;//指针p指向查找路径上访问的最后一个结点并返回false
        return False;
     }
   //查找成功
   else if(key==T->data)
    {
       *p=T;
      return True;
   }
  else if(key<T->data)//待查找元素小于结点数据
      return SearchBST(T->lchild,key,T,p);//在左子树继续查找
  else
      return SearchBST(T->rchild,key,T,p);//在右子树继续查找
}

二叉排序树的插入操作:

1)在二叉排序树找不到待插入的数据key则执行2)步骤

2)待插数据初始化为结点s,若树为空则直接赋值结点s给树

3)待插入数据key小于根结点数据则插入为左孩子

4)  待插入数据key大于根结点数据则插入为右孩子

C伪代码:

//定义结点结构
typedef struct BiTNode
{
   int data;  //结点数据
   struct BiTNode *lchild, *rchild;//左右孩子指针
}BiTNode,*BiTree
//二叉树的数据插入
Status InsertBST(BiTree *T,int key)
{
  BiTree p,s;//创建二叉树结点
  //在二叉排序树中找不到key
  if(!SearchBST(*T,key,NULL,&p))
    {
        //s结点的初始化
        s=(BiTree)malloc(sizeof(BiTNode));
        s->data=key;
        s->lchild=s->rchild=NULL;
        //若p结点为空
        if(!p)
              *T=s;
        else if (key<p->data)//待插入的值key小于p结点指向的数据
              p->lchild=s;//s插入为左孩子
        else//待插入的值key大于p结点指向的数据
             p->rchild=s;//s插入为右孩子
       return True;
   }
//树中已有关键字相同的结点,不再插入
  else
     return False;
}

构建一棵二叉排序树示例:

//生成一棵二叉树
int i;
int a[10]={62,88,58,47,35,73,51,99,37,93};
Bitree T=NULL;
for(i=0;i<10;i++)
{
    InsertBST(&T,a[i]);
}

二叉排序树的删除操作:

删除结点的三种情况:

1)删除叶子结点

2)删除的结点只有左或右子树的

3)删除的结点有左右子树

//定义结点结构
typedef struct BiTNode
{
   int data;  //结点数据
   struct BiTNode *lchild, *rchild;//左右孩子指针
}BiTNode,*BiTree
//删除元素等于key的数据结点
Status DeleteBST(BiTree *T,int key)
{
 //不存在关键字等于key的数据元素
   if(!*T)
       return False;
  else
  {
       if(key==(*T)->data)     //找到关键字等于key的数据元素
               return Delete(T);
       else if(key<(*T)->data)//待删除的元素key小于查找到的元素---则在结点的左子树搜索
              return DeleteBST(&(*T)->lchild,key);
       else                               //待删除的元素key大于查找到的元素---则在结点的右子树搜索
              return DeleteBST(&(*T)->rchild,key);
  }
}
Status Delete(BiTree *p)
{ 
     BiTree q,s;
    //第一种情况,删除结点只有左子树或右子树
     if((*p)->rchild==NULL)//只有左子树
      {  
            q=*p;
            *p=(*p)->lchild; 
            free(q);
      }  
    else if((*p)->lchild==NULL)//只有右子树
     {
          q=*p;
          *p=(*p)->rchild;
          free(q);
    }
  //第二种情况:删除的结点有左子树和右子树
  else
    {
      q=*p;//待删除的结点给临时变量q
      s=(*p)->lchild;//待删除结点指向的左子树给临时变量s
      while(s->rchild)//左子树s一直向右找,直到找到待删结点的前驱
         {
            q=s;
            s=s->rchild;
         }
    (*p)->data=s->data;//s指向被删结点的直接前驱,将它的值直接赋值给要删除的结点*p
    if(q!=*p)//被删结点的直接前驱p!=被删结点的直接前驱的根结点q
       q->rchild=s->lchild;//根结点q的右孩子指针指向被删结点的直接前驱的左孩子
    else
        q->lchild=s->lchild;
   free(s);
    } 
}

上述代码需注意:

1)q!=*p的情况:

0fa82f70d8a010f4fbf68a49eec467dc_watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2hlZGEz,size_16,color_FFFFFF,t_70.png

db83bb2d07500a9a2528e69e3f9f0424_watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2hlZGEz,size_16,color_FFFFFF,t_70.png

2) q=*p的情况:

若上图的结构修改为:

没有结点37和36,s指向35。

p和q的指向相同都是47结点处,则将s->lchild指向的29赋值给q->lchild

 

后续:如何解决二叉排序树多次插入新结点而导致的不平衡?

目录
相关文章
|
5月前
|
算法 C++
查找方式:依次查找与二分查找
查找方式:依次查找与二分查找
|
7月前
二叉树的创建、插入和删除
二叉树的创建、插入和删除
41 1
|
8月前
|
存储
单链表相关操作(插入,删除,查找)
单链表相关操作(插入,删除,查找)
70 4
|
8月前
顺序表的插入,删除,修改和查找(详细解析)
顺序表的插入,删除,修改和查找(详细解析)
96 5
|
8月前
双链表的插入,删除以及遍历
双链表的插入,删除以及遍历
52 6
|
算法
查找
查找是指在图中寻找特定的节点或边的过程。在图中进行查找操作可以帮助我们找到与目标节点或边相关的信息,或者判断图中是否存在某个节点或边。 在图中进行查找操作的常见算法有: 1. 深度优先搜索(DFS):从图中的一个节点开始,沿着一条路径一直深入直到无法再深入为止,然后回溯到上一个节点,继续深入其他路径,直到找到目标节点或遍历完所有节点。 2. 广度优先搜索(BFS):从图中的一个节点开始,先访问它的所有邻居节点,然后再依次访问邻居的邻居节点,直到找到目标节点或遍历完所有节点。 3. Dijkstra算法:用于在带权有向图中找到从一个节点到其他节点的最短路径。该算法通过不断更新节点的最短距离来逐步
86 0
|
8月前
|
算法 C语言
【408数据结构与算法】—顺序表的插入、删除和查找(四)
【408数据结构与算法】—顺序表的插入、删除和查找(四)
|
存储 C++
链表操作:插入、删除与遍历
(笔者画图不易呜呜)链表是一种基本的数据结构,它可以用来存储一系列的元素,并且支持灵活的插入、删除操作。在计算机科学中,链表常常用于构建更复杂的数据结构,如栈、队列以及图等。
363 0
链表学习(链表的创建,插入,删除,查找,遍历)
链表学习(链表的创建,插入,删除,查找,遍历)
135 0
二叉排序树的建立、查找、插入、删除
二叉排序树的建立、查找、插入、删除
121 0

热门文章

最新文章