3

我意识到这对于 Java 程序员来说是一个激烈争论、有争议的话题,但我相信我的问题有些独特。我的算法需要通过引用传递。我正在对一般树(即n-children)进行顺时针/逆时针前序遍历以分配虚拟(x,y)坐标。这仅仅意味着我在访问它们时计算(并标记)我访问的树的节点。

/**
 * Generates a "pre-ordered" list of the nodes contained in this object's subtree
 * Note: This is counterclockwise pre-order traversal
 * 
 * @param clockwise set to true for clockwise traversal and false for counterclockwise traversal
 * 
 * @return Iterator<Tree> list iterator
 */
public Iterator<Tree> PreOrder(boolean clockwise)
{
    LinkedList<Tree> list = new LinkedList<Tree>();
    if(!clockwise)
        PreOCC(this, list);
    else
        PreO(this,list);
    count = 0;
    return list.iterator();
}
private void PreOCC(Tree rt, LinkedList<Tree> list)
{
    list.add(rt);
    rt.setVirtual_y(count);
    count++;
    Iterator<Tree> ci = rt.ChildrenIterator();
    while(ci.hasNext())
        PreOCC(ci.next(), list);      
}
private void PreO(Tree rt, LinkedList<Tree> list, int count)
{
    list.add(rt);
    rt.setX_vcoordinate(count);
    Iterator<Tree> ci = rt.ReverseChildrenIterator();
    while(ci.hasNext())
        PreO(ci.next(), list, ++count);
}

这里我生成树的结构:

Tree root = new Tree(new Integer(0));
root.addChild(new Tree(new Integer(1), root));
root.addChild(new Tree(new Integer(2), root));
root.addChild(new Tree(new Integer(3), root));
Iterator<Tree> ci = root.ChildrenIterator();
ci.next();
Tree select = ci.next();
select.addChild(new Tree(new Integer(4), select));
select.addChild(new Tree(new Integer(5), select));

这是我打印节点遍历的顺序及其分配给各个节点的坐标时的输出。

0 3 2 5 4 1
0 1 2 3 4 3

0 1 2 4 5 3
0 1 2 3 4 3

注意:前两行是顺时针前序遍历和 x 坐标的分配。接下来的两行是逆时针前序遍历和 y 坐标的分配。

我的问题是如何让第二行阅读: 0 1 2 3 4 5

编辑 1:这是我用来打印访问节点的顺序和分配的坐标的代码。

Iterator<Tree> pre = root.PreOrder(true);
System.out.println("              \t");
while(pre.hasNext())
    System.out.print(pre.next() + "\t");
    
pre = root.PreOrder(true);
System.out.println();
System.out.println("x-coordinates:\t");
while(pre.hasNext())
System.out.print(pre.next().getVirtual_x() + "\t");
    
System.out.println();
System.out.println();
    
Iterator<Tree> preCC = root.PreOrder(false);
System.out.println("              \t");
while(preCC.hasNext())
    System.out.print(preCC.next() + "\t");
    
preCC = root.PreOrder(false);
System.out.println();
System.out.println("x-coordinates:\t");
while(preCC.hasNext())
System.out.print(preCC.next().getVirtual_y() + "\t");

这里还有一个更好地解释 x,y 坐标的引用。顶点。顶点的 y 坐标。

计算 T 的顶点的逆时针预排序(排序从 0 到 n - 1 编号),将它们用作顶点的 x 坐标。

计算 T 的顶点的顺时针预排序(排序从 0 到 n - 1 编号),将它们用作顶点的 y 坐标。

4

3 回答 3

13

Java 的值传递,总是——对于基元和对象。它是为非原始对象传递的引用,因此您可以更改它们指向的对象的状态,但不能更改引用本身。

来自“Java 编程语言”中的 James Gosling:

“...Java 中只有一种参数传递模式——按值传递——这让事情变得简单......”

我认为这是这方面的最终权威。

我意识到这对 Java 程序员来说是一个激烈争论的话题

不,没有辩论。詹姆斯·高斯林从一开始就将这一点融入了语言中。如果你认为这是有争议的,那你可悲的是被迷惑或无知。

于 2010-10-30T20:26:14.017 回答
0

您不需要通过引用传递,您需要一个具有副作用的函数。通过引用传递将是实现此目的的一种方法;使用可变对象作为函数参数将是另一种情况。

private void PreO(Tree rt, LinkedList<Tree> list, int[] count)
{
    list.add(rt);
    rt.setX_vcoordinate(count[0]);
    Iterator<Tree> ci = rt.ReverseChildrenIterator();
    while(ci.hasNext()) {
        ++count[0];
        PreO(ci.next(), list, count);
    }
}
于 2010-10-31T00:46:14.757 回答
0

实际上,在 Java 中有一种通过引用传递的方法:

class Pointer {
    private Object ptr;
    public Pointer(Object v)  { set(v);  }
    public void set(Object v) { ptr = v; }
    public Object get()       { return ptr; }
}

你使用它们:

public void swap(Pointer a, Pointer b) {
    Object tmp = a.get();
    a.set(b.get());
    b.set(tmp);
}

并像这样调用交换:

public static void main(String[] args) {
    Integer one = 1; 
    Integer two = 2;
    Pointer pone; pone.set(one);
    Pointer ptwo; ptwo.set(two);
    swap(pone, ptwo);
    System.out.println((Integer) pone.get());
    System.out.println((Integer) ptwo.get());
}

但是,如果您真的这样做,那么您可能是疯了,或者只是还没有在 Java 中思考。

于 2010-10-30T20:39:06.347 回答