面试知识点--链表如何逆转

这个问题应该是面试最常见的题型之一了,很多大公司都会经常提问,如阿里巴巴。它的原理简单,学过数据结构,C语言,熟悉链表的同学应该很容易就掌握。但如果不熟练的话,也容易把代码写复杂了,或者写不出来。
下面我带大家分析一下这个算法。

先定义一个链表节点,

struct ListNode
{

int val;
ListNode *next;
ListNode(int v) : val(v), next(NULL) {}
};

这个节点结构很简单,有一个整数值,一个指向下个节点的指针。ListNode(int v) : val(v), next(NULL) {}是C/C++常用的初始化方法,这个可以看做是ListNode结构的构造函数,val(v)是对val初始化,next(NULL)对next进行初始化,这种初始化速度比较快。

然后创建一个0,1,2,3共4个元素的链表。

ListNode* createList()
{
ListNode *root = new ListNode(0);
ListNode *p1 = new ListNode(1);
ListNode *p2 = new ListNode(2);
ListNode *p3 = new ListNode(3);
root->next = p1;
p1->next = p2;
p2->next = p3;
return root;
}

我们采用new来创建,使用C++来实现。创建完成后,生成一个单链表,共有4个元素。

然后,以下是核心的逆转算法函数,我们会详细的进行分析。

ListNode* reverseList(ListNode *root)
{
//如果链表为空,直接返回null
if (root == NULL)
return root;
//定义cur指针,指向当前列表的当前元素
ListNode *cur = root;
//定义pre指针,指向前一个元素
ListNode *pre = NULL;
//定义post指针,指向后一个元素
ListNode *post = NULL;
//链表逆转后,指向逆转链表的首元素,或者表示新的逆转链表头
ListNode *revRoot = NULL;
//只要当前指向不为null,就一直循环
while (cur != NULL)
{
//将当前元素的指向位置赋值给post,即让post指向当前元素的下一个元素
post = cur->next;
//如果post为null,说明已经到了链表的末尾,则让revRoot指向当前元素
if (post == NULL)
revRoot = cur;
//将当前元素的前一个元素的位置赋值给cur,即让当前元素指向前一个元素,而不再指向后一个元素
cur->next = pre;
//将前一个元素的指向赋值成当前指向,即pre指向当前元素
pre = cur;
//同上,cur指向后一个元素
cur = post;
}
return revRoot;
}

我们看一下这个循环的执行过程,为方便理解,我这里画了一下循环执行图,

1、初始状态

这里写图片描述

2、第一次循环执行后

这里写图片描述

3、第二次循环执行后

这里写图片描述

4、第三次循环执行后

这里写图片描述
5、第四次循环执行后

这里写图片描述

6、最终状态

这里写图片描述

然后我们写一个main函数来测试一下。

int main()
{
ListNode *root = createList();
cout << "init List is: ";
showList(root);
root = reverseList(root);
cout << "reverse List is: ";
showList(root);
deleteList(root);
}

显示函数:

void showList(ListNode* root)
{
while(root != NULL)
{
cout << root->val << " ";
root = root->next;
}
cout << endl;
}

删除函数:

void deleteList(ListNode *root)
{
ListNode *p = root;
while(root != NULL)
{
p = root->next;
delete(root);
root = p;
}
}

我们看到执行结果如下所示,
init List is:
0 1 2 3
reverse List is:
3 2 1 0

以上就是链表逆转的典型写法,大家都明白了吗?如有因为欢迎留言交流。
另外, 链表还可以使用递归的方式实现,如下是递归实现的方法,有兴趣的也可以研究一下它的实现逻辑。

//递归法实现链表的逆置

pNode reverseList_reverse(pNode head)
{
pNode current_head, head_next;
if (head == NULL)
return NULL;
if (head->next == NULL)//边界条件
return head;
else{
current_head = head;//记下当前的头结点a0
head_next = head->next;//记下当前头结点后面的结点a1
head = reverseList_reverse(head_next);//返回(a1...an)逆转后的头结点
head_next->next = current_head;//用上面保存的地址(逆转后的尾结点)指向原来的头结点a0
current_head->next = NULL;//将a0的next域置零
}
return head;//返回a0
}

本文参考了如下文章链接:
https://www.cnblogs.com/kaituorensheng/archive/2014/01/18/3524888.html
http://blog.csdn.net/worldwindjp/article/details/18861093
对以上文章的作者表示感谢。

这里写图片描述
本公众号将以推送Android各种技术干货或碎片化知识,以及整理老司机日常工作中踩过的坑涉及到的经验知识为主,也会不定期将正在学习使用的新技术总结出来进行分享。每天一点干货小知识把你的碎片时间充分利用起来。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值