C++ 二叉搜索树插入如何使用递归?
我在理解二进制搜索树插入的递归部分时遇到了一些问题C++ 二叉搜索树插入如何使用递归?,c++,c,algorithm,recursion,data-structures,C++,C,Algorithm,Recursion,Data Structures,我在理解二进制搜索树插入的递归部分时遇到了一些问题 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)
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]
*/
所以
20->right=
300(tmp地址)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]
在某种程度上你是对的。永远不能有高度大于2的子树(不是树)
在这段代码中,您永远不会有root->right->right
,因为就代码而言,当您调用
root->left=插入(root->left,数据)代码>
(本地)根指针现在指向刚刚插入的节点。(本地)根指向根->左。
因此,您可以拥有任意高度的树(但是,本地根指针指向高度的子树请注意,insert()
始终返回作为参数传递给它的root
,除非root==NULL
。因此,您插入的新节点无法“遍历树”.递归调用中发生的事情并不重要--您总是返回与在非空
NULL
情况下传递的相同的root
尽管有些人教授递归,但我认为(无论如何,对于我的大脑)不尝试取消递归是有帮助的,而是考虑逻辑是否有意义:
如果向您传递了一个非NULL
节点和datadata
,如果执行root->left=insert(root->left,data)
并假设insert()
神奇地“正常工作”(即它将数据插入左树并返回该树的根),您会得到正确的结果吗
如果逻辑检查左、右两种情况,则考虑基本情况:如果你通过了<代码> null <代码>节点,你会返回正确的一个元素树吗?
如果逻辑也检查出基本情况,那么您知道您的代码必须是正确的,因为递归步骤是有意义的,并且您知道您将进入一个基本情况,这也是有意义的(因为当您沿着树走下去时,您最终将到达一个NULL
节点).我想对你来说,困惑可能来自两个不同的来源。
首先,无法将树注释到代码中。其次,只有在以空指针传递函数时才会创建新节点。只有小于15的值才能转到左侧。改为类似于此(取决于添加顺序):
当您将其添加到25时,结果如下所示:
15
/ \
20
/ \
30
/
25
我将尝试一步一步地解释这段代码。当在第一个函数调用的原始树中添加25时,第一个节点不为NULL,并且25>15,因此
else
{
root->right = insert(root->right, data);
}
调用。这将递归调用同一个插入函数,但现在使用20节点作为比较。再次不为null且25>20,因此如上所述在右节点上调用插入。这将再次调用递归函数,但现在在30。25您忘记了根->右是作为根传递到函数中的地址的根->右。每次对insert的调用都会在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]
*/
20->right = 25;
return 20;
然后它将该树返回到调用插入(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->right,正好是20
insert(20, 25)
这将再次在20 right节点上调用insert,该节点恰好为空
insert(null,25)
现在让我们看看回报
insert(null,25)返回一个包含25个节点的节点,然后从堆栈中删除
return 25;
insert(20,25)返回一个带有25的节点
/* consider following BST with their addresses[]:
20 [200]
\
25 [300]
*/
20->right = 25;
return 20;
现在我们回到最初的insert(15,25)调用。它返回了20。它也是这样
15->right = 20;
return 15;
root->right=root->right->right=tmp;
-第一个root->right=
从哪里来?它似乎不知从何处出现…它来自条件25>15错误…插入什么(root->right,25)
return?这是一个递归函数,在到达基本情况后,它返回新节点,设置为root->right->right,然后它再次展开到root->right。当它展开时,您忘记了返回到上一个函数的指针已经更改了它上面级别的根的指针“然后返回此”树“至呼叫插入(15->右,25)”否。前20->右存储插入地址(25->右,25)然后root->right存储20->right的地址。它又是300。很抱歉,它应该返回指向子树根的指针。是的。它是对的。返回来自上一个语句return root;这就是它返回root而不是root->right的原因。我怎么可能没有注意到它。呸,终于找到它了。是的。我很高兴我加入了你可以用你能看到的方式把它拿出来。30是一个打字错误。我已经改正了。”然后所有函数都会将这个新创建的节点返回到原始函数调用。“怎么做?你能用例子详细说明一下吗?它不会一直返回到原始调用。你必须回到调用的每个迭代堆栈中才能插入。它
15->right = 20;
return 15;