面试-反转链表
面试题目
经典算法题目 : 反转单链表 reverse list
对于一个普通的单链表,可以定义成结构体形式:
// 定义链表节点
struct ListNode
{
int val;
ListNode * next;
}
请写一个函数实现单链表的翻转
题目解析
一般来说,单链表的反转有递归和非递归的方式来进行实现, 此处的反转实现 参考反转链表图示 其中递归方式的实现比较难以理解, 进攻参考
递归方式
// 递归方式
ListNode * ReverseList_re(ListNode * head)
{
// 如果空链表或者 单节点链表
if(head ==nullptr || head->next == nullptr)
return head;
// 依次进行每个节点的执行
ListNode * new_head = ReverseList_re(head->next);
// 对于每一个节点 反转前后实现
head->next->next = head;
head->next = nullptr;
return new_head;
}
非递归方式
- // ref:[链表反转图文讲解](https://blog.csdn.net/FX677588/article/details/72357389)
- // 非递归方式
- ListNode * ReverseList(ListNode *head)
- {
- // 如果空链表或者 单节点链表
- if(head == nullptr || head->next == nullptr)
- return head;
- // 新建两个节点 P用来遍历head, new_head 为新链表的头
- ListNode *p = head, *new_head = nullptr;
- while(p != nullptr)
- {
- ListNode * tmp = p->next; // 存储当前节点的指针位置
- p->next = new_head; // 将当前节点指向新节点的头
- new_head = p; // 新链表 移动头
- p = tmp; // 旧链表指针移动
- }
- // 返回新的节点值
- return new_head;
- }
- // 不返回操作 非递归 反转链表
- void ReverseList2(ListNode * &head)
- {
- // 如果空链表或者 单节点链表
- if(head == nullptr || head->next == nullptr)
- return ;
- // 新建两个节点 P用来遍历head, new_head 为新链表的头
- ListNode *p = head, *new_head = nullptr;
- while(p != nullptr)
- {
- ListNode * tmp = p->next; // 存储当前节点的指针位置
- p->next = new_head; // 将当前节点指向新节点的头
- new_head = p; // 新链表 移动头
- p = tmp; // 旧链表指针移动
- }
- // 复用 head 指针
- head = new_head;
- }
附加内容
测试工程 实现
// 链表操作类的 测试
#include <iostream>
using namespace std;
// 定义链表节点 值和指针
struct ListNode
{
int val;
ListNode *next;
};
// 定义链表的 增 删 查 改
// CRUD
// 创建链表 // 根据首指针 创建首指针节点
void CreateHead(ListNode *head, int data)
{
}
// 在链表尾头部添加新节点
void AddNode(ListNode * & head,int data)
{
// 创建 新节点 //申请空间
ListNode *p = (ListNode*) malloc(sizeof(ListNode));
p->val = data;
p->next = nullptr;
// 如果是一个空链表 直接赋值到head 然后返回
if(head == nullptr)
{
head = p;
return ;
}
// 指向新节点 返回新节点
p->next = head;
head = p;
}
// 删除节点
// 查找节点
// 更新节点值
// 打印List 所有节点值
void PrintList(ListNode *head)
{
// 从某个节点开始 打印所有节点的值
ListNode *p = head; // 临时节点 便于输出 避免 改变 head 值
while(p != nullptr)
{
// cout<<(long)p%65536<<":"; // 输出指针的一个 数字表示
cout<<p->val<<"->";
p = p->next;
}
cout<<"NULL"<<endl;
}
// 反转链表
// ref:[链表反转图文讲解](https://blog.csdn.net/FX677588/article/details/72357389)
// 非递归方式
ListNode * ReverseList(ListNode *head)
{
// 如果空链表或者 单节点链表
if(head == nullptr || head->next == nullptr)
return head;
// 新建两个节点 P用来遍历head, new_head 为新链表的头
ListNode *p = head, *new_head = nullptr;
while(p != nullptr)
{
ListNode * tmp = p->next; // 存储当前节点的指针位置
p->next = new_head; // 将当前节点指向新节点的头
new_head = p; // 新链表 移动头
p = tmp; // 旧链表指针移动
}
// 返回新的节点值
return new_head;
}
// 不返回操作 非递归 反转链表
void ReverseList2(ListNode * &head)
{
// 如果空链表或者 单节点链表
if(head == nullptr || head->next == nullptr)
return ;
// 新建两个节点 P用来遍历head, new_head 为新链表的头
ListNode *p = head, *new_head = nullptr;
while(p != nullptr)
{
ListNode * tmp = p->next; // 存储当前节点的指针位置
p->next = new_head; // 将当前节点指向新节点的头
new_head = p; // 新链表 移动头
p = tmp; // 旧链表指针移动
}
// 复用 head 指针
head = new_head;
}
// 递归方式
ListNode * ReverseList_re(ListNode * head)
{
// 如果空链表或者 单节点链表
if(head ==nullptr || head->next == nullptr)
return head;
// 依次进行每个节点的执行
ListNode * new_head = ReverseList_re(head->next);
// 对于每一个节点 反转前后实现
head->next->next = head;
head->next = nullptr;
return new_head;
}
// 主函数 测试 demo
#define LENGTH 20
int main(void)
{
ListNode *head = nullptr;
// 生成随机链表
for(int i=0;i<LENGTH;++i)
AddNode(head,rand()%LENGTH);
PrintList(head);
// 反转链表 并输出
head = ReverseList(head);
PrintList(head);
// 反转链表 并输出
ReverseList2(head);
PrintList(head);
// 反转链表 并输出 递归实现
head = ReverseList_re(head);
PrintList(head);
// system("pause");
return 0;
}