【问题标题】:Ovewriting toString method in deque class using generics使用泛型覆盖双端队列类中的 toString 方法
【发布时间】:2018-02-12 16:13:59
【问题描述】:

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

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

我知道已经有一个双端队列接口,但是这是在 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());

    }
}

【问题讨论】:

    标签: java tostring deque


    【解决方案1】:

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

    currTailcurrHead 在你的 while 循环中都不会改变,所以如果双端队列非空,你的条件 currHead != null &amp;&amp; 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,因为它允许您设置在每个字符串之间使用的分隔符,这正是您正在做的。

    【讨论】:

      猜你喜欢
      • 2018-07-13
      • 1970-01-01
      • 2013-08-20
      • 2020-03-14
      • 1970-01-01
      • 1970-01-01
      • 2012-03-01
      • 2015-06-24
      • 2013-04-04
      相关资源
      最近更新 更多