如果你有许多list,这里将会是大量的时间,我指的是对于单向链表查找时间复杂度O(N)相对于数组O(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));
}
}
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);/*此处原为+1*/
}
}
/** 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];
}
}
C、203
100+101+....+999+1000=495550,大概500000
这张图片展示SLList代表Single-Linked List(单向链表),而ALList代表Array-Backed List(数组支持链表)的区别,即O(N)和O(NlogN)存疑
为了让alist更加通用实现了如下变化
/* Array based list.
@author Josh Hug
*/
// 0 1 2 3 4 5 6 7
//items:[ 6 9 -1 2 0 0 0 0]
//size:5
/*Invariants:
addlast:The next item we want to add,will go into position size
getlast:The item we want to return is in position size -1
size:The number of items in the list should be size.
*/
public class AList<Item> {
private Item[] items;
private int size;
/**
* Creates an empty list.
*/
public AList() {
items = (Item[]) new Object[100];
size = 0;
}
/*Resizes the underlying array to the target capacity.*/
private void resize(int capacity) {
Item[] a = (Item[]) new object[capacity];
System.arraycopy(items, 0, a, 0, size);
items = a;
}
/*Inserts x into the back of the list.*/
public void addLast(Item x) {
if (size == items.length) {
resize(size + 1);
}
items[size] = x;
size = size + 1;
}
/*Returns the item from the back of the List.*/
public Item getlast() {
return items[size - 1];
}
/*Gets the ith item in the list (0 is the front).*/
public Item get(int i) {
return items[i];
}
/*Returns the number of items in the list.*/
public int size() {
return size;
}
/*Deletes item from back of the list and returns deleted item.*/
public Item removeLast() {
Item x = getLast();
items[size - 1] = null;
size = size - 1;
return x;
}
}