题目:输入一个链表的头节点,反转这个链表,并返回反转后链表的头节点,链表定义如下:
struct ListNode
{
int m_nKey;
ListNode* m_pNext;
};
解答:
算法一:我们需要额外的两个变量来存储当前节点pCurrent的上一个节点pPrev和下一个节点pNext。假设经过若干次操作,我们将当前节点pCurrent之前的指针都反转完成,这些节点的m_pNext指针都指向前面的一个节点。现在我们遍历到pCurrent,这时需要调整该节点的m_pNext指针使其指向pPrev节点。但要注意调整了m_pNext指针的指向后,后面的链表就会断开,因此我们需要在调整pCurrent的m_pNext指针之前先将pNext节点保存下来。反转后的头节点就是原来的尾节点。
核心代码如下:
//反转链表核心算法
ListNode* ReverseList(ListNode* pHead)
{
ListNode* pReverseHead = NULL;
ListNode* pNode = pHead->m_pNext;
ListNode* pPrev = NULL;
while(pNode != NULL)
{
//存储当前节点pNode的下一个节点
ListNode* pNext = pNode->m_pNext;
//如果下一个节点为空,那么当前节点pNode就是反转后的头指针了
if(pNext == NULL)
{
pReverseHead = pNode;
}
//将当前节点改为指向pPrev节点
pNode->m_pNext = pPrev;
//移动两个指针
pPrev = pNode;
pNode = pNext;
}
//添加头指针
ListNode* pReturn = (ListNode*)malloc(sizeof(ListNode));
pReturn->m_pNext = pReverseHead;
return pReturn;
}
算法二:递归法,基本思想是在反转当前节点之前先调用递归函数反转后续节点,该方法在反转后的最后一个节点会形成一个环,所以必须将函数的返回节点的m_pNext域置为NULL。
ListNode* ReverseLink(ListNode* pHead)
{
if(pHead->m_pNext == NULL)
return pHead;
ListNode* pReturn = ReverseLink(pHead->m_pNext);
pHead->m_pNext->m_pNext = pHead;
pHead->m_pNext = NULL;
return pReturn;
}
//反转链表的递归算法
ListNode* ReverseList2(ListNode* pHead)
{
ListNode* pReverseHead = pHead;
//考虑只有0个或1个节点
if(pHead->m_pNext == NULL || pHead->m_pNext->m_pNext == NULL)
{
return pHead;
}
pReverseHead->m_pNext = ReverseLink(pReverseHead->m_pNext);
return pReverseHead;
}
完整测试代码如下:
#include <iostream>
struct ListNode
{
int m_nKey;
ListNode* m_pNext;
};
void InitList(ListNode** head)
{
*head = (ListNode*)malloc(sizeof(ListNode));
(*head)->m_pNext = NULL;
}
void InsertList(ListNode* head, int data)
{
assert(head != NULL);
ListNode* pNewNode = (ListNode*)malloc(sizeof(ListNode));
pNewNode->m_nKey = data;
pNewNode->m_pNext = head->m_pNext;
head->m_pNext = pNewNode;
}
void PrintList(ListNode* pHead)
{
if(pHead == NULL)
{
return;
}
ListNode* pTempNode = pHead->m_pNext;
while(pTempNode != NULL)
{
std::cout<<pTempNode->m_nKey<<std::endl;
pTempNode = pTempNode->m_pNext;
}
}
//反转链表核心算法
ListNode* ReverseList(ListNode* pHead)
{
ListNode* pReverseHead = NULL;
ListNode* pNode = pHead->m_pNext;
ListNode* pPrev = NULL;
while(pNode != NULL)
{
//存储当前节点pNode的下一个节点
ListNode* pNext = pNode->m_pNext;
//如果下一个节点为空,那么当前节点pNode就是反转后的头指针了
if(pNext == NULL)
{
pReverseHead = pNode;
}
//将当前节点改为指向pPrev节点
pNode->m_pNext = pPrev;
//移动两个指针
pPrev = pNode;
pNode = pNext;
}
//添加头指针
ListNode* pReturn = (ListNode*)malloc(sizeof(ListNode));
pReturn->m_pNext = pReverseHead;
return pReturn;
}
ListNode* ReverseLink(ListNode* pHead)
{
if(pHead->m_pNext == NULL)
return pHead;
ListNode* pReturn = ReverseLink(pHead->m_pNext);
pHead->m_pNext->m_pNext = pHead;
pHead->m_pNext = NULL;
return pReturn;
}
//反转链表的递归算法
ListNode* ReverseList2(ListNode* pHead)
{
ListNode* pReverseHead = pHead;
//考虑只有0个或1个节点
if(pHead->m_pNext == NULL || pHead->m_pNext->m_pNext == NULL)
{
return pHead;
}
pReverseHead->m_pNext = ReverseLink(pReverseHead->m_pNext);
return pReverseHead;
}
int main()
{
ListNode* pListHead = NULL;
InitList(&pListHead);
//建立两个链表
for(int i=9; i>=0; i--)
{
InsertList(pListHead, i);
}
std::cout<<"链表反转之前:"<<std::endl;
PrintList(pListHead);
//ListNode* pReverseHead = ReverseList(pListHead);
ListNode* pReverseHead = ReverseList2(pListHead);
std::cout<<"链表反转之后:"<<std::endl;
PrintList(pReverseHead);
system("pause");
return 0;
}
分享到:
相关推荐
链表的反转是一个很常见、很基础的数据结构题,输入一个单向链表,输出逆序反转后的链表,如图:上面的链表转换成下面的链表。实现链表反转有两种方式,一种是循环迭代,另外一种方式是递归。 第一种方式:循坏...
利用算法5建立两个非递减有序单向链表,然后合并成一个非递减链表。 (7).利用算法1建立的链表,删除链表中的重复元素。 (8).利用算法1建立的链表,实现将其分解成两个链表,其中一个全部为奇数,另一个全部为偶数...
算法概述:要求实现将一条单向链表反转并考虑时间复杂度。 算法分析: 数组法(略): 将列表元素逐个保存进数组,之后再逆向重建列表 点评:实现逻辑最简单,需要额外的内存开销。 移动指针: 通过三个指针逐个从链...
根据链表数据结构的知识,进行初步练习,从单链表的反转、环的检测、两个有序链表的合并、判断单向链表是否是回文字符串四个题目着手,分别进行代码实现。 首先定义单链表类: # 结点类 class Node(object): def _...
问题:给一个单向链表,把它从头到尾反转过来。比如: a -> b -> c ->d 反过来就是 d -> c -> b -> a 。 分析:假设每一个node的结构是: 代码如下:class Node { char value; Node next;}因为在对链表进行反转的...
2、单向链表反转 3、单向链表是否有环 4、合并两个有序链表 5、删除链表倒数第 n 个结点 6、求单向链表的中间结点 二、栈 1、Java实现顺序栈、链式栈 三、队列 1、顺序队列、链式队列 2、循环队列 四、排序算法 1、...
单向链表 一个节点指向下一个节点 双向链表 一个节点有两个指针域 自由主题 循环链表 能通过任何一个节点找到其他所有的节点,将两种(双向/单向)链表的最后一个结点指向第一个结点...
单向链表的数据结构及其相关算法:单向链表结构包含两个要素,即头结点head和链表大小size,具体操作包括: 链表的增删 链表是否为空 链表的大小 链表的打印输出 删除链表重复节点 链表倒数第K个元素 链表的反转 ...
从单向链表中选择一个随机节点 动态规划 最长公共子序列 最长递增子序列 编辑距离 最小分区 覆盖距离的方法 矩阵中的最长路径 子集和问题 游戏的最优策略 0-1 背包问题 布尔括号问题 排序和搜索 二分查找 在已排序和...
单向链表 Leetcode [无代码] [无代码] 1、两数之和 2. 两数相加 3. 无重复字符的最长子串 14. 最长公共前缀 21. 合并两个有序链表 23. 合并K个排序链表 33. 搜索旋转排序数组 42. 接雨水 53. 最大子序和 56. 合并...
判断青蛙过河leetcode ...单向链表 cn.diyai.linklist.ListNode 链表中环的入口结点 删除链表中重复的结点 复杂链表的复制 二叉搜索树与双向链表 两个链表的第一个公共结点 从尾到头打印链表 链表中倒数第k个结点 反转
反转单向链表 - , 从链表中删除重复项 - , 删除具有给定键的节点 - 链表的插入排序 - , 两个列表的交点 - , 从最后一个节点开始的第 N 个 - 用头交换第 N 个节点 - 合并两个排序链表 - 归并排序 - , , 反转偶数节点 ...
包括:单向链表的添加、遍历、修改、删除,常见面试题:单向链表有效个数、查找倒数第K个节点、单链表反转、反向遍历链表 主要包含双向链表:com.imyiren.datastructure.linkedlist.DoubleLinkedList 包括:双向链表...
该目录包含以下数据结构和算法实现以及项目和问题解决。 数组 矩阵旋转 90 度到位。 创建数组类:insert()、removeAt()、indexOf()、print()、max()、reverse()、insertAt()。 链表 具有所需方法的基本单链表实现。 ...
删除单向链表的节点 C++ Leetcode 链表中的倒数第k个节点 go&&C++ 牛客网 二叉树镜像 C++ 牛客网 链表的反转 C++ 牛客网 树的子结构 C++ 牛客网 二叉树的后序遍历 C++ Leetcode 旋转图像 C++ Leetcode 二叉树的堂兄...
(单向链表的增删改查,栈,递归) 面试题18:删除链表的节点(O(1)内删除节点,python函数的引用传递机制) 面试题22:链表中倒数第k个节点(代码的鲁棒性(空指针,越界输入等),一次使用多个指针遍历链表) 面试...
leetcode变形词数据结构和算法 目标是每天提交 1 ...从单向链表中删除节点 7 7.7 从列表中删除第 k 个最后一个元素 7 7.8 从排序列表中删除重复项 7 7.9 实现单链表循环右移 7 7.10 实现奇偶合并 7
今天遇到单向链表的反转的问题,于是静下心来好好想了一番。下面这篇文章主要给大家介绍了关于单链表反转的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们...
基础算法:反转单向链表 7月16号 7月11号 7月9号 复习 : HashTable和HashMap的区别详解 LeetCode 27. 删除元素(Remove Element) 7月8号 7月5号 复习hashMap concurrentHashmap [LeetCode 70. 爬楼梯(Climbing ...
反转单向链表和双向链表 用curr,prev,next注意不要断链 在行和列都排好序的矩阵中找数,从右上角开始 打印两个单链表的相交的问题,注意还要考虑有环没有。 如何找到入环的节点? 当快慢指针相遇时,把快指针指向...