BST(排序二叉树/二叉搜索树)的插入,查找,删除

BST:

  1. 空树
  2. 左右子树若存在,左子树上任一结点都小于根结点的值,右子树上都大于根结点值;它的左右子树也都是BST。

BST提高查找、插入和删除效率

结构体:

typedef struct BST
{
    int nValue;
    struct BST *pLeft;
    struct BST *pRight;
}BinaryTree;

创建:

给定一个值,首先看树是否是空树,空树则新插入的值为根,若所要插入值 大于 ’当前结点值 ‘则向结点左子树搜索 直到遇到空值,反之亦然

void InsertBST(BinaryTree **pTree,int x);

void CreateBST(int arr[],int len);

 1 void Insert(BinaryTree **pTree,int x)
 2  {
 3      BinaryTree *pTemp = NULL;//新建一个temp存待插入数
 4      pTemp = (BinaryTree*)malloc(sizeof(BinaryTree));
 5      pTemp->nValue = x;
 6      pTemp->pLeft = NULL;
 7      pTemp->pRight = NULL;
 8 
 9      //树为空时插入的直接是根
10      if(*pTree     == NULL)
11      {
12          *pTree = pTemp;
13          return;             
14 
15      }
16      BinaryTree *pMark = *pTree;
17      while(pMark)
18      {
19                  //遍历至待插入位置
20                  //大于‘根结点‘情况,找到空的放右
21          if(pMark->nValue < x)
22          {
23              if(pMark->pRight == NULL)
24              {
25                  pMark->pRight = pTemp;
26                  return ;
27              }
28              pMark = pMark->pRight;//非空继续遍历树下一个结点
29          }
30                  //小于’根结点‘情况,找到空放左侧
31          else if(pMark->nValue > x)
32          {
33              if(pMark->pLeft ==NULL)
34                  {
35                      pMark->pLeft = pTemp;
36                      return;
37                  }
38              pMark = pMark->pLeft;
39          }
40          else 
41          {
42              printf("erro\n");
43              free(pTemp);
44              pTemp = NULL;//插入失败,释放掉这块空间
45             return;
46          }
47          
48      }      
49  }
 1 递归:
 2 void Insert2(BinaryTree **pTree,int x)
 3 {
 5     if(*pTree     == NULL)
 6     {       
 7         BinaryTree *pTemp = NULL;
 8         pTemp = (BinaryTree*)malloc(sizeof(BinaryTree));
 9         pTemp->nValue = x;
10         pTemp->pLeft = NULL;
11         pTemp->pRight = NULL;
12         *pTree = pTemp;
13         return;            
14     }
15     BinaryTree *pCur = *pTree;
16     if(pCur->nValue <x)
17         Insert2(&(pCur->pRight),x);
18     else if(pCur->nValue > x)
19         Insert2(&(pCur->pLeft),x);
20     else 
21     {
22         printf("erro\n");
23         return;
24     }
25 }

 

 1 BinaryTree* CreateBST(int arr[],int nlen)
 2  {
 3      if(arr == NULL || nlen <=0)
 4          return  NULL;//待插入为空时直接返回空
 5      BinaryTree *pTree = NULL;
 6      int i;
 7      for(i =0;i<nlen;i++)
 8      {
 9          Insert(&pTree,arr[i]);
10      }
11      return pTree;
12  }    

 删除:先搜索结点位置,再删除

          搜索和插入类似,只不过是遇到值相同停止。 

          删除则有3种情况:

  1. 是叶子结点——直接删除
  2. 度为1的结点——删除后结点的父亲与左孩子或者右孩子相连
  3. 度为2的结点——找到待删结点的左最大或者右最小来顶替这个位置,保证BST结构不被破坏。(左最大或者右最小 这两个点肯定是度为1或者度为0 的点)问题转换为度为1结点情况

老师给出的代码是倒着,先将情况3->情况2/1 对情况2而言,1是特殊情况即左右孩子为空。我自己的思路是封装3种情况,然后再判断,代码还有点问题

通过搜索找到待删结点位置,找到其父亲结点位置,本身位置,这里返回两个值,直接使用二级指针来修改这两个值(所以在删除的函数里有定义pFather后再传入)

 1 void Search(BinaryTree *pTree,int x,BinaryTree **pDel,BinaryTree **pFather)
 2  {
 3      while(pTree)
 4      {
 5          
 6          if(x < pTree->nValue )
 7          {
 8               *pFather = pTree;
 9              pTree = pTree->pLeft;
10          }
11          else if(x > pTree->nValue)
12          {
13               *pFather = pTree;
14              pTree = pTree ->pRight;
15          }
16          else 
17          {
18              *pDel = pTree;
19              return;
20          }}
21 pFather = NULL;//待删的点为根结点时,手动赋NULL 22 }
 1 void Delete(BinaryTree **pTree,int x)
 2 {
 3     BinaryTree *pDel = NULL;   //待删除结点
 4     BinaryTree *pFather = NULL;
 5     Search(*pTree,x,&pDel,&pFather);
 6     if(pDel == NULL)return;     
 7     //根、非根             ?
 8     //两个孩子,此时无法直接换根达到目的,是不是根影响不大
 9     if(pDel->pRight  != NULL && pDel->pLeft != NULL)
10     {
11         //找左边最大的    
12         pFather = pDel;
13         BinaryTree *pMark = pDel->pLeft; //pMark标记左边最大的位置
14         
15         while(pMark->pRight)
16         {
17             pFather = pMark;
18             pMark = pMark->pRight;
19         }
20         //换值
21         pDel->nValue = pMark->nValue;
22         pDel = pMark;
23     }
24     //1个孩子或者0个孩子 
25     //根    ——直接换根
26     if(pFather == NULL)    
27     {
28         (*pTree) = pDel->pLeft ? pDel->pLeft :pDel->pRight;
29         free(pDel);
30         pDel  = NULL;
31         return;
32     }
33     //非根
34     if(x <pFather->nValue)
35     {
36         pFather->pLeft = pDel->pLeft ? pDel ->pLeft : pDel->pRight;     
37         //x在pFather的左边,pDel的左存在则直接与pFather相连,反之与右相连;
38         //特殊情况两个都为NULL;
39     }
40     else
41     {
42         pFather->pRight = pDel->pLeft ? pDel ->pLeft : pDel->pRight;
43     }  
44     free(pDel);
45     pDel = NULL;
46     
47 }

 BST变成有序双向链表(递归实现):

void BSTtoList(BinaryTree *pTree,BinaryTree **pHead,BinaryTree **pTail)
{
    if(pTree == NULL)return;
    //BST中序遍历即实现有序的
    //
    BSTtoList(pTree->pLeft,pHead,pTail);
    //
    if(*pHead == NULL)
    {
        *pHead = pTree;
        *pTail = pTree;
    }
    else
    {
        (*pTail)->pRight = pTree;
        pTree->pLeft = *pTail;
        (*pTail) = pTree;
    }
    //
    BSTtoList(pTree->pRight,pHead,pTail);
}

 

posted @ 2021-05-15 17:11  七里橙花  阅读(386)  评论(0)    收藏  举报