方法一:
思路:如1->2->3->4,先1<-2,然后2<-3 一次类推
该方法是改变链表的整体结构,未创建一个新的链表
比喻:1 2 3 4 的顺序,先把1和2切下来,让2指向1,再把3切下来,让3指向2,最后把4切下来,让4指向3,最后头指针指向4
#include <stdio.h>
#include <stdlib.h>
typedef struct node {
int data;
struct node *next;
}Node;
// 请在此添加你的代码
/********** Begin *********/
void ShowList(Node *h)
{
while(h!=NULL)
{
printf("%d ",h->data );
h=h->next;
}
printf("\n");
}
Node *CreatList(void)
{
int n,i,data;
Node *p=NULL,*head=NULL,*tail=NULL;
scanf("%d",&n);
for(i=0;i<=n;i++)
{
p=(Node *)malloc(sizeof(Node));
if(i==0)
{
head=p;
tail=p;
}else{
scanf("%d",&data);
p->data =data;
p->next =NULL;
tail->next=p;
tail=p;
}
}
return head;//创建一个头节点是空的链表
}
Node *ReverseList(Node *h)
{
//思路:如1->2->3->4,先1<-2,然后2<-3 一次类推
//该方法是改变链表的整体结构,未创建一个新的链表
//比喻:1 2 3 4 的顺序,先把1和2切下来,让2指向1,再把3切下来,让3指向2,最后把4切下来,让4指向3
//最后头指针指向4
Node *p=NULL,*q=NULL,*head=NULL;
head=h;
p=h->next ;
h->next =NULL;
while(p)
{
//p是遍历链表的指针
q=p;// q是p的上一个节点
p=p->next ;
q->next=head;//head指向的是q的上一个节点
head=q;//让head指向下一个节点,即q
}//循环结束时,p=NULL,q指向的是旧链表的尾节点,新链表的头节点,起到了头指针的作用
Node *blank;
blank=(Node *)malloc(sizeof(Node));
blank->next =q;
q=blank;
return q;
}
void freenode(Node *head)
{
Node *p=head;
while(head!=NULL)
{
head=head->next ;
free(p);
p=head;
}
}
/********** End **********/
int main(void)
{
Node *phead;
phead = CreatList(); //phead指向的节点是空的
printf("链表逆置前的数据:\n");
ShowList(phead->next);//第一个节点是空的
phead = ReverseList(phead->next); //第一个节点是空的
printf("链表逆置后的数据:\n");
ShowList(phead->next ); //第一个节点是空的
free(phead);//释放空间
return 0;
}
方法2:
遍历数组,把每个节点用头插法创建一个新链表也可以起到逆置链表的作用
过程:1->2->3->4 , 空->1 2->3->4 , 空->1->2 3->4 , 空->1->2->3 4 , 空->1->2->3->4
#include <stdio.h>
#include <stdlib.h>
typedef struct node {
int data;
struct node *next;
}Node;
// 请在此添加你的代码
/********** Begin *********/
void ShowList(Node *h)
{
while(h!=NULL)
{
printf("%d ",h->data );
h=h->next;
}
printf("\n");
}
Node *CreatList(void)
{
int n,i,data;
Node *p=NULL,*head=NULL,*tail=NULL;
scanf("%d",&n);
for(i=0;i<=n;i++)
{
p=(Node *)malloc(sizeof(Node));
if(i==0)
{
head=p;
tail=p;
}else{
scanf("%d",&data);
p->data =data;
p->next =NULL;
tail->next=p;
tail=p;
}
}
return head;//创建一个头节点是空的链表
}
Node *ReverseList(Node *h)
{
Node *p=NULL,*q=NULL;
Node *head=NULL,*rhead=NULL;//新链表的头指针
rhead=(Node *)malloc(sizeof(Node));
//rhead是新链表头部的空节点
p=h;
q=h->next;
p->next =NULL;
while(p)
{
//p是遍历链表的指针
//q是p的下一节点
if(head==NULL)
{
//判断是否是第一个节点
head=p;
rhead->next=head;
}else{
//头插法
p->next=head;//1.先把新的节点的尾指针指向旧链表的第二个节点
rhead->next=p;//2.然后让旧链表头节点的尾指针指向p
head=p;//3.移动head的位置
}
p=q;
if(q==NULL)
{
break;//当p位于最后一个节点时,q指向NULL,q->next会越界
//因此在此判断是否遍历到最后一个节点然后跳出循环
}
q=q->next;
p->next =NULL;
}
return rhead;
}
void freenode(Node *head)
{
Node *p=head;
while(head!=NULL)
{
head=head->next ;
free(p);
p=head;
}
}
/********** End **********/
int main(void)
{
Node *phead;
phead = CreatList(); //phead指向的节点是空的
printf("链表逆置前的数据:\n");
ShowList(phead->next);//第一个节点是空的
phead = ReverseList(phead->next); //第一个节点是空的
printf("链表逆置后的数据:\n");
ShowList(phead->next);//第一个节点是空的
freenode(phead);//释放空间
return 0;
}
方法3:就地逆置法
先假定有一个函数,可以将以head
为头结点的单链表逆序,并返回新的头结点。利用这个函数对问题进行求解:将链表分为当前表头结点和其余部分,递归的过程就是,先将表头结点从链表中拆出来,然后对其余部分进行逆序,最后将当前的表头结点链接到逆序链表的尾部。递归的终止条件就是链表只剩一个节点时,直接返回这个节点。
过程:1->2->3->4 ---> 3<-4 ---> 2<-3<-4 ---> 1<-2<-3<-4
#include <stdio.h>
#include <stdlib.h>
typedef struct node {
int data;
struct node *next;
}Node;
// 请在此添加你的代码
/********** Begin *********/
void ShowList(Node *h)
{
while(h!=NULL)
{
printf("%d ",h->data );
h=h->next;
}
printf("\n");
}
Node *CreatList(void)
{
int n,i,data;
Node *p=NULL,*head=NULL,*tail=NULL;
scanf("%d",&n);
for(i=0;i<n;i++)
{
p=(Node *)malloc(sizeof(Node));
scanf("%d",&data);
p->data =data;
if(i==0)
{
head=p;
tail=p;
}else{
p->next =NULL;
tail->next=p;
tail=p;
}
}
return head;
}
Node *converse(Node *head)
{
Node *newHead;
if(head==NULL||head->next==NULL)
return head;
/*递归*/
newHead=converse(head->next);
/*回溯:将当前表头结点链接到逆序链表的尾部*/
head->next->next=head;
head->next=NULL;
return newHead;
}
/********** End **********/
int main(void)
{
Node *phead;
phead = CreatList();
printf("链表逆置前的数据:\n");
ShowList(phead);
phead = converse(phead);
printf("链表逆置后的数据:\n");
ShowList(phead);
return 0;
}
小结
注意:如果适用头插法创建一个链表,需要在头部放一个空节点,否则输入1 2 3 4时,排放的顺序为1 4 3 2 ,尾插法则不需要,但链表有一个空的头结点会方便删除和增加节点。