在这两天的刷题中,遇到一个求链表的翻转问题,坦白讲,这个问题我想得思路有很多种,但在这么多种的思路中,没有一个是能够轻易实现的。题目如下。
链表翻转。给出一个链表和一个数k,比如链表1→2→3→4→5→6,k=2,翻转后2→1→4→3→6→5,若k=3,翻转后3→2→1→6→5→4,若k=4,翻转后4→3→2→1→5→6,用程序实现Node* RotateList(Node* list, size_t k).
最开始,我想得第一种解法是在区间内进行交换,但是这是一个链表,只能next,不能head++,tail–。于是这种思路报废。第二种,是局部进行逆置,但是在逆置的时候,容易出现的问题,且不能保证程序能一直运行起来,对起始结点和尾结点没法进行循环。第三种,是在一个循环条件中反复判断,判断的条件和需要注意的细节太多,这种思路也只能想想。最后一种,也就是我接下来要讲的这种,递归进行翻转,把一个大问题不断化简成小问题,然后再去一一串起来。
整体步骤如下图所示。
剩下的结点递归的原理和上图一样,就不赘余了。讲到这里,对这个题的解题思路已经很明确了,源码如下。
size_t Size(Node* head)
{
if (head == NULL)
return 0;
Node* cur = head;
size_t count = 0;
while (cur)
{
++count;
cur = cur->_next;
}
return count;
}
//思路:以K为一组进行逆置,然后进行递归
//每次保存翻转的最后一个结点指向的下一个
//最后把这些结点全部串起来
Node* RotateList(Node* head, size_t k)
{
if (k <= 1)
return head;
if (head == NULL || head->_next == NULL)
return head;
size_t size = Size(head);
size_t pos = k;
Node* newHead = NULL;
Node* next = NULL; //用来保存一组逆置的最后一个结点的下一个指向
Node* prev = NULL;
Node* cur = head; //
if (size < k)
return head;
while (pos >= 1) //在一组里进行逆置
{
next = cur->_next;
pos--;
if (pos == 0)
newHead = cur;
cur->_next = prev;
prev = cur;
cur = next;
}
Node* last = newHead;
while (last->_next != NULL) //找到最后一个结点,保存起来
last = last->_next;
Node* nextHead = RotateList(next, k); //对下一个K组继续进行逆置
last->_next = nextHead;
return newHead;
}
结果如下。
总结:对于链表问题,一定要把握好一个原则,无论怎么变,对链表更改前,一定要保存下一个结点。