通常会碰到这个题目,相信这实际开发中这个问题也很有用途。开始遇到这个问题的时候,我相信大家都能容易想到解决这个问题最通用的方法,就是设置三个变量,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 d c b a
a b c d e f