问题描述:有链表{L0, L1, L2, ..., Ln},重新排列后得到{L0, Ln, L1, Ln-1...}。
约束条件:空间复杂度S(1),只能改变Node* next指针。
备注: 微软2014笔试最后一题。
思路一:遍历链表,每次遍历找到链表末端的节点,将其插入最终的位置。此方法时间复杂度O(n^2)。
思路二:第一趟遍历统计链表长度;第二趟遍历找到中间位置的节点;第三趟遍历将后半截链表的节点倒置;第四趟将后半截链表的节点插入前半截链表。每一趟都是单重循环,故时间复杂度为O(n)。
#include<iostream>
using namespace std;
class Node
{
public:
int index;
Node* next;
Node(int i) : index(i), next(NULL)
{}
};
//输出链表
void print(Node* ptr)
{
while(ptr)
{
cout << ptr->index << " ";
ptr = ptr->next;
}
cout << endl;
}
void list_reorder(Node* head)
{
if(NULL == head || NULL == head->next)
return;
Node* p = NULL;
Node* q = NULL;
Node* r = NULL;
int length = 0;
int index = 0;
//第一趟遍历统计链表长度
p = head;
while(p)
{
++length;
p = p->next;
}
//第二趟遍历找到链表中间节点
p = head;
while(index++ != length / 2)
p = p->next;
//第三趟遍历将后半截链表倒置
q = p->next;
if(q)
r = q->next;
p->next = NULL;
while(q)
{
q->next = p;
p = q;
q = r;
if(r)
r = r->next;
}
//第四趟遍历将后半截链表的节点插入前半截链表
q = p;
p = head;
r = p->next;
while(true)
{
p->next = q;
p = r;
if(NULL == (r = q->next))
break;
q->next = p;
q = r;
if(NULL == (r = p->next))
break;
}
}
void main()
{
int N = 9;
Node* head = NULL;
Node* ptr = NULL;
for(int i = 0; i < N; ++i)
{
if(NULL == head)
{
head = new Node(i);
ptr = head;
}
else
{
ptr->next = new Node(i);
ptr = ptr->next;
}
}
print(head);
list_reorder(head);
print(head);
while(head)
{
ptr = head->next;
delete head;
head = ptr;
}
}