繁体   English   中英

编写连接两个双向链表 L 和 M 的方法

[英]Write a method for concatenating two doubly linked lists L and M

package linkedlists;

import linkedlists.DoublyLinkedList.Node;


public class DoublyLinkedList<E> {

  //---------------- nested Node class ----------------
  /**
   * Node of a doubly linked list, which stores a reference to its
   * element and to both the previous and next node in the list.
   */
  public static class Node<E> {

    /** The element stored at this node */
    private E element;               // reference to the element stored at this node

    /** A reference to the preceding node in the list */
    private Node<E> prev;            // reference to the previous node in the list

    /** A reference to the subsequent node in the list */
    private Node<E> next;            // reference to the subsequent node in the list

    /**
     * Creates a node with the given element and next node.
     *
     * @param e  the element to be stored
     * @param p  reference to a node that should precede the new node
     * @param n  reference to a node that should follow the new node
     */
    public Node(E e, Node<E> p, Node<E> n) {
      element = e;
      prev = p;
      next = n;
    }

    // public accessor methods
    /**
     * Returns the element stored at the node.
     * @return the element stored at the node
     */
    public E getElement() { return element; }

    /**
     * Returns the node that precedes this one (or null if no such node).
     * @return the preceding node
     */
    public Node<E> getPrev() { return prev; }

    /**
     * Returns the node that follows this one (or null if no such node).
     * @return the following node
     */
    public Node<E> getNext() { return next; }

    // Update methods
    /**
     * Sets the node's previous reference to point to Node n.
     * @param p    the node that should precede this one
     */
    public void setPrev(Node<E> p) { prev = p; }

    /**
     * Sets the node's next reference to point to Node n.
     * @param n    the node that should follow this one
     */
    public void setNext(Node<E> n) { next = n; }
    
  } //----------- end of nested Node class -----------

  // instance variables of the DoublyLinkedList
  /** Sentinel node at the beginning of the list */
  private Node<E> header;                    // header sentinel

  /** Sentinel node at the end of the list */
  private Node<E> trailer;                   // trailer sentinel

  /** Number of elements in the list (not including sentinels) */
  private int size = 0;                      // number of elements in the list

  /** Constructs a new empty list. */
  public DoublyLinkedList() {
    header = new Node<>(null, null, null);      // create header
    trailer = new Node<>(null, header, null);   // trailer is preceded by header
    header.setNext(trailer);                    // header is followed by trailer
  }

  // public accessor methods
  /**
   * Returns the number of elements in the linked list.
   * @return number of elements in the linked list
   */
  public int size() { return size; }

  /**
   * Tests whether the linked list is empty.
   * @return true if the linked list is empty, false otherwise
   */
  public boolean isEmpty() { return size == 0; }

  /**
   * Returns (but does not remove) the first element of the list.
   * @return element at the front of the list (or null if empty)
   */
  public E first() {
    if (isEmpty()) return null;
    return header.getNext().getElement();   // first element is beyond header
  }

  /**
   * Returns (but does not remove) the last element of the list.
   * @return element at the end of the list (or null if empty)
   */
  public E last() {
    if (isEmpty()) return null;
    return trailer.getPrev().getElement();    // last element is before trailer
  }

  // public update methods
  /**
   * Adds an element to the front of the list.
   * @param e   the new element to add
   */
  public void addFirst(E e) {
    addBetween(e, header, header.getNext());    // place just after the header
  }

  /**
   * Adds an element to the end of the list.
   * @param e   the new element to add
   */
  public void addLast(E e) {
    addBetween(e, trailer.getPrev(), trailer);  // place just before the trailer
  }

  /**
   * Removes and returns the first element of the list.
   * @return the removed element (or null if empty)
   */
  public E removeFirst() {
    if (isEmpty()) return null;                  // nothing to remove
    return remove(header.getNext());             // first element is beyond header
  }

  /**
   * Removes and returns the last element of the list.
   * @return the removed element (or null if empty)
   */
  public E removeLast() {
    if (isEmpty()) return null;                  // nothing to remove
    return remove(trailer.getPrev());            // last element is before trailer
  }

  // private update methods
  /**
   * Adds an element to the linked list in between the given nodes.
   * The given predecessor and successor should be neighboring each
   * other prior to the call.
   *
   * @param predecessor   node just before the location where the new element is inserted
   * @param successor     node just after the location where the new element is inserted
   */
  private void addBetween(E e, Node<E> predecessor, Node<E> successor) {
    // create and link a new node
    Node<E> newest = new Node<>(e, predecessor, successor);
    predecessor.setNext(newest);
    successor.setPrev(newest);
    size++;
  }

  /**
   * Removes the given node from the list and returns its element.
   * @param node    the node to be removed (must not be a sentinel)
   */
  private E remove(Node<E> node) {
    Node<E> predecessor = node.getPrev();
    Node<E> successor = node.getNext();
    predecessor.setNext(successor);
    successor.setPrev(predecessor);
    size--;
    return node.getElement();
  }

  /**
   * Produces a string representation of the contents of the list.
   * This exists for debugging purposes only.
   */
  public String toString() {
    StringBuilder sb = new StringBuilder("(");
    Node<E> walk = header.getNext();
    while (walk != trailer) {
      sb.append(walk.getElement());
      walk = walk.getNext();
      if (walk != trailer)
        sb.append(", ");
    }
    sb.append(")");
    return sb.toString();
  }
  
  public DoublyLinkedList<E> concatenate(DoublyLinkedList<E> L, DoublyLinkedList<E> M) {
      
      M.header = L.trailer;
      M.trailer = L.header;
      
      return L;
  }
  
//main method
  public static void main(String[] args)
  {
      //create and populate a doubly linked list
      DoublyLinkedList<String> list = new DoublyLinkedList<String>();
      list.addFirst("MSP");
      list.addLast("ATL");
      list.addLast("BOS");
      //
      list.addFirst("LAX");
      
     System.out.println(list);
     System.out.println(list.first());
      //

      
     
  }
} 

任务:在本练习中,您将使用教科书的 DoublyLinkedList 实现(第 2 周的讲座示例。编写一个将两个双向链表 L 和 M 与 header 和尾部标记节点连接成单个列表 L' 的方法。编写一个main 方法来测试新方法。提示:将 L 的结尾连接到 M 的开头。

我很难解决这个问题,我写了这段代码

public DoublyLinkedList<E> concatenate(DoublyLinkedList<E> L, DoublyLinkedList<E> M) {
      
      M.header = L.trailer;
      M.trailer = L.header;
      
      return L;
  }

并修改了几个小时,但仍然无法得到它是什么。 任何人都可以帮忙吗?

主要的

DoublyLinkedList<String> list1 = new DoublyLinkedList<String>();
     list1.addFirst("A");
     list1.addLast("B");
     list1.addLast("C");
     list1.addLast("D");

     
DoublyLinkedList<String> list2 = new DoublyLinkedList<String>();
     list2.addFirst("1");
     list2.addLast("2");
     list2.addLast("3");
     list2.addLast("4");

     
     list1.concatenate(list2);
     
     System.out.println(list1);

分析

  1. Sentinel 节点用于headertrailer
  2. 总共将有4哨兵节点
  3. 合并后应该只有2哨兵节点

方法

列表L

headerL -> NodeL1 -> NodeL2 -> trailerL -> headerL

trailerL <- headerL <- NodeL1 <- NodeL2 <- trailerL

列表M

headerM -> NodeM1 -> NodeM2 -> trailerM -> headerM

trailerM <- headerM <- NodeM1 <- NodeM2 <- trailerM

预期结果

headerL -> NodeL1 -> NodeL2 -> NodeM1 -> NodeM2 -> trailerM -> headerL

trailerM <- headerL <- NodeL1 <- NodeL2 <- NodeM1 <- NodeM2 <- trailerM

代码中的问题

public DoublyLinkedList<E> concatenate(DoublyLinkedList<E> L,
                                       DoublyLinkedList<E> M) {

      M.header = L.trailer;
      M.trailer = L.header;

      return L;
  }

更新 M.header 和 M.trailer 无济于事,因为它只会重新分配哨兵节点。

方法

  1. header.next、header.prev、trailer.next、trailer.prev 是更改的主要候选者
  2. header.next.prev、tailer.prev.next 是更新的其他候选。

建议

  1. 鉴于这些情况,最好将 append 第一个列表和第二个列表(trailerL 将与 headerM 连接)
  2. 在 headerL 和 trailM 之间创建引用
  3. 删除拖车L
  4. 删除标头M
    // join trail of first list with head of second list
    Node trailerL = L.trailer;
    Node headerM = M.header;

    L.trailer.setNext(M.header);
    M.header.setPrev(L.trailer);

    // join head of first list with tail of second list
    // this will be header and trailer of the merged list
    L.header.setPrev(M.trailer);
    M.trailer.setNext(L.header);

    L.size += 2;

   // delete trailerL and headerM
   remove(trailerL);
   remove(headerM);

在 DoublyLinkedList class 中尝试此方法

   public void concatenate(final DoublyLinkedList<E> other) {
       final Node trailerL = this.trailer;
       final Node headerM = other.header;

       this.trailer.setNext(other.header);
       other.header.setPrev(this.trailer);

       this.header.setPrev(other.trailer);
       other.trailer.setNext(this.header);

       this.size += 2;

       this.remove(trailerL);
       this.remove(headerM);
   }

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM