在Java中反转链表

评论 0 浏览 0 2020-09-27

1.绪论

在本教程中,我们将在Java中实现两种链表的反转算法

2.链表的数据结构

链表是一种线性数据结构,其中每个元素中的指针决定了其顺序。链接列表的每个元素都包含一个数据字段来存储列表数据,以及一个指针字段来指向序列中的下一个元素。同时,我们可以使用一个head指针来指向链接列表的起始元素。

linkedlist

在我们反转链接列表后,head将指向原链接列表的最后一个元素,而每个元素的指针将指向原链接列表的前一个元素。

reversedlinkedlist1

在Java中,我们有一个LinkedList类,为ListDeque接口提供双链列表的实现。然而,在本教程中,我们将使用一个一般的单链列表数据结构。

首先,让我们从一个ListNode类开始,以表示一个链表的元素。

public class ListNode {

    private int data;
    private ListNode next;

    ListNode(int data) {
        this.data = data;
        this.next = null;
    }

   // standard getters and setters
}

ListNode类有两个字段。

  • 一个整数值,代表元素的数据。
  • 一个指向下一个元素的指针/引用值

一个链接列表可以包含多个ListNode对象。例如,我们可以用一个循环来构造上面的链接列表样本。

ListNode constructLinkedList() {
    ListNode head = null;
    ListNode tail = null;
    for (int i = 1; i <= 5; i++) {
        ListNode node = new ListNode(i);
        if (head == null) {
            head = node;
        } else {
            tail.setNext(node);
        }
        tail = node;
    }
    return head;
}

3.迭代算法的实现

让我们在Java中实现iterative算法

ListNode reverseList(ListNode head) {
    ListNode previous = null;
    ListNode current = head;
    while (current != null) {
        ListNode nextElement = current.getNext();
        current.setNext(previous);
        previous = current;
        current = nextElement;
    }
    return previous;
}

在这个迭代算法中,我们使用两个ListNode变量,previouscurrent,来代表链接列表中的两个相邻元素。在每次迭代中,我们将这两个元素反转,然后转移到下两个元素。

最后,current 指针将是null,,而previous指针将是旧链表的最后一个元素。因此,previous 也是反转链表的新头指针,我们从方法中返回它。

我们可以用一个简单的单元测试来验证这种迭代式的实现。

@Test
public void givenLinkedList_whenIterativeReverse_thenOutputCorrectResult() {
    ListNode head = constructLinkedList();
    ListNode node = head;
    for (int i = 1; i <= 5; i++) {
        assertNotNull(node);
        assertEquals(i, node.getData());
        node = node.getNext();
    }
 
    LinkedListReversal reversal = new LinkedListReversal();
    node = reversal.reverseList(head);
 
    for (int i = 5; i >= 1; i--) {
        assertNotNull(node);
        assertEquals(i, node.getData());
        node = node.getNext();
    }
}

在这个单元测试中,我们首先构建一个有五个节点的链接列表样本。同时,我们验证链表的每个节点都包含正确的数据值。然后,我们调用迭代函数来反转链表。最后,我们检查反转的链表,以确保数据是按预期反转的。

4.递归 算法实现

现在,让我们在Java中实现递归算法吧。

ListNode reverseListRecursive(ListNode head) {
    if (head == null) {
        return null;
    }
    if (head.getNext() == null) {
        return head;
    }
    ListNode node = reverseListRecursive(head.getNext());
    head.getNext().setNext(head);
    head.setNext(null);
    return node;
}

reverseListRecursive函数中,我们递归地访问链表中的每个元素,直到到达最后一个。这最后一个元素将成为反转链表的新头。同时,我们将访问过的元素追加到部分反转的链表的末尾。

同样地,我们可以用一个简单的单元测试来验证这个递归的实现。

@Test
public void givenLinkedList_whenRecursiveReverse_thenOutputCorrectResult() {
    ListNode head = constructLinkedList();
    ListNode node = head;
    for (int i = 1; i <= 5; i++) {
        assertNotNull(node);
        assertEquals(i, node.getData());
        node = node.getNext();
    }
 
    LinkedListReversal reversal = new LinkedListReversal();
    node = reversal.reverseListRecursive(head);
 
    for (int i = 5; i >= 1; i--) {
        assertNotNull(node);
        assertEquals(i, node.getData());
        node = node.getNext();
    }
}

5.总结

在本教程中,我们实现了两种算法来逆转一个链表。一如既往,文章的源代码在GitHub上。

最后更新2023-03-11
0 个评论
标签