(C语言)链表逆置

题目:

将一个链表按逆序排列,即将链头当链尾,链尾当链头。
**输入提示:"\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;
    }
}  

 原文链接:链表逆置_本题要求实现一个函数,将给定单向链表逆置,即表头置为表尾,表尾置为表头。链表结-CSDN博客      

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值