链表的归并排序

今天做了链表的冒泡排序和归并排序,复习了二叉树的遍历,明天继续。

冒泡效率低,前一篇已经讲过,这篇来记录归并排序,归并排序最坏和平均时间复杂度都是O(nlogn),而且属于稳定排序,所以掌握了可以使用在几乎所有情况。

这里先说对链表的二路归并排序思路:

1.先把链表从中间分成两个子链表

public static ListNode divide(ListNode L){
		ListNode start, middle, temp;
		start = L;
		middle = null;
		temp = L;
		while(temp != null && temp.next != null)
		{
			temp = temp.next.next;
			middle = start;
			start = start.next;
		}

		middle.next = null;
		return start;
	}

其中temp节点和middle、start节点,作为快慢指针遍历一遍链表,middle最后记录下前一个子链表的最后一个节点位置,start记录下后一个子链表的头结点位置,操作完之后原本的L链表,在middle位置被截断,middle位置的节点的后继成为空,这里可以看出java变量的特性,如果不是用构造方法新建的变量,类似start = L这样的语法,start和L只是两个类似指针的变量,指向同一块内存区域,所以当middle.next被清空了之后原来的内存区域也被操作,所以在函数内没有操作L,L也变化了

2.递归方法对两个子链表做归并排序

public static ListNode merge(ListNode L1, ListNode L2){
		ListNode temp1 = L1;
		ListNode temp2 = L2;
		ListNode s = null;
		ListNode lc = null;
		if(temp1.val <= temp2.val)
		{
			s = temp1;
			lc = s;
			temp1 = temp1.next;
		}else{
			s = temp2;
			lc = s;
			temp2 = temp2.next;
		}
		
		while(temp1 != null && temp2 != null)
		{
			if(temp1.val <= temp2.val)
			{
				s.next = temp1;
				temp1 = temp1.next;
				s = s.next;
			}else{
				s.next = temp2;
				temp2 = temp2.next;
				s = s.next;
			}
		}
		
		if(temp1 == null)s.next = temp2;
		else if(temp2 == null) s.next = temp1;
		
		return lc;
	}
	
	public static ListNode mergeSortList(ListNode head){
		if(head == null || head.next == null) return head;
		ListNode a,b;
		b = divide(head);
		a = head;
		head = merge(mergeSortList(a),mergeSortList(b));
		return head;
	}
merge函数里面的lc和前面讲到的是一样的道理,在一开始用一个额外的变量存储链表的头地址,在链表被操作的面目全非之后lc还能指向正确的头地址。其中的归并方法,首先找出传入的两个链表的头结点的值哪个更小,就记录到临时变量s.next中,同时记录到 lc 中,同时小值开头的链表头后移(只是这么理解,实际只是一个指针),然后s变成自己的后继,也就是刚才那个较小的头结点本身,而头本身变成了自己的后继,之后判断如果两个链表都还没有走到头的话,继续判断两段的头结点的大小,此时的两段链表为其中一条去掉了小的头,另一条不变,所以等于重复了刚才的过程,最后的结果是较小的节点被赋值给s.next,前一次s指向的地址是两个(注意:这里两个链表内部是有序的)链表的最小节点,所以现在这个最小节点的next指向第二小的节点,第二小的节点本身往后移动,s成为这个第二小的点本身,以此类推,最后两个链表会成为一个有序链表,但是会留下最后一个最大的节点空出来,被存在变量temp1/2中,所以在最后把这个节点接上,如代码所示。

在主函数里,递归实现归并。

下面是测试代码,在OJ上也AC了

public static void main(String args[]){
		ListNode l = new ListNode(5);
		ListNode ll = new ListNode(3);
		ListNode lll = new ListNode(6);
		ListNode llll = new ListNode(2);
		ListNode lllll = new ListNode(8);
		ListNode llllll = new ListNode(9);
		
		l.next = ll;
		ll.next = lll;
		lll.next = llll;
		llll.next = lllll;
		lllll.next = llllll;
		
		ListNode n = mergeSortList(l);
		//System.out.print(re.val);
		while(n != null)
		{
			System.out.print(n.val);
			n = n.next;
		}
	}

output:235689

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值