【问题标题】:Nodes, Queues, De-queues节点、队列、出队
【发布时间】:2013-04-04 06:54:30
【问题描述】:

我正在做这个在同一个类中创建队列和出队的小项目,同时使用我自己的 Node 类和接口。

我面临的问题是我已经完成了所有方法,但无法让方法 removeLast 工作,因为在被删除后我无法让后链接到它之前的节点。请帮我提出你的建议?谢谢。

我的节点类。

public class Node<T> {

  T info;
  Node<T> next;

  public Node(T element) {
    info = element;
    next = null;
  }

  public void setInfo(T element) {
    info = element;
  }

  public T getInfo() {
    return info;
  }

  public void setNext(Node<T> next) {
    this.next = next;
  }

  public Node<T> getNext() {
    return next;
  }

}

我的接口类

public interface DequeInterface<T> {

  void addFront(T element);

  void addLast(T element);

  T removeFront();

  T removeLast();

  boolean isEmpty();

  int getSize();
}

我的双端队列类

import java.util.NoSuchElementException;

public class Deqeue<T> implements DequeInterface {

  public Node<T> front;
  public Node<T> rear;
  int size;

  public Deqeue() {
    front = null;
    rear = null;
    size = 0;
  }

  @Override
  public T removeFront() {
    if (isEmpty()) {
      throw new NoSuchElementException();
    }
    T element = front.getInfo();
    front = front.getNext();
    size--;
    return element;
  }

  @Override
  public T removeLast() {
    if (isEmpty()) {
      throw new NoSuchElementException();
    }
    T element = rear.getInfo();
    size--;
    return element;
  }

  @Override
  public int getSize() {
    return size;
  }

  @Override
  public boolean isEmpty() {
    return rear == null;
  }

  @Override
  public void addFront(Object element) {
    Node<T> newNode = front;

    if (newNode == null) {
      rear = front;
    }
      front = new Node(element);
      front.setNext(newNode);
      size++;
  }

  @Override
  public void addLast(Object element) {
    Node<T> newNode = rear;

    if (newNode == null) {
      front = rear;
    }
      rear = new Node(element);
      newNode.setNext(rear);
      size++;

    }
  }

【问题讨论】:

    标签: java queue nodes deque


    【解决方案1】:

    问题是您的列表是单链接的。不幸的是,删除单链表的最后一个节点需要遍历整个列表。一些替代方案:

    【讨论】:

    • thnx 兄弟,这是双倍的,但你能帮我如何开始吗
    • 所有其他答案似乎都与此有关。但请注意(正如其他评论者所提到的)——如果不更改节点类,您将无法做到这一点。根据定义,双向链表的节点有 2 个链接:一个链接到列表中的下一个节点,另一个链接到前一个节点。
    【解决方案2】:

    您也可以让您的Node 引用之前的Node。这将创建一个双向链表。

    public class Node<T> {
    
        T info;
        Node<T> next;
        Node<T> prev;
    
        public Node(T element) {
            info = element;
            next = null;
            prev = null;
        }
    
    
        public void setInfo(T element) {
            info = element;
        }
    
        public T getInfo() {
            return info;
        }
    
        public void setNext(Node<T> next) {
            this.next = next;
        }
    
        public Node<T> getNext() {
            return next;
        }
    
        public void setPrev(Node<T> prev) {
            this.prev = prev;
        }
    
        public Node<T> getPrev() {
            return prev;
        }
    }
    

    然后在Deque 类中更改您的removeFrontremoveLast 方法以考虑prev

    public T removeFront() {
        if (isEmpty()) {
           throw new NoSuchElementException();
        }
        T element = front.getInfo();
        front = front.getNext();
        front.setPrev(null); //<<<--------------------------
        size--;
        return element;
    }
    
    @Override
    public T removeLast() {
        if (isEmpty()) {
           throw new NoSuchElementException();
         }
        T element = rear.getInfo();
        rear.getPrev().setNext(null) //<<<--------------
        rear=rear.getPrev(); //<<<--------------
    
        size--;
        return element;
     }
    

    当然,addFirstaddLast 方法也必须更新

    @Override
    public void addFront(Object element) {
        Node<T> newNode = front;
    
        front = new Node(element);
        front.setNext(newNode);
        if (newNode == null) {
            rear = front;
        }else{
            newNode.setPrev(front);
        }
        size++;
    }
    
    @Override
    public void addLast(Object element) {
        Node<T> newNode = rear;
        rear = new Node(element);
        newNode.setNext(rear);
    
        if (newNode == null) {
            front = rear;
        }else{
            newNode.setNext(rear);
        } 
        size++;
    }
    

    如果您不允许更改Node 的代码并且只能更改removeLast() 方法,那么您可以这样做:

    @Override
    public T removeLast() {
        if (isEmpty()) {
           throw new NoSuchElementException();
         }
        T element = rear.getInfo();
        if(rear==first){
            rear=null;
            first=null;
        }else{
            Node<T> prev = first;
            while(prev.getNext()!=rear){
                prev=prev.getNext();
            }
            rear=prev;
            prev.setNext(null);
       }
        size--;
        return element;
     }
    

    但这会相当低效,因为它需要从头开始遍历整个列表。

    【讨论】:

    • thnx bro 非常感谢,这是让它双链接设置对吗?我的另一个问题可以在不更改节点类的情况下完成吗?
    • 是的,但这会使 removeLast 方法非常低效。您必须遍历整个链表才能到达最后一个节点,同时记住前一个节点。见编辑
    【解决方案3】:

    每个节点都应该有一个指向下一个节点的指针指向前一个节点。

    【讨论】:

      【解决方案4】:

      您可以使您的列表双重链接(额外的管理和错误的机会),或者您可以在每次 removeLast 时迭代列表并重新设置为新的最后一个(从最后一个删除时性能更差,尤其是在大型列表上。 )

      【讨论】:

        【解决方案5】:

        最简单的方法是实现双向链表,而不是链表。因此,您的节点类将需要跟踪前一个元素。您将需要更新您的添加功能以支持此功能。完成后,您的 remove last 函数将如下所示:

          @Override
          public T removeLast() {
            if (isEmpty()) {
              throw new NoSuchElementException();
            }
            T element = rear.getInfo();
            size--;
            rear.getPrev().setNext(null);
            rear = rear.getPrev();
            return element;
          }
        

        【讨论】:

        • 我需要在代码中更改的只是方法吗?节点类中没有添加任何内容?
        • 老哥,不改节点类的情况下可以翻倍吗?
        • @user2272227 不,双向链表的全部本质是一个节点对它后面和前面的节点都有引用。
        猜你喜欢
        • 2013-10-20
        • 1970-01-01
        • 1970-01-01
        • 2017-06-27
        • 1970-01-01
        • 1970-01-01
        • 2021-08-22
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多