二叉树增删改查 && 程序实现
二叉排序树定义
一棵空树,或者是具有下列性质的二叉树:
(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 }