严蔚敏数据结构中二叉排序树删除操作的问题(与链表比较)
2018-02-21 23:03
513 查看
在严蔚敏的《数据结构》中,我看到二叉排序树中有几行代码,我理解的不是很清楚,如下,想请教大家,并且加深自己对指针这一块的理解,代码片段如下:Status Delete(BiTree& p)
{
//从二叉排序树中删除结点p,并重接它的左或右子树
if(! p->rchild) //右子树为空则只需重接它的左子树
{
q = p;
p = p->lchild;
free(q);
}
//剩余情况在此省略了...
}
对于上面这三行代码,我有一点疑惑之处在于:我们虽然执行了p = p->lchild,但是依据链表知识的学习,假设p所指向的结点的父结点为f的话,不应该也改变f->lchild或者f->rchild吗?后来,我查到有人对这几行的解释是:q = p; //我们不妨设p是其父结点的rchild, 所以这行代码的意思就是:
//将父结点的->rchild空间中存放的待删除结点p的地址放入q中
p = p->lchild; //将待删除结点左孩子的地址放入父结点的->rchild空间中
free(q);
我带着疑惑与少许的理解,把书中所给的伪代码修改成可以跑通的,我用45, 24, 53, 45, 12, 24, 50, 40这几个数做一个测试,正确的二叉排序树应该是这样:
我们以删除53为例,部分代码片段如下:int Delete (BiTree& T, BiNode*& p)
{
if (! p->lchild && ! p->rchild )
{
p = NULL;
delete p;
}
else //左右子树至少有一个不空
{
if ( ! p->lchild ) //左子树为空,右子树不空
{
}
else if ( ! p->rchild ) //右子树为空
{
BiNode* q = p;
p = p->lchild;
delete q;
}
else //左右子树都不空
{
}
}
return 0;
}
在调试中,我发现在执行"p = p- >lchild"之前,45, 53, 50三个结点的地址如图所示:
而在执行了"p = p->lchild; delete q;”这两句话之后,45的rchild的地址就变成了eec8也就是说45成功得按照我们的意愿指向了50,并且删除了53这个结点。那么我觉得可以理解为,45所代表的的这个结点的rchild域中原先存的是e918,在执行了"p = p->lchild"之后,原先存的e918被修改成了eec8。 带着对这部分的理解,我想起学过的链表删除某个元素的操作,假设我们要删出p结点之后的那个结点
//一般来说,会这样操作
ListNode* q = p->next;
p->next = q->next;
delete q;我觉得,按照在二叉排序树中删除53的那个操作,我做如下操作是可以的,代码片段如下,但是调试的结果是: p结点的next域中的地址并没有改变struct ListNode
{
int data;
ListNode* next;
};
typedef ListNode* List;
.....
ListNode* Locate (List& L, int data)
{
ListNode* p;
for ( p = L; p->next->data != data; p = p->next );
return p;
}
//删除结点p的后一个结点
int Delete (List& T, ListNode*& p)
{
ListNode* q = p->next;
q = q->next;
delete q;
return 0;
}
....
我拿0~5这5个数作为测试,地址如下:
(下面这段话中,都是以先不执行delete或者free为基础说的)
以删除2这个结点为测试,按照"q = q->next"执行后,完全没有效果,只是q指针的地址变成了ecd8,p的next域中的地址还是eb18,也就是说没有删除q这个结点;相反的按照"p->next = q->next"来执行,就可以成功得更改p的next域中的地址为ecd8。
总结问题:我是用C语言写的二叉排序树的删除,但是用了C++中的引用,我看还有其他方法是用二级指针的,我个人认为使用"引用/二级指针"是都可以的,所以问题应该没有出在这里。但是为什么同样"q = q->next"操作,在二叉排序树中,q的父结点的孩子域中的地址就改变了,但是在链表中q的父结点的next域中的地址却不变?
{
//从二叉排序树中删除结点p,并重接它的左或右子树
if(! p->rchild) //右子树为空则只需重接它的左子树
{
q = p;
p = p->lchild;
free(q);
}
//剩余情况在此省略了...
}
对于上面这三行代码,我有一点疑惑之处在于:我们虽然执行了p = p->lchild,但是依据链表知识的学习,假设p所指向的结点的父结点为f的话,不应该也改变f->lchild或者f->rchild吗?后来,我查到有人对这几行的解释是:q = p; //我们不妨设p是其父结点的rchild, 所以这行代码的意思就是:
//将父结点的->rchild空间中存放的待删除结点p的地址放入q中
p = p->lchild; //将待删除结点左孩子的地址放入父结点的->rchild空间中
free(q);
我带着疑惑与少许的理解,把书中所给的伪代码修改成可以跑通的,我用45, 24, 53, 45, 12, 24, 50, 40这几个数做一个测试,正确的二叉排序树应该是这样:
我们以删除53为例,部分代码片段如下:int Delete (BiTree& T, BiNode*& p)
{
if (! p->lchild && ! p->rchild )
{
p = NULL;
delete p;
}
else //左右子树至少有一个不空
{
if ( ! p->lchild ) //左子树为空,右子树不空
{
}
else if ( ! p->rchild ) //右子树为空
{
BiNode* q = p;
p = p->lchild;
delete q;
}
else //左右子树都不空
{
}
}
return 0;
}
在调试中,我发现在执行"p = p- >lchild"之前,45, 53, 50三个结点的地址如图所示:
而在执行了"p = p->lchild; delete q;”这两句话之后,45的rchild的地址就变成了eec8也就是说45成功得按照我们的意愿指向了50,并且删除了53这个结点。那么我觉得可以理解为,45所代表的的这个结点的rchild域中原先存的是e918,在执行了"p = p->lchild"之后,原先存的e918被修改成了eec8。 带着对这部分的理解,我想起学过的链表删除某个元素的操作,假设我们要删出p结点之后的那个结点
//一般来说,会这样操作
ListNode* q = p->next;
p->next = q->next;
delete q;我觉得,按照在二叉排序树中删除53的那个操作,我做如下操作是可以的,代码片段如下,但是调试的结果是: p结点的next域中的地址并没有改变struct ListNode
{
int data;
ListNode* next;
};
typedef ListNode* List;
.....
ListNode* Locate (List& L, int data)
{
ListNode* p;
for ( p = L; p->next->data != data; p = p->next );
return p;
}
//删除结点p的后一个结点
int Delete (List& T, ListNode*& p)
{
ListNode* q = p->next;
q = q->next;
delete q;
return 0;
}
....
我拿0~5这5个数作为测试,地址如下:
(下面这段话中,都是以先不执行delete或者free为基础说的)
以删除2这个结点为测试,按照"q = q->next"执行后,完全没有效果,只是q指针的地址变成了ecd8,p的next域中的地址还是eb18,也就是说没有删除q这个结点;相反的按照"p->next = q->next"来执行,就可以成功得更改p的next域中的地址为ecd8。
总结问题:我是用C语言写的二叉排序树的删除,但是用了C++中的引用,我看还有其他方法是用二级指针的,我个人认为使用"引用/二级指针"是都可以的,所以问题应该没有出在这里。但是为什么同样"q = q->next"操作,在二叉排序树中,q的父结点的孩子域中的地址就改变了,但是在链表中q的父结点的next域中的地址却不变?
相关文章推荐
- 数据结构(4)--循环链表的应用之约瑟夫环问题以及线性表总结之顺序表与链表的比较
- 华南理工数据结构大作业第一题单链表 删除创建等各种简易操作
- 数据结构:链表创建、显示、求和、插入、删除等操作的代码实现
- 数据结构之链表与数组(二) -单向链表上的简单操作问题
- 《数据结构》严蔚敏版(java解)——第二章 线性表05 双端链表操作
- 数据结构之单向链表操作1-(插入,删除,交换,反转,排序等操作)
- 数据结构上机测试2-1:单链表操作A (顺序建表+关键字删除)
- 左程云_算法与数据结构 — 链表问题 — 03删除链表的中间节点和a/b处的节点
- 关于动态存储分配函数的调用,在已经过排序的数组中查找及删除内容的操作,余数的分析,删除字符数组中的空格,对链表的逆置,在源字符串中查找子字符串的个数,函数指针以及函数的调用,循环赋值带来的问题以及插入
- C++数据结构---链表(删除操作)
- 数据结构之循环链表操作3-(合并,拆分,插入,删除,建立等)
- 数据结构:链表的基本操作(创建,删除,插入,逆序,摧毁)
- 【数据结构 _双向链表_List_0960】双向链表的操作问题
- 数据结构:单链表(二)之链表节点排序,升序插入数据,删除指定的所有节点,翻转链表操作
- 链表的相关操作查找插入删除(c++ 数据结构)
- 数据结构之链表操作,创建,插入,删除,查找。
- 数据结构之 线性表---单链表操作A (删除链表中的指定元素)
- 数据结构之链表与数组(二) -单向链表上的简单操作问题
- 【数据结构_链表_List_0953】单链表的删除操作实现
- 数据结构链表的操作集合(建立,遍历,插入,删除,排序,长度,空判断等)