单链表的反转,原来还可以反转的这么艺术

本文介绍三种实现单链表反转的有效方法:通过三个指针遍历调整、利用栈的特性后进先出以及构建新链表。分析了每种方法的时间和空间复杂度,并提供了详细的C语言代码示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

通常会碰到这个题目,相信这实际开发中这个问题也很有用途。开始遇到这个问题的时候,我相信大家都能容易想到解决这个问题最通用的方法,就是设置三个变量,p,q,t,分别指向三个节点,然后遍历一遍单链表,改变各个节点的指针的指向,但是这个方法会很绕,如果没有清晰的思路很容易把自己绕晕。下面贴上应用三个指针的代码,大家看懂代码之后我在继续分析。
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
typedef struct Node
{
        char data;
        struct Node *next;
}Node,*LinkList;
void create_list(LinkList *head)
{
        int n;
        int i;
        char data;
        Node *temp,*p;
        printf("input the node numbers:");
        scanf("%d",&n);
        for(i=0;i<n;i++)
        {
                scanf("%c",&data);
                p=(Node*)malloc(sizeof(Node));
                p->data=data;
                p->next=NULL;
                if((*head)==NULL)
                {
                        (*head)=p;
                        temp=p;
                }
                else
                {
                        temp->next=p;
                        temp=p;
                        p=NULL;
                }
        }
}
void print_list(LinkList head)
{
        Node *p=head;
        while(p!=NULL)
        {
                printf("%c\t",p->data);
                p=p->next;

        }
        printf("\n");
}
void inverse_list(LinkList *head)
{
        if((*head)==NULL||(*head)->next==NULL)
                return;
        Node *p,*q,*t;
        p=*head;
        q=p->next;
        p->next=NULL;//注意,很重要,要不然就会出现无限循环
        while(q->next!=NULL)
        {
                t=q->next;
                q->next=p;
                p=q;
                q=t;
        }
        q->next=p;
        *head=q;
}
int main(void)
{
        LinkList head=NULL;
        LinkList h;
        create_list(&head);
        print_list(head);
        inverse_list(&head);
        print_list(head);
        h=_inverse_list(head);
        print_list(h);
        return 0;
}

注意代码中的那个标注,要不然会造成无限的循环打印。其实只要有个清晰的思路,这个也不会搞晕的,但是下面还有更简单的方法,那就是使用栈。可以一次遍历链表,把链表中的各个节点存入到堆栈中,然后在操作栈,因为栈的特性是后进先出,那么这样很简单的就可以把链表反转。

看下上面两个思路的效率吧,因为第一个个涉及到两个指针的重新指向,时间复杂度是n的4倍,而操作栈也要n的两倍,而且需要空间的开销,这两个算法都不是很好。

下面给出第三种方法。那就是重新设置一个头节点,让其代表一个心的链表,然后依次遍历之前给定的链表,每次遍历取出一个节点,插入到新链表的开头,那么这样一次遍历之后就重新建立了一个链表,而且是之前链表的反转,说的可能不太明白,但是直接上代码,大家要是想弄的清晰的话可以画图,会很清新的。总之一点就是把新读取的节点插入到头节点之前。

Node *_inverse_list(LinkList head)
{
        if(head==NULL||head->next==NULL)
                return head;
        Node *h=NULL;
        Node *p=head;
        while(head)
        {       p=head->next;
                head->next=h;
                h=head;
                head=p;
        }
        return h;
}
编译程序:gcc -Wall inverse.c -o inverse

输入为6abcdef

打印结果为:

a b c d e  f
f e b  a
a b e  f

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值