单链表反转是一个经典的面试题。
单链表反转问题可以类比成一个倒叙的数列进行插入排序,实际上是将第二个开始的每个元素提取到链表的最前面。
单链表数据结构定义:
1 struct ListNode { 2 int val; 3 ListNode *next; 4 ListNode(int x) : val(x), next(NULL) {} 5 };
有三个问题需要注意:
1.在将第二个元素开始的每个元素提取到链表最前面时,需要将第一个元素指向提取元素的后一个元素(否则循环无法进行)。
2.修改提取元素指向链表头。
3.具体逻辑。head指向未进行任何操作时的第一个节点,且在循环中一直指向这个节点;tail指向当前提取的节点,显然开始时tail=head->next;prev指向链表头,且一直指向的是链表头,很显然开始prev=head
具体操作为:
head->next=tail->next; //将head指向提取节点的后一个节点
tail->next=p; //将提取的节点插入到链表头
p=tail; //修改链表头尾提取的节点
tail=head->next; //将tail指向下一个提取的节点
此问题也可以使用递归方法进行实现
用递归方法实现即为一直进行递归head=head->next找到最后一个节点
然后从最后一个节点开始,重新建立链表的关系,实现的代码如下:
ListNode * ReverseList(ListNode * head) { //递归终止条件:找到链表最后一个结点 if (head == NULL || head->next == NULL) return head; else { ListNode * newhead = ReverseList(head->next);//先反转后面的链表,从最后面的两个结点开始反转,依次向前 head->next->next = head;//将后一个链表结点指向前一个结点 head->next = NULL;//将原链表中前一个结点指向后一个结点的指向关系断开 return newhead; } }
同时实现单链表反转一个简易并且容易理解的方法是:使用栈,将每个节点的指针入栈(而不是节点本身),然后stack.pop()进行出栈指针,重新建立单链表的关系,只是这种方法需要消耗O(n)的空间,但是相对来说易于操作和理解。