Java 中的循环链表

Circular LinkedList in Java

我正在通过阅读一本书来复习我的数据结构,其中一个问题是通过不使用 "first" & "last" 指针来构建循环单链表,而是允许使用一个引用 "current" 访问它。我不确定我是否理解这个问题,我一直认为我至少需要首先或最后。这是我的实现,但它有 "first",不知道如何绕过它。您能否评论一下我如何调整我的代码以消除对 first 的依赖?

class Link {
    public int iData;              
    public Link next;              

    public Link(int id) { // constructor
        iData = id;                         
    }                          

    public void displayLink() {
        System.out.print(iData + " ");
    }
}  // end class Link

然后是列表本身:

public class CircularLinkedList {
    private Link first;
    private Link current;    

    public Link getCurrent(){
        return current;
    }

    public void setCurrent(int data){

    }

    public void advance(){
        current = current.next;
    }

    public void insert(int data) {
        Link newLink = new Link(data);
        if (first == null) { 
            first = current = newLink;
        } else {
            current.next = newLink;
        }
        current = newLink;
        newLink.next = first;
    }
    ...
}

使用Node current, int currentIndex, int size。让最后一个节点的 next 指向列表的第一个节点(=循环)。使用当前索引,您可以遍历 (size - 1) 个元素以到达 current.

的前一个节点

如果你有一个循环链表,那么每个节点指向一个连续循环中的下一个节点。所以没有最后也没有第一个。在这种情况下,您只需要一个指向数据结构的指针(问题调用 "current"),因为您可以遍历整个列表,直到回到开始的位置。

一个节点可能如下所示:

public class ListNode<T> {
    private T element;
    private ListNode<T> next;
}

所以在这种环境下,当您将第一个节点添加到列表中时,它的 "next" 指针将指向它自己。当您添加第二个节点时,每个 "next" 指针将指向另一个。当您添加第三个节点时,它们将分别指向下一个节点,并且大概这是以某种方式排序的。添加的每个额外节点将被插入到循环中的适当位置。

像这样的数据结构的一个很好的用法是每天或每小时重复一次的时间表。所有事件都可以存储在循环列表中,"current" 指针始终指向下一个安排的事件。

显然,在搜索这样的列表时,您需要保留对第一个节点的引用。这是您知道是否搜索了整个列表的唯一方法,因为它没有以空 "next" 指针结尾。

编辑: 正如下面(广泛的)评论中所讨论的,"tail" 指针对于插入操作来说似乎是一个非常好的主意。这是我发布的原始方法,已重命名为 insertAfter:

public void insertAfter(int data) {
    Link newLink = new Link(data);
    if (current == null) { 
        newLink.next = newLink;
        current = newLink;
    } else {
        newLink.next = current.next;
        current.next = newLink;
    }
}

尾指针总是指向列表的最后一个节点。这也将是第一个节点之前的节点,因为列表是循环的。所以在操作指针的时候一定要保持(tail.next == current)。这是新的插入方法:

public void insert(int data) {
    Link newLink = new Link(data);
    if (current == null) { 
        current = newLink;
        tail = newLink;
        newLink.next = newLink; // tail.next = current!
    } else {
        tail.next = newLink; // tail.next = current!
        newLink.next = current;
        current = newLink; // tail is unchanged, newLink is current
    }
}

插入值应该正确地使它们乱序。添加时要保持顺序,应使用add方法:

public void add(int data) {
    this.insert(data);
    this.advance();
}

这是 advance 的代码:

public void advance() {
    if (current != null) {
        tail = current;
        current = tail.next; // tail.next = current!
    }
}

像这样用于创建列表时...

list1.add(1);
list1.add(2);
list1.add(3);
list2.insert(3);
list2.insert(2);
list2.insert(1);

...两个列表都按 1-2-3 排序,当前为 1。

由于链表是循环的,所以不会有第一个和最后一个元素。

您可以从任何节点(在此上下文中为当前节点)开始遍历整个列表。

所以Nodeclass只有下一个参考,CircularLinkedList只有当前参考。

希望对您有所帮助。
祝你好运。