使用泛型在deque类中编写toString方法

时间:2018-02-12 16:14:00

标签: java tostring deque

我正在尝试使用toString方法打印双端队列中的第一个和最后一个元素但是我不能完全确定我是否正确覆盖了toString方法。

据我所知,这些方法似乎都表现正常但我无法分辨,因为我无法看到任何可读的输出。

我知道已经有一个deque接口,但这是在Java中使用泛型的练习的一部分。

这段代码应该创建一个双端队列,能够在双端队列的前面添加值,从前面删除值,向后面添加值并从后面删除值。

这是有问题的课程:

import java.util.Iterator;
import java.util.NoSuchElementException;

class Deque<T> implements Iterable<T> {
    private class Node<T> {
        public Node<T> left, right;
        private final T item;

        public Node(T item) {
            if (item == null) {
                throw new NullPointerException();
            }
            this.item = item;
        }

        public void connectRight(Node<T> other) {
            this.right = other;
            other.left = this;
        }
    }

    private class DequeIterator implements Iterator<T> {

        private Node<T> curr = head;

        public boolean hasNext() {
            return curr != null;
        }

        public void remove() {
            throw new UnsupportedOperationException();
        }

        public T next() {
            if (!hasNext()) {
                throw new NoSuchElementException();
            }
            T item = curr.item;
            curr = curr.right;
            return item;
        }
    }

    private Node<T> head, tail;
    private int size;

    public Iterator<T> iterator() {
        return new DequeIterator();
    }

    public Deque() {
    }

    public int size() {
        return size;
    }

    public boolean isEmpty() {
        return size() == 0;
    }

    public void checkInvariants() {
        assert size >= 0;
        assert size > 0 || (head == null && tail == null);
        assert (head == null && tail == null) || (head != null && tail != null);
    }

    public void addFirst(T item) {
        Node<T> prevHead = head;
        Node<T> newHead = new Node<T>(item);
        if (prevHead != null) {
            newHead.connectRight(prevHead);
        } else {
            tail = newHead;
        }
        head = newHead;
        size++;
        checkInvariants();
    }

    public void addLast(T item) {
        Node<T> newTail = new Node<T>(item);
        Node<T> prevTail = tail;
        if (prevTail != null) {
            prevTail.connectRight(newTail);
        } else {
            head = newTail;
        }
        tail = newTail;
        size++;
        checkInvariants();
    }

    public T removeFirst() {
        if (isEmpty()) {
            throw new java.util.NoSuchElementException();
        }
        size--;
        Node<T> prevHead = head;
        head = prevHead.right;
        prevHead.right = null;
        if (head != null) {
            head.left = null;
        }
        checkInvariants();
        return prevHead.item;
    }

    public T removeLast() {
        if (isEmpty()) {
            throw new java.util.NoSuchElementException();
        }
        size--;
        Node<T> prevTail = tail;
        tail = prevTail.left;
        prevTail.left = null;
        if (tail != null) tail.right = null;
        checkInvariants();
        return prevTail.item;
    }

    @Override
    public String toString() {
        Node<T> currTail = tail;
        Node<T> currHead = head;
        head = currHead.right;
        tail = currTail.left;

        StringBuilder builder = new StringBuilder();

        while (currHead != null && currTail != null) {
            builder.append(currHead.item + "\n");
        }

        return builder.toString();

    }

    public static void main(String[] args) {
        Deque<Double> d = new Deque<Double>();
        d.addFirst(1.0);
        System.out.println(d);
        d.addLast(1.0);
        //d.removeFirst();
        //d.removeLast();

        System.out.println(d.toString());

    }
}

1 个答案:

答案 0 :(得分:0)

首先,你要将实例变量的头部和尾部设置为各自的邻居,这绝对不是你要做的事情。这会使您的队列处于不一致状态,其中第二个元素是头部,但它仍然有一个左邻居,即原始头部。尾巴也一样。通常,toString方法不应有副作用。

{while}循环中currTailcurrHead都没有变化,因此如果双曲线非空,则条件currHead != null && currTail != null将始终为真。您必须在循环中设置这些变量,但是,您不需要一次从两端进行迭代。从一开始就迭代就足够了。然后,您可以使用for循环,如下所示:

@Override
public String toString() {
    final StringJoiner stringJoiner = new StringJoiner("\n");

    for (Node<T> node = head; node != null; node = node.right) {
        stringJoiner.add(node.item.toString());
    }

    return stringJoiner.toString();
}

这会在每次迭代后将变量node设置为它的右邻居,如果双端队列为空,则node将从一开始就为空,并且不会按预期输入循环

这只是更简洁(我认为)的版本:

@Override
public String toString() {
    final StringJoiner stringJoiner = new StringJoiner("\n");

    Node<?> node = head;

    while (node != null) {
        stringJoiner.add(node.item.toString());
        node = node.right;
    }

    return stringJoiner.toString();
}

基本上是你的尝试,只是修复了。

并非我使用了StringJoiner而不是StringBuilder,因为它允许您设置每个字符串之间使用的分隔符,这正是您正在做的事情。