题目:
将一个链表按逆序排列,即将链头当链尾,链尾当链头。 **输入提示:"\n请输入链表(非数表示结束)\n" **输入提示:"结点值:" **输出提示:"\n原来表:\n" **输出格式:"%4d" **输出提示:"\n\n反转表:\n" **输出格式:"%4d" 程序的运行示例如下: 请输入链表(非数表示结束) 结点值:3 结点值:4 结点值:5 结点值:6 结点值:7 结点值:end 原来表: 3 4 5 6 7 反转表: 7 6 5 4 3
思想:
1.输入:
(1)通过scanf的返回值看是否输入成功,若为0则输入失败,故可直接作为进入循环的条件。
(2)因为直接将结点值输入结点需要先创立结点,故可先将数据放在一个temp里,若判断是数字,再创立结点将数据放进去。
2.逆置:
逆置的主要思想为先正向链接结点,再从前开始反向连接,我用了两种方法。
法一:
完整代码:
#include <stdio.h>
#include<stdlib.h>
struct line
{
int num;
struct line *next;
}*p1, *p2;
struct line *creat()
{
int temp;
struct line *head = NULL;
printf("\n请输入链表(非数表示结束)\n结点值:");
while (scanf("%d", &temp))
{
p1 = (struct line *)malloc(sizeof(struct line));
(head == NULL) ? (head = p1) : (p2->next = p1);
p1->num = temp;
printf("结点值:");
p2 = p1;
}
p2->next = NULL;
return head;
}
output(struct line *outhead)
{
for (p1 = outhead; p1 != NULL; printf("%4d", p1->num), p1 = p1->next);
{
}
}
struct line *turnback(struct line *oldhead)
{
struct line* p, *s, *head;
head->next = oldhead;
p = oldhead;
head->next = NULL;
if(p->next == NULL)
{
return p;
}
else
{
do
{
s = p;
p = p->next;
s->next = head->next;
head->next = s;
}while(p->next != NULL);
}
p->next = head->next;
head->next = NULL;
return p;
}
int main(void)
{
struct line *head;
head = creat();
printf("\n原来表:\n");
output(head);
head = turnback(head);
printf("\n\n反转表:\n");
output(head);
return 0;
}
剖析:
struct line *turnback(struct line *oldhead)
{
struct line* p, *s;
struct line* head;//创立一个空的头结点,作为中间站,是该方法的核心
head->next = oldhead;//将空结点与传入的链表相连接
p = oldhead;//再创立一个结点p指向传入的链表的头结点,也可以不创立
head->next = NULL;//先将空结点的指针域置空
if(p->next == NULL)//判断是否只有一个结点,因为后续循环用的是do while,若只有一个节点,进入了循环会出错
{
return p;
}
else
{
do
{
s = p;//创立一个s,和p指向同一个结点,因为下一步会将p后移一位,故相当于s标记了p前面一个结点
p = p->next;
s->next = head->next;//将s的指针指向head指向的地方
head->next = s;//第一次s指向head指向的地方,是NULL,作为新链表的尾结点,后续将head的指针指向s,作为标记p前面的那一个结点,以保后续s指向下一个结点了,还能和前一个结点连接上
}while(p->next != NULL);
}
p->next = head->next;
head->next = NULL;//完成逆置后再将head和链表断开
return p;
}
原文链接:链表逆置详细讲解(图文)-CSDN博客
法二:
完整代码:
#include <stdio.h>
#include<stdlib.h>
struct line
{
int num;
struct line *next;
}*p1, *p2;
struct line *creat()
{
int temp;
struct line *head = NULL;
printf("\n请输入链表(非数表示结束)\n结点值:");
while (scanf("%d", &temp))
{
p1 = (struct line *)malloc(sizeof(struct line));
(head == NULL) ? (head = p1) : (p2->next = p1);
p1->num = temp;
printf("结点值:");
p2 = p1;
}
p2->next = NULL;
return head;
}
void output(struct line *outhead)
{
for (p1 = outhead; p1 != NULL; printf("%4d", p1->num), p1 = p1->next);
{
}
}
struct line *turnback(struct line *head)
{
struct line *p=NULL,*tmp1=NULL,*tmp2=NULL;
p=head;
while(p)
{
//解决链表只有一个结点问题
if(p->next==NULL)
{
return p;
break;
}
if(tmp1==NULL)
{
tmp1=p->next;
p->next=NULL;
}
else
{
tmp1=tmp2;
}
//解决链表只有两个结点问题
if(tmp1->next==NULL)
{
tmp1->next=p;
return tmp1;
break;
}
tmp2=tmp1->next;
tmp1->next=p;
//对tmp2指针指向最后一个结点的处理
if(tmp2->next==NULL)
{
tmp2->next=tmp1;
return tmp2;
break;
}
p=tmp1;
}
}
int main()
{
struct line *head;
head = creat();
printf("\n原来表:\n");
output(head);
head = turnback(head);
printf("\n\n反转表:\n");
output(head);
return 0;
}
剖析:
主要思想:
(1)创立三个指针,依次指向第一个结点,第二个结点,第三个结点,然后后续先将三个结点通过temp1 = p->next, temp2 = temp1->next连接起来。
(2)然后通过temp1->next = p将前两个结点逆置,第三个指针用于保证一直和链表连着。
(3)然后通过p = temp1, temp1 = temp2, temp2 = temp1->next将三个指针整体向右移动一个。
struct line *turnback(struct line *head)
{
struct line *p=NULL,*tmp1=NULL,*tmp2=NULL;
p=head;
while(p)
{
if(p->next==NULL)//判断是否只有一个结点
{
return p;
break;
}
if(tmp1==NULL)//判断是否是第一个结点,因为第一个结点变成尾结点,指针域需置空
{
tmp1=p->next;
p->next=NULL;
}
else
{
tmp1=tmp2;
}
if(tmp1->next==NULL)//判断是否只有两个结点
{
tmp1->next=p;
return tmp1;
break;
}
tmp2=tmp1->next;
tmp1->next=p;
//对tmp2指针指向最后一个结点的处理
if(tmp2->next==NULL)
{
tmp2->next=tmp1;
return tmp2;
break;
}
p=tmp1;
}
}