面试题

本文详细解析了一种带有随机指针的复杂链表复制算法,通过插入法实现新旧链表的交织与分离,避免了额外空间的使用,展示了完整的Java实现代码及运行结果。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

import java.util.Random;

/**
 * 面试题:这是一个链表题,链表不光有next域还有一个指向任意链上任意一个结点的随机域random,
 * 注意random可以指向null,请完成对一个链表的复制。
 * 
 * 解答: 如果没有随机域random,这个题目就很简单,扫描一遍构建新结点即可,现在的难处在于复制 链表中random
 * 指向的结点可能还没创建,所以需要先创建所有结点并复制数据域,这一步只需 遍历一遍即可,然后再处理链接域
 * 方法1:	1、创建新结点newNode并复制数据域
 * 			2、保存oldList的链接状态
 * 			3、将oldList的oldNode结点next域指向对应的newNode
 * 			4、newNode.random = old.random.next
 * 			5、利用2保存的状态恢复oldList的next域
 * 方法1中第二2步需要一个O(n)的辅助空间。
 * 
 * 方法2:	1、在oldNode[i]与oldNode[i+1]插入newNode[i],最后一个结点直接放在末尾
 * 			2、newNode.random = newNode.random.next建立复制链表的随机域
 * 			3、恢复两个链表的next域
 * 
 * @author jiqunpeng email jiqunpeng@gmail.com
 * 
 *  
 */
public class RandomLink {
	public RandomLink next = null;
	public RandomLink random = null;
	public long id = Long.MIN_VALUE;
	private static Random rand = new Random(47);

	/**
	 * 构造一个长度为n的链表
	 * 
	 * @param n
	 * @return
	 */
	public static RandomLink generator(int n) {
		RandomLink[] list = new RandomLink[n];
		for (int i = 0; i < n; i++) {
			list[i] = new RandomLink();
			list[i].id = i;
		}
		for (int i = 0; i < n; i++) {
			if (i == n - 1)// 最后一个结点next域为null
				list[i].next = null;
			else
				list[i].next = list[i + 1];
			int r = rand.nextInt(n + 1);
			if (r == n)
				list[i].random = null;
			else
				list[i].random = list[r];
		}
		return list[0];// 返回头结点
	}
	/**
	 * 按方法2复制链表
	 * @param oldList
	 * @return
	 */
	public static RandomLink copy(RandomLink oldList) {
		// 将新的结点插入到两个结点之间
		RandomLink oldNode = oldList;
		while (oldNode.next != null) {
			RandomLink newNode = new RandomLink();
			newNode.id = oldNode.id;
			newNode.next = oldNode.next;
			oldNode.next = newNode;
			oldNode = newNode.next;
		}
		// 最后一个新结点插入到末尾即可
		RandomLink lastNode = new RandomLink();
		lastNode.id = oldNode.id;
		lastNode.next = null;
		oldNode.next = lastNode;
		// 构造新链表的随机链域
		oldNode = oldList;
		RandomLink copyNode = oldList.next;
		RandomLink newNode;
		while (oldNode != null) {
			newNode = oldNode.next;
			// 复制新结点的随机链域
			if (oldNode.random == null)
				newNode.random = null;
			else
				newNode.random = oldNode.random.next;
			oldNode = oldNode.next.next;
		}
		// 恢复结点的next域
		oldNode = oldList;
		newNode = oldNode.next;
		while (true) {
			oldNode.next = newNode.next;// 重新链接旧结点的next
			oldNode = oldNode.next;// 下一个旧结点
			if (oldNode == null)
				break;
			newNode.next = oldNode.next;// 重新链接新结点的next
			newNode = newNode.next;// 下一个新结点
		}
		return copyNode;
	}

	public String getString() {
		return super.toString().split("@")[1];
	}

	@Override
	public String toString() {
		String nextId;
		if (next == null)
			nextId = "null";
		else
			nextId = Long.valueOf(next.id).toString() + "@" + next.getString();//
		String rId;
		if (random == null)
			rId = "null";
		else
			rId = Long.valueOf(random.id).toString() + "@" + random.getString();//
		return super.toString() + "\t" + id + "\t" + nextId + "\t" + rId;
	}

	public static void printList(RandomLink list) {
		RandomLink node = list;
		while (node != null) {
			System.out.println(node);
			node = node.next;
		}
	}

	public static void main(String[] args) {
		RandomLink list = RandomLink.generator(5);
		System.out.println("原始链表:");
		RandomLink.printList(list);
		RandomLink copyList = RandomLink.copy(list);
		System.out.println("复制后的原始链表:");
		RandomLink.printList(list);
		System.out.println("复制后的链表:");
		RandomLink.printList(copyList);
	}
}


转载于:https://my.oschina.net/huichen/blog/415285

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值