您的位置:首页 > Web前端

剑指Offer(反转链表)

2018-06-27 10:51 148 查看

链表一般我们建立的时候都会有一个头结点和一个尾节点,头结点没有存储值,只是起到指向下一个的作用,尾节点有数值,但是指向的下一个尾NULL,这个概念需要弄明白了才能去操作链表。那么如何构建一个标准的链表呢?

首先我们定义一个结构体:

struct ListNode
{
int val;
struct ListNode* next;
};
然后我们来创建链表:
ListNode *L;
ListNode *r,*p;
L=new ListNode;
r=L;
for(int i=0;i<5;i++)
{
p=new ListNode;
p->val=i;
r->next=p;
r=p;
}
r->next=NULL;
这是一种尾插法的方法来创建链表,L提供的便是链表的头结点,所以没有对它进行赋值,而是将直接指向了新节点p,再看看结尾,最后一个节点p加进去之后,r转移到链表的尾部,这个时候的链表并没有结束符,所以我们需要在最后加上r->next=NULL,来保证链表的完整性。

对于标准的链表,我们打印链表时自然不需要打印第一个头结点,后面所有的节点都需要被打印,因此我们可以很容易的想到通过判断节点的next来判断链表的走势。

r=L->next;
while(r!=NULL)
{
cout<<r->val<<" ";
r=r->next;
}
cout<<endl;
r的初始位置必须从头结点的下一个开始,这样便不会打印头结点的内容,而且头结点也不是我们想要的内容。

结果展示:


搞清楚链表的概念之后,我们再来看看链表的反转就容易多了。

反转链表便是将原来指向的后一个节点的方向改为指向前一个节点,那么对于原来的头结点,肯定是要抛弃的,而对于尾节点,则需要重新新建一个节点,我们大可不必这么麻烦,因为由于链表的特殊性,我们完全可以将原来的头结点重新指向链表的尾节点,让原本头结点的下一个节点指向NULL,毕竟总共的节点数没有变化。

class solution
{
public:
ListNode* ReverseList(ListNode* pHead)
{
if(pHead==NULL)
return NULL;
ListNode* pCurent,*pPrev,*pNext;
pCurent=pHead->next;
pPrev=NULL;

while(pCurent!=NULL)
{
pNext=pCurent->next;
if(pNext==NULL)
{
pCurent->next=pPrev;
pHead->next=pCurent;
return pHead;
}
pCurent->next=pPrev;
pPrev=pCurent;
pCurent=pNext;
}
}
};

好,我们来分析一下这个过程:首先,如果这个头结点是空的肯定返回错误。我们创建三个关键的节点pCurent代表当前的节点位置,pPrev代表前一个节点,pNext代表后一个节点。由于头结点的下一个节点才是真的节点,所以pCurent的初始值肯定为头结点的下一个,而第一次循环pCurent需要指向pPrev,这个时候的pCurent定然是尾节点了,所以pPrev肯定要初始为NULL,那么下一个节点pNext也当然是pCurent的下一个了。链表的第一次反转,即pCurent的第一次反转,pCurent指向了pPrev,pPrev需要向后移动一位(pPrev=pCurent),pCurent也需要向后移动一位(pCurent=pNext)。到了第二次循环的时候,pNext也重新跟新了。

那么何时结束循环呢,我们看到循环里的判断是:pCurent!=NULL,那就是说需要等到pCurent移动到原来链表的最后一位的下一个,那当然是一个NULL了,也就是说这个时候的pNext=NULL。所以我们在循环里加入了一个if判断,如果pNEXT==NULL了,那就说明链表到结尾了,这个时候被闲置的pHead便可以作为新的头结点并指向pCurent。

这里值得注意的是,if执行的时候不能直接返回中断函数,因为链表的最后阶段还没有完成,pCurent还需要指向前一个节点。

运行结果:


然而有的时候笔试给的链表不带有头结点,那么这个时候的变化是什么呢,因为没有头结点,所以翻转式pCurent的初始值变为pHead。

代码:
class solution
{
public:
ListNode* ReverseList(ListNode* pHead)
{
if(pHead==NULL)
return NULL;
ListNode* pCurent,*pPrev,*pNext;
pCurent=pHead;
pPrev=NULL;

while(pCurent!=NULL)
{
pNext=pCurent->next;
if(pNext==NULL)
{
pCurent->next=pPrev;
return pCurent;
}
pCurent->next=pPrev;
pPrev=pCurent;
pCurent=pNext;
}
}
};

阅读更多
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: