链表反转即假设有一链表1->2->3,反转后为3->2->1
以下的方法是没有头节点只有首元节点的情况
方法一:迭代法
如图所示,创建三个指针。小方块从左到右的值分别为1、2、3,假设
是以1->2->3的方向,那么,如果想实现链表反转,可以让中间的mid指针
从原来指向end变为指向pre,然后三个指针整体向右移动,mid再指向pre,直到end指向了NULL为止。最后让头指针指向mid即可,此时方向变为3->2->1
代码如下:
#include<Stdio.h>
#include<Stdlib.h>
typedef struct Node{
int elem;
struct Node *next;
}node;
node *initNode(){
node *end=(node *)malloc(sizeof(node));//尾指针
node *p=(node *)malloc(sizeof(node));//首元节点
p->elem=1;
p->next=NULL;
end=p;
for(int i=2;i<=3;i++){
node *newnode=(node *)malloc(sizeof(node));
newnode->elem=i;
newnode->next=NULL;
//尾插法
end->next=newnode;
end=newnode;
}
return p;
}
void show(node *p){
node *temp=p;
while(temp){
printf("%d",temp->elem);
temp=temp->next;
}
printf("\n");
}
node *iteration(node *p){
if(p==NULL||p->next==NULL){
return p;
}else{
node *pre=NULL;
node *mid=p;
node *end=p->next;
while(true){
mid->next=pre;
if(end==NULL){
break;
}
//整体右移
pre=mid;
mid=end;
end=end->next;
}
p=mid;//原来的头指针指向mid(因为此时mid为首元节点)
return p;
}
}
int main(void){
node *p=initNode();
show(p);
p=iteration(p);
show(p);
return 0;
}
方法二:递归法
该方法是通过递归,使得指针指向最后一个结点,然后从后往前改变指针的指向,从而实现反转。
有几点需要注意的:
1.需要建立一个头指针,返回该头指针。
2.需要建立一个从后往前递归的指针,从而不断地改变指针指向,即
head->next->next=head;
3.最重要的一点!!!
必须把原来结点的指针域置空,即head->next=NULL;不然,请看第二张图:
由于我们马上要写的函数当head指针指向1的时候,便结束循环,如果我们只写head->next->next=head;前面的2和3的指针域与确实分别指向1和2;
但是1的指针域指向的是2,当我们遍历的时候,由于循环结束的条件是:
while(temp){
temp=temp->next;
}
当temp指针指向1的时候,temp->next指向2,即temp此时指向2,然后while循环判断不为空,从而执行temp=temp->next,又指向了1。1和2之间就形成了一个循环链表,永远不会结束循环,你会在屏幕上看到2121212121无限循环…,所以必须把原来的指针域置空!!!!
代码如下:
#include<stdio.h>
#include<stdlib.h>
typedef struct Node{
int elem;
struct Node *next;
}node;
node *initNode(){
node *end=NULL;
node *p=(node *)malloc(sizeof(node));
p->next=NULL;
p->elem=1;
end=p;
for(int i=2;i<3;i++){
node *newnode=(node *)malloc(sizeof(node));
newnode->next=NULL;
newnode->elem=i;
end->next=newnode;
end=newnode;
}
return p;
}
void show(node *p){
node *temp=p;
while(temp){
printf("%d ",temp->elem);
temp=temp->next;
}
printf("\n");
}
node *recursion(node *p){
if(p==NULL||p->next==NULL){
return p;
}else{
node *newnode = recursion(p->next);
p->next->next=p;
p->next=NULL;
return newnode;
}
}
int main(void){
node *p=initNode();
show(p);
p=recursion(p);
show(p);
return 0;
}
有一点需要提一下:
node *newnode = recursion(p->next);
…
return newnode;
返回值是newnode,这个值不变,一直指向末尾(即反转后链表的头指针)
而每次返回p都会左移,直到移动到原链表第一个结点为止。
方法三:新建链表
该方法是新建一个链表,然后循环要反转的链表中的每个元素,通过头插法(因为头插法会改变数据原来的顺序,正好适合反转)插入到新链表中的方法。
在这里提一下:
有头结点和没有头结点的头插法写法是不一样的,而尾插法写法是一样的
有头结点的头插法:
node *head;//头结点
head->next=NULL;
node *newnode=(node *)malloc(sizeof(node));
newnode->next=head->next;
head->next=newnode;
没有头结点的头插法:
node *p;//首元节点
p->elem=xxx;
p->next=NULL;
node *newnode=(node *)malloc(sizeof(node));
newnode->next=p;
p=newnode;
无论是否有头结点的尾插法:
node *end=NULL;//尾指针
node *head=(node *)malloc(sizeof(node));//有头结点
//只有首元结点则node *p=(node *)malloc(sizeof(node));和上面一样
head->next=NULL;
end=head;
node *newnode=(node *)malloc(sizeof(node))
end->next=newnode;
end=newnode;
代码如下:
#include<stdio.h>
#include<stdlib.h>
typedef struct Node{
int elem;
struct Node *next;
}node;
node *initNode(){
node *end=NULL;
node *p=(node *)malloc(sizeof(node));
p->next=NULL;
p->elem=1;
end=p;
for(int i=2;i<4;i++){
node *newnode=(node *)malloc(sizeof(node));
newnode->next=NULL;
newnode->elem=i;
end->next=newnode;
end=newnode;
}
return p;
}
void show(node *p){
node *temp=p;
while(temp){
printf("%d ",temp->elem);
temp=temp->next;
}
printf("\n");
}
node *head(node *p){
node *new_p=NULL;
node *temp=NULL;
if(p==NULL||p->next==NULL){
return p;
}
while(p){
temp=p;
p=p->next;
temp->next=new_p;
new_p=temp;
}
return new_p;
}
int main(void){
node *p=initNode();
show(p);
p=head(p);
show(p);
return 0;
}
注意一点:
while(p){
temp=p;
p=p->next;
temp->next=new_p;
new_p=temp;
}
这部分代码中,p=p->next必须在temp=p后面,如果放在最后面,由于
temp->next=new_p,使得temp指向的结点到后面所有结点的链断了(因为该节点的指针域不指向后面而指向new_p了),但是此时p也指向该结点,所以,此时的p=p->next为NULL(因为断链了)
方法4:在原链表上直接反转
思路是这样的:我们需要创建两个指针,如下图(图中有一个头指针p没画出来)。然后把第二个结点移除,操作类似于删除结点,就是让第一个结点的指针域指向第三个结点,
即pre->next=end->next,然后让第二个结点指向第一个结点,
即end->next=p,然后p指向end,接下来让end指针指向pre->next,即第三个结点。一直循环下去,直到end为NULL。
代码如下:
#include<stdio.h>
#include<stdlib.h>
typedef struct Node{
int elem;
struct Node *next;
}node;
node *initNode(){
node *end=NULL;
node *p=(node *)malloc(sizeof(node));
p->next=NULL;
p->elem=1;
end=p;
for(int i=2;i<4;i++){
node *newnode=(node *)malloc(sizeof(node));
newnode->next=NULL;
newnode->elem=i;
end->next=newnode;
end=newnode;
}
return p;
}
void show(node *p){
node *temp=p;
while(temp){
printf("%d ",temp->elem);
temp=temp->next;
}
printf("\n");
}
pre=mid;
mid=end;
end=end->next;
}
p=mid;
return p;
}
}
node *recursion(node *p){
if(p==NULL||p->next==NULL){
return p;
}else{
node *newnode = recursion(p->next);
p->next->next=p;
p->next=NULL;
return newnode;
}
}
node *head(node *p){
node *new_p=NULL;
node *temp=NULL;
if(p==NULL||p->next==NULL){
return p;
}
while(p){
temp=p;
p=p->next;
temp->next=new_p;
new_p=temp;
}
return new_p;
}
node *local(node *p){
node *pre=NULL;
node *end=NULL;
if(p==NULL||p->next==NULL){
return p;
}
pre=p;
end=p->next;
while(end){
pre->next=end->next;
end->next=p;
p=end;
end=pre->next;
}
return p;
}
int main(void){
node *p=initNode();
show(p);
p=recursion(p);
show(p);
p=head(p);
show(p);
p=local(p);
show(p);
return 0;
}