C#节点指针问题
使用C#设置子节点时遇到一些问题。我正在尝试构建一个节点树,其中每个节点都有一个int值,并且最多可以有几个等于其值的子节点 当我在一个节点中迭代寻找空(null)子节点以便向该节点添加新节点时,就会出现我的问题。我可以找到并返回空节点,但当我将新节点设置为空节点时,它将失去与父节点的连接 因此,如果我添加1个节点,那么它将链接到我的头部节点,但如果我尝试添加第二个节点,它不会成为头部节点的子节点。我正试图用单元测试来构建它,因此下面的测试代码表明,实际上,头部并没有将新节点显示为其子节点(也通过visual Studio调试器确认): 这是我的密码C#节点指针问题,c#,tree,C#,Tree,使用C#设置子节点时遇到一些问题。我正在尝试构建一个节点树,其中每个节点都有一个int值,并且最多可以有几个等于其值的子节点 当我在一个节点中迭代寻找空(null)子节点以便向该节点添加新节点时,就会出现我的问题。我可以找到并返回空节点,但当我将新节点设置为空节点时,它将失去与父节点的连接 因此,如果我添加1个节点,那么它将链接到我的头部节点,但如果我尝试添加第二个节点,它不会成为头部节点的子节点。我正试图用单元测试来构建它,因此下面的测试代码表明,实际上,头部并没有将新节点显示为其子节点(也通
public class Node
{
public Node[] children;
public int data;
public Node(int value)
{
data = value;
children = new Node[value];
for(int i = 0; i < value; i++)
{
children[i] = null;
}
}
}
public class Problem3
{
public Node _head;
public int nodeCount;
public Problem3()
{
_head = null;
nodeCount = 0;
}
public Node addNode(int value, Node currentNode)
{
if(value < 1)
{
return null;
}
Node temp = new Node(value);
//check head
if (_head == null)
{
_head = temp;
nodeCount++;
return _head;
}
//start at Current Node
if (currentNode == null)
{
currentNode = temp;
nodeCount++;
return currentNode;
}
//find first empty child
Node emptyChild = findEmptyChild(currentNode);
emptyChild = temp;
nodeCount++;
return emptyChild;
}
public Node findEmptyChild(Node currentNode)
{
Node emptyChild = null;
//find first empty child of current node
for (int i = 0; i < currentNode.children.Length; i++)
{
if (currentNode.children[i] == null)
{
return currentNode.children[i];
}
}
//move to first child and check it's children for an empty
//**this causes values to always accumulate on left side of the tree
emptyChild = findEmptyChild(currentNode.children[0]);
return emptyChild;
}
公共类节点
{
公共节点[]子节点;
公共int数据;
公共节点(int值)
{
数据=价值;
子节点=新节点[值];
for(int i=0;i
<>我觉得问题是我试图把节点当作指针,就像我在C++中那样,但是它不像我预期的那样工作。 函数不可能返回句柄(或指针)初始化函数中不存在的值,或者提供足够的变量使其在函数外部初始化 一种解决方案是将函数
findEmptyChild
重命名为类似initializeEmptyChild(Node currentNode,Node newNode)
,向其添加一个Node
参数(调用时为temp
值),并在return
之前的循环中初始化以前为空的节点
,currentNode.children[i]=newNode
另一个解决方案不是只返回一个节点
,而是返回两个值,一个父节点和一个找到空子节点的索引,Tuple findEmptyChild(Node currentNode)
,并在循环中,而不是返回currentNode。子节点[i]
可以返回新的元组(currentNode,i)
。调用函数时,您会将代码更改为
var parentAndIndex = findEmptyChild(currentNode);
parentAndIndex.Item1.children[parentAndIndex.Item2] = temp;
查看代码的这一部分:
Node temp = new Node(value);
//...
Node emptyChild = findEmptyChild(currentNode);
emptyChild = temp;
您正在将emptyChild
分配给一个新节点,这样做会“断开”与任何父节点的连接。您应该这样写:
emptyChild.data = temp.data;
emptyChild.children = temp.children;
正如其他人所说,可以改进使用空检查的方法。您提到,Node.data
保存给定节点的子节点数,因此您可以简单地说,当您有Node.data==0
时,该节点应被视为空的或空的。例如,不要有:
rootNode.children[0] = null; // rootNode can have a lot of children
rootNode.children[1] = null;
//...
你应该:
rootNode.children[0] = new Node(0);
rootNode.children[1] = new Node(0);
//...
此时,您的代码将类似于:
public class Node
{
public Node[] children;
public int data;
public Node(int value)
{
data = value;
children = new Node[value];
// Instead of "pointing" to null,
// create a new empty node for each child.
for (int i = 0; i < value; i++)
{
children[i] = new Node(0);
}
}
}
public class Problem3
{
public Node _head;
public int nodeCount;
public Problem3()
{
_head = null;
nodeCount = 0;
}
public Node addNode(int value, Node currentNode)
{
if (value < 1)
{
return null;
}
Node temp = new Node(value);
//check head
if (_head == null)
{
_head = temp;
nodeCount++;
return _head;
}
//start at Current Node
if (currentNode == null)
{
currentNode = temp;
nodeCount++;
return currentNode;
}
//find first empty child
Node emptyChild = findEmptyChild(currentNode);
if (emptyChild != null)
{
emptyChild.data = temp.data;
emptyChild.children = temp.children;
nodeCount++;
}
return emptyChild;
}
public Node findEmptyChild(Node currentNode)
{
// Null checking.
if (currentNode == null)
return null;
// If current node is empty, return it.
if (currentNode.data == 0)
return currentNode;
// If current node is non-empty, check its children.
// If no child is empty, null will be returned.
// You could change this method to check even the
// children of the children and so on...
return currentNode.children.FirstOrDefault(node => node.data == 0);
}
}
一些调试可能会有帮助…作为起点-您的
findEmptyChild
总是返回null
-不确定您希望从中得到什么。看看这里的答案:一般来说,在数组中管理null不是一个好方法,只需使用列表即可。Alexei,当我搜索孩子时,我想找到第一个空的这样我就可以在数组索引中放置一个节点了。就像head(root)一样如果为null,则将节点分配给head,我希望找到一个null子节点并将节点分配给它。但这样做会在我当前的实现中失去与父节点的连接。本质上,我正在尝试将null节点的指针传递回去,以便我可以将节点分配给该指针。是的,这是我退出后在脑海中运行的解决方案之一晚上。我想这就是我要走的路线。
public class Node
{
public Node[] children;
public int data;
public Node(int value)
{
data = value;
children = new Node[value];
// Instead of "pointing" to null,
// create a new empty node for each child.
for (int i = 0; i < value; i++)
{
children[i] = new Node(0);
}
}
}
public class Problem3
{
public Node _head;
public int nodeCount;
public Problem3()
{
_head = null;
nodeCount = 0;
}
public Node addNode(int value, Node currentNode)
{
if (value < 1)
{
return null;
}
Node temp = new Node(value);
//check head
if (_head == null)
{
_head = temp;
nodeCount++;
return _head;
}
//start at Current Node
if (currentNode == null)
{
currentNode = temp;
nodeCount++;
return currentNode;
}
//find first empty child
Node emptyChild = findEmptyChild(currentNode);
if (emptyChild != null)
{
emptyChild.data = temp.data;
emptyChild.children = temp.children;
nodeCount++;
}
return emptyChild;
}
public Node findEmptyChild(Node currentNode)
{
// Null checking.
if (currentNode == null)
return null;
// If current node is empty, return it.
if (currentNode.data == 0)
return currentNode;
// If current node is non-empty, check its children.
// If no child is empty, null will be returned.
// You could change this method to check even the
// children of the children and so on...
return currentNode.children.FirstOrDefault(node => node.data == 0);
}
}
[TestMethod]
public void addSecondNodeAsFirstChildToHead()
{
//arange
Problem3 p3 = new Problem3();
p3.addNode(2, p3._head); // Adding two empty nodes to _head, this means that now _head can
// contain two nodes, but for now they are empty (think of them as
// being "null", even if it's not true)
Node expected = null;
Node expected2 = p3._head.children[0]; // Should be the first of the empty nodes added before.
// Be careful: if you later change p3._head.children[0]
// values, expected2 will change too, because they are
// now pointing to the same object in memory
int count = 2;
//act
Node actual = p3.addNode(1, p3._head); // Now we add a non-empty node to _head, this means
// that we will have a total of two non-empty nodes:
// this one fresly added and _head (added before)
Node expected3 = p3._head.children[0]; // This was an empty node, but now should be non-empty
// because of the statement above. Now expected2 should
// be non-empty too.
//assert
Assert.AreNotEqual(expected, actual, "Node not added"); //pass
// This assert won't work anymore, because expected2, expected 3 and actual
// are now pointing at the same object in memory: p3._head.children[0].
// In your code, this assert was working because
// In order to make it work, you should replace this statement:
// Node expected2 = p3._head.children[0];
// with this one:
// Node expected2 = new Node(0); // Create an empty node.
// expected2.data = p3._head.children[0].data; // Copy data
// expected2.children = p3._head.children[0].children;
// This will make a copy of the node instead of changing its reference.
Assert.AreNotEqual(expected2, actual, "Node not added as first child");
// Now this will work.
Assert.AreEqual(expected3, actual, "Node not added as first child");
Assert.AreEqual(count, p3.nodeCount, "Not added"); //pass
}