如何修改链表来处理双向链表?

时间:2014-02-01 12:42:11

标签: java linked-list

如何实现将Sequence ADT定义为双链表的类SequenceDLList?

我一直在尝试用单链表修改下面的代码....但是没有到达那里。 这应该有用..

class SequenceListException extends Exception {
    SequenceListException() {
        super();
    }
    SequenceListException(String s) {
        super(s);
}
}


 */

public class SequenceList
{
/**
 * Member class Node encapsulates the nodes of the linked list in 
 * which the stack is stored. Each node contains a data item and a
 * reference to another node - the next in the linked list.
 */
    protected class Node
    {

    public Node(Object o)
    {
        this(o, null);
    }

    public Node(Object o, Node n)
    {
        datum = o;
        next = n;
    }

    //The Node data structure consists of two object references.
    //One for the datum contained in the node and the other for
    //the next node in the list.

    protected Object datum;
    protected Node next;
}

//We use object references to the head and tail of the list (the head
//and tail of the sequence, respectively).
private Node listHead;
private Node listTail;

//Only require a single constructor, which sets both object
//references to null.
/**
 * Constructs an empty sequence object.
 */
public SequenceList()
{
    listHead = null;
    listTail = null;
}

/**
 * Adds a new item at the start of the sequence.
 */
public void insertFirst(Object o)
{
    //There is a special case when the sequence is empty.
    //Then the both the head and tail pointers needs to be 
    //initialised to reference the new node.
    if(listHead == null) {
        listHead = new Node(o, listHead);
        listTail = listHead;
    }

    //In the general case, we simply add a new node at the start
    //of the list via the head pointer.
    else {
        listHead = new Node(o, listHead);
    }
}

/**
 * Adds a new item at the end of the sequence.
 */
public void insertLast(Object o)
{
    //There is a special case when the sequence is empty.
    //Then the both the head and tail pointers needs to be 
    //initialised to reference the new node.
    if(listHead == null) {
        listHead = new Node(o, listHead);
        listTail = listHead;
    }

    //In the general case, we simply add a new node to the end
    //of the list via the tail pointer.
    else {
        listTail.next = new Node(o, listTail.next);
        listTail = listTail.next;
    }
}

/**
 * Adds a new item at a specified position in the sequence.
 */
public void insert(Object o, int index) throws SequenceListException
{
    //Check the index is positive.
    if(index < 0) {
        throw new SequenceListException("Indexed Element out of Range");
    }

    //There is a special case when the sequence is empty.
    //Then the both the head and tail pointers needs to be 
    //initialised to reference the new node.
    if(listHead == null) {
        if(index == 0) {
        listHead = new Node(o, listHead);
        listTail = listHead;
        }
        else throw new SequenceListException("Indexed element is out of range");
    }

    //There is another special case for insertion at the head of
    //the sequence.
    else if(index == 0) {
        listHead = new Node(o, listHead);
    }

    //In the general case, we need to chain down the linked list
    //from the head until we find the location for the new
    //list node. If we reach the end of the list before finding
    //the specified location, we know that the given index was out
    //of range and throw an exception.
    else {
        Node nodePointer = listHead;
        int i = 1;
        while(i < index) {
            nodePointer = nodePointer.next;
            i += 1;
            if(nodePointer == null) {
                throw new SequenceListException("Indexed Element out of Range");
            }
        }

        //Now we've found the node before the position of the
        //new one, so we 'hook in' the new Node.

        nodePointer.next = new Node(o, nodePointer.next);

        //Finally we need to check that the tail pointer is
        //correct. Another special case occurs if the new
        //node was inserted at the end, in which case, we need
        //to update the tail pointer.
        if(nodePointer == listTail) {
            listTail = listTail.next;
        }
    }
}

/**
 * Removes the item at the start of the sequence.
 */
public void deleteFirst() throws SequenceListException
{
    //Check there is something in the sequence to delete.
    if(listHead == null) {
        throw new SequenceListException("Sequence Underflow");
    }

    //There is a special case when there is just one item in the
    //sequence. Both pointers then need to be reset to null.
    if(listHead.next == null) {
        listHead = null;
        listTail = null;
    }

    //In the general case, we just unlink the first node of the
    //list.
    else {
        listHead = listHead.next;
    }
}

/**
 * Removes the item at the end of the sequence.
 */
public void deleteLast() throws SequenceListException
{
    //Check there is something in the sequence to delete.
    if(listHead == null) {
        throw new SequenceListException("Sequence Underflow");
    }

    //There is a special case when there is just one item in the
    //sequence. Both pointers then need to be reset to null.
    if(listHead.next == null) {
        listHead = null;
        listTail = null;
    }

    //In the general case, we need to chain all the way down the
    //list in order to reset the link of the second to last 
    //element to null.
    else {
        Node nodePointer = listHead;
        while(nodePointer.next != listTail) {
            nodePointer = nodePointer.next;
        }

        //Unlink the last node and reset the tail pointer.
        nodePointer.next = null;
        listTail = nodePointer;
    }
}

/**
 * Removes the item at the specified position in the sequence.
 */
public void delete(int index) throws SequenceListException
{
    //Check there is something in the sequence to delete.
    if(listHead == null) {
        throw new SequenceListException("Sequence Underflow");
    }

    //Check the index is positive.
    if(index < 0) {
        throw new SequenceListException("Indexed Element out of Range");
    }

    //There is a special case when there is just one item in the
    //sequence. Both pointers then need to be reset to null.
    if(listHead.next == null) {
        if(index == 0) {
        listHead = null;
        listTail = null;
        } else throw new SequenceListException("Indexed element is out of range.");
    }

    //There is also a special case when the first element has to
    //be removed.

    else if(index == 0) {
        deleteFirst();
    }

    //In the general case, we need to chain down the list to find
    //the node in the indexed position.
    else {
        Node nodePointer = listHead;
        int i = 1;
        while(i < index) {
            nodePointer = nodePointer.next;
            i += 1;
            if (nodePointer.next == null) {
                throw new SequenceListException("Indexed Element out of Range");
            }

        }

        //Unlink the node and reset the tail pointer if that
        //node was the last one.
        if(nodePointer.next == listTail) {
            listTail = nodePointer;
        }
        nodePointer.next = nodePointer.next.next;
    }
}

/**
 * Returns the item at the start of the sequence.
 */
public Object first() throws SequenceListException
{
    if(listHead != null) {
        return listHead.datum;
    }
    else {
        throw new SequenceListException("Indexed Element out of Range");
    }
}

/**
 * Returns the item at the end of the sequence.
 */
public Object last() throws SequenceListException
{
    if(listTail != null) {
        return listTail.datum;
    }
    else {
        throw new SequenceListException("Indexed Element out of Range");
    }
}

/**
 * Returns the item at the specified position in the sequence.
 */
public Object element(int index) throws SequenceListException
{
    //Check the index is positive.
    if(index < 0) {
        throw new SequenceListException("Indexed Element out of Range");
    }

    //We need to chain down the list until we reach the indexed
    //position

    Node nodePointer = listHead;
    int i = 0;
    while (i < index) {
        if(nodePointer.next == null) {
            throw new SequenceListException("Indexed Element out of Range");
        }
        else {
            nodePointer = nodePointer.next;
            i += 1;
        }
    }

    return nodePointer.datum;
}

/**
 * Tests whether there are any items in the sequence.
 */
public boolean empty()
{
    return (listHead == null);
}

/**
 * Returns the number of items in the sequence.
 */
public int size()
{
    //Chain down the list counting the elements

    Node nodePointer = listHead;
    int size = 0;
    while(nodePointer != null) {
        size += 1;
        nodePointer = nodePointer.next;
    }
    return size;
}

/**
 * Empties the sequence.
 */
public void clear()
{
    listHead = null;
    listTail = null;
}

}

3 个答案:

答案 0 :(得分:2)

正如其他人已经提到的那样,每个节点都必须在列表中引用它的下一个前一个邻居。

基本上,整个解决方案看起来与您的示例不同。您必须注意,无论您在何处添加或删除节点,都需要相应地调整相邻节点的引用。

唯一不同的方法是 deleteLast 。在这里,您不需要遍历整个列表来查找倒数第二个节点。您只需使用最后一个节点的“prev”参考。

我担心我刚做完作业,但无论如何这里都是完整的例子。请注意,我根本没有真正测试该代码:

class SequenceListException extends Exception {

    SequenceListException() {
        super();
    }

    SequenceListException(String s) {
        super(s);
    }
}

public class SequenceList {

    /**
     * Member class Node encapsulates the nodes of the linked list in which the
     * stack is stored. Each node contains a data item and a reference to
     * another node - the next in the linked list.
     */
    protected class Node {

        public Node(Object o) {
            this(o, null, null);
        }

        public Node(Object o, Node p, Node n) {
            datum = o;
            prev = p;
            next = n;
        }
        // The Node data structure consists of three object references.
        // One for the datum contained in the node and two for 
        // the next and previous node in the list.
        protected Object datum;
        protected Node next;
        protected Node prev;
    }

    // We use object references to the head and tail of the list (the head
    // and tail of the sequence, respectively).
    private Node listHead;
    private Node listTail;

    // Only require a single constructor, which sets both object
    // references to null.
    /**
     * Constructs an empty sequence object.
     */
    public SequenceList() {
        listHead = null;
        listTail = null;
    }

    /**
     * Adds a new item at the start of the sequence.
     */
    public void insertFirst(Object o) {
        // There is a special case when the sequence is empty.
        // Then the both the head and tail pointers needs to be 
        // initialised to reference the new node.
        if (listHead == null) {
            listHead = new Node(o);
            listTail = listHead;
        } 
        // In the general case, we simply add a new node at the start
        // of the list via the head pointer.
        else {
            listHead.prev = new Node(o, null, listHead);
            listHead = listHead.prev;
        }
    }

    /**
     * Adds a new item at the end of the sequence.
     */
    public void insertLast(Object o) {
        // There is a special case when the sequence is empty.
        // Then the both the head and tail pointers needs to be 
        // initialised to reference the new node.
        if (listHead == null) {
            listHead = new Node(o);
            listTail = listHead;
        } 
        // In the general case, we simply add a new node to the end
        // of the list via the tail pointer.
        else {
            listTail.next = new Node(o, listTail, null);
            listTail = listTail.next;
        }
    }

    /**
     * Adds a new item at a specified position in the sequence.
     */
    public void insert(Object o, int index) throws SequenceListException {
        // Check the index is positive.
        if (index < 0) {
            throw new SequenceListException("Indexed Element out of Range");
        }

        // There is a special case when the sequence is empty.
        // Then the both the head and tail pointers needs to be 
        // initialised to reference the new node.
        if (listHead == null) {
            if (index == 0) {
                listHead = new Node(o);
                listTail = listHead;
            } else {
                throw new SequenceListException("Indexed element is out of range");
            }
            return;
        }

        // There is another special case for insertion at the head of
        // the sequence.
        if (index == 0) {
            insertFirst(o);
            return;
        } 

        // In the general case, we need to chain down the linked list
        // from the head until we find the location for the new
        // list node. If we reach the end of the list before finding
        // the specified location, we know that the given index was out
        // of range and throw an exception.
        Node nodePointer = listHead;
        int i = 1;
        while (i < index) {
            nodePointer = nodePointer.next;
            i += 1;
            if (nodePointer == null) {
                throw new SequenceListException("Indexed Element out of Range");
            }
        }

        // Now we've found the node before the position of the
        // new one, so we 'hook in' the new Node.
        Node newNode = new Node(o, nodePointer, nodePointer.next);
        if (nodePointer.next != null) {
            nodePointer.next.prev = newNode;
        }
        nodePointer.next = newNode;

        // Finally we need to check that the tail pointer is
        // correct. Another special case occurs if the new
        // node was inserted at the end, in which case, we need
        // to update the tail pointer.
        if (nodePointer == listTail) {
            listTail = newNode;
        }
    }

    /**
     * Removes the item at the start of the sequence.
     */
    public void deleteFirst() throws SequenceListException {
        // Check there is something in the sequence to delete.
        if (listHead == null) {
            throw new SequenceListException("Sequence Underflow");
        }

        // There is a special case when there is just one item in the
        // sequence. Both pointers then need to be reset to null.
        if (listHead.next == null) {
            listHead = null;
            listTail = null;
            return;
        }

        // In the general case, we just unlink the first node of the
        // list.
        listHead = listHead.next;
        listHead.prev = null;
    }

    /**
     * Removes the item at the end of the sequence.
     */
    public void deleteLast() throws SequenceListException {
        // Check there is something in the sequence to delete.
        if (listHead == null) {
            throw new SequenceListException("Sequence Underflow");
        }

        // There is a special case when there is just one item in the
        // sequence. Both pointers then need to be reset to null.
        if (listHead.next == null) {
            listHead = null;
            listTail = null;
            return;
        }

        // In the general case, we just unlink the last node of the
        // list.
        listTail = listTail.prev;
        listTail.next = null;
    }

    /**
     * Removes the item at the specified position in the sequence.
     */
    public void delete(int index) throws SequenceListException {
        // Check there is something in the sequence to delete.
        if (listHead == null) {
            throw new SequenceListException("Sequence Underflow");
        }

        // Check the index is positive.
        if (index < 0) {
            throw new SequenceListException("Indexed Element out of Range");
        }

        // There is a special case when there is just one item in the
        // sequence. Both pointers then need to be reset to null.
        if (listHead.next == null) {
            if (index == 0) {
                listHead = null;
                listTail = null;
            } else {
                throw new SequenceListException("Indexed element is out of range.");
            }
            return;
        } 

        // There is also a special case when the first element has to
        // be removed.
        if (index == 0) {
            deleteFirst();
            return;
        } 

        // In the general case, we need to chain down the list to find
        // the node in the indexed position.
        Node nodePointer = listHead;
        int i = 1;
        while (i < index) {
            nodePointer = nodePointer.next;
            i += 1;
            if (nodePointer.next == null) {
                throw new SequenceListException("Indexed Element out of Range");
            }

        }

        // Unlink the node and reset the tail pointer if that
        // node was the last one.
        if (nodePointer.next == listTail) {
            listTail = nodePointer;
        }
        // Change reference of node after the node which is removed.
        if (nodePointer.next.next != null) {
            nodePointer.next.next.prev = nodePointer;
        }
        // Change reference of node before the node which is removed.
        nodePointer.next = nodePointer.next.next;
    }

    /**
     * Returns the item at the start of the sequence.
     */
    public Object first() throws SequenceListException {
        if (listHead != null) {
            return listHead.datum;
        } else {
            throw new SequenceListException("Indexed Element out of Range");
        }
    }

    /**
     * Returns the item at the end of the sequence.
     */
    public Object last() throws SequenceListException {
        if (listTail != null) {
            return listTail.datum;
        } else {
            throw new SequenceListException("Indexed Element out of Range");
        }
    }

    /**
     * Returns the item at the specified position in the sequence.
     */
    public Object element(int index) throws SequenceListException {
        // Check the index is positive.
        if (index < 0) {
            throw new SequenceListException("Indexed Element out of Range");
        }

        // We need to chain down the list until we reach the indexed
        // position
        Node nodePointer = listHead;
        int i = 0;
        while (i < index) {
            if (nodePointer.next == null) {
                throw new SequenceListException("Indexed Element out of Range");
            } else {
                nodePointer = nodePointer.next;
                i += 1;
            }
        }

        return nodePointer.datum;
    }

    /**
     * Tests whether there are any items in the sequence.
     */
    public boolean empty() {
        return (listHead == null);
    }

    /**
     * Returns the number of items in the sequence.
     */
    public int size() {
        //Chain down the list counting the elements

        Node nodePointer = listHead;
        int size = 0;
        while (nodePointer != null) {
            size += 1;
            nodePointer = nodePointer.next;
        }
        return size;
    }

    /**
     * Empties the sequence.
     */
    public void clear() {
        listHead = null;
        listTail = null;
    }

    public Node lastNode() {
        return listTail;
    }

    public Node firstNode() {
        return listHead;
    }
}

答案 1 :(得分:0)

在双向链表中,每个节点指向下一个节点和前一个节点。 所以它会是这样的。所以我会给你一个提示。您的节点应该有一个Node next和Node previous

 ________        _______
|       |       |      |
|       |------>|      |
|       |<------|      |
|       |       |      |
|_______|       |______|

答案 2 :(得分:0)

您使用对象和Node next构建Node。要将此列为双向链接列表,您还需要存储previous Node

private class DLNode<T> {
    private final T datum;
    private DLNode<T> next;
    private DLNode<T> previous;
    private DLNode(final T datum) { this.datum = datum; }
    // Manipulate next and previous directly instead of setting them in constructors.
}

public DLNode<T> insertAfter(DLNode<T> node, T datum) {
    final DLNode<T> inserted = new DLNode<T>(datum);
    final DLNode<T> currentNext = node.next;
    inserted.next = currentNext;
    inserted.previous = node;
    currentNext.previous = inserted;
    node.next = inserted;
    return inserted;