二叉树增删改查 && 程序实现
二叉排序树定义
一棵空树,或者是具有下列性质的二叉树:
(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 }
二叉树增删改查 && 程序实现的更多相关文章
- Java web 简单的增删改查程序(超详细)
就是简单的对数据进行增删改查.代码如下: 1.bean层:用来封装属性及其get set方法 toString方法,有参构造方法,无参构造方法等. public class Bean { privat ...
- 通用mapper的增删改查方法 留存 备忘
Mybatis通用Mapper介绍与使用 前言 使用Mybatis的开发者,大多数都会遇到一个问题,就是要写大量的SQL在xml文件中,除了特殊的业务逻辑SQL之外,还有大量结构类似的增删改查SQ ...
- PHP程序中使用PDO对象实现对数据库的增删改查操作的示例代码
PHP程序中使用PDO对象实现对数据库的增删改查操作(PHP+smarty) dbconn.php <?php //------------------------使用PDO方式连接数据库文件- ...
- 使用ASP.NET Core MVC 和 Entity Framework Core 开发一个CRUD(增删改查)的应用程序
使用ASP.NET Core MVC 和 Entity Framework Core 开发一个CRUD(增删改查)的应用程序 不定时更新翻译系列,此系列更新毫无时间规律,文笔菜翻译菜求各位看官老爷们轻 ...
- Hibernate第一个程序(最基础的增删改查) --Hibernate
本例实现Hibernate的第一个程序,Hibernate的优点我想大家都很清楚,在这里不做过多赘述.总之,使用Hibernate对数据库操作,也就是来操作实体对象的! 项目目录: 一.第一步要做的就 ...
- [译]聊聊C#中的泛型的使用(新手勿入) Seaching TreeVIew WPF 可编辑树Ztree的使用(包括对后台数据库的增删改查) 字段和属性的区别 C# 遍历Dictionary并修改其中的Value 学习笔记——异步 程序员常说的「哈希表」是个什么鬼?
[译]聊聊C#中的泛型的使用(新手勿入) 写在前面 今天忙里偷闲在浏览外文的时候看到一篇讲C#中泛型的使用的文章,因此加上本人的理解以及四级没过的英语水平斗胆给大伙进行了翻译,当然在翻译的过程中发 ...
- 什么是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标准中定义 ...
- C#通过窗体应用程序操作数据库(增删改查)
为了体现面向对象的思想,我们把“增删改查”这些函数封装到一个数据库操作类里: 为了便于窗体程序与数据库之间进行数据交互,我们建一个具有数据库行数据的类,通过它方便的在窗体程序与数据库之间传输数据: 我 ...
- [刘阳Java]_程序员Java编程进阶的5个注意点,别编程两三年还是增删改查
此文章也是关注网上好几篇技术文章后,今天分享出来.因为,总有在程序学习路上的小伙伴会感到迷茫.而迷茫存在的情况如下 第一种:在大学学习中出现的迷茫,不知道Java到底要学什么.学习Java的标准是什么 ...
随机推荐
- Hbase Region合并
业务场景: Kafka+SparkStreaming+Hbase由于数据大量的迁移,再加上业务的改动,新增了很多表,导致rerigon总数接近4万(36个节点) 组件版本: Kafka:2.1.1 S ...
- MySQL常用字符串函数和日期函数
数据函数 SELECT ABS(-8); /*绝对值*/ SELECT CEILING(9.4); /*向上取整*/ SELECT FLOOR(9.4); /*向下取整*/ SELECT RAND() ...
- 系统吞吐量与QPS/TPS
QPS/TPS QPS:Queries Per Second意思是"每秒查询率",是一台服务器每秒能够相应的查询次数,是对一个特定的查询服务器在规定时间内所处理流量多少的衡量标准. ...
- 【MYSQL】win7安装mysql-5.7.10绿色版
1.下载 :mysql下载地址 2.解压缩 3.环境变量配置 MYSQL_HOME=D:\mysql-5.7.11-win32 PATH=%MYSQL_HOME%\bin 4.修改配置文件 a.)将m ...
- DOS的FOR命令用法总结
鉴于dos自带的关于for命令的帮助信息看起来太简单,自己总结了一下,并增加了必要的实例,以备日后自己查阅.其中一些地方可能存在理解错误,敬请指出. [转发请注明出处]
- 算法模板 - C++ 高精度运算
C++算法板子 高精度 高精度推荐用python来写,python有大整数,这里写的是关于C++的高精度运算模板 1.高精 * 低精 #include <iostream> #includ ...
- ajax异步实现文件分片上传
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...
- SQL函数知识点
SQL函数知识点 SQL题目(一) 1.查询部门编号为10的员工信息 select*from emp where empno=10; 2.查询年薪大于3万的人员的姓名与部门编号 select enam ...
- node集群(cluster)
使用例子 为了让node应用能够在多核服务器中提高性能,node提供cluster API,用于创建多个工作进程,然后由这些工作进程并行处理请求. // master.js const cluster ...
- 【LinuxShell】free 命令详解
前言 free命令用来显示Linux中的内存使用信息,包括空闲的.已用的物理内存,swap内存,及被内核使用的buffer.在Linux系统监控的工具中,free命令是最经常使用的命令之一. 命令格式 ...