我想了解递归。 我理解数学的愚蠢例子,但我不确定它的本质。
我有一个例子,我不明白它是如何工作的:
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它会旋转树。
每次都可以旋转树吗?
答案 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根子树,您还需要旋转。旋转被多次调用,但是在不同的子树上。