Useless Programmer 的专栏

走走停停, 留个纪念

颠倒一个链表的顺序

对于颠倒一个链表的顺序这里我们介绍两种可行的方法: 递归的和非递归的.


我们先说说递归的方法:

(1)如果一个链表为空链表,那么他的逆序还是为空,也就是这个链表本身了.

(2)如果一个链表中只有一个节点,那么他的逆序就是这个链表本身.

(3)如果一个链表的长度大于一,那么我们做如下递归.

把当前链表的除了头节点(head)之外的剩余节点组成的链表逆序,也就是递归调用,并得到剩余链表逆序后的头结点(ph),

此时将head的下一个节点的的next指向head, 并将head的next指针置空.然后返回ph.


说起来比较抽象,画图模拟一下吧:

(1).(2)点很简单,我们只说(3):


我们调用函数reverse(head), 将整个链表的头部传进去.然后head不为空,且head.next不为空,那么递归调用,reverse(head.next),此时链表长度减一.程序一直递归,直至当前传入的链表长度为1时,程序返回该子链表本身,其实就只有一个节点,也就是原链表的最后一个节点,此时程序返回ph(就是唯一的那个节点)到上一次调用处,此时程序处在倒数第二层调用.情况如下

图中的ph就是最后一次递归返回的节点,head为倒数第二次递归时链表的头结点.此时如何完成节点顺序的倒置呢,如下:


该过程分为两步: 

第一步先是将head的后一个节点的next指向当前头结点.

第二部再是将head的next置为空,去掉head.next和ph之间的关系.

此时的链表变为:


然后倒数第二层递归执行完成,将ph返回给倒数第三层.情形如下:


图中框起来部分就是倒数第二层递归时已经完成逆序的部分,当前递归中应该处理此时的head与ph之间的关系

此时依然完成上面已经提到过的那两步:


此时绿线部分便是在此次循环过程中完成的工作,一次类推.直至将整个链表逆序.


程序源码:

public Node reverse(Node head){
	if (head == null){
		return head;
	}
	if (head.next == null){
		return head;
	}
	Node ph = reverse(head.next);
	head.next.next = head;
	head.next = null;
	return ph;
}


下面我们来说说非递归的方法:

非递归过程比较简单,此处仅给出实现代码:

public Node reverse1(Node head){
	if (head == null){
		return null;
	}
	Node p = head;
	Node previous = null;
	while (p.next != null){
		p.next = previous;
		previous = p;
		p = previous.next;
	}
	p.next = previous;
	return p;
}

整个过程中使用previous保存已经处理过的上一个节点,总是将当前节点的next指向上一个节点.而上一个节点恰恰就是原链表中当前节点的下一个节点,以此来实现链表的颠倒.

注意事项为头结点的上一个节点为空,因此previous应该初始化为空,还有一点就是原链表的尾会成为新链表的头,而原链表的尾部的next为空,因此需要单独处理,也就是在推出循环后,将p.next指向previous.

阅读更多
版权声明:本文为博主原创文章,欢迎转载 https://blog.csdn.net/zhaoruixiang1111/article/details/49932603
个人分类: 算法学习
想对作者说点什么? 我来说一句

链表倒置的实现

2014年09月22日 937B 下载

链表的倒置

2011年10月05日 937B 下载

链表倒置C程序

2012年11月05日 1KB 下载

没有更多推荐了,返回首页

不良信息举报

颠倒一个链表的顺序

最多只允许输入30个字

加入CSDN,享受更精准的内容推荐,与500万程序员共同成长!
关闭
关闭