简体   繁体   English

实现单链表

[英]Implementing Singly Linked List

I am trying to learn data structure, but I ran into the dreaded NullPointerException and I am not sure how to fix it. 我正在尝试学习数据结构,但遇到了令人恐惧的NullPointerException ,但不确定如何解决它。

My SinglyLinkedList<E> class implements an interface, LinkedList , where I redefined some methods like, add(), get(), contains() , and more. 我的SinglyLinkedList<E>类实现了LinkedList接口,我在其中重新定义了一些方法,例如add(), get(), contains()等。

The NullPointerException happens when I use the clear() method. 当我使用clear()方法时,会发生NullPointerException It points at the method removeLast() under nodeBefore.setNext(null) . 它指向nodeBefore.setNext(null)下的removeLast()方法。 It also points to the clear() method under remove(head.getElement()) . 它还指向remove(head.getElement())下的clear()方法。

Also, if there is anything I can improve upon in my code please let me know. 另外,如果我的代码有什么需要改进的地方,请告诉我。

public class SinglyLinkedList<E> implements LinkedList<E> {

    private class Node<E> {

        public Node<E> next;
        public E element;

        public Node(E element) {

            this.element = element;
        }

        public Node (E element, Node<E> next) {

            this.element = element;
            this.next = next;
        }

        public E getElement() {

            return element;
        }

        public Node<E> getNext() {

            return next;
        }

        public void setElement(E element) {

            this.element = element;
        }

        public void setNext(Node<E> next) {

            this.next = next;
        }

        public String toString() {

            return ("[" + element + "] ");
        }
    }

    public Node<E> head;
    public Node<E> tail;
    public int total;      

    public SinglyLinkedList() {

        this.head = null;
        this.tail = null; 
        this.total = 0;
    }

    public E get(int index) {

        if (index < 0 || index > size()) {
            return null;
        }

        if (index == 0) {
            return head.getElement();
        }

        Node<E> singly = head.getNext();

        for (int i = 1; i < index; i ++) {

            if (singly.getNext() == null) {
              return null;
            }       

            singly = singly.getNext();      
        }

        System.out.println("\n" + singly.getElement());

        return singly.getElement(); 
    }

    public void add(E element) {
        Node<E> singlyAdd = new Node<E>(element);

        if (tail == null) {
            head = singlyAdd;
            tail = singlyAdd;
        } else {
            tail.setNext(singlyAdd);
            tail = singlyAdd;
        }     

        total++;
    }             

    public void display() {
        if (head == null) {
            System.out.println("empty list");
        } else {
            Node<E> current = head;
            while (current != null) {
                System.out.print(current.toString());
                current = current.getNext();
            }
        }

    }

    public boolean contains(E data) {

        if (head == null) {
            return false;
        }

        if (head.getElement() == data) {
            System.out.println(head);
            return true;                                
        }

        while (head.getNext() != null) {
            head = head.getNext();

            if (head.getElement() == data) {
                System.out.println(head);                
                return true;                               
            }             

        } 

        return false;         
    }       

    private Node<E> removeFirst() {
        if (head == null) {
            System.out.println("We cant delete an empty list");
        }    

        Node<E> singly = head;            
        head = head.getNext();
        singly.setNext(null);
        total--;

        return singly;     
    } 

    private Node<E> removeLast() {

        Node<E> nodeBefore;
        Node<E> nodeToRemove;     

        if (size() == 0) {
            System.out.println("Empty list");
        }    

        nodeBefore = head;

        for (int i = 0; i < size() - 2; i++) {
          nodeBefore = nodeBefore.getNext();
        }    

        nodeToRemove = tail;    

        nodeBefore.setNext(null);
        tail = nodeBefore;
        total--;

        return nodeToRemove;
    }       

    public E remove(int index) {      

        E hold = get(index);     

        if (index < 0 || index >= size()) {
            return null;
        } else if (index == 0) { 

            removeFirst();    
            return hold;
        } else {

            Node<E> current = head;
            for (int i = 1; i < index; i++) {                
                current = current.getNext();
            }  

            current.setNext(current.getNext().getNext());
            total--; 
            return hold;
        }       
    }       

    public int size() {
        return getTotal();
    }

    public boolean remove(E data) {      

        Node<E> nodeBefore, currentNode; 

        if (size() == 0) {
            System.out.println("Empty list");
        }            

        currentNode = head;

        if (currentNode.getElement() == data) {
            removeFirst();
        }

        currentNode = tail;
        if (currentNode.getElement() == data) {
            removeLast();
        }

        if (size() - 2 > 0) {
            nodeBefore = head;
            currentNode = head.getNext();
            for (int i = 0; i < size() - 2; i++) {
                if (currentNode.getElement() == data) {

                    nodeBefore.setNext(currentNode.getNext());
                    total--;
                    break;
                }

                nodeBefore = currentNode;
                currentNode = currentNode.getNext();
            } 
        } 

        return true;
    }

    public void clear() {

        while (head.getNext() != null) {    
            remove(head.getElement());    
        }

        remove(head.getElement());    
    }

    private int getTotal() {
        return total;
    } 
}

For your clear method, I don't see that you do any per element cleanup, and the return type is void , so all you want is an empty list. 对于您的clear方法,我没有看到您对每个元素进行任何清理,并且返回类型为void ,因此您只需要一个空列表。 The easiest way is to simply clear everything, like in the constructor: 最简单的方法是简单地清除所有内容,例如在构造函数中:

public void clear() {
    this.head = null;
    this.tail = null; 
    this.total = 0;
}

Another comment: 另一条评论:

in contains , you do contains ,您可以

while (head.getNext() != null) {
        head = head.getNext();

        if (head.getElement() == data) {
            System.out.println(head);                
            return true;                               
        }             
    } 

which may have two problems (where the first applies to the entire class), 这可能有两个问题(第一个问题适用于整个班级),

  1. you compare with == data which compares references, where you probably want to compare values with .equals(data) 您将其与== data进行比较,该== data将比较引用,您可能希望在其中将值与.equals(data)进行比较

Edit: Ie n.getElement().equals(data) instead of n.getElement() == data . 编辑:n.getElement().equals(data)而不是n.getElement() == data

(Or, if n and data may be null , something like (data != null ? data.equals(n.getElement()) : data == n.getElement()) (或者,如果ndata可能为null ,则类似(data != null ? data.equals(n.getElement()) : data == n.getElement())

  1. you use the attribute head as the scan variable which modifies the state of the list. 您可以使用属性head作为扫描变量,以修改列表的状态。 Do you really want that? 你真的想要那个吗?

The problem arises when you delete the last element within clear : remove(head.getElement()); 当您删除clear的最后一个元素时,就会出现问题: remove(head.getElement()); . For some reason, you first remove the head and then the tail . 由于某种原因,您首先要移开head ,然后移去tail But when calling removeLast , you use the head (which is already null ). 但是,当调用removeLast ,您使用的是head (已经为null )。 Within removeLast this is the line, which causes the NullPointerException : nodeBefore.setNext(null); removeLast这行代码会导致NullPointerExceptionnodeBefore.setNext(null); . My advice would be to write the clear() method as @bali182 has suggested: 我的建议是按照@ bali182的建议编写clear()方法:

public void clear() {
    this.head = null;
    this.tail = head;
    this.total = 0;
}

One advice: if you are writing methods to search or delete entries, you should never use == when dealing with objects (or even better: don't use == at all when dealing with objects). 一条建议:如果您正在编写搜索或删除条目的方法,则在处理对象时永远不要使用== (甚至更好:在处理对象时根本不要使用== )。 You may want to read this thread . 您可能需要阅读此主题

From within clear method, you are calling remove(head.getElement()); 从clear方法中,您正在调用remove(head.getElement()); meaning you are trying to call LinkedList's remove method. 表示您正在尝试调用LinkedList的remove方法。 And since you are overriding each functionality and so is add, you don't maintain internal state of LinkedList and hence you get exception. 而且由于覆盖了每个功能,添加也是如此,因此您不维护LinkedList的内部状态,因此会出现异常。 Code in remove is: 删除中的代码是:

    public boolean remove(Object o) {
    if (o==null) {
        for (Entry<E> e = header.next; e != header; e = e.next) {
            if (e.element==null) {

So here since you are not using functionality of LinkedList, header would be null and doing header.next would return NullPointerException. 所以在这里,因为您没有使用LinkedList的功能,所以header将为null,并且执行header.next将返回NullPointerException。

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

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