Creating a LinkedList class from scratch

后端 未结 11 780
慢半拍i
慢半拍i 2020-12-02 06:52

We were given an assignment to create a LinkedList from scratch, and there are absolutely no readings given to guide us on this migrane-causing task. Also everything online

11条回答
  •  无人及你
    2020-12-02 07:00

    How about a fully functional implementation of a non-recursive Linked List?

    I created this for my Algorithms I class as a stepping stone to gain a better understanding before moving onto writing a doubly-linked queue class for an assignment.

    Here's the code:

    import java.util.Iterator;
    import java.util.NoSuchElementException;
    
    public class LinkedList implements Iterable {
        private Node first;
        private Node last;
        private int N;
    
        public LinkedList() {
            first = null;
            last = null;
            N = 0;
        }
    
        public void add(T item) {
            if (item == null) { throw new NullPointerException("The first argument for addLast() is null."); }
            if (!isEmpty()) {
                Node prev = last;
                last = new Node(item, null);
                prev.next = last;
            }
            else {
                last = new Node(item, null);
                first = last;
            }
            N++;
        }
    
        public boolean remove(T item) {
            if (isEmpty()) { throw new IllegalStateException("Cannot remove() from and empty list."); }
            boolean result = false;
            Node prev = first;
            Node curr = first;
            while (curr.next != null || curr == last) {
                if (curr.data.equals(item)) {
                    // remove the last remaining element
                    if (N == 1) { first = null; last = null; }
                    // remove first element
                    else if (curr.equals(first)) { first = first.next; }
                    // remove last element
                    else if (curr.equals(last)) { last = prev; last.next = null; }
                    // remove element
                    else { prev.next = curr.next; }
                    N--;
                    result = true;
                    break;
                }
                prev = curr;
                curr = prev.next;
            }
            return result;
        }
    
        public int size() {
            return N;
        }
    
        public boolean isEmpty() {
            return N == 0;
        }
    
        private class Node {
            private T data;
            private Node next;
    
            public Node(T data, Node next) {
                this.data = data;
                this.next = next;
            }
        }
    
        public Iterator iterator() { return new LinkedListIterator(); }
    
        private class LinkedListIterator implements Iterator {
            private Node current = first;
    
            public T next() {
                if (!hasNext()) { throw new NoSuchElementException(); }
                T item = current.data;
                current = current.next;
                return item;
            }
    
            public boolean hasNext() { return current != null; }
    
            public void remove() { throw new UnsupportedOperationException(); }
        }
    
        @Override public String toString() {
            StringBuilder s = new StringBuilder();
            for (T item : this)
                s.append(item + " ");
            return s.toString();
        }
    
        public static void main(String[] args) {
            LinkedList list = new LinkedList<>();
            while(!StdIn.isEmpty()) {
                String input = StdIn.readString();
                if (input.equals("print")) { StdOut.println(list.toString()); continue; }
                if (input.charAt(0) == ('+')) { list.add(input.substring(1)); continue; }
                if (input.charAt(0) == ('-')) { list.remove(input.substring(1)); continue; }
                break;
            }
        }
    }
    

    Note: It's a pretty basic implementation of a singly-linked-list. The 'T' type is a generic type placeholder. Basically, this linked list should work with any type that inherits from Object. If you use it for primitive types be sure to use the nullable class equivalents (ex 'Integer' for the 'int' type). The 'last' variable isn't really necessary except that it shortens insertions to O(1) time. Removals are slow since they run in O(N) time but it allows you to remove the first occurrence of a value in the list.

    If you want you could also look into implementing:

    • addFirst() - add a new item to the beginning of the LinkedList
    • removeFirst() - remove the first item from the LinkedList
    • removeLast() - remove the last item from the LinkedList
    • addAll() - add a list/array of items to the LinkedList
    • removeAll() - remove a list/array of items from the LinkedList
    • contains() - check to see if the LinkedList contains an item
    • contains() - clear all items in the LinkedList

    Honestly, it only takes a few lines of code to make this a doubly-linked list. The main difference between this and a doubly-linked-list is that the Node instances of a doubly-linked list require an additional reference that points to the previous element in the list.

    The benefit of this over a recursive implementation is that it's faster and you don't have to worry about flooding the stack when you traverse large lists.

    There are 3 commands to test this in the debugger/console:

    • Prefixing a value by a '+' will add it to the list.
    • Prefixing with a '-' will remove the first occurrence from the list.
    • Typing 'print' will print out the list with the values separated by spaces.

    If you have never seen the internals of how one of these works I suggest you step through the following in the debugger:

    • add() - tacks a new node onto the end or initializes the first/last values if the list is empty
    • remove() - walks the list from the start-to-end. If it finds a match it removes that item and connects the broken links between the previous and next links in the chain. Special exceptions are added when there is no previous or next link.
    • toString() - uses the foreach iterator to simply walk the list chain from beginning-to-end.

    While there are better and more efficient approaches for lists like array-lists, understanding how the application traverses via references/pointers is integral to understanding how many higher-level data structures work.

提交回复
热议问题