什么是反转链表
反转链表,又可以称为翻转或逆置链表,如下图所示:
即让第一个表元变成最后一个表元,第二个表元变成倒数第二个表元.....最后一个表元变成第一个表元
本文介绍三种方法,其他方法皆大同小异。
三种方法中:第一种方法采用在自身链表中进行操作,不引入其他任何链表。后两种方法采取引入一个工作链表,将反转后的链表放到工作链表里面。
先给出基本的结构:
#include <stdio.h>
#include <stdlib.h>
struct intnode {
int value;
struct intnode *next;
} *q, *q1, *q2;
void show(struct intnode *p) {
while (p) {
printf("%d ", p->value);
p = p->next;
}
}
q,q1,q2用来取值,进而验证反转的正确性
法一:循环颠倒指向:
从第一个开始颠倒,直到最后一个,简单朴实,注意的是颠倒之后,指针指向完全颠倒,即head指向了原来的最后一个表元
struct intnode *reverse(struct intnode *head) {
struct intnode *pre, *cur, *t;//t是辅助表元,pre是前驱,cur是后驱
pre = NULL;
cur = head;
while (cur != NULL) {//关键就在这往下四行
t = cur->next;//保护cur的后继指针,以免丢失
cur->next = pre;//让cur指向pre
pre = cur;//调整pre为cur
cur = t;//cur指向下一个,进行下一次循环颠倒
}
return pre;
}
当然,为了完备性,上述应该再考虑head=NULL的情况,但上述并未进行考虑。其中,while循环中的四行代码是这个方法的关键。请读者细细品味。
在这里,我们把颠倒后的链表返回。所以构建了struct intnode * reverse函数,当然也可以用void,直接将反转后的链表输出,而不再返回。
void reverse(struct intnode *head) {//当然,法一不返回结构指针也可以,同理下述
struct intnode *pre, *cur, *t;//t是辅助表元,pre是前驱,cur是后驱
pre = NULL;
cur = head;
while (cur != NULL) {//关键就在这往下四行
t = cur->next;//保护cur的后继指针,以免丢失
cur->next = pre;//让cur指向pre
pre = cur;//调整pre为cur
cur = t;//cur指向下一个,进行下一次循环颠倒
}
show(pre);
}
法二:头插法插入到工作链表:
引入工作链表,通过头插法,把链表按顺序插入到工作链表中
struct intnode *reverse(struct intnode *head) {//头插法
struct intnode *new_head = NULL, *temp = NULL;
if (head == NULL || head->next == NULL)
return head;
while (head != NULL) {
temp = head; //将 temp 从 head 中摘除
head = head->next;
temp->next = new_head; //将 temp 插入到 new_head 的头部
new_head = temp;
}
return new_head;
}
在这里,关键的也是while之中的四行代码,把需要反转的链表,按顺序依次,头插法插入工作链表中,这样,新形成的工作链表就是反转好的链表。
法三:递归插入到工作链表:
引入工作链表,通过递归,实现反转。
struct intnode *reverse(struct intnode *head) {
if (head == NULL || head->next == NULL)
return head;
else {
struct intnode *new_head = reverse(head->next);//通过递归,从前往后依次颠倒
head->next->next = head;
head->next = NULL;
return new_head;
}
}
进而,主函数内随便给链表取值,验证下结果正确性
int main() {
q = (struct intnode *)malloc(sizeof(struct intnode));
q1 = (struct intnode *)malloc(sizeof(struct intnode));
q2 = (struct intnode *)malloc(sizeof(struct intnode));
q->next = q1;
q1->next = q2;
q2->next = NULL;
q->value = 1;
q1->value = 2;
q2->value = 3;//随便初始化几个值来验证最后结果
show(q);
printf("\n");
q = reverse(q);
show(q);
return 0;
}
完整代码
#include <stdio.h>
#include <stdlib.h>
struct intnode {
int value;
struct intnode *next;
} *q, *q1, *q2;
void show(struct intnode *p) {
while (p) {
printf("%d ", p->value);
p = p->next;
}
}
/*法一:循环颠倒指向:从第一个开始颠倒,直到最后一个,简单朴实,注意的是
颠倒之后,指针指向完全颠倒,即head指向了原来的最后一个表元
另注:返回一个指针,函数要用指针类型的* */
struct intnode *reverse(struct intnode *head) {
struct intnode *pre, *cur, *t;//t是辅助表元,pre是前驱,cur是后驱
pre = NULL;
cur = head;
while (cur != NULL) {//关键就在这往下四行
t = cur->next;//保护cur的后继指针,以免丢失
cur->next = pre;//让cur指向pre
pre = cur;//调整pre为cur
cur = t;//cur指向下一个,进行下一次循环颠倒
}
return pre;
}
void reverse(struct intnode *head) {//当然,法一不返回结构指针也可以,同理下述
struct intnode *pre, *cur, *t;//t是辅助表元,pre是前驱,cur是后驱
pre = NULL;
cur = head;
while (cur != NULL) {//关键就在这往下四行
t = cur->next;//保护cur的后继指针,以免丢失
cur->next = pre;//让cur指向pre
pre = cur;//调整pre为cur
cur = t;//cur指向下一个,进行下一次循环颠倒
}
show(pre);
// head=pre;
}
/*法二:递归:通过递归,把反转后的链表放到新的链表里面*/
struct intnode *reverse(struct intnode *head) {
if (head == NULL || head->next == NULL)
return head;
else {
struct intnode *new_head = reverse(head->next);//通过递归,从前往后依次颠倒
head->next->next = head;
head->next = NULL;
return new_head;
}
}
/*法三,同法二,但不递归:通过头插法,把反转后的链表放到新的链表里面*/
struct intnode *reverse(struct intnode *head) {//头插法
struct intnode *new_head = NULL, *temp = NULL;
if (head == NULL || head->next == NULL)
return head;
while (head != NULL) {
temp = head; //将 temp 从 head 中摘除
head = head->next;
temp->next = new_head; //将 temp 插入到 new_head 的头部
new_head = temp;
}
return new_head;
}
int main() {
q = (struct intnode *)malloc(sizeof(struct intnode));
q1 = (struct intnode *)malloc(sizeof(struct intnode));
q2 = (struct intnode *)malloc(sizeof(struct intnode));
q->next = q1;
q1->next = q2;
q2->next = NULL;
q->value = 1;
q1->value = 2;
q2->value = 3;//随便初始化几个值来验证最后结果
show(q);
printf("\n");
reverse(q);
show(q);
return 0;
}