How to reverse a linked list?

白昼怎懂夜的黑 提交于 2019-11-28 18:22:22

You reverse the list iteratively and always have the list in the interval [head, previous] correctly reversed(so current is the first node that has its link not set correctly). On each step you do the following:

  • You remember the next node of current so that you can continue from it
  • You set the link of current to be pointing to previous, which is the correct direction if you think about it
  • You change previous to be current, because now current also has its link set correctly
  • You change the first node that does not hae its link set correctly to be the one remebered in the first step

If you do that for all the nodes you can prove(with induction for instance). That the list will be correctly reversed.

Michael Borgwardt

The code simply walks the list and inverts the links until it reaches the previous tail, which it returns as the new head.

Before:

Node 1 (Head) -> Node 2 -> Node 3 -> Node 4 (Tail) -> null

After:

   null <- Node 1 (Tail) <- Node 2 <- Node 3 <- Node 4 (Head)
user2507212
public Node getLastNode( )
{
    if( next != null )
        return next.getLastNode( );
    else
        return this;
}

public Node reverse( Node source )
{
    Node reversed = source.getLastNode( );
    Node cursor = source;

    while( cursor != reversed )
    {
        reversed.addNodeAfter( cursor.getInfo( ) );
        cursor = cursor.getNodeAfter( );
    }

    source = reversed;
    return source;
}

I call it "cherry picking". The idea is to minimize the number of swaps. Swapping happens between a near and far index. Its a 2-Pass algorithm.

    (Odd length)  A -> B -> C -> D -> E
    (Even length) A -> B -> C -> D

    Pre-Condition: N >= 2

    Pass 1: Count N, the number of elements

    Pass 2: 
            for(j=0 -> j<= (N/2 -1))
            {
              swap(j, (N-1)-j)
            }

Example 1:

   For above Odd length list, N = 5 and there will be two swaps 

      when j=0, swap(0, 4) //post swap state: E B C D A
      when j=1, swap(1, 3) //post swap state: E D C B A


   The mid point for odd length lists remains intact.

Example 2:

   For above Even length list, N = 4 and there will be two swaps 

      when j=0, swap(0, 3) //post swap state: D B C A
      when j=1, swap(1, 2) //post swap state: D C B A
  • Swapping applies to data only, not to pointers, there might be any sanity checks missed, but you got the idea.

Reversing a singly linked list using iteration

current = head //point current pointer to head of the linked list

while(current != NULL)
{
forward = current->link; //point to the next node
fforward = forward->link; //point the next node to next node
fforward->link = forward;//1->2->3,,,,,,,,,this will point node 3 to node 2
forward->link = current; //this will point node 2 to node 1
if(current == head)
current->link = NULL;// if current pointer is head pointer it should point to NULL while reversing

current = current->link; //traversing the list
}
head = current; //make current pointer the head pointer
  list_t *reverse(list_t *a)
  {
    list_t *progress = NULL;
    while(a)
    {
      list_t *b; //b is only a temporary variable (don't bother focusing on it)
      b = a->next;
      a->next = progress; //because a->next is assigned to another value, we must first save a->next to a different variable (to be able to use it later)
      progress = a; //progress is initially NULL (so a->next = NULL (because it is the new last element in the list))
      a = b; //we set a to b (the value we saved earlier, what a->next was before it became NULL)
      /*
        now, at next iteration, progress will equal a, and a will equal b.
        so, when I assign a->next = progress, I really say, b->next = a.
        and so what we get is: b->a->NULL.
        Maybe that gives you an idea of the picture?
        What is important here is:
          progress = a
        and
          a = b
        Because that determines what a->next will equal:
          c->b->a->0
        a's next is set to 0
        b's next is set to a
        c's next is set to b
      */
    }
    return progress;
  }

The basic idea is to detach the head node from the first list and attach it to the head of a second list. Keep repeating until the first list is empty.

Pseudocode:

function reverseList(List X) RETURNS List
   Y = null
   WHILE X <> null
      t = X.next
      X.next = Y
      Y = X
      X = t
   ENDWHILE
   RETURN Y
ENDfunction

If you wish to leave the original list undisturbed then you can code a copying version recursively with the use of a helper function.

function reverseList(List X) RETURNS List
   RETURN reverseListAux(X, null)
ENDfunction

function reverseListAux(List X, List Y) RETURNS List
   IF X = null THEN
       RETURN Y
   ELSE
       RETURN reverseListAux(X.next, makeNode(X.data, Y))
ENDfunction

Note that the helper function is tail recursive. This means that you can create a copying reversal using iteration.

function reverseList(List X) RETURNS List
   Y = null
   WHILE X <> null
     Y = makeNode(x.data, Y)
     X = X.next   
   ENDWHILE
   RETURN Y
ENDfunction

// implementation of singly linked list reversal function

struct Node
{
    int data;
    struct Node* link;
}
Node* head = NULL;

void reverseList()
{
    Node* previous, *current, *next;
    previous = NULL;
    current = head;

while(current != NULL)
{
    next = current-> link;
    current->link = previous;
    previous = current;
    current = next;
}

    head = previous;
}

The easiest way to think about it is to think like this:

  1. First add the head of the list to a new linked list.
  2. Keep iterating through the original and keep adding the nodes before the head of the new linked list.

Diagram:

Initially:

Original List -> 1 2 3 4 5
New List -> null

1st Iteration

Original List -> 1 2 3 4 5
New List -> 1->null [head shifted to left, now newHead contains 1 and points to null]

2nd Iteration

Original List -> 1 2 3 4 5
New List -> 2-> 1->null [head shifted to left, now newHead contains 2 and points to next node which is 1]

3rd Iteration

Original List -> 1 2 3 4 5
New List ->3 -> 2-> 1->null [head shifted to left, now newHead contains 2 and points to next node which is 1]

Now it keeps looping through till the end. So finally the new list becomes:

  New List->  5 -> 4 -> 3 -> 2 -> 1 -> null

The code for the same should be like this (made it easy to understand):

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) { val = x; }
 * }
 */

public ListNode reverseList(ListNode head) {
    if(head == null) {
        return null;
    }

    if(head.next == null) {
        return head;
    }

    ListNode current = head;
    ListNode previous = new ListNode(head.val);
    previous.next = null;

    while(current.next != null) {
        current = current.next;
        previous = addBeforeHead(current, previous);
    }

    return previous;
}

private ListNode addBeforeHead(ListNode node, ListNode head) {
    if (node == null) return null;
    ListNode temp = new ListNode(node.val);

    temp.next = head;
    head = temp;

    return head;
}
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!