第一种:将整个链表一分为二(一个小链表,一个大链表),小链表包括头结点和首元结点,大链表是除这两个结点之外的整个链表的结点。(前提这不是空表。可以只看王道的代码不看这种)
从后面的大链表中依次取出一个结点头插法插入小链表中直至取完所有结点。
注:我们需要声明两个指针s和b,s初期用来将链表分为两个,后期用来做工作指针。b用来保存和更新大链表的每个结点的地址
初始操作:声明指针s指向首元结点,声明指针b指向首元结点的后继结点(即保存了大链表的第一个结点地址),然后将首元结点的next指针置位NULL。这样我们就成功的将链表分为两个链表了。
循环操作:每次只要b不为NULL就进入循环,然后将p指向b,p的next指向L的next,L的next指向p,b指向b的后继
// An highlighted block
LinkList Reverse_1(LinkList L){
Lnode *s,*b;
s=L->next; //small指针指向首元结点
b=s->next //big指针指向大链表的第一个结点
s->next=NULL;//大小链表实现分离
while(b!=NULL){ // 大链表不为空,继续取结点。
s=b; // small指针取大链表的第一个结点
b=b->next; //更新下次要取的大链表的结点
s->next=L->next //头插法插入小链表
L->next=s;//同上
}
return L
}
王道书上是,小链表只有头结点,大链表包括所有数据结点。原理基本一样
//
LinkList Reverse_1(LinkList L){
Lnode *p,*r;//p为工作指针,r为p的后继,以防断链
p=L->next; //从第一个元素结点开始
L->next=NULL;//先将头结点L的next置为NULL,实现大小链表独立
while(p!=NULL){ // 依次将大链表的元素结点摘下
r=p->next; // 暂存p的后继
p->next=L->next ; // 头插法
L->next=p;// 头插法
p=r;
}
return L;
}
第二种:先撇开头结点,将元素结点从首元结点开始依次反转。元素结点反转链接完成之后,此时p指针指向现在反转链表的第一个元素结点也就是首元结点,只需将头结点链接上他,反转完成。
假设当链表有三个元素结点时,在操作之前首先将现在的首元结点未来的尾结点的next域指向NULL。可以想象一下只有三个元素结点存在,当前p指针已经指向了第一个,且第一个结点的next指向NULL,我们需要将第二个结点的next域指向第一个,且保证更改第二个next域时不会丢失第三个结点的地址,所以我们需要一个r指针来保存这个结点(或链表有更多结点时)的地址,当p指向第二个结点时,r指针保存了第三个结点的地址,但是p已经指向了第二个了,没办法找到第一个节点的地址,所以还需要一个pre指针指向p的前驱结点。由于每次循环,p指针操作都完成了一个链表结点的反转,且是在循环中p取代了r再做反转操作,r继续指向后继结点,所以判断是否到了链表尾,是否该结束则应该是利用r指针。
即 pre=p; p=r;r=r->next;p->next=pre;
总结:p是工作指针,利用r指针保存的p的后继地址来遍历每个结点,利用pre指针,使得每个结点的next指向其前驱结点
LinkList Reverse_2(LinkList L){
Lnode *pre,*p=L->next,*r=p->next;
p->next=NULL;
while(r!=NULL){ //r为空说明是最后一个结点
pre=p; //依次遍历
p=r;
r=r->next;
p->next=pre; //指针反转
}
L->next=p; //处理最后一个结点
retrun L;
}