免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
12下一页
最近访问板块 发新帖
查看: 2564 | 回复: 14
打印 上一主题 下一主题

[C] 新手求解BST树删除单个节点,出现两个错误 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2015-05-09 14:02 |只看该作者 |倒序浏览
1 要删除的节点存在左右子树时 ,删除有点问题,从验证程序看出来的
2 要删除的节点只有左子树 或 只有又子树 删除成功 但遍历之后最前边多出一个0.
下面附上所有文件内容
------------代码有点长,出错只有删除某个任意节点!!!!!----------------------------------------


BSTree.c 文件如下
#include"BSTree.h"
2 #include<stdio.h>
3 #include<stdlib.h>
4 #include<assert.h>
5
6 //创建一个树
7 tree* create_tree(ElementType *e)
8 {
9 node *n=(node*)malloc(sizeof(node));
10 assert(n!=NULL);
11 n->element=*e;
12 n->left=NULL;
13 n->right=NULL;
14
15 tree *t=(tree*)malloc(sizeof(tree));
16 if(t==NULL)
17 {
18 free(n);
19 return NULL;
20 }
21 t->root=n;
22 return t;
23 }
static void destroy_node(node* n)
26 {
27 if(n==NULL) return;
28 destroy_node(n->left);
29 destroy_node(n->right);
30 free(n);
31 }
32
33 //销毁树
34 void destroy_tree(tree *t)
35 {
36 if(t==NULL); return;
37 destroy_node(t->root);
38 free(t);
39 }
40
41 static node* add_node(node *n,ElementType* e)
42 {
43 node *new=(node*)malloc(sizeof(node));

assert(new!=NULL);
45 new->element=*e;
46 if(n==NULL) return new;
47 else if(*e < (n->element))
48 {
49 n->left =add_node(n->left,e);
50 }
51 else if(*e>(n->element))
52 {
53 n->right=add_node(n->right,e);
54 }
55 return n;
56 }
57 //添加一个节点
58 int add_element(tree *t,ElementType *e)
59 {
60 if(t==NULL || e==NULL) return 0;
61 t->root=add_node(t->root,e);
62 return 1;
63 }

65 static node* find_min(node* n)
66 {
67 if(n->left==NULL) return n;
68 return find_min(n->left);
69 }
70 //找到前驱节点
71 static node* qianqu_node(node* n)
72 {
73 if(n==NULL) return NULL;
74 if(n->right) n=qianqu_node(n->right);
75 return n;
76 }
77 //找到后继节点
78 static node* houji_node(node* n)
79 {
80 if(n==NULL) return NULL;
81 if(n->left) n=houji_node(n->left);
82 return n;
83 }

85 static node* remove_node(node* n,ElementType *e)
86 {
87 if(n==NULL) return NULL;
88 //递归找到要删除的节点
89 if(*e < n->element)
90 n->left=remove_node(n->left,e);
91 else if(*e > n->element)
92 n->right=remove_node(n->right,e);
93 else
94 {
95 //node* temp;
96 //要删除节点左右子树都存在
97 if(n->left && n->right)
98 {
99 node* temp;
100 node *temp1;
101 temp=qianqu_node(n->left);
102 n->element=temp->element;
103 while(temp->left)
104 {
105 temp1=qianqu_node(temp->left);
106 temp->element=temp1->element;
107 temp=temp1;

108 free(temp1);
109 temp1=NULL;
110 }
111 free(temp);
112 temp=NULL;
113 }
114 //要删除节点只有左子树
115 else if(n->left)
116 {
117 node* temp;
118 temp=qianqu_node(n->left);
119 n->element=temp->element;
120 while(temp->left)
121 {
122 temp=qianqu_node(temp->left);
123 n->element=temp->element;
124 }
125 free(temp);
126 temp=NULL;
127 }

128 //要删除节点只有右子树
129 else if(n->right)
130 {
131 node* temp;
132 temp=houji_node(n->right);
133 n->element=temp->element;
134 while(temp->right)
135 {
136 temp=houji_node(temp->right);
137 n->element=temp->element;
138 }
139 free(temp);
140 temp=NULL;
141 }
142 //要删除节点为叶子节点
143 else
144 {
145 node* temp;
146 free(n);
147 n=NULL;
148 }
149 return n;
150 }

151 return n;
152 }
153 //删除一个节点
154 int remove_element(tree *t,ElementType *e)
155 {
156 if(t==NULL || e==NULL) return 0;
157 remove_node(t->root,e);
158 return 1;
159 }
160
161 static node* find_node(node* n,ElementType* e)
162 {
163 if(n==NULL ||e==NULL) return NULL;
164 if(n->element == *e) return n;
165 else if(*e < n->element)
166 return find_node(n->left,e);
167 return find_node(n->right,e);
168 }
169

170 //查找一个元素是否存在
171 ElementType* find_element(tree* t,ElementType *e)
172 {
173 if(t==NULL || e==NULL) return NULL;
174 node* n=find_node(t->root,e);
175 if(n==NULL)
176 return NULL;
177 return &(n->element);
178 }
179
180 static saze_t size_node(node* n)
181 {
182 if(n==NULL) return 0;
183 return 1+size_node(n->left)+size_node(n->right);
184 }
185
186 //所有元素个数
187 saze_t size(tree* t)
188 {
189 if(t==NULL) return 0;
190 return size_node(t->root);
191 }

193 static void node_iterator(node* n)
194 {
195 if(n==NULL) return;
196 node_iterator(n->left);
197 printf("%d,",n->element);
198 node_iterator(n->right);
199 }
200
201 //中序遍历树
202 void mid_iterator(tree *t)
203 {
204 if(t==NULL) return;
205 node_iterator(t->root);
206 printf("\n");
207 }
208

论坛徽章:
0
2 [报告]
发表于 2015-05-09 14:02 |只看该作者
BSTree.h 如下
1 #ifndef __BSTree_H__
2 #define __BSTree_H__
3
4 typedef unsigned int saze_t;
5 typedef int ElementType;
6
7 typedef struct node
8 {
9 ElementType element;
10 struct node* left;
11 struct node* right;
12 }node;
13
14 typedef struct tree
15 {
16 node* root;
17 }tree;
18
19 //创建一个树
20 tree* create_tree(ElementType *e);
21 //销毁树
22 void destroy_tree(tree *t);
23 //添加一个节点

24 int add_element(tree *t,ElementType *e);
25 //删除一个节点
26 int remove_element(tree *t,ElementType *e);
27 //查找一个元素是否存在
28 ElementType* find_element(tree* t,ElementType *e);
29 //所有元素个数
30 saze_t size(tree* t);
31 //中序遍历树
32 void mid_iterator();
33
34 #endif

论坛徽章:
0
3 [报告]
发表于 2015-05-09 14:03 |只看该作者
测试文件 BSTree_test.c 如下
1 #include<stdio.h>
2 #include"BSTree.h"
3 #include<stdlib.h>
4
5 int main(void)
6 {
7 int a=8;
8 int b=12;
9 int c=10;
10 int d=15;
11 int e=16;
12 int f=18;
13 int g=19;
14 int h=17;
15 int i=13;
16 int j=20;
17 tree *t=create_tree(&j);
18 add_element(t,&b);
19 add_element(t,&c);
20 add_element(t,&d);
21 add_element(t,&e);
22 add_element(t,&f);
23 add_element(t,&g);

24 add_element(t,&a);
25 add_element(t,&h);
26 add_element(t,&i);
27 destroy_tree(t);
28 mid_iterator(t);
29 printf("--------------------------\n");
30 int *ptr;
31 if(ptr=find_element(t,&e))
32 printf("%d is exist\n",*ptr);
33 else printf("%d is not exist\n",*ptr);
34 printf("size of t:%d\n", size(t));
35 remove_element(t,&c);
36 printf("--------AFTER--REMOVE----------\n ");
37 mid_iterator(t);
38 return 0;
39 }

论坛徽章:
0
4 [报告]
发表于 2015-05-10 12:29 |只看该作者
求大手  @大神

论坛徽章:
14
水瓶座
日期:2014-06-10 09:51:0215-16赛季CBA联赛之江苏
日期:2017-11-27 11:42:3515-16赛季CBA联赛之八一
日期:2017-04-12 14:26:2815-16赛季CBA联赛之吉林
日期:2016-08-20 10:43:1215-16赛季CBA联赛之广夏
日期:2016-06-23 09:53:58程序设计版块每日发帖之星
日期:2016-02-11 06:20:00程序设计版块每日发帖之星
日期:2016-02-09 06:20:0015-16赛季CBA联赛之上海
日期:2015-12-25 16:40:3515-16赛季CBA联赛之广夏
日期:2015-12-22 09:39:36程序设计版块每日发帖之星
日期:2015-08-24 06:20:002015亚冠之德黑兰石油
日期:2015-08-07 09:57:302015年辞旧岁徽章
日期:2015-03-03 16:54:15
5 [报告]
发表于 2015-05-11 10:13 |只看该作者
三种情况:
1、没儿子的,直接删
2、有一个儿子的,把儿子当爹的儿子,然后删
3、有两个儿子的,找到后继(或者前驱),保存其内容,删掉后继(或者前驱),替换要删除节点的内容

不太可能写错吧

请按code模式贴代码,您这样写真心是不想让人看呀

论坛徽章:
7
天秤座
日期:2014-08-07 13:56:30丑牛
日期:2014-08-27 20:34:21双鱼座
日期:2014-08-27 22:02:21天秤座
日期:2014-08-30 10:39:11双鱼座
日期:2014-09-21 20:07:532015年亚洲杯之日本
日期:2015-02-06 14:00:282015亚冠之大阪钢巴
日期:2015-11-02 14:50:19
6 [报告]
发表于 2015-05-11 13:47 |只看该作者
为啥都不喜欢gdb呢,裸看代码多累啊,而且贴代码至少set nonu吧……

论坛徽章:
0
7 [报告]
发表于 2015-05-11 16:06 |只看该作者
新手  是要在gdb里list 再贴出?回复 6# MeRcy_PM


   

论坛徽章:
0
8 [报告]
发表于 2015-05-11 16:07 |只看该作者
写的是比较原始的  没有父指针,结构体中只有两个左右子树的指针回复 5# lxyscls


   

论坛徽章:
7
天秤座
日期:2014-08-07 13:56:30丑牛
日期:2014-08-27 20:34:21双鱼座
日期:2014-08-27 22:02:21天秤座
日期:2014-08-30 10:39:11双鱼座
日期:2014-09-21 20:07:532015年亚洲杯之日本
日期:2015-02-06 14:00:282015亚冠之大阪钢巴
日期:2015-11-02 14:50:19
9 [报告]
发表于 2015-05-11 21:02 |只看该作者
116                     else if(n->left)
(gdb)
119                             temp=qianqu_node(n->left);
(gdb) p *n
$19 = {element = 10, left = 0x602390, right = 0x0}
(gdb) p *n->left
$20 = {element = 8, left = 0x0, right = 0x0}
(gdb) n
120                             n->element=temp->element;
(gdb) p *temp
$21 = {element = 8, left = 0x0, right = 0x0}
(gdb) n
121                             while(temp->left)
(gdb)
126                             free(temp);
(gdb) disp *n
1: *n = {element = 8, left = 0x602390, right = 0x0}
(gdb) disp *n->left
2: *n->left = {element = 8, left = 0x0, right = 0x0}
(gdb) n
127                             temp=NULL;
2: *n->left = {element = 0, left = 0x0, right = 0x0}
1: *n = {element = 8, left = 0x602390, right = 0x0}
(gdb)


$19:10节点只有左儿子
$20:10节点左儿子8是叶子节点
119:找到前驱8
120:值拷贝,把前驱的值拷贝给自己,自己从10变成8
121:原8是叶子节点,while不执行
126:释放原来的8的指针
126未执行前n->left是8,free完n->left是0,
127行把一个临时变量置零,但是没有把原来的指针从树上删除,原来的节点10值改变,同时左儿子的指针指向一个野指针

论坛徽章:
7
天秤座
日期:2014-08-07 13:56:30丑牛
日期:2014-08-27 20:34:21双鱼座
日期:2014-08-27 22:02:21天秤座
日期:2014-08-30 10:39:11双鱼座
日期:2014-09-21 20:07:532015年亚洲杯之日本
日期:2015-02-06 14:00:282015亚冠之大阪钢巴
日期:2015-11-02 14:50:19
10 [报告]
发表于 2015-05-11 21:09 |只看该作者
回复 1# UFancyMe
代码还有一堆问题,我看你用例里面先建立树,然后立刻摧毁树,然后去查找,去删除节点,删除时候又有free,我一直纳闷为啥没有报double free的错误
直到GDB
destroy_tree (t=0x602030) at BST.c:35
35              if(t==NULL); return;
(gdb) n
38      }
注意if后面的分号。

   
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP