倒置链表

题目描述:给出单向链表的头节点l,如何只遍历一次就将链表中的所有元素倒转。

算法描述:

首先给出单向链表的结构

    struct LinkList {
        int data;
        LinkList *next;
    };

遍历一次链表,对于每一个节点p,记录p的前驱pre,将p节点的后继(即next域)指向pre,即可完成倒转。

算法步骤:

1、设p节点指向头指针l的下一个节点(即指向第一个元素),pre设为NULL
2、若p的下一个节点为空,跳到4,否则跳到3
3、将q指向p的下一个节点,将p的next域指向pre节点,将pre指向p节点,将p指向q节点,跳到2
4、将p的next域指向pre节点
5、结束

实现:

    p = l->next;
    pre = NULL;
    while (p->next != NULL) {
        q = p->next;
        p->next = pre;
        pre = p;
        p = q;
    }
    p->next = pre;
    return p;

算法说明:

显然,这道题目如果通过记录data域来实现调转,算法复杂度在O(n^2)级,因为在不使用辅助数组的情况下,每次颠倒需要从头节点以O(n)的时间复杂度找到需要颠倒的节点。所以我们不妨换一个想法,从链表的next域下手。很容易想到,如果我们将每个节点的next域都指向它的前驱而不是后继,就可实现调转。我们不妨具体举例说明。

  1->2->3->4->5

假设前两个节点已经完成倒转,那么链表就可以表示成:

  1<-2 
  3->4->5

可以看出,链表变为了两部分。这时我们需要一个指针记录3的当前后继(也就是4),以完成后续遍历,之后将3的next域指向2,并记录3的位置(以便4指向3),即可完成前3个节点的倒转。

你可能感兴趣的:(倒置链表)