Java:当我将带有头虚拟节点的循环双向链接列表插入时,我的虚拟节点会随机移动。为什么?

时间:2018-12-03 06:03:33

标签: java nodes doubly-linked-list

我写了一个圆形的双向链表,前面有一个虚拟节点。在DLL类的初始化期间,我创建了虚拟节点。当我在jGrasp中使用调试器并使用可视化工具时,在插入多个数字后,我的虚拟节点会乱七八糟,不会停留在最前面。我不了解如何修改链表。作为序言,我的节点类具有一个整数val和两个名为prev和next的指针。 我注意到的一件事是,在赋值语句curr = dummy之后,虚拟节点被改组为上一次插入的curr。

public class DLL {

    Node curr;
    Node help;
    Node dummy = new Node(null, null, -1);

    public DLL() {
        this.curr = curr;
        this.help = help;
        dummy.next = dummy;
        dummy.prev = dummy;
    }

    public boolean isEmpty() {
        if (dummy.next == dummy && dummy.prev == dummy) {
            return true;
        }
        return false;
    }

    public void push(int elem) {
        if (isEmpty()) {
            Node sec = new Node(dummy, dummy, elem);
            dummy.next = sec;
            dummy.prev = sec;
        } else {
            curr = dummy;
            while (curr.next != dummy) {
                curr = curr.next;
            }
            Node n = new Node(curr, dummy, elem);
            curr.next = n;
            dummy.prev = n;
        }
    }

    public void reverse() {
        curr = dummy;
        help = dummy;
        while (curr.next != help || curr != help) {
            curr = curr.next; // increment curr
            help = help.prev; // decrement help    
            swap(curr, help); // swap
        }
    }
    public void swap(Node curr, Node help) {
        int temp = curr.val;
        curr.val = help.val;
        help.val = temp;
    }
    public boolean contains(int elem) {
        curr = dummy.next;
        while (curr != dummy && elem != curr.val) {
            curr = curr.next;
            if (curr == dummy) {
                return false;
            }
        }

        return true;
    }
}

这是我使用的小型测试类:

public class testDLL {
    public static void main(String[] args) {
        DLL dlink = new DLL();
        dlink.push(4);
        dlink.push(6);
        dlink.push(3);
        dlink.push(2);
        assert dlink.contains(4) == true;
        assert dlink.contains(6) == true;
        assert dlink.contains(3) == true;
        assert dlink.contains(2) == true;
        dlink.reverse();

    }
}

2 个答案:

答案 0 :(得分:1)

欢迎来到SO。我会建议您如何自己解决问题,而不是为您找到问题。

您的测试试图一次性测试太多。为了使测试生效,所有方法都必须有效。更好的方法是(尽可能)单独测试每种方法,然后构建以测试更复杂的场景。

因此,请首先使此测试生效:

DLL list = new DLL();
assertTrue(list.isEmpty());

然后

DLL list = new DLL();
list.push(5);
assertTrue(list.contains(5));

很快您会发现您需要一种方法来以不同的格式获取列表以进行测试。这很典型。

DLL list = new DLL();
list.push(5);
list.push(7);
list.push(5);
assertEquals(list.asList(), List.of(5, 7, 5));

DLL list = new DLL();
list.push(5);
list.push(7);
list.reverse();
assertEquals(list.asList(), List.of(7, 5));

以此类推。

这样,您可以在继续操作之前检查每种方法是否适用于基本值。

现在有几个设计指标:您使用虚拟节点存储头和尾是不寻常的。搞乱值很容易(如您所愿)。如果列表为空并且指向单个项目的相同节点,则最好将头和尾存储为null(或者最好是Optional.empty)的单独变量。

答案 1 :(得分:0)

我已经解决了这个问题。我没有设置curr = dummy,而是设置了curr = head。在DLL顶部初始化虚拟对象后,立即将head设置为dummy。这样一来,我就不会改变自己的头脑。

相关问题