今天想到一个链表逆转的简单算法,向大家介绍一下。
链表的定义大家都十分熟悉,我们不再累述。链表分文单链表和双向链表,谈到链表逆转,这里仅仅需要考虑单链表即可。因为双向链表的每个节点都有指向其前驱和后继的指针,用不到对其逆转。
如下图表示的单链表:
只需要额外定义三个临时节点指针,分别为crrt, pre和tail, crrt表示当前节点指针,pre表示前节点的前驱节点,tail表示当前节点后继节点指针。
算法思想分两个关键点,1 crrt为当前要逆转的节点,要把crrt的next指针从指向tail改为指向pre,所以要先用pre记录下crrt的前驱节点,crrt->next=pre就完成了当前节点的指针逆转,2 这一步骤完成之后,crrt节点需要向后移动,如果crrt->next的值没变,仍然指向其后继节点,那么向后移动节点我们可以使用crrt=crrt->next的方法,但是现在crrt->next已经改变成了指向前驱的指针,所以我们要用另一个tail指针指向crrt->next,向后移动当前指针,只需要crrt=tail即可。这样就完成了向后移动节点的工作。
算法复杂分析,首先来分析空间复杂度,上面也已经说的很清楚,只需要三个辅助的节点空间即可,不需要其他额外空间,所以时间复杂度为O(1)。然后再分析空间复杂度,三个指针一同从链表头到尾移动一趟,逆转的操作就可完成,所以时间复杂度为O(n)。
从理论上分析链表逆转的时间复杂度,最低也是O(n),因为要完成链表逆转,需呀对每个节点操作一次,对链表的每个节点都遍历一次的时间复杂度就是O(n)。所以本算法已经达到了最低的时间复杂度。如果有哪个朋友还有更简便的算法,希望不吝赐教。
算法的完整code:
typedef struct strlink{
char data;
struct strlink *next;
}strlink;
/* function name:translate, translate the string
param: the string that to be translate
return value: the list that have been translated
*/
strlink* translate( strlink* s)
{
static strlink* rtn;
if(NULL==s||NULL==s->next)
return NULL;
strlink *pre, *now, *tail;
now=s;
tail=now->next;
//pre=now;
//pre->next=NULL;
while(NULL!=tail)
{
pre=now;
now=tail;
tail=now->next;
now->next=pre;
}
pre=s;
pre->next=NULL;
s=now;
rtn=now;
return rtn;
}