本文整理了CS61B中的链表IntList、SLList、DLList、AList实现。

1 IntList

public class IntList {
	public int first;
	public IntList rest;

	public IntList(int f, IntList r) {
		first = f;
		rest = r;
	}

	/** Return the size of the list using... recursion! */
	public int size() {
		if (this.rest == null) {/* base case */
			return 1;
		}
		return 1 + this.rest.size();
	}

	/** Return the size of the list using no recursion! */
	public int iterativeSize() {
		/* You can not assign "this" in Java*/
		IntList p = this;
		int totalSize = 0;
		while (p != null) {
			totalSize += 1;
			p = p.rest;
		}
		return totalSize;
	}

	/** Returns the ith value in this list.*/
	public int get(int i) {
		IntList p = this;
		int nth = 0;
		if (i >= p.size()) {
			return -1;
		}
		while (nth != i) {
			p = p.rest;
			nth += 1;
		}
		return p.first;
	}

	public static void main(String[] args) {
		IntList L = new IntList(15, null);
		L = new IntList(10, L);
		L = new IntList(5, L);
		System.out.println(L.size());
		System.out.println(L.iterativeSize());
		System.out.println(L.get(2));
	}
} 

2 SLList

 /** An SLList is a list of integers, which hides the terrible truth
   * of the nakedness within. */
public class SLList {	
	private static class IntNode {
		public int item;
		public IntNode next;

		public IntNode(int i, IntNode n) {
			item = i;
			next = n;
			System.out.println(size);
		}
	} 

	/* The first item (if it exists) is at sentinel.next. */
	private IntNode sentinel;
	private int size;

	private static void lectureQuestion() {
		SLList L = new SLList();
		IntNode n = IntNode(5, null);
	}

	/** Creates an empty SLList. */
	public SLList() {
		sentinel = new IntNode(63, null);
		size = 0;
	}

	public SLList(int x) {
		sentinel = new IntNode(63, null);
		sentinel.next = new IntNode(x, null);
		size = 1;
	}

 	/** Adds x to the front of the list. */
 	public void addFirst(int x) {
 		sentinel.next = new IntNode(x, sentinel.next);
 		size = size + 1;
 	}

 	/** Returns the first item in the list. */
 	public int getFirst() {
 		return sentinel.next.item;
 	}

 	/** Adds x to the end of the list. */
 	public void addLast(int x) {
 		size = size + 1; 		

 		IntNode p = sentinel;

 		/* Advance p to the end of the list. */
 		while (p.next != null) {
 			p = p.next;
 		}

 		p.next = new IntNode(x, null);
 	}
 	
 	/** Returns the size of the list. */
 	public int size() {
 		return size;
 	}

	public static void main(String[] args) {
 		/* Creates a list of one integer, namely 10 */
 		SLList L = new SLList();
 		L.addLast(20);
 		System.out.println(L.size());
 	}
}

3 DLList(LinkedListDeque链表双边队列)

/**
 * Created by JianjunChen on 08/16/2020
 * This is a Linked List Doubly ended queue Data Structure using Lists!
 * @Rule The amount of memory that your program uses at any given time must be
 * proportional to the number of items.
 * @Rule Do not maintain references to items that are no longer in the deque.
 * @Rule Implement all the methods listed above in “The Deque API” section.
 */


public class LinkedListDeque<T> {
    /**LinkedNode Nested Class*/
    private class LinkedNode {
        private LinkedNode prev; /* Doubly Linked List*/
        private T item;
        private LinkedNode next;

        public LinkedNode(LinkedNode p, T i, LinkedNode n) {
            prev = p;
            item = i;
            next = n;
        }
    }

    private LinkedNode sentinel;
    //private LinkedNode last;
    private int size;

    /** Constructor of LinkedListDeque */
    public LinkedListDeque() {
        sentinel = new LinkedNode(null, null, null);
        sentinel.prev = sentinel;
        sentinel.next = sentinel;
        //last = sentinel;
        size = 0;
    }

    /** Adds an item of type T to the front of the deque.*/
    public void addFirst(T item) {
        LinkedNode first = new LinkedNode(sentinel, item, sentinel.next);
        /* Note that the order cannot be reversed since if we firstly write
         * sentinel.next = first; the sentinel.next.prev will equal to first.prev!!!!*/
        sentinel.next.prev = first;
        sentinel.next = first;
        size += 1;
    }

    /** Adds an item of type T to the back of the deque. */
    public void addLast(T item) {
        LinkedNode last = new LinkedNode(sentinel.prev, item, sentinel);
        /* Note that the order cannot be reversed!!! */
        sentinel.prev.next = last;
        sentinel.prev = last;
        size += 1;
    }

    /** Returns true if deque is empty, false otherwise. */
    public boolean isEmpty() {
        if (sentinel.next == sentinel) {
            return true;
        }
        return false;
    }

    /** Returns the number of items in the deque. */
    public int size() {
        return size;
    }

    /* Prints the items in the deque from first to last, separated by a space. */
    public void printDeque() {
        LinkedNode p = sentinel;
        while (p.next != sentinel) {
            System.out.print(p.next.item + " ");
            p = p.next;
        }
    }

    /** Removes and returns the item at the front of the deque.
    If no such item exists, returns null.*/
    public T removeFirst() {
        if (isEmpty()) {
            return null;
        }

        T firstItem = sentinel.next.item;
        /* Note that the order cannot be reversed!!!*/
        sentinel.next.next.prev = sentinel;
        sentinel.next = sentinel.next.next;

        size -= 1;
        return firstItem;
    }

    /** Removes and returns the item at the back of the deque.
     * If no such item exists, returns null. */
    public T removeLast() {
        if (isEmpty()) {
            return null;
        }

        T lastItem = sentinel.prev.item;
        /* Note that the order cannot be reversed!!! */
        sentinel.prev.prev.next = sentinel;
        sentinel.prev = sentinel.prev.prev;

        size -= 1;
        return lastItem;

    }

    /** Gets the item at the given index, where 0 is the front, 1 is the next item,
    * and so forth. If no such item exists, returns null. Must not alter the deque! */
    public T get(int index) {
        if (index > size - 1) {
            return null;
        }

        LinkedNode p = sentinel.next;
        int i = 0;
        while (i != index) {
            p = p.next;
            i += 1;
        }
        return p.item;
    }

    /** Helper method for getRecursive */
    private T getRecursiveHelper(LinkedNode currentNode, int index) {
        if (index == 0) {
            return currentNode.item;
        }
        return getRecursiveHelper(currentNode.next, index - 1);
    }

    /** Same as get but using recursion!! */
    public T getRecursive(int index) {
        if (index > size - 1) {
            return null;
        }

        return getRecursiveHelper(sentinel.next, index);
    }
}

4 AList(ArrayDeque数组双边队列)

/**
 * Created by JianjunChen on 08/18/2020
 * This is a Array based Doubly Ended Queue Data Structure!!
 * @Rule The starting size of your array should be 8.
 * @Rule Implement all the methods listed above in “The Deque API” section.
 * @Rule The amount of memory that at any given time must be proportional to the number
 * of items. For arrays of length 16 or more, your usage factor should always be at least 25%.
 *
 */


// Circular ArrayDeque
public class ArrayDeque<T> {
    private int initialCapacity = 8; //initial array capacity
    private int capacity;  //current array capacity
    private int eFactor = 2; //expanding factor
    private double usageFactor;
    private int mCapacity = 16; // The minimum capacity for contraction
    private double mRatio = 0.25; //The minimum usage ratio before contraction
    private int cFactor = 2; //contraction factor
    private T[] items;
    private int size;
    private int nextFirst;
    private int nextLast;

    public ArrayDeque() {
        capacity = initialCapacity;
        items = (T[]) new Object[initialCapacity];
        size = 0;
        nextFirst = 4;
        nextLast = 5;
    }

    /** Finding the next nextFirst and nextLast index in circle ArrayDeque. */
    private int oneMinus(int index) {
        if (index == 0) { // whether the index is out of bounds!
            index = capacity - 1;
        } else {
            index -= 1;
        }
        return index;
    }

    private int onePlus(int index) {
        if (index == capacity - 1) { // whether the index is out of bounds!
            index = 0;
        } else {
            index += 1;
        }
        return index;
    }

    /** Resize the original array to a new array with given capacity. */
    private void resize(int newCapacity) {
        T[] a = (T[]) new Object[newCapacity];

        int currentFirst = onePlus(nextFirst);
        int currentLast = oneMinus(nextLast);

        if (currentFirst < currentLast) {
            int length = currentLast - currentFirst + 1;
            System.arraycopy(items, currentFirst, a, 0, length);
            nextFirst = newCapacity - 1;
            nextLast = length;
        } else {
            int firstRightCount = capacity - currentFirst;
            int firstLeftCount = capacity - firstRightCount;
            System.arraycopy(items, currentFirst, a, 0, firstRightCount);
            System.arraycopy(items, 0, a, firstRightCount, firstLeftCount);

            nextFirst = newCapacity - 1;
            nextLast = capacity;
        }

        capacity = newCapacity;
        items = a;

    }

    /** Adds an item of type T to the front of the deque.
     * @Rule Must take constant time, except during resizing operations.
     */
    public void addFirst(T item) {
        items[nextFirst] = item;
        size += 1;
        nextFirst = oneMinus(nextFirst);

        //The array is full, needed resize operation!
        if (size == capacity) {
            resize(size * eFactor);
        }
    }

    /** Adds an item of type T to the back of the deque.
     * @Rule Must take constant time, except during resizing operations.
     */
    public void addLast(T item) {
        items[nextLast] = item;
        size += 1;
        nextLast = onePlus(nextLast);

        //The array is full, needed resize operation!
        if (size == capacity) {
            resize(size * eFactor);
        }
    }

    /** Returns true if deque is empty, false otherwise. */
    public boolean isEmpty() {
        if (size == 0) {
            return true;
        }
        return false;
    }

    /** Returns the number of items in the deque. */
    public int size() {
        return size;
    }

    /** Prints the items in the deque from first to last, separated by a space. */
    public void printDeque() {
        if (isEmpty()) {
            return;
        }
        int index = onePlus(nextFirst);
        while (index != nextLast) {
            System.out.print(items[index] + " ");
            index = onePlus(index);
        }
    }

    private void contract() {
        usageFactor = (double) size / capacity;
        if (usageFactor <= mRatio && capacity >= mCapacity) {
            int newCapacity = capacity / cFactor;
            resize(newCapacity);
        }
    }

    /** Removes and returns the item at the back of the deque. If no such item exists, returns null.
     * @Rule must take constant time, except during resizing operations.
     */
    public T removeFirst() {
        if (isEmpty()) {
            return null;
        }

        int currentFirst = onePlus(nextFirst);
        T currentFirstItem = items[currentFirst];
        nextFirst = currentFirst;
        items[nextFirst] = null;
        size -= 1;

        contract();

        return currentFirstItem;
    }

    /** Removes and returns the item at the back of the deque. If no such item
     * exists, returns null..
     * @Rule must take constant time, except during resizing operations.
     */
    public T removeLast() {
        if (isEmpty()) {
            return null;
        }

        int currentLast = oneMinus(nextLast);
        T currentLastItem = items[currentLast];
        nextLast = currentLast;
        items[nextLast] = null;
        size -= 1;

        return currentLastItem;
    }

    /**
     * Gets the item at the given index, where 0 is the front, 1 is the next item, and so forth.
     * If no such item exists, returns null. Must not alter the deque!
     * @Rule must take constant time.
     */
    public T get(int index) {
        if (index >= size) {
            return null;
        }

        int indexFromFirst = nextFirst + 1 + index;
        if (indexFromFirst >= capacity) {
            indexFromFirst -= capacity;
        }

        return items[indexFromFirst];
    }
}