建议
最好先看代码,然后按照代码画图理解,还有问题可以看看b站视频看完还是得自己画画理解。(亲测有效)
建立链表
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
typedef struct Node{
int num;
struct Node* next;
}Node;
//初始化
Node* Begin(){
Node * head;
head=(Node*)malloc(sizeof(Node));
head->next=NULL;
return head;
}
//建立,尾插法
void Creat(Node* head){
Node*r,*s;
int num;
r=head;
while(1){
scanf("%d",&num);
if(num){
s=(Node*)malloc(sizeof(Node));
s->num=num;
r->next=s;
r=s;
}else break;
}
r->next=NULL;
}
//输出
void output(Node* head){
Node*p;
p=head->next;
while(p){
printf("%d ",p->num);
p=p->next;
}
}
int main(){
Node*ha,*hb;
ha=Begin();
printf("请输入数字:\n");
Creat(ha);
//hb=Begin();
//hb->next=reserve(ha);
printf("您反转后的数字为: \n");
reserve(ha);//选择hb后注释掉此行
output(ha);//看方法选择hb
}
头插法
原理:在建立链表的时候使得输入的数据按输入先后倒序存入(即最先存储的最终在尾结点以此类推),注意并不是原地反转。
代码实现:
//头插法倒转
void creat(Node*head){
Node*s,*r;
int num;
s->next=NULL;
while(1){
scanf("%d",&num);
if(num==0)break;
s=(Node*)malloc(sizeof(Node));
s->num=num;
s->next=head->next;
head->next=s;
}
}
类似头插法的原地反转
思路:
- 引入p,q;
- 让p指向链表的首元结点
- q指向p的下一个
- 让头结点指向空,即原链表成了空表,(仍能通过p得到原来结点的数据 )
- 利用p,q依次取出原链表的每一个元素并插入到头结点的后面–>实现逆序
(呜呜呜孩子还不会用电脑画流程图,凑活看吧…)
代码实现:
void reserve(Node*head){
Node*p,*q;
p=head->next;
head->next=NULL;
while(p){
q=p->next;
p->next=head->next;
head->next=p;
p=q;
}
}
迭代法
思路:
- 设置三个指针分别表示之前(pre),现在(cur),下一个(next)
- pre初始化为空,cur初始化为首元结点
- next指向cur的下一个;cur指向pre;pre跳到cur;cur跳到next…
- 重复3,直到cur为空,此时pre跳到了链表的尾结点,跳出循环 返回pre,
- 注意返回的pre不能直接做头结点因为他存数据了最好做首元结点
代码实现:
Node* reserve(Node*head){
Node *cur,*pre,*Next;
pre=NULL;
cur=head->next;
while(cur){
Next=cur->next;
cur->next=pre;
pre=cur;
cur=Next;
}
return pre;
}
递归法
思路:
- 不断调用自身(通过传入参数head->next,类似形成叠加图层)直到找出尾结点(new);
- 让当前层的head的下一个结点指向head自己,再让自己指向空;
- 像:…–>a–>b变成…->a<–b;
- 最终返回new作为首元结点(new存放数据了);
Node* reserve(Node*head){
//printf("11");
if(head->next==NULL){
return head;
//printf("dd");
}
else{
Node* new=reserve(head->next);
//printf("pp");
head->next->next=head;
head->next=NULL;
return new;
}
}
//用这个方法得output中条件改一下while(p->next)
好耶!!!你会了四种方法!!!