说起链表,是大家最熟悉的数据结构了,也是大学上课时比较先讲到的。那么是否真正掌握了呢。
单链表逆置是最常考的题目,但完全写正确好像三种方式也没那么容易吧。
第一种:非递归,思路就是从头结点开始,记录头结点的下一个结点,同时将头结点的指针指向之前的结点(设为NULL),然后将头结点的值赋给之前的结点,然后继续下一个结点的逆置,直到为空。
第二种: 递归方式。思路就是一直递归,直到最后一个结点的之前一个结点结束,这时然后最后一个结点的指针指向之前一个结点,同时将之前一个结点的指针置为空(这样顺便修改了原来链表头结点的指针为空)。难点在于怎么返回逆置之后的头结点。
第三种: 栈。既然可以递归了那么考虑用栈来解决。
好了,貌似单链表比较复杂的操作我们掌握了。问题解决了,那么是否能灵活运用呢?看下面一道题目(微软2014年校招编程题)
Given a singly linked list L: (L0 , L1 , L2...Ln-1 , Ln). Write a program to reorder it so that it becomes(L0 , Ln , L1 , Ln-1 , L2 , Ln-2...).
struct Node
{
int val_;
Node* next;
};
Notes:
1)Space Complexity should be O(1)
2)Only the ".next" field of a node is modifiable.
注意:空间复杂度为O(1)意味着不能有大于O(1)的辅助空间。
注意是从尾倒着插,可能会用到逆置,那解题思路是神马呢?
根据长度将链表分为两半,对后面的链表进行逆置,然后将两个链表合并(擦,神一样的思路啊,这就是链表逆置和合并的灵活应用了,当做为笔试题是否能想到呢。。。),好了,废话不多说了,代码在下面,看注释吧。
#include<iostream>
#include<string>
#include<stack>
using namespace std;
struct ListNode{
int value;
ListNode* next;
};
//增加元素
void AddToList(ListNode** pHead,int value){
ListNode* pTemp = *pHead;
pTemp = (ListNode *)malloc(sizeof(ListNode));
pTemp->value = value;
pTemp->next = NULL;
if(*pHead == NULL)
*pHead = pTemp;
else{
ListNode* pNTemp = *pHead;
while(pNTemp->next != NULL)
pNTemp = pNTemp->next;
pNTemp->next = pTemp;
}
}
//求长度
int ListLen(ListNode* pHead){
int n =0;
while(pHead != NULL){
pHead = pHead->next;
n++;
}
return n;
}
//非递归逆置
ListNode* Reverse(ListNode* pHead){
ListNode* pTemp = pHead;
ListNode *pre,*plast = NULL;
while(pTemp!= NULL){
pre = pTemp->next;
pTemp->next = plast;
plast = pTemp;
pTemp = pre;
}
return plast;
}
//递归逆置,关键是如何在递归中找到起点(原来的最后一点)
ListNode* Reverse_recurve(ListNode* pHead){
if(pHead == NULL || pHead->next == NULL )
return pHead;
ListNode *pHead1 = Reverse_recurve(pHead->next);
pHead->next->next = pHead;
pHead->next = NULL;
return pHead1;
}
//用栈逆置
ListNode* Reverse_stack(ListNode* pHead){
stack<ListNode*> lstack;
while(pHead != NULL){
lstack.push(pHead);
pHead = pHead->next;
}
pHead = lstack.top();
ListNode* plast = pHead;
ListNode* pre;
lstack.pop();
while(!lstack.empty()){
pre = lstack.top();
lstack.pop();
plast->next = pre;
plast = pre;
}
plast->next = NULL;
return pHead;
}
//合并链表
void merge(ListNode* pHead,int n){
ListNode* pTemp1 = pHead,*pTemp2,*pTemp;
if(n%2 == 0)
n = n/2;
else
n = n/2+1;
while(n-1){
pTemp1 = pTemp1->next;
n--;
}
pTemp = pTemp1->next;
pTemp1->next = NULL;
//逆置
pTemp = Reverse(pTemp);
//合并
while(pTemp != NULL){
pTemp1 = pHead->next;
pTemp2 = pTemp->next;
pTemp->next = pHead->next;
pHead->next = pTemp;
pHead = pTemp1;
pTemp = pTemp2;
}
return;
}
int main(){
ListNode* pHead = NULL;
AddToList(&pHead,1);
AddToList(&pHead,2);
AddToList(&pHead,3);
AddToList(&pHead,4);
AddToList(&pHead,5);
//AddToList(&pHead,6);
ListNode* pHead1 = pHead;
pHead1 = Reverse(pHead1);
pHead = pHead1;
while(pHead1->next != NULL){
printf("%d->",pHead1->value);
pHead1 = pHead1->next;
}
printf("%d\n",pHead1->value);
//递归
pHead1 = pHead;
pHead1 = Reverse_recurve(pHead1);
pHead = pHead1;
while(pHead1->next != NULL){
printf("%d->",pHead1->value);
pHead1 = pHead1->next;
}
printf("%d\n",pHead1->value);
//栈
pHead1 = pHead;
pHead1 = Reverse_stack(pHead1);
pHead = pHead1;
while(pHead1->next != NULL){
printf("%d->",pHead1->value);
pHead1 = pHead1->next;
}
printf("%d\n",pHead1->value);
//微软题目
pHead1 = pHead;
int len = ListLen(pHead);
merge(pHead,len);
while(pHead->next != NULL){
printf("%d->",pHead->value);
pHead = pHead->next;
}
printf("%d\n",pHead->value);
system("PAUSE");
return 0;
}
输出结果如下: