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

二叉排序树定义

一棵空树,或者是具有下列性质的二叉树:
(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\n",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("================职 工 信 息 管 理 系 统============\n\n");
198     printf("  ------- 姓名:陈晓\n");
199     printf("  ------- 学号:1828070055\n");
200     printf("  ------- 学院:欧亚国际学院\n");
201     printf("  ------- 年级专业:2018级通信工程\n");
202     printf("\n==================================================\n");
203     printf("\n\n\n");
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 ("***********************************************************************************************************************************\n");
216         printf ("***********************************************************************************************************************************\n");
217         printf ("**                                                    员工信息系统                                                      **\n");
218         printf ("***********************************************************************************************************************************\n");
219         printf ("***********************************************************************************************************************************\n");
220         printf ("***********************************************************************************************************************************\n");
221         printf ("***********************************************************************************************************************************\n");
222         printf ("**                                                丨                             丨                                              **\n");
223         printf ("**********************----------------------------丨[0]查看所有成员              丨----------------------------********************\n");
224         printf ("**                                                丨                             丨                                              **\n");
225         printf ("**********************----------------------------丨[1]删除成员                  丨----------------------------********************\n");
226         printf ("**                                                丨                             丨                                              **\n");
227         printf ("**********************----------------------------丨[2]修改成员信息              丨----------------------------********************\n");
228         printf ("**                                                丨                             丨                                              **\n");
229         printf ("**********************----------------------------丨[3]增加成员                  丨----------------------------********************\n");
230         printf ("**                                                丨                             丨                                              **\n");
231         printf ("**********************----------------------------丨[4]插入成员                  丨----------------------------********************\n");
232         printf ("**                                                丨                             丨                                              **\n");
233         printf ("**********************----------------------------丨[5]结束                      丨----------------------------********************\n");
234         printf ("**                                                丨                             丨                                              **\n");
235         printf ("**********************------------------------------------请输入相应数字---------------------------------------********************\n");
236         printf ("***注意: 程序每运行一次3功能,二叉树上内容会更新为最近的信息,之前的信息默认删除。所以建议3功能运行一次,之后想插入成员运行4功能***\n");
237         printf ("***********************************************************************************************************************************\n");
238         scanf("%d",&x);
239         if(x==0)
240         {
241             system("cls");
242             printf("请依次输入编号: 姓名: 性别: 出生年月: 学历: 职务: 电话: 住址: \n");
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("删除成功\n");
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("编号: 姓名: 性别: 出生年月: 学历: 职务: 电话: 住址: \n");
263             printf("%d %s %s %d %d %d %s %s %s %s\n",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("依次输入修改后的 姓名: 性别: 出生年月: 学历: 职务: 电话: 住址: \n");
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("请依次输入编号: 姓名: 性别: 出生年月: 学历: 职务: 电话: 住址: \n");
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("请依次输入编号: 姓名: 性别: 出生年月: 学历: 职务: 电话: 住址: \n");
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("程序运行结束\n");
295             break;
296             system("pause");
297         }
298         else
299         {
300             system("cls");
301             printf("输入错误\n");
302             system("pause");
303         }
304     }
305     return;
306 }
307 int main()
308 {
309     display();
310     Menu();
311     return 0;
312 }

原文地址:https://www.cnblogs.com/kongbursi-2292702937/p/12115652.html

时间: 2024-10-28 14:03:45

二叉树增删改查 && 程序实现的相关文章

项目:员工信息增删改查程序

现要求写一个简单的员工信息增删改查程序,需求如下: 当然此表你在文件存储时可以这样表示 1,Alex Li,22,13651054608,IT,2013-04-01 2,Jack Wang,28,13451024608,HR,2015-01-07 3,Rain Wang,21,13451054608,IT,2017-04-01 4,Mack Qiao,44,15653354208,Sales,2016-02-01 5,Rachel Chen,23,13351024606,IT,2013-03-1

员工信息增删改查程序 (大神版)

#_*_coding:utf-8_*_#第一部分:sql解析import osdef sql_parse(sql): ''' sql_parse--->insert_parse,delete_parse,update_parse,select_parse sql解析总控 :param sql:用户输入的字符串 :return: 返回字典格式sql解析结果 ''''' parse_func={ 'insert':insert_parse, 'delete':delete_parse, 'updat

通用mapper的增删改查方法 留存 备忘

Mybatis通用Mapper介绍与使用 前言 使用Mybatis的开发者,大多数都会遇到一个问题,就是要写大量的SQL在xml文件中,除了特殊的业务逻辑SQL之外,还有大量结构类似的增删改查SQL.而且,当数据库表结构改动时,对应的所有SQL以及实体类都需要更改.这工作量和效率的影响或许就是区别增删改查程序员和真正程序员的屏障.这时,通用Mapper便应运而生-- 什么是通用Mapper 通用Mapper就是为了解决单表增删改查,基于Mybatis的插件.开发人员不需要编写SQL,不需要在DA

[转]什么是Pro*C/C++,嵌入式SQL,第一个pro*c程序,pro*c++,Makefile,Proc增删改查

1 什么是Pro*C/C++ 1.通过在过程编程语言C/C++中嵌入SQL语句而开发出的应用程序 2.什么是嵌入式SQL 1.在通用编程语言中使用的SQL称为嵌入式SQL 2.在SQL标准中定义了很多中语言的嵌入式SQL 3.各个厂商对嵌入式SQL的具体实现不同 3.什么是Pro*C/C++ 1.在C/C++语言中嵌入SQL语句而开发出的应用程序. 2.目的:使c/c++这种效率语言称为访问数据库的工具. 4.嵌入式SQL的载体是宿主语言 宿主语言 Pro程序 C/C++ Pro*C/C++ F

C#通过窗体应用程序操作数据库(增删改查)

为了体现面向对象的思想,我们把"增删改查"这些函数封装到一个数据库操作类里:   为了便于窗体程序与数据库之间进行数据交互,我们建一个具有数据库行数据的类,通过它方便的在窗体程序与数据库之间传输数据. 首先,建立程序的主窗体 ㈠添加数据 当点击"增加",弹出一个子窗体,通过子窗体往数据库中添加一条数据 private void button1_Click(object sender, EventArgs e) { Form5 insert= new Form5();

2017-01-11小程序常规增删改查

小程序常规增删改查 1.以收货地址的增删改查为例 2.文件目录 js文件是逻辑控制,主要是它发送请求和接收数据, json 用于此页面局部 配置并且覆盖全局app.json配置, wxss用于页面的样式设置, wxml就是页面,相当于html 3.wxml代码 <form bindsubmit="addSubmit"> <view class="consignee"> <text class="consignee-tit&qu

什么是Pro*C/C++,嵌入式SQL,第一个pro*c程序,pro*c++,Makefile,Proc增删改查

 1 什么是Pro*C/C++ 1.通过在过程编程语言C/C++中嵌入SQL语句而开发出的应用程序 2.什么是嵌入式SQL 1.在通用编程语言中使用的SQL称为嵌入式SQL 2.在SQL标准中定义了很多中语言的嵌入式SQL 3.各个厂商对嵌入式SQL的具体实现不同 3.什么是Pro*C/C++ 1.在C/C++语言中嵌入SQL语句而开发出的应用程序. 2.目的:使c/c++这种效率语言称为访问数据库的工具. 4.嵌入式SQL的载体是宿主语言 宿主语言          Pro程序 C/C++

【实战问题】【11】增删改查在SQLServer客户端都是正常的。但在程序里用mybatis的时候,新增会失败

前言: 我的情况和参考博客里的是一样的,所以此处仅做备份. 增删改查在SQLServer客户端都是正常的.但是在程序里用mybatis的时候,只有删改查是正常的,新增会失败.报错:17023 不支持的特性 正文: 检查jar包 oracle的jdbc驱动有很多版本,jdk1.5的驱动是classes12.jar,而jdk1.6(也就是官方所说的6.0)的驱动就是ojdbc6. 根据自己的情况选择合适的jar包,且不要把两个jar包都放进去 参考博客: myBatis+oracle11g inse

MYSQL所有的增删改查等等语句,作为程序员的你,够用了

MYSQL的常用命令和增删改查语句和数据类型 连接命令:mysql -h[主机地址] -u[用户名] -p[用户密码]   创建数据库:create database [库名]   显示所有数据库: show databases;   打开数据库:use [库名]   当前选择的库状态:SELECT DATABASE();   创建数据表:CREATE TABLE [表名]([字段名] [字段类型]([字段要求]) [字段参数], ......);   显示数据表字段:describe 表名;