【问题标题】:How do I remove an element from a doubly circular linked list properly?如何正确地从双循环链表中删除元素?
【发布时间】:2019-03-30 08:58:55
【问题描述】:

我必须使用我自己的构造函数来实现一个双循环链表,我已经完成了很多,但不知道为什么 remove 方法不起作用。

我进行了大量研究,但很难找到符合我需求的任何东西。问题是我没有永久的头尾指针,就像通常在双向链表中一样,但必须使用“头”作为起点和终点。

带有标题元素的构造函数

public MyDoubleLinkedList() {
        header = new DEntry(0, null, null);
        header.next = header;
        header.previous = header;
        size = 0;
    }

listEntrys 的内部类

    class DEntry {
        /** the data element represented by this entry */
        private final int data;

        /** reference to the previous element in the list */
        private DEntry previous;

        /** reference to the next element in the list */
        private DEntry next;

        /**
         * @param data     the data object this entry represents
         * @param previous reference to the previous element in the list
         * @param next     reference to the next element in the list
         */
        public DEntry(int data, DEntry previous, DEntry next) {
            this.data = data;
            this.previous = previous;
            this.next = next;
        }
    }

添加到列表的方法:

    /**
     * Adds a new element into the list at the position specified
     * 
     * @param position the 0 based position at which to add the passed value
     * @param value    the value to add
     * @return 0 if adding was successful, -1 if not
     */
    public int add(int position, int value) {
        // TODO: please put your code here
        DEntry listEntry = new DEntry(value, null, null);

        DEntry temp = header;
        int i = 0;

        if (position < 0 || position > size) {
            return -1;
        }

        if (position == 0) {
            temp = header;

        } else {
            while (i < position) {
                temp = temp.next;
                i++;
            }
        }

        listEntry.next = temp.next;
        listEntry.previous = temp.next;
        temp.next = listEntry;
        temp.next.previous = listEntry.next;
        size++;

        return 0;
    }

从列表中删除的方法

    /**
     * Removes an element at the position specified from the list
     * 
     * @param position the 0 based position of the value to remove
     * @return value of the removed entry if removing was successful, -1 if not
     */
    public int remove(int position) {
        // TODO: please put your code here

    DEntry toBeDeleted = header;

        if(position < 0 || position > size) {
            return -1;
        }
        if(getEntry(position) == null) {
            return -1;
        } else {
        toBeDeleted = getEntry(position);
        }

        int dataOfDeletedNode = toBeDeleted.data;

        if(position == 0) {
            header.previous.next = toBeDeleted.next;
            header.next.previous = toBeDeleted.previous;
        } else if(position == size){
            toBeDeleted.previous.next = header.next;
            toBeDeleted.next.previous = toBeDeleted.previous;
        } else {
            toBeDeleted.previous.next = toBeDeleted.next;
            toBeDeleted.next.previous = toBeDeleted.previous;
        }



        size--;
        System.out.println(dataOfDeletedNode);
        return dataOfDeletedNode;
    }

如果我运行代码

list.add(0, 10);
list.add(1, 20);
list.add(0, 30);
remove(1); // 10 should be deleted

我得到的不是 30、20,而是 20。

【问题讨论】:

  • 顺便说一句,是否有任何理由使用该 while 循环而不是 DEntry toBeDeleted = getEntry(position);?无论如何,您都在循环直到产生效果,那为什么不一步完成呢?
  • 还要注意if (position == size) 的主体永远不会被执行——你已经检查过position 严格小于size
  • 是的,getEntry(position) 正是这样做的,但我已经到了绝望到想尝试一切的地步。会尽快改变它!也感谢关于尺寸限制的提示!
  • 我还会检查您调用remove(1) 之前的结果是否符合您的预期。
  • 在删除调用发出之前打印列表:30、10、20。对我来说似乎是正确的。它也以某种方式切断了已删除元素的前一个元素。

标签: java linked-list doubly-linked-list circular-list


【解决方案1】:

看来您的主要问题的根源是 add 方法。实际上,在您的代码中链接新节点存在很大问题,这是我通过阅读您的代码检测到的唯一问题。因此,您的 add 方法应该是这样的:

public int add(int position, int value) {
    DEntry listEntry = new DEntry(value, null, null);

    DEntry temp = header;

    if (position < 0 || position > size) {
        return -1;
    }

    if (position == 0) {
        temp = header;

    } else {
        int i = 0;
        while (i < position) {
            temp = temp.next;
            i++;
        }
    }

    listEntry.next = temp.next;
    listEntry.previous = temp;
    temp.next = listEntry;
    size++;

    return 0;
}
  1. listEntry 将是临时节点之后的下一个节点。那么它的前一个指针应该指向温度。
  2. 在临时节点之后放置新节点不需要对临时链接的先前链接进行任何更改。因此,您在代码中的最后一个链接是有问题的。

【讨论】:

  • 非常感谢!你是对的。如果我 f.e.,这个列表效果很好。添加这样的元素:list.add(0, 10); list.add(1, 20); list.add(2, 30);然后在特定位置删除一个。但是,如果我在位置 0 处添加每个元素,然后在位置 3 处删除元素,它会删除位置 3 处的元素以及之前链接的所有元素。
  • 从你上面的评论可以理解,你的数据结构索引和你使用的size变量有冲突。大小变量的范围是 [1,...],但您的数据结构的范围是 [0,...]。奇怪的是,您的列表中有 3 个从索引 0 到 2 的实例,而您删除了索引 3 处的实例。请仔细检查此问题,并在可能的情况下告诉我。
【解决方案2】:

我可以同时解决这个问题。确实是我的 add 方法阻止了我的 remove 方法正常工作。

部分错误是我的 while 循环停止在 (i

这是我想出的 add 方法,一切正常。

public int add(int position, int value) {

    // Creates a new listEntry 
    DEntry listEntry = new DEntry(value, null, null);
    DEntry temp = header;

    int i = 0;

    if (position < 0 || position > size) {
        return -1;
    }

        while (i <= position) {
            temp = temp.next;
            i++;
        }

    // setting the elements neighbours
    listEntry.next = temp;
    listEntry.previous = temp.previous;

    // placing the new element between last and next
    temp.previous.next = listEntry;
    temp.previous = listEntry;

    // places the new entry in the list
    temp = listEntry;
    size++;

    return 0;
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-07-23
    • 1970-01-01
    • 2020-12-03
    • 1970-01-01
    • 1970-01-01
    • 2018-05-24
    相关资源
    最近更新 更多