• 二叉树增删改查 && 程序实现


    二叉排序树定义

    一棵空树,或者是具有下列性质的二叉树:
    (1)若左子树不空,则左子树上所有结点的值均小于它的根结点的值;
    (2)若右子树不空,则右子树上所有结点的值均大于它的根结点的值;
    (3)左、右子树也分别为二叉排序树;
    (4)没有键值相等的结点。

    二叉树删除节点

    二叉排序树删除节点的时候为其删除后还是一个二叉排序树,要对不同的情况进行分别处理

    1、p结点为叶子结点,即PL(左子树)和PR(右子树)均为空树。由于删去叶子结点不破坏整棵树的结构,则可以直接删除此子结点。

    2、p结点只有左子树PL或右子树PR,此时只要令PL或PR直接成为其双亲结点*f的左子树(当*p是左子树)或右子树(当*p是右子树)即可,作此修改也不破坏二叉排序树的特性。

    3、p结点的左子树和右子树均不空。在删去*p之后,为保持其它元素之间的相对位置不变,可按中序遍历保持有序进行调整,可以有两种做法:
    其一是令*p的左子树为*f的左/右(依*p是*f的左子树还是右子树而定)子树,*s为*p左子树的最右下的结点,而*p的右子树为*s的右子树;
    其二是令*p的直接前驱(或直接后继)替代*p,然后再从二叉排序树中删去它的直接前驱(或直接后继)-即让*f的左子树(如果有的话)成为*p左子树的最左下结点(如果有的话),再让*f成为*p的左右结点的父结点。

    二叉排序树性能分析

    每个结点的C(i)为该结点的层次数。最坏情况下,当先后插入的关键字有序时,构成的二叉排序树蜕变为单支树,树的深度为其平均查找长度(n+1)/2(和顺序查找相同),最好的情况是二叉排序树的形态和折半查找的判定树相同,其平均查找长度和log 2 (n)成正比。

    给定值的比较次数等于给定值节点在二叉排序树中的层数。如果二叉排序树是平衡的,则n个节点的二叉排序树的高度为Log2n+1,其查找效率为O(Log2n),近似于折半查找。如果二叉排序树完全不平衡,则其深度可达到n,查找效率为O(n),退化为顺序查找。一般的,二叉排序树的查找性能在O(Log2n)到O(n)之间。因此,为了获得较好的查找性能,就要构造一棵平衡的二叉排序树。

    程序功能要求

    代码:

      1 //二叉排序树
      2 #include <stdio.h>
      3 #include <stdlib.h>
      4 #define maxn 20
      5 typedef long long ll;
      6 typedef struct Node
      7 {
      8     int id,year,month,day;
      9     char name[maxn],student[maxn],level[maxn],sex[maxn],phone[maxn],local[maxn];
     10 
     11 } nodes;
     12 typedef struct TreeNode
     13 {
     14     struct TreeNode* lchild;
     15     struct TreeNode* rchild;
     16     nodes val;
     17 } TreeNode;
     18 //构造树节点
     19 TreeNode* createTreeNode(nodes val)  //这就是创造一个树节点,给他的左右子树都赋值为NULL
     20 {
     21     TreeNode *node;
     22     node = (TreeNode*)malloc(sizeof(TreeNode));
     23     node->val = val;
     24     node->lchild = NULL;
     25     node->rchild = NULL;
     26     return node;
     27 }
     28 //根据这个数组里面的值创建一颗二叉树
     29 TreeNode* createTree(nodes *array,int length)
     30 {
     31     TreeNode *root = createTreeNode(array[0]);  //创建一个数顶点
     32     TreeNode *temp = root;
     33     TreeNode *parent = root;
     34     int i = 1;  //数组里面的值是从0——length,但是0号位置用过了
     35     while(i<length)
     36     {
     37         temp = root;  //这个位置作用就是每次给树上插入节点都从根节点开始遍历寻找位置
     38         while(temp)
     39         {
     40             parent = temp;  //parent用来记录要把数组中第i位值插到哪个位置
     41             if(temp->val.id>array[i].id)  //比这个节点值大的去左子树
     42             {
     43                 temp = temp->lchild;
     44             }
     45             else if(temp->val.id<array[i].id)  //比这个节点值小的去右子树
     46             {
     47                 temp = temp->rchild;
     48             }
     49             else  //不会重复插入同一树节点
     50             {
     51                 break;
     52             }
     53         }
     54         if(parent->val.id>array[i].id)
     55             parent->lchild=createTreeNode(array[i]);
     56         else
     57             parent->rchild=createTreeNode(array[i]);
     58         i++;
     59     }
     60     return root;  //创建树的根节点
     61 }
     62 //删除节点的核心方法
     63 void deleteNode(TreeNode *node,TreeNode *parent)
     64 {
     65     int flag = -1;
     66     if(parent->lchild==node)
     67     {
     68         flag=1;
     69     }
     70     else
     71     {
     72         flag=0;
     73     }
     74     if(node->lchild==NULL&&node->rchild==NULL)  //如果被删节点左右子树都不存在,那就把这个节点直接删了就完了(so easy)
     75     {
     76         if(flag==1)
     77         {
     78             parent->lchild = NULL;
     79         }
     80         else
     81         {
     82             parent->rchild = NULL;
     83         }
     84     }
     85     else if(node->lchild!=NULL&&node->rchild==NULL) //删除节点有左子树
     86     {
     87         //重接左子树
     88         if(flag==1)
     89         {
     90             parent->lchild = node->lchild;
     91         }
     92         else
     93         {
     94             parent->rchild = node->lchild;
     95         }
     96     }
     97     else if(node->rchild!=NULL&&node->lchild==NULL) //删除节点有右子树
     98     {
     99         //重接右子树
    100         if(flag==1)
    101         {
    102             parent->lchild = node->rchild;
    103         }
    104         else
    105         {
    106             parent->rchild = node->rchild;
    107         }
    108     }
    109     else
    110     {
    111         //左右子树都不空
    112         //右子树取最小的拿过来替代删除节点 或者将删除节点左子树上最大的替代 因为左子树最大的和右子树最小的都一定是叶子节点
    113         //替代之后,既能保持排序二叉树的特性,移除叶子节点也很轻松
    114         TreeNode *pre = node;
    115         TreeNode *in = node->rchild;//往右一步
    116         while(in->lchild) //向左搜索 找到最左边的
    117         {
    118             pre = in;//保存前缀节点
    119             in = in->lchild;
    120         }
    121         //替补
    122         node->val = in->val;
    123         if(pre==node)//判断删除节点右子树是否只有一个节点
    124             pre->rchild = NULL;
    125         else//如果不是 则删除pre的左子树
    126             pre->lchild = NULL;
    127     }
    128 }
    129 //递归寻找删除节点的位置
    130 void del(TreeNode *node,int key,TreeNode *parent)
    131 {
    132     if(node==NULL)
    133         return;
    134     if(key==node->val.id)
    135     {
    136         deleteNode(node,parent);  //找到的话就删除这个节点,但是要注意删除这个节点后二叉树的结构(具体细节在另一个函数中)
    137     }
    138     else if(key>node->val.id)
    139     {
    140         del(node->rchild,key,node);
    141     }
    142     else
    143     {
    144         del(node->lchild,key,node);
    145     }
    146 }
    147 //先序输出
    148 void output(TreeNode *root)
    149 {
    150     if(root==NULL)
    151         return;
    152     printf("%d %s %s %d %d %d %s %s %s %s
    ",root->val.id,root->val.name,root->val.sex,root->val.year,root->val.month,root->val.day,root->val.student,root->val.level,root->val.phone,root->val.local);
    153     output(root->lchild);
    154     output(root->rchild);
    155 }
    156 //查找节点
    157 TreeNode* searchTree(TreeNode *root,int key)
    158 {
    159     if(root==NULL)
    160     {
    161         return NULL;
    162     }
    163     if(root->val.id==key)
    164     {
    165         return root;
    166     }
    167     root->val.id>key?searchTree(root->lchild,key):searchTree(root->rchild,key);//向左或向右查找
    168 }
    169 //插入节点
    170 TreeNode* insertNode(nodes value,TreeNode *root)
    171 {
    172     if(root==NULL)
    173     {
    174         TreeNode *node = createTreeNode(value);
    175         return node;
    176     }
    177     if(root->val.id == value.id) //如果相等 则直接返回
    178     {
    179         return root;
    180     }
    181     if(root->val.id>value.id)
    182     {
    183         //向左遍历
    184         root->lchild = insertNode(value,root->lchild);
    185     }
    186     else
    187     {
    188         //向右遍历
    189         root->rchild = insertNode(value,root->rchild);
    190     }
    191     return root;
    192 }
    193 void display()
    194 {
    195     system("cls");
    196     //陈晓 2018级通信工程 欧亚国际学院 学号1828070055
    197     printf("================职 工 信 息 管 理 系 统============
    
    ");
    198     printf("  ------- 姓名:陈晓
    ");
    199     printf("  ------- 学号:1828070055
    ");
    200     printf("  ------- 学院:欧亚国际学院
    ");
    201     printf("  ------- 年级专业:2018级通信工程
    ");
    202     printf("
    ==================================================
    ");
    203     printf("
    
    
    ");
    204     system("pause");
    205 }
    206 void Menu()
    207 {
    208     nodes a[1005];
    209     TreeNode *p1;
    210     int x,y,i;
    211     TreeNode *root;
    212     while(1)
    213     {
    214         system("cls");
    215         printf ("***********************************************************************************************************************************
    ");
    216         printf ("***********************************************************************************************************************************
    ");
    217         printf ("**                                                    员工信息系统                                                      **
    ");
    218         printf ("***********************************************************************************************************************************
    ");
    219         printf ("***********************************************************************************************************************************
    ");
    220         printf ("***********************************************************************************************************************************
    ");
    221         printf ("***********************************************************************************************************************************
    ");
    222         printf ("**                                                丨                             丨                                              **
    ");
    223         printf ("**********************----------------------------丨[0]查看所有成员              丨----------------------------********************
    ");
    224         printf ("**                                                丨                             丨                                              **
    ");
    225         printf ("**********************----------------------------丨[1]删除成员                  丨----------------------------********************
    ");
    226         printf ("**                                                丨                             丨                                              **
    ");
    227         printf ("**********************----------------------------丨[2]修改成员信息              丨----------------------------********************
    ");
    228         printf ("**                                                丨                             丨                                              **
    ");
    229         printf ("**********************----------------------------丨[3]增加成员                  丨----------------------------********************
    ");
    230         printf ("**                                                丨                             丨                                              **
    ");
    231         printf ("**********************----------------------------丨[4]插入成员                  丨----------------------------********************
    ");
    232         printf ("**                                                丨                             丨                                              **
    ");
    233         printf ("**********************----------------------------丨[5]结束                      丨----------------------------********************
    ");
    234         printf ("**                                                丨                             丨                                              **
    ");
    235         printf ("**********************------------------------------------请输入相应数字---------------------------------------********************
    ");
    236         printf ("***注意: 程序每运行一次3功能,二叉树上内容会更新为最近的信息,之前的信息默认删除。所以建议3功能运行一次,之后想插入成员运行4功能***
    ");
    237         printf ("***********************************************************************************************************************************
    ");
    238         scanf("%d",&x);
    239         if(x==0)
    240         {
    241             system("cls");
    242             printf("请依次输入编号: 姓名: 性别: 出生年月: 学历: 职务: 电话: 住址: 
    ");
    243             output(root);
    244             system("pause");
    245         }
    246         else if(x==1)
    247         {
    248             system("cls");
    249             printf("输入你要删除人的编号: ");
    250             scanf("%d",&y);
    251             del(root,y,root);//删除
    252             printf("删除成功
    ");
    253             system("pause");
    254         }
    255         else if(x==2)
    256         {
    257             system("cls");
    258             printf("输入你要修改人的编号: ");
    259             scanf("%d",&y);
    260             p1=searchTree(root,y);
    261 
    262             printf("编号: 姓名: 性别: 出生年月: 学历: 职务: 电话: 住址: 
    ");
    263             printf("%d %s %s %d %d %d %s %s %s %s
    ",p1->val.id,p1->val.name,p1->val.sex,p1->val.year,p1->val.month,p1->val.day,p1->val.student,p1->val.level,p1->val.phone,p1->val.local);
    264             printf("依次输入修改后的 姓名: 性别: 出生年月: 学历: 职务: 电话: 住址: 
    ");
    265             scanf("%s%s%d%d%d%s%s%s%s",p1->val.name,p1->val.sex,&p1->val.year,&p1->val.month,&p1->val.day,p1->val.student,p1->val.level,p1->val.phone,p1->val.local);
    266 
    267             system("pause");
    268         }
    269         else if(x==3)
    270         {
    271             system("cls");
    272             printf("输入你要添加多少人信息: ");
    273             scanf("%d",&y);
    274             printf("请依次输入编号: 姓名: 性别: 出生年月: 学历: 职务: 电话: 住址: 
    ");
    275             for(i=0;i<y;++i)
    276             {
    277                 scanf("%d%s%s%d%d%d%s%s%s%s",&a[i].id,a[i].name,a[i].sex,&a[i].year,&a[i].month,&a[i].day,a[i].student,a[i].level,a[i].phone,a[i].local);
    278 
    279             }
    280             root = createTree(a,y);
    281             system("pause");
    282         }
    283         else if(x==4)
    284         {
    285             system("cls");
    286             printf("请依次输入编号: 姓名: 性别: 出生年月: 学历: 职务: 电话: 住址: 
    ");
    287             scanf("%d%s%s%d%d%d%s%s%s%s",&a[0].id,a[0].name,a[0].sex,&a[0].year,&a[0].month,&a[0].day,a[0].student,a[0].level,a[0].phone,a[0].local);
    288             root = insertNode(a[0],root);//插入
    289             system("pause");
    290         }
    291         else if(x==5)
    292         {
    293             system("cls");
    294             printf("程序运行结束
    ");
    295             break;
    296             system("pause");
    297         }
    298         else
    299         {
    300             system("cls");
    301             printf("输入错误
    ");
    302             system("pause");
    303         }
    304     }
    305     return;
    306 }
    307 int main()
    308 {
    309     display();
    310     Menu();
    311     return 0;
    312 }
    View Code
  • 相关阅读:
    Thinphp+nginx配置伪静态
    Potyczki Algorythmiczne 2013
    接下来一段时间会对大家进行网络通信的魔鬼训练理解socket
    项目中怎样做技术选型
    面试官问我:你做事仔细吗?
    【编程一生】2021年总结数据可视化技巧
    一个反直觉的sql
    CURD系统怎么做出技术含量惊艳面试官
    深入理解函数式编程
    历史文章分类汇总
  • 原文地址:https://www.cnblogs.com/kongbursi-2292702937/p/12115652.html
Copyright © 2020-2023  润新知