算法——找单链表中点

超级简单,做个记录。

设两个指针,一个每次走两步,一个每次走一步,到头了就是中点。

类似与找单链表倒数第几个元素这样到算法。

实现如下:

package com.song.algorithm;

public class FindMid {
	public static class Node{
		Node next;
		String data;
		public Node(String data){
			this.data = data;
		}
	}
	
	public static Node findMiddle(Node start){
		Node prev;
		if(start == null ){
			return null;
		}else{
			if(start.next != null) {
				prev = start.next;
			}else{
				return start;
			}
		}
		Node follow = start;
		while(prev.next != null){
			prev = prev.next;
			if(prev.next != null){
				prev = prev.next;
				follow = follow.next;
			}else{
				break;
			}
		}
		return follow;
	}
	/**
	 * @param args
	 */
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		Node n1 = new Node("n1");
		Node n2 = new Node("n2");
		Node n3 = new Node("n3");
		Node n4 = new Node("n4");
//		Node n5 = new Node("n5");
//		Node n6 = new Node("n6");
		n1.next = n2;
		n2.next = n3;
		n3.next = n4;
//		n4.next = n5;
//		n5.next = n6;
		Node res = findMiddle(n1);
		System.out.println(res.data);
	}

}


### 带头节点的单链表实现归并排序 对于带头节点的单链表来说,归并排序可以通过递归的方法来完成。具体而言,整个过程分为三个主要部分:分割、递归调用以及合并。 #### 分割链表 为了有效地分割链表,可以利用快慢指针技术到链表中间位置,并将其切分为两部分[^3]。这种方法不仅适用于偶数长度的链表也适合奇数长度的情况。当快指针到达链表末端时,慢指针正好位于链表中央或接近中央的位置。之后切断此处连接使得原链表被划分为前后两个独立的部分。 #### 递归调用 一旦完成了初步划分,则需继续对每一半执行相同的操作直到每一段仅剩下一个元素为止。这时自然形成了多个已经排好序的小片段等待后续组合起来形成最终完整的有序列表[^1]。 #### 合并链表 最后一步就是把上述获得的一系列短序列重新组装回一起构成一个新的整体——即完全排列后的长串。这通常涉及到比较相邻项之间的大小关系从而决定它们之间相对顺序的过程[^2]。 以下是具体的 Java 实现代码: ```java class ListNode { int val; ListNode next; public ListNode(int x) { this.val = x; } } public class MergeSortLinkedList { private static final ListNode HEAD_SENTINEL = new ListNode(0); /** * 归并排序入口函数 */ public static void sort(ListNode head) { if (head == null || head.next == null) return; // 使用哨兵节点作为新的头部 HEAD_SENTINEL.next = head; doMergeSort(head); } /** * 进行实际的归并排序逻辑 */ private static ListNode doMergeSort(ListNode startNode){ if(startNode==null||startNode.next==null)return startNode; // 寻链表中点 ListNode mid=findMidPoint(startNode), secondHalf=mid.next; mid.next=null; // 对前一半进行排序 ListNode sortedFirstPart=doMergeSort(startNode); // 对后一半进行排序 ListNode sortedSecondPart=doMergeSort(secondHalf); // 将这两部分合并在一起 return merge(sortedFirstPart,sortedSecondPart); } /** * 查链表中的中点 */ private static ListNode findMidPoint(ListNode node){ ListNode slow=node, fast=node; while(fast!=null&&fast.next!=null&&fast.next.next!=null){ slow=slow.next; fast=fast.next.next; } return slow; } /** * 合并两个已排序的链表 */ private static ListNode merge(ListNode l1,ListNode l2){ ListNode dummyHead=new ListNode(-1),current=dummyHead; while(l1!=null && l2 != null){ if(l1.val<l2.val){ current.next=l1; l1=l1.next; }else{ current.next=l2; l2=l2.next; } current=current.next; } // 如果还有剩余未处理的数据则直接接上去 current.next=(l1!=null)?l1:l2; return dummyHead.next; } } ``` 此段程序展示了如何在一个带虚拟头结点(sentinel)的单向链接结构上应用归并排序算法。通过引入辅助性的`HEAD_SENTINEL`变量简化了一些边界条件下的操作流程。此外还定义了几种私有静态方法用于支持核心功能,包括寻链表中部(`findMidPoint`)、执行真正的排序工作(`doMergeSort`)以及将两个升序链表合成为一个更大的升序链表(`merge`)。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值