记一道关于链表逆序的面试题

    上周末参加了一次面试,国内知名互联网企业,面试全程也是相当紧张。

    在第二轮当中,面试官让手写一个“最简单的”链表反转函数。

    在以前的面试中我也遇到面试官要求现场写链表反转,我一般都会写循环迭代的方式,因为这题主要是考察指针使用的灵活程度,代码并不复杂,两个指针一次遍历并反转next指针指向就好了。

    并且据我的经验,如果写成递归形式,那么最终的执行过程中不断调用自身有可能导致栈爆掉(stack overflow),除非是尾递归并且加上了优化。经过一番思索,我感觉链表逆序的递归形式并不太容易写成尾递归(因为最终需要将开始的头结点的next赋值为nullptr),所以花了几分钟,最后交给面试官的答案纸上依然写了循环迭代的形式。

    当然,面试官也和我说,这肯定不是最简单的写法。

    面试回来思考了下,并且上网查了一下,也没找到比较称心的简单算法。无外乎迭代,递归,然后自己写了个稍微麻烦点写法的尾递归。代码如下:

//迭代
node* reverse_1(node* l)
{
	if (!l)
		return l;
	node* p1 = l;
	node* p2 = l->n;
	p1->n = nullptr;
	while (p1 && p2)
	{
		node* p = p2->n;
		p2->n = p1;
		p1 = p2;
		p2 = p;
	}
	return p1;
}
//常规递归
node* reverse_2(node* l)
{
	if (!l || !l->n)
		return l;
	node* p = reverse_2(l->n);
	l->n->n = l;
	l->n = nullptr;
	return p;
}
//尾递归,需要增加一个辅助递归函数
node* reverse_3_help(node* prev, node* curr)
{
	if (!curr)
		return curr;
	node* next = curr->n;
	curr->n = prev;
	if (!next)
		return curr;
	return reverse_3_help(curr, next);
}
node* reverse_3(node* l)
{
	node* prev = nullptr;
	node* curr = l;
	return reverse_3_help(prev, curr);
}

    实际的结果是,reverse_1写法最常规,执行情况也最理想,速度快,并且不存在栈溢出的问题,reverse_2在链表长度超过一定范围时会导致栈溢出,编译器的优化也无法解决问题,reverse_3也是递归,但是使用了reverse_3_help这个辅助的递归函数实现了尾递归,当然,在没有优化的情况下依然存在栈溢出的问题,但是编译器可以优化尾递归调用,加上优化选项后编译出的程序一样不会出现栈溢出的情况,并且执行效率和reverse_1差不多。

    亲测数据:

    list长度过长时reverse_2段错误,测试长度为200000时,结果如下:

reverse_1-BEGIN:15:13:40:894...
reverse_1-END  :     0.468217ms.
reverse_2-BEGIN:15:13:40:896...
reverse_2-END  :     6.229769ms.
reverse_3-BEGIN:15:13:40:902...
reverse_3-END  :     0.461505ms.

    至于“最简单的”链表逆序,我暂时还没有想到。若有哪位大神可以不吝赐教,定感激涕零。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值