单链表的翻转也算是面试中常见的面试题目了,本文根据网上查阅的资料给大家总结了两种方法。
准备:
首先,我们先来看我们节点和函数的定义,以及客户端应用:
#include <stdio.h>
#include <stdlib.h> //提供malloc()
//节点结构
struct Node{
int val;
struct Node * next;
};
typedef struct Node node,* list;
//单链表翻转函数
//一、新建链表,头结点插入法
list func1(list head);
//二、就地翻转,改变原链表
list func2(list head);
//客户端
int main(void){
//带翻转链表
list mylist = (list)malloc(sizeof(node));
mylist -> val = 1;
mylist -> next = NULL;
int i = 2;
node * cur = mylist;
while(i < 6){
node * pnode = (node *)malloc(sizeof(node));
pnode -> val = i;
cur -> next = pnode;
cur = cur -> next;
i ++;
}
//函数调用
//cur = func1(mylist);
cur = func2(mylist);
while(cur){
printf("%d ",cur -> val);
cur = cur -> next;
}
return 0;
}
接下来我们来看我们的两个单链表翻转方法:
一、新建链表,头结点插入法:
该方法的思想是:新建链表,遍历原链表,将每个节点逐一插入到新建链表的头部,最后新建链表就是原链表的翻转形式。
代码:
list func1(list head){
//新链表
list newList = (list)malloc(sizeof(node));
if(head == NULL || newList == NULL){
return NULL;
}
node * pnew = newList; //新链表头结点指针
node * pold = head; //原链表遍历节点指针
node * tmp;
//初始化
pnew -> val = pold -> val;
pnew -> next = NULL;
pold = pold -> next;
while(pold){
tmp = (node *)malloc(sizeof(node));
tmp -> val = pold -> val;
tmp -> next = pnew;
pnew = tmp; //在新链表头部插入
pold = pold -> next;
}
return pnew; //返回新链表
}
二、就地翻转
就地翻转就是改变原来的链表,不增加新链表。
思想:每次都将原第一个节点之后的那个节点放在链表的开头处,我们来看看一个例子:
原序列是 1 2 3 4 5 ,原第一个节点是 1 ,将 1 后的 2 放在链表的开头处,变成 2 1 3 4 5 ,再将 1 后面的 3 放在链表的开头处,变成 3 2 1 4 5 ……..直到 1 后面没有元素,翻转结束。
代码:
list func2(list head){
if(head == NULL){
return NULL;
}
node * pone = head; //这个指针指向原来的第一个节点,该指针保持不变
node * p1 = pone -> next; //原第一个节点后面的第一个元素
node * p2;
while(p1){ //原第一个节点后面的第一个元素为空时翻转完成
p2 = p1 -> next;
p1 -> next = head;
head = p1;
pone -> next = p2;
p1 = pone -> next;
}
return head; //返回翻转后的头指针
}
结尾:
网上还有提供其他的方法如:
- 类似第二个方法,我们可以将前面的节点移动到原来的最后一个节点的后面。
- 遍历链表,将节点放到数组中,然后逆序遍历数组输出的新的链表中。
后面提到的方法大家可以试试。
关于这个问题的资源网上好多,这里仅仅做记录,大神勿喷。
扫描二维码关注公众号,回复:
1452359 查看本文章