Search code examples
golinked-list

Reverse LinkedList in one line


I just found a solution for Reverse LinkedList on LeetCode using one line in Go. It realy works, but I can't understand how.

There it is:

func reverseList(head *ListNode) (prev *ListNode) {
    for head != nil {
        prev, head, head.Next = head, head.Next, prev 
    }
    
    return
}

For example let the list is [1->2->3->4->5->nil].

I got that it's work like:

  1. Firstly go execute head.Next = prev (head.Next = nil, so now head = [1->nil])

  2. Then, prev = head (At this step prev = [1->nil] like head in previous step)

  3. head = head.Next and there is magic. For prev on second step Go was use head = [1->nil], but after this step head = [2->3->4->5->nil]

So while head != nil it's iterates and at 2nd step prev = [2->1->nil] , head = [3->4->5->nil] and so on.

This line can be represented like:

for head != nil {
        a := *head
        prev, a.Next = &a, prev
        head = head.Next
    }

Am I right? Why does it work like this?


Solution

  • Variables on the left side of the expression, are assigned to the values on the right side of the expression at that time. This is a clever use of the language.

    To make it easier to understand let's go through an example.

    Setup

    This is our linked list:
    1 -> 2 -> 3 -> 4 -> nil

    Before the function is executed,

    • head is *Node 1
    • prev is nil (uninitialized)
    • head.Next is *Node 2

    Step by step

    prev, head, head.Next = head, head.Next, prev
    

    Let's break this down,

    • prev (nil) = head (*Node 1)
    • head (*Node 1) = head.Next (*Node 2)
    • head.Next (*Node 2) = prev (nil)

    The next iteration,

    • prev (*Node 1) = head (*Node 2)
    • head (*Node 2) = head.Next (*Node 3)
    • head.Next (*Node 3) = prev (*Node 1)

    Summary

    Basically, it reverses head.Next to the previous node and moves prev and head to the next nodes.

    Compare this to the textbook algorithm in Go to make it clear:

    func reverseList(head *ListNode) *ListNode {
        var prev *ListNode
    
        for head != nil {
            nextTemp := head.Next
            head.Next = prev
            prev = head
            head = nextTemp
        }
    
        return prev
    }