二叉搜索树

/*
      二叉搜索树: 1.每个数据都具有唯一的关键字
                            2.比根节点关键字打的放右边,小的放左边,所以每一次缩减都可以至少排除一半的数
                            3.二叉搜索树的每一个子树都是二叉搜索树
                             
               采用中序遍历进行排序,左,根,右
*/

#include<stdio.h>
#include<stdlib.h>
#include<string.h>

//每一个节点的数据
typedef   struct   dataPair
{
     int    first;           //关键字
     char   second[20];      //数据
}DATA,*LPDATA;

//二叉树结构体
ytpedef  struct  treeNode
{
      DATA   data;
      struct   treeNode*LChild;
      struct   treeNode*RChild;
}NODE,*LPNODE;

//封装一个二叉树组
typedef   struct   binarySearchTree
{ 
         LPNODE    root;    //用根节点表示整个数组
         int   treeSize;         //树中结点数
}BST,*LPBST;

//创建树
LPBST  createBST()
{
    LPBST  tree = (LPBST)malloc(sizeof(BST));
    tree->root = NULL;
    tree->treeSize = 0;
    return  tree;
}

//创建节点
LPNODE  createNode(DATA  data)
{
    LPNODE  newNode = (LPNODE)malloc(sizeof(NODE));
    newNode->data = data;
    newNode->LChild = NULL;
    newNode->RChild = NULL;
    return  newNode;  
}

//万金油函数
int  size(LPBST  tree)
{
    return   tree->treeSize;
}
int   empty(LPBST  tree)
{
    return   tree->treeSize == 0;
}

//打印遍历
void   printNode(LPNODE  curNode)
{
    printf("%d\t%s\n",curNode->data.first,curNode->data.second);
}

//中序遍历
void   midOrder(LPNODE  tree)
{
    if(tree != NULL)
    {
        midOrder(tree->LChild);  //通过循环midOrder函数,实现重复寻找
        printNode(tree);
        midOrder(tree->RChild); 
    }
}

//插入节点
void   insertNode(LPBST  tree,DATA  data)
{
    //插入的话,找到叶子结点就可以了,通过关键字比较大小
    LPNODE  newNode = createNode(data);
    //找合适的位置插入
    LPNODE  pMove = tree->root;
    LPNODE  pMoveParent = NULL;    //记录空NULL 的上一个节点,只有找到最末尾的下一个NULL(空)才找到最后的节点
    while(pMove != NULL)
    {
        pMoveParent = pMove;   //记录移动节点的父结点,即pMove上一个结点
        if(data.first < pMove->data.first)
        {
            pMove = pMove->LChild; 
        }
        else  if(data.first>pMove->data.first)
        {
             pMove = pMove->RChild; 
        }
        else
        {
             //修改相同关键字的结点的数据
             strcpy(pMove->data.second,data.second)
             return;
        }
     }
        //退出循环,找到了合适的位置
        if(tree->root == NULL) //一次都不循环
        {
            tree->root = newNode; 
        }
        else
        {
            //判断pMoveParent插在pMove的左边还是右边
            if(pMoveParent->data.first > data.first)
            {
                 pMoveParent->LChild = newNode;  //插入的节点数据比根部小,插在左边
            }
            else
            {
                 pMoveParent->RChild = newNode;  //比根部大,插在右边
            }
        }
    }
    tree->treeSize++;
}

//查找,通过关键字去查找
LPNODE  searchBST(LPNODE  tree,int  first)
{
    LPNODE  pMove = tree->root;
    if(pMove == NULL)
          return   pMove; 
    else
    {
        while(pMove->data.first != first)
        {
             if(pMove->data.first > first)
             {
                  pMove = pMove->LChild; 
             } 
             else
             {
                 pMove = pMove->RChild; 
             }
             if(pMove == NULL)
                return   pMove;
        } 
        return  pMove;
    }
}

//二叉搜索树的删除,先删除根节点,是需要调整的,一种是:从左子树中找根节点左边最大的数放上去;另一种是:从右子树最左边把根节点右边最小的数放上去
void   erase(LPBST  tree,int   first)
{
     //删除根节点,必定会影响父结点,和孩子节点(根节点,左子树结点,右子树结点全部的指针都要保存),所以需要去保存影响的节点,在这里创建新的节点为连接方式
     LPNODE   pMove = tree->root;
     LPNODE   pMoveParent = NULL;
     while(pMove != NULL && pMove->data.first != first)
     { 
          pMoveParent = pMove;
          if(first < pMove->data.first)
          {
              pMove = pMove->LChild;  //往左边寻找 
          }
          else  if(first > pMove->data.first)
          {
              pMove = pmove->RChild; 
          }
          else
             break;
     }
     if(pMove == NULL)
     {
         printf("没有找到指定位置,无法删除");
         system("pause");
         return;
     }
     //删除节点的左右子树都存在,我们要找左子树的最右边放上去,因为左子树最右边的数是最大的,如果不是它,就不能完成按大小顺序排列
     if(pMove->LChild != NULL && pMove->RChild != NULL)
     {
          //找最右边放上去,moveNode为移动的指针,moveNodeParent为moveNode的父结点
          LPNODE  moveNode = pMove->LChild;
          LPNODE  moveNodeParent = pMove;
          //找最右边放上去,如果不等于空,就等于还没有找到删除节点的左子树的最右边,要往下走
          while(moveNode->RChild != NULL)
          {
                moveNodeParent = moveNode;
                moveNode = moveNode->RChild;
          }
          LPNODE  newNode = createNode(moveNode->data);
          newNode->LChild = pMove->LChild;
          newNode->RChild = pMove->RChild;  //保存pMove删除结点的左右子树
          //分类讨论删除的节点
          if(pMoveParent == NULL) //删除的是根节点
              tree->root = newNode;
          else if(pMove == pMoveParent->LChild)  
              pMoveParent->LChild = newNode;
          else
             pMove->RChild = newNode;
           //调整二叉树     
          if(moveNodeParent == pMove)
          {
             pMoveParent = newNode; 
          }
          else
          {
             pMoveParent = moveNodeParent; 
          }
          free(pMove);
          pMove = moveNode;
     }
     LPNODE  sNode = NULL;
     //如果删除结点左右存在节点,保存删除结点的下一个节点
     if(pMove->LChild != NULL)
        sNode = pMove->LChild;
     else
         sNode = pMove->RChild;
     if(tree->root == pmove)
     {
         tree->root = sNode; 
     }
     else
     {
         if(pMove == pMoveParent->LChild)
         {
              pMoveParent->LChild = sNode;
         } 
         else
         {
         	  pMoveParent->RChild = sNode;
         }
     }
     free(pMove);
     tree->treeSize--;
}

int  main()
{
       LPBST  tree = createBST();
       DATA   array[8] = { 50 ,"明"10 ,"其",80,"鬼",30,"五",60,"死",55,"卡尔",45,"冥王",20,"鬼王"};
       for(int  i=0;i<8;i++)
       {
           insertNode(tree,aray[i]); 
       }
  	   printf("中序遍历结果:\n");
       midOrder(tree->root);
       //输出结果,按数字大小进行排序
       
       printf("查找55:");
       printNode(searchBST(tree,55));  //查找到的是 “卡尔”

       erase(tree,30);
       midOrder(tree->root);
       printf("\n");

       system("pause");
       return   0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值