【数据结构】单链表反转

链表反转一般有两种解法:递归和迭代。首先给出链表的定义

typedef struct tagLNode {//带头结点的单链表
	int data;
	struct tagLNode *next;//尾结点为0表示结束。若尾结点指向头结点则为循环单链表
}LinkList;

假设链表为head->1->2->3->4->5->NULL。

递归法

LinkList *  reverse(LinkList *head) {
	if (head == NULL) return 0;
	else if (head->next == NULL) return head;
	LinkList *temp=reverse(head->next);
        //temp->next=head;
	head->next->next = head;
	head->next = NULL;
	return temp;
}

一开始我的想法是,先递归到最后一层,也就是reverse(5),这层的运行结果是返回5号结点给上层的temp,那么我们回到了第四层:head就是4号结点,temp是5号。让temp的后续变成head不行吗?在这一层是可以的。那么我们再回到第三层,head是3号结点,temp是5号结点(请注意,后续为4号结点),再执行temp->next=head时,5号结点的后续又变为3号,问题来了,程序好像在打转。所以问题在于我们返回的temp永远是5号结点,不能更改temp的后继。正确做法是head->next->next = head,每层发生的事情与temp无关,它只负责返回5号结点。

这里想说说递归的缺点:首先递归存在重复计算(参考斐波那契数列),而且每次递归都是一次函数调用,每次调用都需要在内存栈中分配空间来保存参数、返回地址和临时变量,这就导致了弹栈入栈的时间消耗。递归还可能导致调用栈溢出:每个进程栈的容量是有限的,调用层级太多就会超出栈的容量,导致调用栈溢出

迭代法

LinkList *  reverse(LinkList *head) {
	if (head == NULL || head->next == NULL) return head;//0个或1个元素时无须反转
	LinkList *prev = head;//前续结点
	LinkList *p = head->next;//当前结点
	prev->next = NULL;//头结点后继应为空
	if (p->next == NULL) {//如果只有2个元素,应特殊处理
		p->next = prev;
		return p;
	}
	LinkList *next = p->next;//后继结点
	while (next){
		p->next = prev;//当前结点的后继应为前一结点
		prev = p;
		p = next;
		next = next->next;//这三结点都往移动
	}
	p->next = prev;//最后的一个结点手动指向prev
	return p;//返回最后一个结点,也是新链表的头结点
}

迭代法的好处就是简单易懂:由于每次循环会断开p与原始后继的链子,需要用next指针来保存后继结点,然后就是循环调用p->next=prev,移动这三个结点即可。

总结

我总以为自己理解的链表的操作,可是隔一段时间就忘了,可能是没有深入分析。另外这是我的第一篇博客,也是被一位大佬鼓动,加油吧!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值