简体   繁体   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());
      //

      
     
  }
} 

Task: In this exercise, you will use the DoublyLinkedList implementation of the textbook (week 2 lecture examples. Write a method for concatenating two doubly linked lists L and M, with header and trailer sentinel nodes, into a single list L′. Write a main method to test the new method. Hint: Connect the end of L into the beginning of M.任务:在本练习中,您将使用教科书的 DoublyLinkedList 实现(第 2 周的讲座示例。编写一个将两个双向链表 L 和 M 与 header 和尾部标记节点连接成单个列表 L' 的方法。编写一个main 方法来测试新方法。提示:将 L 的结尾连接到 M 的开头。

I am having difficulties solving this problem, I wrote this code我很难解决这个问题,我写了这段代码

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

and modify it a lot for a couple of hours, but still cannot get what is it.并修改了几个小时,但仍然无法得到它是什么。 Can anyone help?任何人都可以帮忙吗?

Main主要的

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);

Analysis分析

  1. Sentinel nodes are used for header and trailer Sentinel 节点用于headertrailer
  2. Totally there will be 4 sentinel nodes总共将有4哨兵节点
  3. After merging there should only be 2 sentinel nodes合并后应该只有2哨兵节点

Approach方法

ListL列表L

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

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

ListM列表M

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

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

Expected result预期结果

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

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

Issues in code代码中的问题

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

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

      return L;
  }

Updating M.header and M.trailer will not help as it only reassigns the sentinel nodes.更新 M.header 和 M.trailer 无济于事,因为它只会重新分配哨兵节点。

Approach方法

  1. The header.next, header.prev, trailer.next, trailer.prev are the primary candidates for change header.next、header.prev、trailer.next、trailer.prev 是更改的主要候选者
  2. header.next.prev, tailer.prev.next are the other candidates for update. header.next.prev、tailer.prev.next 是更新的其他候选。

Suggestion建议

  1. Given these scenarios, it better to append the first list and second list (trailerL will join with headerM)鉴于这些情况,最好将 append 第一个列表和第二个列表(trailerL 将与 headerM 连接)
  2. Create reference between headerL and trailerM在 headerL 和 trailM 之间创建引用
  3. Remove trailerL删除拖车L
  4. Remove headerM删除标头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);

Try this method inside the DoublyLinkedList class在 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