二叉搜索树插入如何使用递归
How binary search tree insertion works using recursion?
我在理解二叉搜索树插入的递归部分时遇到了一些麻烦。
bstnode* insert(bstnode* root,int data)
{
if(root==NULL){
bstnode* tmp= new bstnode();
tmp->data=data;
tmp->left=tmp->right=NULL;
return tmp;
}
if(data<root->data)
root->left = insert(root->left, data);
else
root->right = insert(root->right, data); //can't understand the logic here
return root;
}
/* consider following BST with their addresses[]:
15 [100]
/
10 20 [200]
tmp [300]
*/
根据我的说法root->right = insert(root->right, data);
应该将新创建的节点的地址存储在root->right
中,因此此代码不适用于高度为>2 的树。
但是,它可以完美地适用于任意数量的节点。
我在这里一定错过了一些关键细节。
假设我想在 BST 中插入 25,即插入(根,25(;
作为 25>15:-
我在这里分解递归部分:root->right = insert(root->right, 25);
或15->right = insert(15->right,25);
在这里,再次递归调用它,因为 25>20
insert(root->right, 25)
=> root->right->right
= insert(root->right->right, 25);
或insert(15->right, 25)
=> 20->right
= insert(20->right, 25);
insert(20->right,25)
NULL
,因此会创建一个新的节点tmp
。
insert(20->right,25);
返回tmp
.
现在展开递归。
//20->right = insert(20->right, 25);
所以
20->right=
300(TMP地址(;
//insert(15->right, 25) => 20->right
//and 15->right = insert(15->right,25);
15->right = 20->next;
因此15->right
= [300] 地址。
或 root->right
= [300] 地址。
我的方法有什么问题?
再次概述递归调用:
15->right = insert(15->right,25);
15->right = [20->right = insert(20->right,25)]; //20->right is NULL so creating new node
15->right = [20->right= 300 address of tmp];
15->right = [20->right or 300]
15->right = [300] // but in reality 15->right = [200]
您忘记了 root->right 是您作为 root 传递给函数的地址的 root->right。 每次插入调用都以 root->right 或 root->left 传递,具体取决于遍历的方式。
此语句不正确:
root->right = root->right->right = tmp;
返回函数的迭代后,它将从堆栈中删除,因此在这种情况下,我们有 3 次调用,我会将您的数字放在指针值的位置。
insert(15->right,25)
insert(20->right,25)
最后一个是 null,因此它创建具有 25 的节点并将其返回到调用插入(20->right,25(,并将 25 设置为 20->right,因此您有一个如下所示的树
/* consider following BST with their addresses[]:
20 [200]
25 [300]
*/
然后,它将此树返回到调用 insert(15->right,25(,并将该树设置为我们刚刚返回的树,以便我们得到最终的树
/* consider following BST with their addresses[]:
15 [100]
/
30 20 [200]
25 [300]
*/
编辑:让我看看我是否可以澄清。 让我们再看看你的树
/* consider following BST with their addresses[]:
15 [100]
/
10 20 [200]
tmp [300]
*/
我们想插入 25,所以我们调用(我将再次使用树的那个节点上的值来表示我们正在传递的指针( 插入(15, 25(
然后调用 insert on root->right,恰好是 20
insert(20, 25)
此调用现在在 20 个右侧节点上再次插入,恰好为空
insert(null,25)
所以现在让我们看看回报
insert(null,25( 返回一个包含 25 的节点,然后从堆栈中删除
return 25;
insert(20,25( 获取其对 25 节点的返回。 它将右子项设置为 25,如下所示
20->right = 25;
return 20;
现在我们回到 insert(15,25( 的原始调用。 它返回了 20。 所以它确实如此
15->right = 20;
return 15;
我认为这种困惑可能来自两个不同的来源。首先,注释到代码中的树是不可能的。其次,仅当函数在空指针中传递时,才会创建新节点。只有小于 15 的值才能转到左侧。它会是这样的(取决于添加顺序(:
15
/
20
/
30
当您添加 25 时,它将如下所示:
15
/
20
/
30
/
25
我将尝试逐步完成代码来解释。当在第一个函数调用上将 25 添加到原始树时,第一个节点不是 NULL,25> 15,因此
else
{
root->right = insert(root->right, data);
}
被称为。这会递归调用相同的插入函数,但现在使用 20 节点进行比较。同样不是空和 25> 20,所以如上所述在右侧节点上调用插入。这再次调用递归函数,但现在在 30 上。25<30,因此它在左侧节点上调用函数。此时,函数已在 NULL 指针中传递,因为那里没有任何内容,因此创建一个新节点并将其放置在该位置。
请注意,除非root == NULL
,否则insert()
始终返回作为参数传递给它的root
。因此,您插入的新节点无法"向上走"。递归调用中发生的情况并不重要 - 您始终返回在非NULL
情况下传递的相同root
。
尽管有些人教授递归的方式,但我认为(无论如何对我的大脑(不要试图展开递归,而是考虑逻辑是否有意义,这是有帮助的:
如果您传递了一个非NULL
节点并data < root->data
,如果您执行root->left = insert(root->left, data)
并假设insert()
神奇地"正常工作"(即,它将data
插入左树并返回该树的根(,您会得到正确的结果吗?
逻辑同时检查左情况和右情况,则考虑基本情况:如果传递了NULL
节点,是否会返回正确的单元素树?
如果逻辑也检查出基本情况,那么你就知道你的代码一定是正确的,因为递归步骤是有意义的,并且你知道你将落在一个也有意义的基本情况中(因为你最终会到达一个NULL
节点当你走下树(。
在某种程度上你是对的。您永远不能有高度为>2 的子树(不是树(。
在此代码中,您将永远不会有root->right->right
因为就代码而言,当您调用 root->left = insert(root->left, data);
指针现在指向刚刚插入的节点。(本地(根指向root->left.
因此,您可以拥有任何高度的树(但是,本地根指针指向高度 <2( 的子树(
- 使用递归的数组的最小值.这是怎么回事
- 使用递归时获取变量的奇怪值
- 如何使用递归打印修改后的星号三角形图案
- 使用递归模板动态分配的多维数组
- 有没有办法使用递归函数找到数组中最小值的 INDEX?C++
- 如何使用递归循环我的代码(当用户输入无效输入时,它会再次提示他们)?
- 是否总是可以将使用递归编写的程序重写为不使用递归的程序C++,性能观点是什么?
- 使用递归 c++ 打印模式
- 二叉树结构平衡,使用递归时EXC_BAD_ACCESS
- 使用递归输出数组
- C++ 模板使用递归实现循环
- 在气泡排序中使用递归
- 如何使用递归检查数字是否有重复数字?
- 使用递归反转和打印出数组的内容
- C++ 使用递归而不是 for 循环
- 使用递归的矩阵中的最小成本路径
- 在尝试使用递归查找集合子集的总数时,我遇到了分割错误
- 使用递归的序列到达数组末尾的最小跳转次数
- 如何使用递归打印最长公共子序列中涉及的字符串?
- 基例如何影响使用递归函数的哪些行