CS61B Project1 checkpoint 数组实现循环队列中出现的一个微妙的错误

191 阅读2分钟

在学61B时, 有个错误, 让我的强迫症狠狠地犯了, 毕竟就差那么一点点

而这个错误小到只是两个语句的顺序调换, 我却花了近两小时寻找...

然而这个错误却至关重要!

Autograder报错如下

image.png 乍一看这是get()函数的报错, 我反复思索也觉得我的get()函数应该没问题, 都有点怀疑人生了

    public T get(int index) {
        if (index < 0 || index >= size) {
            return null;
        }
        return data[(start + index) % data.length];
    }

事实上确实没问题...

而是我addLast和removeLast函数出了问题

原代码

    public void addFirst(T item) {
        if (size == data.length) {
            // resize();
            System.out.println("Deque is full");
            return;
        }
        start = start == 0 ? data.length - 1 : start - 1;
        data[start] = item;
        size++;
    }

    public void addLast(T item) {
        if (size == data.length) {
            // resize();
            System.out.println("Deque is full");
            return;
        }        
        end = (end == data.length - 1) ? 0 : end + 1;
        data[end] = item;
        size++;
    }

    public T removeFirst() {
        if (isEmpty()) {
            System.out.println("Empty Deque");
            return null;
        }
        T result = data[start];
        start = (start == data.length - 1) ? 0 : start + 1;
        size--;
        return result;
    }

    public T removeLast() {
        if (isEmpty()) {
            System.out.println("Empty Deque");
            return null;
        }
        T result = data[end];
        end = (end == 0) ? data.length - 1 : end - 1;
        size--;
        return result;
    }

正确实现

    public void addFirst(T item) {
        if (size == data.length) {
            // resize();
            System.out.println("Deque is full");
            return;
        }
        start = start == 0 ? data.length - 1 : start - 1;
        data[start] = item;
        size++;
    }

    public void addLast(T item) {
        if (size == data.length) {
            // resize();
            System.out.println("Deque is full");
            return;
        }
        data[end] = item;
        end = (end == data.length - 1) ? 0 : end + 1;
        size++;
    }

    public T removeFirst() {
        if (isEmpty()) {
            System.out.println("Empty Deque");
            return null;
        }
        T result = data[start];
        start = (start == data.length - 1) ? 0 : start + 1;
        size--;
        return result;
    }

    public T removeLast() {
        if (isEmpty()) {
            System.out.println("Empty Deque");
            return null;
        }
        end = (end == 0) ? data.length - 1 : end - 1;
        T result = data[end];
        size--;
        return result;
    }

diff一下

image.png

出错原因

start和end二者关系没有明确, 一开始我以为start是头节点的索引, 而end是尾节点的索引

两种可行的解决方法

  • 一种方法是start为头节点索引, end为尾节点下一个的索引
  • 还有一种方法是start为头节点上一个索引, end为尾节点的索引

这样插入或删除节点时, 更新节点的顺序就比较清晰了

为什么是这样呢?

只需讨论插入第一个节点的情况就可以知道:

倘若以一开始错误的想法, 在插入一个节点后, start或end中的一个必会移动(分离)

但是按照原来的规定, start和end应该在同一索引(插入的节点), 插入第二个节点才需要分离

当然对插入第一个节点进行特殊处理也是可行的, 或者特殊初始化start和end亦可

但我觉得有些麻烦, 降低代码可读性


我傻了, 其实课上有提示

image.png