CS61B srping 2018 proj1A-Data Structures https://sp18.datastructur.es/ 有关于Sentinel Node的介绍

参考答案
或者

ArrayDeque的核心是 用数组存储首尾相接的“数据圆环”,ArrayDeque的first 和last 指向实际存储数据的 最开始一个和最后一个,如何向数组加入/去除数据并能保证首尾相接是关键,
比如有索引0~99 共100个元素,
假设 初始索引是 0 ,此时addFirst,就要“向左”添加下一个元素x,下一个元素的x的索引是0-1 ==> -1 ,但-1不能作为数组索引,所以对-1做一个偏移, -1+length =>99;形成了数据回环。
类似的,
假设 初始索引是 99 ,此时addLast,就要“向右”添加下一个元素x,下一个元素的x的索引是99+1 ==> 100 ,但100不能作为(该)数组索引,所以对100做一个偏移, 100-length =>0;形成了数据回环。

提示:不用取模/取余也就是"%"运算也可以,证据
具体实现参见上面的参考答案等。

proj1A 数据结构

skeleton地址
开始这个proj之前,至少应该对SLList, DLList,AList有所了解

介绍

在proj1A里要用 list和Array 来创建“Double Ended Queue” ,在接下来的proj1B里要对应编写测试。LinkedListDeque.java and ArrayDeque.java是这个proj里边要操作的文件, 推荐使用intelliJ。

找到课程提供的skeleton

找到proj1a的文件夹(反正找到就行,按照课程网页介绍可不一定能找到emmmm),里边应该有个LinkedListDequeTest.java文件,应该像这个样子:示范/或者说没找到哦在这里能找到
LinkedListDequeTest.java文件 中包含了一些测试示范,你可以仿照编写来测试你的程序。 这里貌似没有JUnit的使用痕迹。
课程提供的LinkedListDequeTest.java文件仅仅包含了课程认为必要的测试内容,请根据其内容至少编写两条测试。
否则会出现测试没有覆盖所有 API的情况。

The Deque API /Deque的API介绍

Deque非常像 课程视频里介绍的SLList and AList ,这有一个cpp(网站上)版本的介绍

emmm,如果你忘记了SLList和AList,可以去看看这里
Deque就是 Double-ended queues的缩写,可长可短,动态变化,可以在首/尾增加或减少元素,Deque普遍包含下列的API:

  • public void addFirst(T item): Adds an item of type T to the front of the deque.
  • public void addLast(T item): Adds an item of type T to the back of the deque.
  • public boolean isEmpty(): Returns true if deque is empty, false otherwise.
  • public int size(): Returns the number of items in the deque.
  • public void printDeque(): Prints the items in the deque from first to last, separated by a space.
  • public T removeFirst(): Removes and returns the item at the front of the deque. If no such item exists, returns null.
  • public T removeLast(): Removes and returns the item at the back of the deque. If no such item exists, returns null.
  • public T get(int index): 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!

要编写泛型而不是固定某个类型的Deque,如何编写可以看这里:cs61B lecture5
看这个视频也行:cs61B 第6?5节视频

对于泛型类vs sentinel的具体处理 ,可以看这个博文:CS61B資料結構及演算法筆記:(二)單向串列及雙向串列

开始任务

1. Linked List Deque /链表Deque

注意课程第4-5节(5-6?)已经包含了所有完成本项目的内容。
先在项目文件夹中创建LinkedListDeque.java文件,随后编写一个以链表作为存储载体的Deque,具体要求如下:

  • add and remove operations must not involve any looping or recursion. A single such operation must take “constant time”, i.e. execution time should not depend on the size of the deque.
  • get must use iteration, not recursion.
  • size must take constant time.
  • 使用内存数量和Deque实际存储数据的数量应该差不多,比如你加了10000个元素,又减了9999个,那使用内存数量应该是更趋向于1而不是10000,而且注意不允许“已经被删除的”对象在内存里常驻,做好对“已经被删除的”对象的引用管理。
  • 要完成前文已经提到的api,并还要完成下面两个:
  • public LinkedListDeque(): Creates an empty linked list deque.
  • public T getRecursive(int index): Same as get, but uses recursion.
  • 可以增加private(helper)方法或者private类

可以参考课程上关于doubly linked lists的内容,可以参考关于sentinel node的内容,推荐用circular sentinel,下面是参考的ppt:
two sentinel topology,Double sentinel
and circular sentinel topology.

You are not allowed to use Java’s built in LinkedList data structure (or any data structure from java.util.*) in your implementation.
不让用Java自带的链表什么的类似数据结构

下方是作为参考的程序,不一定对,emmmmm。

SLList
public class SLList<ItemType>  {


    private static class ItemNode<ItemType> {
        public ItemType item ;
        public ItemNode next;
        public ItemNode(ItemType f, ItemNode n){
            item=f;
            next=n;
        }
    }
    public int size;
    private ItemNode<ItemType> sentinel ;
    public SLList(){
        sentinel = new ItemNode<ItemType>(null,null);
    }
    public SLList(ItemType item){

        sentinel = new ItemNode<ItemType>(null,null);
        sentinel.next=new ItemNode(item,null);
        size+=1;
}
    public void addFirst(ItemType item){
        size+=1;
        sentinel.next=new ItemNode<>(item,sentinel.next);

}
    public void addLast(ItemType item){
        size+=1;


        ItemNode<ItemType> tmpPtr= sentinel.next;
        while(tmpPtr.next!=null){
            tmpPtr=tmpPtr.next;

        }
        tmpPtr.next=new ItemNode(item,null);
    }

    public static void main(String[] args) {

        SLList<Integer> list = new SLList(5);
        list.addFirst(4);
        list.addFirst(3);
        list.addFirst(2);
        list.addLast(6);
        list.addFirst(1);
        list.addLast(7);


    }
}




DLList 此处观看sentinel的规避办法 (让sentinel和其他节点明显不一样,防止被篡改,虽然没啥必要)
```plaintext
public class DLList<ItemType> {
// Doubly linked list 每个 node上需要有双向的“通道”
//   建议使用一个sentinel 规避 last可能指向sentinel 也可能指向正常节点的情况。

    private static class ItemNode<ItemType> {
        public ItemType item;
        public ItemNode next;
        public ItemNode prev;

        public ItemNode(ItemNode p, ItemType i, ItemNode n) {
            prev = p;
            item = i;
            next = n;
        }
    }
/**
 * 为了让sentinel 更加明显,且不会被轻易修改
 */

    private static class SentinelNode<ItemType,T2> extends ItemNode {
        public final ItemType item;
        public ItemNode<T2> next;
        public ItemNode<T2> prev;

        public SentinelNode(ItemNode p, ItemType i, ItemNode n) {
            super(p,i,n);
            prev = p;
            item = i;
            next = n;

        }
    }

    public int size;
    private SentinelNode<String,ItemType> sentinel;

    public DLList() {
//initialization sentinel
        sentinel = new SentinelNode<String,ItemType>(null, "this is sentinel,don't change its value", null);
        sentinel.prev = sentinel;
        sentinel.next = sentinel;

    }

    public DLList(ItemType item) {
//initialization sentinel
        sentinel = new SentinelNode<String,ItemType>(null, "this is sentinel,don't change its value", null);
        sentinel.prev = sentinel;
        sentinel.next = sentinel;
        ItemNode<ItemType> newNode = new ItemNode(null, item, null);
        sentinel.next = newNode;
        newNode.next=sentinel;
        sentinel.prev=newNode;
        newNode.prev=sentinel;

        size += 1;
    }

    public void addFirst(ItemType item) {

        ItemNode<ItemType> newNode = new ItemNode<>(null,item, null);
        if(size==0){
            sentinel.next=newNode;
            sentinel.prev=newNode;
            newNode.prev=sentinel;
            newNode.next=sentinel;
        }
        else {
            ItemNode oldFirstNode= sentinel.next;
            newNode.next=oldFirstNode;
            newNode.prev=sentinel;
            sentinel.next=newNode;
            oldFirstNode.prev=newNode;

        }
        size += 1;
    }

    public void addLast(ItemType item) {
        ItemNode<ItemType> newNode = new ItemNode<>(null,item, null);

       if(size==0){
           sentinel.next=newNode;
           sentinel.prev=newNode;
           newNode.prev=sentinel;
           newNode.next=sentinel;
       }
       else {
           ItemNode oldLastNode= sentinel.prev;
           newNode.next=sentinel;
           newNode.prev=oldLastNode;
           sentinel.prev=newNode;
           oldLastNode.next=newNode;

       }
        size += 1;

    }

    public static void main(String[] args) {
        DLList list = new DLList(5);
        list.addFirst(4);
        list.addFirst(3);
        list.addFirst(2);
        list.addLast(6);
        list.addFirst(1);
        list.addLast(7);


    }
}




##### LinkedListDeque
```plaintext
public class LinkedListDeque<ItemType> {

   private static class ItemNode<ItemType> {
        public ItemType item;
        public ItemNode next;
        public ItemNode prev;

        public ItemNode(ItemNode p, ItemType i, ItemNode n) {
            prev = p;
            item = i;
            next = n;
        }
    }
/**
 * 为了让sentinel 更加明显,且不会被轻易修改
 */

    private static class SentinelNode<ItemType> extends ItemNode {
        public final ItemType item;
        public ItemNode next;
        public ItemNode prev;

        public SentinelNode(ItemNode p, ItemType i, ItemNode n) {
            super(p,i,n);
            prev = p;
            item = i;
            next = n;

        }
    }
    private int size;
    public SentinelNode<String> sentinel;
    public LinkedListDeque(){
        // in this situation ,size is 0,because ,it's empty.
        sentinel = new SentinelNode<String>(null,"this is a sentinel ,don't mess with it",null);
        sentinel.prev=sentinel;
        sentinel.next=sentinel;
    }

    public LinkedListDeque(ItemType item){
        // in this situation ,size is 1 ,because during the initialization ,an item is added into the list.
        sentinel = new SentinelNode<String>(null,"this is a sentinel ,don't mess with it",null);
        ItemNode<ItemType> newNode= new ItemNode<>(null,item,null);
        sentinel.prev=newNode;
        sentinel.next=newNode;
        size+=1;
    }


    public void addFirst(ItemType item){
//        初始化一个Node,随后插入到要插入的位置
        ItemNode<ItemType> newNode= new ItemNode<>(null,item,null);
//        如果是空列表
    if(size==0){

        sentinel.next=newNode;
        sentinel.prev=newNode;
        newNode.prev=sentinel;
        newNode.next=sentinel;
    }
//    如果不是空列表
    else{
        ItemNode<ItemType> oldFirstNode = sentinel.next;
        sentinel.next=newNode;
        newNode.prev=sentinel;
        newNode.next=oldFirstNode;
        oldFirstNode.prev=newNode;
    }
        size+=1;
    }


    public void addLast(ItemType item){
        //        初始化一个Node,随后插入到要插入的位置
        ItemNode<ItemType> newNode= new ItemNode<>(null,item,null);
//        如果是空列表
        if(size==0){
            sentinel.next=newNode;
            sentinel.prev=newNode;
            newNode.prev=sentinel;
            newNode.next=sentinel;
        }
//        如果不是空列表
        else{
            ItemNode<ItemType> oldLastNode = sentinel.prev;
            sentinel.prev=newNode;
            newNode.next=sentinel;
            newNode.prev=oldLastNode;
            oldLastNode.next=newNode;
        }
        size+=1;
    }
    public boolean isEmpty(){
        return size==0;
    }
    public int size(){
        return size;
    }

    public String printDeque(){
        String resultStr="";
        if(size==0){
            System.out.println("");
            return  resultStr;
        }
        else{
            ItemNode tmpPtr= sentinel.next;
            while(tmpPtr.next!=null){
                System.out.print(tmpPtr.item+" ");
                resultStr+=tmpPtr.item+" ";
                tmpPtr=tmpPtr.next;
                if(tmpPtr.next==null){
                    System.out.println();
                }
            }
        }
        return resultStr;
    }
//    不准有 loitering ,no 废弃对象不被处理
public ItemType removeFirst(){
        if(size==0){
            return null;
        }

    ItemNode<ItemType> oldFirstNode = sentinel.next;
    sentinel.next=oldFirstNode.next;
    oldFirstNode.next.prev=sentinel;
    oldFirstNode.prev=null;
    oldFirstNode.next=null;
    size-=1;
    return oldFirstNode.item;
}

    public ItemType removeLast(){
        if(size==0){
            return null;
        }
        ItemNode<ItemType> oldLastNode = sentinel.prev;
        sentinel.prev=oldLastNode.prev;
        oldLastNode.prev.next=sentinel;
        oldLastNode.prev=null;
        oldLastNode.next=null;
        size-=1;
        return oldLastNode.item;
    }

    public ItemType get(int index){
        if(index>size-1||index<0){
            return null;
        }
        ItemNode<ItemType> tmpPtr =sentinel.next;
        while(index!=0){
            index-=1;
            tmpPtr=tmpPtr.next;
        }
        return tmpPtr.item;
    }
    public ItemType getRecursive(int index){
        if(index>size-1||index<0){
            return null;
        }
        ItemNode<ItemType> tmpPtr =sentinel.next;
        if(index==0){
            return tmpPtr.item;
        }
        else {
            return gRHelper(tmpPtr.next,index-1);
        }
    }
    private ItemType gRHelper(ItemNode ptr,int idx){
        ItemNode<ItemType> tmpPtr =ptr;
        if(idx==0){
            return tmpPtr.item;
        }
        return gRHelper(ptr.next,idx-1);
    }
    public static void main(String[] args) {

    }
}


LinkedListDequeTest
/** Performs some basic linked list tests. */
public class LinkedListDequeTest {

	/* Utility method for printing out empty checks. */
	public static boolean checkEmpty(boolean expected, boolean actual) {
		if (expected != actual) {
			System.out.println("isEmpty() returned " + actual + ", but expected: " + expected);
			return false;
		}
		return true;
	}

	/* Utility method for printing out empty checks. */
	public static boolean checkSize(int expected, int actual) {
		if (expected != actual) {
			System.out.println("size() returned " + actual + ", but expected: " + expected);
			return false;
		}
		return true;
	}

	/* Prints a nice message based on whether a test passed.
	 * The \n means newline. */
	public static void printTestStatus(boolean passed) {
		if (passed) {
			System.out.println("Test passed!\n");
		} else {
			System.out.println("Test failed!\n");
		}
	}

	/** Adds a few things to the list, checking isEmpty() and size() are correct,
	  * finally printing the results.
	  *
	  * && is the "and" operation. */
	public static void addIsEmptySizeTest() {
		System.out.println("Running add/isEmpty/Size test.");
//		System.out.println("Make sure to uncomment the lines below (and delete this print statement).");

		LinkedListDeque<String> lld1 = new LinkedListDeque<String>();

		boolean passed = checkEmpty(true, lld1.isEmpty());

		lld1.addFirst("front");

		// The && operator is the same as "and" in Python.
		// It's a binary operator that returns true if both arguments true, and false otherwise.
		passed = checkSize(1, lld1.size()) && passed;
		passed = checkEmpty(false, lld1.isEmpty()) && passed;

		lld1.addLast("middle");
		passed = checkSize(2, lld1.size()) && passed;

		lld1.addLast("back");
		passed = checkSize(3, lld1.size()) && passed;

		System.out.println("Printing out deque: ");
		lld1.printDeque();

		printTestStatus(passed);

	}


	/** Adds an item, then removes an item, and ensures that dll is empty afterwards. */
	public static void addRemoveTest() {

		System.out.println("Running add/remove test.");

//		System.out.println("Make sure to uncomment the lines below (and delete this print statement).");

		LinkedListDeque<Integer> lld1 = new LinkedListDeque<Integer>();
		// should be empty
		boolean passed = checkEmpty(true, lld1.isEmpty());

		lld1.addFirst(10);
		// should not be empty
		passed = checkEmpty(false, lld1.isEmpty()) && passed;

		lld1.removeFirst();
		// should be empty
		passed = checkEmpty(true, lld1.isEmpty()) && passed;


		printTestStatus(passed);

	}
    /*
    * check add and remove function
    *
    * */
    public static void addRemoveTest2(){

        LinkedListDeque<Integer> lld1 = new LinkedListDeque<Integer>();
        // should be empty
        boolean passed = checkEmpty(true, lld1.isEmpty());

        lld1.addFirst(5);
        lld1.addFirst(4);
        lld1.addLast(3);
        lld1.addFirst(6);
        lld1.addLast(2);
        lld1.addFirst(7);
        lld1.addLast(1);
        // 7 6 5 4 3 2 1
        passed=checkEmpty(false, lld1.isEmpty())&&passed;
        printTestStatus(passed);
        lld1.removeFirst();
        lld1.removeLast();
        lld1.removeLast();
        lld1.removeFirst();
        String expectedRemainList = "453";

        System.out.println("result should be "+expectedRemainList);

        System.out.print("and actual is");
        String actualResult =lld1.printDeque().replaceAll("\\s+", "");
        passed= expectedRemainList.equals(actualResult);
        System.out.println();

        printTestStatus(passed);
    }
    public static void getTest(){
        LinkedListDeque<Integer> lld1 = new LinkedListDeque<Integer>();
        System.out.println("Running get test.");

        lld1.addFirst(4);
        lld1.addFirst(5);
        lld1.addLast(3);
        lld1.addFirst(6);
        lld1.addLast(2);
        lld1.addLast(0);
        lld1.removeLast();
        lld1.addFirst(7);
        lld1.addLast(1);
        System.out.println("Printing out deque: ");

        System.out.println("should be: \n7 6 5 4 3 2 1\nand actual is:");
        lld1.printDeque();
        // should be 1
        System.out.println("the last item is this method get is "+lld1.get(6));
        boolean passed = lld1.get(6)==1;
        printTestStatus(passed);
    }
    public static void getReTest(){
        LinkedListDeque<Integer> lld1 = new LinkedListDeque<Integer>();
        System.out.println("Running getRecursive test.");

        lld1.addFirst(4);
        lld1.addFirst(5);
        lld1.addLast(3);
        lld1.addFirst(6);
        lld1.addLast(2);
        lld1.addLast(0);
        lld1.removeLast();
        lld1.addFirst(7);
        lld1.addLast(1);
        System.out.println("Printing out deque: ");

        System.out.println("should be: \n7 6 5 4 3 2 1\nand actual is:");
        lld1.printDeque();
        // should be 1
        System.out.println("the last item this method get is "+lld1.getRecursive(6));
        boolean passed = lld1.getRecursive(6)==1;
        printTestStatus(passed);
    }

	public static void main(String[] args) {
		System.out.println("Running tests.\n");
//		addIsEmptySizeTest();
//		addRemoveTest();
//        addRemoveTest2();
//        getTest();
        getReTest();
	}
}

2. Array Deque 数组作为存储载体的 Deque

在project directory 创建ArrayDeque.java, ArrayDeque 类要使用数组作为核心存储数据结构(就是用array存元素,没办法,我的翻译水平无力,但是懂得自然懂,懂linkedList的人都知道这里面门道有多深!)

  • add and remove must take constant time, except during resizing operations.add remove也要消耗恒定时间,除了 resize操作的时候
  • get and size must take constant time. get 和size方法应该消耗恒定时间(那肯定就是特别短的意思)
  • The starting size of your array should be 8. 初始数组长度是8
  • 内存使用应该和元素数量相匹配,(load factor啊,就是实际元素个数/数组总长度)占用率不应低于25%,

包含下列API(就是上面)有过的

  • public void addFirst(T item): Adds an item of type T to the front of the deque.
  • public void addLast(T item): Adds an item of type T to the back of the deque.
  • public boolean isEmpty(): Returns true if deque is empty, false otherwise.
  • public int size(): Returns the number of items in the deque.
  • public void printDeque(): Prints the items in the deque from first to last, separated by a space.
  • public T removeFirst(): Removes and returns the item at the front of the deque. If no such item exists, returns null.
  • public T removeLast(): Removes and returns the item at the back of the deque. If no such item exists, returns null.
  • public T get(int index): 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 ArrayDeque():Creates an empty array deque.

课程墙裂建议使用circular 的解决方案,据说会避免很多special coner cases,resize操作可能很麻烦,要自己好好思考。
在开始ArrayDeque之前,类似的,可以参考AList, 在lectureCode中可以找到AList,如下:

AList 课程原版
/** Array based list.
 *  @author Josh Hug
 */

public class AList {
    /** Creates an empty list. */
    public AList() {
    }

    /** Inserts X into the back of the list. */
    public void addLast(int x) {
    }

    /** Returns the item from the back of the list. */
    public int getLast() {
        return 0;        
    }
    /** Gets the ith item in the list (0 is the front). */
    public int get(int i) {
        return 0;        
    }

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

    /** Deletes item from back of the list and
      * returns deleted item. */
    public int removeLast() {
        return 0;
    }
} 
AList 课程原版实现

implementation:

/** 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;
    }
} 

AList课程原版 test:
import org.junit.Test;
import static org.junit.Assert.*;

/** Tests the AList class.
 *  @author Josh Hug
 */

public class AListTest {
    @Test
    public void testEmptySize() {
        AList L = new AList();
        assertEquals(0, L.size());
    }

    @Test
    public void testAddAndSize() {
        AList L = new AList();
        L.addLast(99);
        L.addLast(99);
        assertEquals(2, L.size());
    }

    
    @Test
    public void testAddAndGetLast() {
        AList L = new AList();
        L.addLast(99);
        assertEquals(99, L.getLast());        
        L.addLast(36);
        assertEquals(36, L.getLast());        
    }

    
    @Test
    public void testGet() {
        AList L = new AList();
        L.addLast(99);
        assertEquals(99, L.get(0));        
        L.addLast(36);
        assertEquals(99, L.get(0));        
        assertEquals(36, L.get(1));        
    }


    @Test
    public void testRemove() {
        AList L = new AList();
        L.addLast(99);
        assertEquals(99, L.get(0));        
        L.addLast(36);
        assertEquals(99, L.get(0));
        L.removeLast(); 
        assertEquals(99, L.getLast());
        L.addLast(100);
        assertEquals(100, L.getLast());
        assertEquals(2, L.size());
    }

    /** Tests insertion of a large number of items.*/
    @Test
    public void testMegaInsert() {
        AList L = new AList();
        int N = 1000000;
        for (int i = 0; i < N; i += 1) {
            L.addLast(i);
        }

        for (int i = 0; i < N; i += 1) {
            L.addLast(L.get(i));
        }
    }

    public static void main(String[] args) {
        jh61b.junit.TestRunner.runTests("all", AListTest.class);
    }
} 
AList speedTest

可以用 time命令来测试程序运行时间。
(是 javac *.class ,然后在 java SpeedTest ,或者使用idea,直接在out/production 类似的文件夹里java SpeedTest

    public static void main(String[] args) {
        AList L = new AList();
        int N = 1000000000;
        for (int i = 0; i < N; i += 1) {
            L.addLast(i);
        }

        for (int i = 0; i < N; i += 1) {
            L.addLast(L.get(i));
        }
    }
}

下面是 自己写的,可以比对上面看看区别。

AList非课程原版实现,无法保甜
/** Array based list.
 *  @author Josh Hug
 */

public class AList {
   private  int[] items;
   private int size ;
//index   0 1 2 3 4 5 6
// items [0 0 0 0 0 0 0]
// size   1 2 3 4 5 6 7
    /** Creates an empty list. */
    public AList() {
        size=0;
        items = new int[8];

    }

    private   int[] createNewArray(int currentLength){
        int[] newArray = new int[currentLength*2];
        System.arraycopy(items,0,newArray,0,size);
        return newArray;
    }
    /** Inserts X into the back of the list. */
    public void addLast(int x) {
        int length = items.length;
        if(size==length){

            int[] newArray= createNewArray(size);
            newArray[size]=x;
            items=newArray;
            size+=1;
            return;
        }


        items[size]=x;
        size+=1;
    }

    /** Returns the item from the back of the list. */
    public int getLast() {
        return items[size-1];
    }
    /** Gets the ith item in the list (0 is the front). */
    public int 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 int removeLast() {
        int length = items.length;
        if(size/length<=0.25){
            int newArrLength = length/2;
            if(newArrLength<16){
                newArrLength= 16;
            }

            int[] newArray = new int[newArrLength];
            System.arraycopy(items,0,newArray,0,length);
            int oldLastItem =newArray[size-1];
            newArray[size-1]=0;
            size-=1;
            items=newArray;
            return oldLastItem;
        }

        int x = getLast();
        items[size-1]=0;
        size-=1;
        return x;
    }
} 
AList测试,不保甜版本

AListTest

import org.junit.Test;
import static org.junit.Assert.*;

/** Tests the AList class.
 *  @author Josh Hug
 */

public class AListTest {
    @Test
    public void testEmptySize() {
        AList L = new AList();
        assertEquals(0, L.size());
    }

    @Test
    public void testAddAndSize() {
        AList L = new AList();
        L.addLast(99);
        L.addLast(99);
        assertEquals(2, L.size());
    }

    
    @Test
    public void testAddAndGetLast() {
        AList L = new AList();
        L.addLast(99);
        assertEquals(99, L.getLast());        
        L.addLast(36);
        assertEquals(36, L.getLast());        
    }

    
    @Test
    public void testGet() {
        AList L = new AList();
        L.addLast(99);
        assertEquals(99, L.get(0));        
        L.addLast(36);
        assertEquals(99, L.get(0));        
        assertEquals(36, L.get(1));        
    }


    @Test
    public void testRemove() {
        AList L = new AList();
        L.addLast(99);
        assertEquals(99, L.get(0));        
        L.addLast(36);
        assertEquals(99, L.get(0));
        L.removeLast(); 
        assertEquals(99, L.getLast());
        L.addLast(100);
        assertEquals(100, L.getLast());
        assertEquals(2, L.size());
    }

    /** Tests insertion of a large number of items.*/
    @Test
    public void testMegaInsert() {
        AList L = new AList();
        int N = 1000000;
        for (int i = 0; i < N; i += 1) {
            L.addLast(i);
        }

        for (int i = 0; i < N; i += 1) {
            L.addLast(L.get(i));
        }
    }

    public static void main(String[] args) {
        jh61b.junit.TestRunner.runTests("all", AListTest.class);
    }
} 
ArrayDeque 不保甜 版本
public class ArrayDeque<ItemType> {
   private int size;
   private  ItemType[] items;
// array   [0 0 0 0 0 0 0 0]
// index   [0 1 2 3 4 5 6 7]
// size    [1 2 3 4 5 6 7 8]
// length  [1 2 3 4 5 6 7 8]

    public ArrayDeque(){
        items=(ItemType[] ) new Object[8];
        size-=0;

    }
    private void resize(int oldLength){
        ItemType[] newArray =(ItemType[] ) new Object[oldLength*2];
        System.arraycopy(items,0,newArray,0,oldLength);
        items=newArray;
    }
//    在有限条件下(可以确定总元素个数不大于数组总长度。(
//    也就是向后移动元素后,元素顺序不变,元素没有移动位置,元素个数没有少,
//    这个操作的关键思路是,从最后一个(如果设置为空)索引,从后往前替换。
    private  void MoveArrayItemBackward() {

        for (int i = items.length - 1; i >0; i--) {
            items[i] = items[i - 1]; // 向后移动元素
//            注意 原始的第 items[0] 没变化
        }

    }
//    类似操作,把元素向前移动。
//    这里也要保证 第一个元素为空,数组总长足够。
    private  void moveArrayItemsForward() {

        for (int i = 0; i <items.length-1; i++) {

            items[i] = items[i + 1]; // 向前移动元素

        }
        items[items.length-1]=null;


    }
//    addFirst 就是把所有元素后移,在空出来的第一个位置加一个
    public void addFirst(ItemType item){
        if(size== items.length){
            resize(items.length);
        }
        if(size==0){
            items[0]=item;
            size+=1;
            return;
        }
        else{
//            这里可以确定 增加一个元素后的元素总个数也没有超过数组总长,因为最开始做了  size和items.length的检查
            MoveArrayItemBackward();
            items[0]=item;
            size+=1;
            return;
        }

    }

    public int size(){
        return size;
    }
    public void addLast(ItemType item){
        if(size== items.length){
            resize(items.length);
        }
        items[size]=item;
        size+=1;
    }
    public boolean isEmpty(){
        return size==0;
    }
    public void printDeque(){
        for(int i =0;i<size;i++){
            System.out.print(items[i]+" ");
        }
    }
    public ItemType removeFirst(){
        int currentLength = items.length;
        double compareResult = (double)size/currentLength;
        if(compareResult<0.25){
            resize((int)Math.floor(items.length/4));
        }

        ItemType FirstItem = items[0];
        items[0]=null;
        moveArrayItemsForward();
        size-=1;
        return FirstItem;
    }

    public ItemType removeLast(){
        int currentLength = items.length;
        double compareResult = (double)size/currentLength;
        if(compareResult<0.25){
            resize((int)Math.floor(items.length/4));
        }
        ItemType lastItem = items[size-1];
        items[size-1]=null;
        size-=1;
        return lastItem;
    }
    public ItemType get(int index){
        if(index<0||index>size-1){
            return null;
        }
        return items[index];
    }
    public static void main(String[] args) {

    }
}
ArrayDequeTest 不保甜 版本
import org.junit.Test;

import static org.junit.Assert.*;

public class ArrayDequeTest {
    @Test
    public void testEmptySize() {
        ArrayDeque L = new ArrayDeque<Integer>();
        assertEquals(0, L.size());

    }

    @Test
    public void testAddFirst() {
        ArrayDeque L = new ArrayDeque<Integer>();
        for (int i = 10; i > 0; i--) {
            L.addFirst(i);
        }
        L.addFirst(0);
        assertEquals(11, L.size());
    }

    @Test
    public void testIsEmpty() {
        ArrayDeque L = new ArrayDeque<Integer>();
        assertTrue(L.isEmpty());
        L.addFirst(1);
        assertFalse(L.isEmpty());
    }

    @Test
    public void testPrintDeque() {
        ArrayDeque L = new ArrayDeque<Integer>();
        System.out.println("testing PrintDeque,\nexpected should be:\n1 2 3 4 5 6 7 8 9 10");
        for (int i = 10; i > 0; i--) {
            L.addFirst(i);

        }
        System.out.println("actual is :");
        L.printDeque();
    }

    @Test
    public void testRemoveFirst() {
        ArrayDeque L = new ArrayDeque<Integer>();

        for (int i = 10; i > 0; i--) {
            L.addFirst(i);

        }
        System.out.println("testing RemoveFirst,\nexpected should be:\n1 2 3 4 " +
                "5 6 7 8 9 10,the first item will disappear in turn");
        for (int i = 0; i < 10; i++) {

            L.removeFirst();
            L.printDeque();
            System.out.println();
        }

    }
    @Test
    public void testRemoveLast() {
        ArrayDeque L = new ArrayDeque<Integer>();

        for (int i = 10; i > 0; i--) {
            L.addFirst(i);

        }
        System.out.println("testing RemoveFirst,\noriginal list is:\n1 2 3 4 " +
                "5 6 7 8 9 10,the last item will disappear in turn");
        for (int i = 0; i < 10; i++) {

            L.removeLast();
            L.printDeque();
            System.out.println();
        }

    }
    @Test
    public void testGet() {
        ArrayDeque L = new ArrayDeque<Integer>();
        L.addFirst(4);
        L.addFirst(5);
        L.addFirst(6);
        L.addLast(5);
        L.addLast(6);
        L.addLast(8);
        L.removeLast();
        L.removeFirst();
        L.removeFirst();
        L.addFirst(3);
        L.addFirst(2);
        L.addFirst(1);
        L.addLast(9);
        L.removeFirst();

        System.out.println("test Get ,should be:\n 2 3 4 5 6 9\nactual is:\n");
        L.printDeque();
        assertEquals(L.get(5), 9);
        System.out.println("get the last item ,should be 9\nactual is:" + L.get(5));


    }

    public static void main(String[] args) {
        jh61b.junit.TestRunner.runTests("all", ArrayDequeTest.class);
    }

}
SpeedTestLinkedList LinkedList的速度测试,貌似超过10w就很慢了。
public class SpeedTestLinkedList
{

        public static void main(String[] args) {
            LinkedListDeque<Integer> L = new LinkedListDeque<Integer>();
            int N = Integer.parseInt(args[0]);
            for (int i = 0; i < N; i += 1) {
                L.addLast(i);

            }

            for (int i = 0; i < N; i += 1) {
                L.addLast(L.get(i));
            }
    }
}

不保证准确。。。。

首尾相接的 ArrayDeque(类似一个sentinel的DLList)
public class ArrayDequeReal<T> {
    private int size;
    private int first;
    private int last;
    private T[] items;

    public  ArrayDequeReal() {
        size = 0;
        first = 0;
        last = 0;
        items =(T[]) new Object[8];
    }

    public void addFirst(T item) {
        checkUpSize();
        if (size == 0) {
            first = 0;
            last = 0;
            items[first] = item;
        }
        else{
            int index = moveIndexLeft(first);
            first=index;
            items[first]=item;
        }
        size+=1;

    }
    public void addLast(T item){
        checkUpSize();
        if (size == 0) {
            first = 0;
            last = 0;
            items[last] = item;
        }
        else{
            int index = moveIndexRight(last);
            last=index;
            items[last]=item;
        }
        size+=1;
    }

    public T removeFirst(){
        checkDownSize();
        if(size==0){
            throw  new Error("错误的,列表是空的,不能remove的");
        }
        T oldFirst= items[first];
        items[first]=null;
        first=moveIndexRight(first);
        size-=1;
        return oldFirst;

    }
    public T removeLast(){
        checkDownSize();
        if(size==0){
            throw  new Error("错误的,列表是空的,不能remove的");
        }
        T oldLast= items[last];
        items[last]=null;
        first=moveIndexLeft(first);
        size-=1;
        return oldLast;

    }
    public T get(int i){
        if(i<0||i>size-1){
            System.out.println("error,out bound");
            return null;
        }
// or you can replace the following things with :" return  items[(i+first)%items.length];"

       int tmpPtr= first;
       while(i!=0){
           tmpPtr=moveIndexRight(tmpPtr);
           i-=1;
       }
        return  items[tmpPtr];
    }

    public int size() {
        return size;
    }
    public boolean isEmpty(){
        return size==0;
    }
    public void printDeque(){
        int tmpPtr = first;
        while(tmpPtr!=last){
            System.out.print(items[tmpPtr]+" ");
            tmpPtr=moveIndexRight(tmpPtr);
        }

    }
    private void checkUpSize(){
        if(size==items.length){
            upSize();
        }
    }
    private void checkDownSize(){
        if(size!=0&&(double)size/items.length<0.25){
            downSize();
        }
    }

    private int moveIndexLeft(int index) {
        int newIndex = (index - 1) % items.length;
        if (newIndex < 0) {
            newIndex += items.length;
        }
        return newIndex;
    }

    private int moveIndexRight(int index) {
        int newIndex = (index + 1) % items.length;
        return newIndex;
    }

    private void downSize() {
        int minLength=8;
        T[] newArray =(T[]) new Object[items.length/4];
        if(newArray.length<minLength){
            return;
        }
        int index=0;
        while(index<size){
            newArray[index]=items[first];
            first=moveIndexRight(first);
            index+=1;
        }
        items=newArray;
        first=0;
        last=index-1;
    }

    private void upSize() {
        T[] newArray = (T[])new Object[items.length*2];
        int index=0;

        while(index<size){
            newArray[index]=items[first];
            first=moveIndexRight(first);
            index+=1;
        }
        items=newArray;
        first=0;
        last=index-1;
    }

}

首尾相接的 ArrayDequeTest
import org.junit.Test;

import static org.junit.Assert.*;

public class ArrayDequeRealTest {

    @Test
    public void testAddFirst(){
        ArrayDequeReal list = new ArrayDequeReal();
        for(int i =0;i<12;i++){

            list.addFirst(i);
        }
        assertEquals(90,list.size());
    }
    @Test
    public void testRemoveFirst(){
        ArrayDequeReal list = new ArrayDequeReal();
        for(int i =0;i<90;i++){

            list.addFirst(i);
        }
        for(int i =0;i<90;i++){

            list.removeFirst();
        }
        assertEquals(0,list.size());
    }

    @Test
    public void testPrintDeque(){
        ArrayDequeReal list = new ArrayDequeReal();
        for(int i =0;i<90;i++){

            list.addFirst(i);
        }
        System.out.println("start test PrintDeque ,should be a list of 0-89");
        list.printDeque();
    }
    @Test
    public void testAddAndRemove(){
        ArrayDequeReal list = new ArrayDequeReal();
        for(int i =1;i<10;i++){
// 8 6 4 2 1 3 5 7 9
            if(i%2==0){
                list.addFirst(i);
                continue;
            }
           list.addLast(i);
        }


        int[] expectedArr= {8,6,4,2,1,3,5,7,9};
        for(int i=0;i<list.size();i++){
            assertEquals(expectedArr[i],list.get(i));
        }

    }
    @Test
   public void testGet(){
        ArrayDequeReal list = new ArrayDequeReal();
        int[] expectedArr = {9,8,7,6,5,4,3,2,1,0,999};
        for(int i =0;i<10;i++){
            list.addFirst(i);
//

        }
        list.addLast(999);
        for(int i =0;i<11;i++){
            if(i==10){
                assertEquals(expectedArr[i], list.get(i));
                assertNotEquals(0,list.get(i));
            }
            assertEquals(expectedArr[i],list.get(i));
                  }

    }
    public static void main(String[] args) {
        jh61b.junit.TestRunner.runTests("all", ArrayDequeTest.class);
    }
}

//  return  items[(i+first)%items.length];

posted @ 2025-01-07 16:27  刘老六  阅读(47)  评论(0)    收藏  举报