我写博客是为了把我自己学到的东西在加深一下印象,希望大家多多指出错误,万分感谢
为了下面方便写子函数,我先把主函数放在前面
#include<stdio.h>
#include<stdlib.h>
struct Node* creatlist(struct Node* head,int n);
struct Node*filplist(struct Node* head);
typedef struct Node{
int num;
struct Node *next;
}node;
int main()
{
node *head=(node*)malloc(sizeof(node));
head->next=NULL;
int n;
printf("输入n:");
scanf("%d",&n);
head=creatlist(head,n);
head=filplist(head);
return 0;
}
node* creatlist(node* head,int n)
{
node *tail,*p;
tail=head;
printf("输入%d个数:",n);
for(int i=0;i<n;i++)
{
p=(node*)malloc(sizeof(node));
scanf("%d",&p->num);
tail->next=p;
tail=p;
}
tail->next=NULL;// 特别重要
return head;
}
一.原地反转法
大家先看一下下面这张图
一开始的初始状态就是第一行的状态,p指针始终在1号结构体上,而q指针指向的结构体就要移到前面去。
第一步就是先让p连上q后面的那个结构体,防止丢失,所以对应的代码为
p=q->next;
第二部就是让q连上p,在让head连上q,所以对应的代码为
q->next=head->next;
head->next=q;
第三步就是再让q到p的前面去,
q=p->next;
后面就依次循环就可以了
而循环的条件是什么呢
看上面的图就可以发现,当程序结束时,q指针指向的是NULL,
所以,我们可以用q !=NULL作为循环结束的条件
接下来我以子函数的形式来写这个程序
struct Node*filplist(struct Node* head)
{
node *p,*q;
p=head->next;
q=head->next->next;
while(q!=NULL)
{
p=q->next;
q->next=head->next;
head->next=q;
q=p->next;
}
return head;
}
以上就是原地反转链表的代码了
二 .头插法反转链表
我写的链表基础这篇博客上说到过用头插法来创建链表是得到的结果是与我们输入的结果相反的,所以我们可以利用头插法来反转链表
话不多说,先看图
看到初始状态,p指向1号结构体,而head的指向的是NULL,这就是初始状态
接下来,通过图不难看出p指向的结构体就是要接到head后面的结构体
第一步就是要先把p指向的下一个结构体用指针q保存下来,所对应的代码为:
q=p->next;
第二步要把p所指向的结构体接到head后面,所对应的代码为:
p-next=head->next;
head->next=p;
第三步就是让p跑到q所在的位置,所对应的代码为:
p=q;
后面就是通过循环来解决了,同样是用while循环来实现,可以看到上图,循环结束的时候p指针是指向NULL的,所以循环终止的条件为p!=NULL。
接下来我以子函数的形式来写这个程序
struct Node*filplist(struct Node* head)
{
node *p,*q;
p=head->next;
head->next=NULL;
while(p!=NULL)
{
q=p->next;
p->next=head->next;
head->next=p;
p=q;
}
return head;
}
以上就是头插法反转链表的代码了
注意:创建链表时最后的一个结构体一定要指向NULL,否则在后续的运行中会出现码指针越界的情况(我踩过的坑)
本人还在刚刚开始学数据结构,对递归和迭代还不清楚,所以只会这两种笨的方法了
以上就是两种关于反转链表的方法了,欢迎大家多多指出错误和提供更好的解决方案。