有人能解释我这种递归吗?

时间:2016-06-08 21:53:55

标签: recursion binary-tree binary-search-tree pseudocode

我想了解递归。 我理解数学的愚蠢例子,但我不确定它的本质。

我有一个例子,我不明白它是如何工作的:

TREE-ROOT-INSERT(x, z)

if x = NIL
   return z
if z.key < x.key
   x.left = TREE-ROOT-INSERT(x.left, z)
   return RIGHT-ROTATE(x)
else 
   x.right = TREE-ROOT-INSERT(x.right, z)
   return LEFT-ROTATE(x)

我知道这段代码的作用: 首先在BST中插入节点,然后每次旋转,以便新节点成为根节点。

但是在我的脑海中分析代码我认为它将节点插入它必须去的地方,然后JUST 1 TIME它会旋转树。

每次都可以旋转树吗?

2 个答案:

答案 0 :(得分:0)

您需要在树的每个级别的递归调用中保持您的位置。当你第一次点击return RIGHT-ROTATE(或左)时,你还没完成;您获取作为ROTATE函数结果的树,并将其放在代码中,其中递归TREE-ROOT-INSERT调用在堆栈中高一级。然后再次旋转,并将当前树返回到堆栈中更高的位置,直到您点击树的原始根。

答案 1 :(得分:0)

理解递归的重要之处在于将递归函数视为抽象黑盒。换句话说,在阅读或推理递归函数时,你应该专注于当前的迭代,将递归函数的调用视为原子(你无法探索的东西),假设它可以做它应该做的事情,并看看如何其结果可用于解决当前迭代。

您已经知道 @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_interact_ui); TableLayout layout = (TableLayout)findViewById(R.id.interactUILayout); TableRow calling = new TableRow(this); TableRow geo = new TableRow(this); final EditText number = new EditText(this); number.setInputType(EditorInfo.TYPE_CLASS_PHONE); number.setHint("###-###-####"); Button call = new Button(this); call.setText("Call"); call.setOnClickListener(new View.OnClickListener() { public void onClick(View view) { call(number.getText().toString()); } }); final EditText address = new EditText(this); address.setHint("Address"); final EditText street = new EditText(this); street.setHint("Street"); final EditText city = new EditText(this); city.setHint("City"); final EditText state = new EditText(this); state.setHint("State"); Button openGeo = new Button(this); openGeo.setText("Maps"); openGeo.setOnClickListener(new View.OnClickListener() { public void onClick(View view) { openGeo(address.getText().toString(),street.getText().toString(), city.getText().toString(), state.getText().toString()); } }); calling.addView(number, new TableRow.LayoutParams(TableRow.LayoutParams.WRAP_CONTENT, TableRow.LayoutParams.WRAP_CONTENT, 1f)); calling.addView(call); geo.addView(address, new TableRow.LayoutParams(TableRow.LayoutParams.WRAP_CONTENT, TableRow.LayoutParams.WRAP_CONTENT, 1f)); geo.addView(street, new TableRow.LayoutParams(TableRow.LayoutParams.WRAP_CONTENT, TableRow.LayoutParams.WRAP_CONTENT, 1f)); geo.addView(city, new TableRow.LayoutParams(TableRow.LayoutParams.WRAP_CONTENT, TableRow.LayoutParams.WRAP_CONTENT, 1f)); geo.addView(state, new TableRow.LayoutParams(TableRow.LayoutParams.WRAP_CONTENT, TableRow.LayoutParams.WRAP_CONTENT, 1f)); geo.addView(openGeo); layout.addView(calling); layout.addView(geo); } 的合同:

将z插入以x为根的二叉搜索树中,对树进行转换,使z成为新的根。

让我们看看这个片段:

TREE-ROOT-INSERT(x, z)

这表示z小于x因此它转到左子树(因为它是BST)。 if z.key < x.key x.left = TREE-ROOT-INSERT(x.left, z) return RIGHT-ROTATE(x) 再次被调用,但我们不会跟进它。相反,我们只是假设它可以做它想要做的事情:它将z插入到以x.left为根的树上,并使z成为新的根。然后你会得到一个波纹管结构的树:

     x
    / \
   z  ...
  / \
... ...

同样,您不知道如何调用TREE-ROOT-INSERT来获取z-rooted子树。在这一刻你不在乎,因为真正重要的部分是如下:如何使整个树根植于z?答案是TREE-ROOT-INSERT(x.left, z)

  

但是在我的脑海中分析代码我认为它将节点插入它必须去的地方,然后JUST 1 TIME它会旋转树。

     

每次都可以旋转树吗?

如果我理解正确,您仍在思考如何以非递归方式解决问题。确实,您可以使用标准BST插入过程将z插入到以x为根的BST中。这将使z处于正确的位置。但是,要将z从该位置带到根目录,您需要旋转超过1次。

在递归版本中,需要旋转才能在获得z-rooted子树后将z引入根目录。但是要从原始的x.left根源子树中获取z根子树,您还需要旋转。旋转被多次调用,但是在不同的子树上。