剑指offer:复杂链表的复制

输入一个复杂链表,返回结果为复制后复杂链表的head

PS:每个节点中有节点值,以及两个指针,一个指向下一个节点,另一个特殊指针指向任意一个节点
(注意,输出结果中请不要返回参数中的节点引用,否则判题程序会直接返回空)

import java.util.HashMap;

/*输入一个复杂链表(每个节点中有节点值,以及两个指针,一个指向下一个节点,另一个特殊指针指向任意一个节点),
返回结果为复制后复杂链表的head。(注意,输出结果中请不要返回参数中的节点引用,否则判题程序会直接返回空)*/

public class Solution {
	public static void main(String[] args)
	{
		RandomListNode node1=new RandomListNode(1);
		RandomListNode node2=new RandomListNode(2);
		RandomListNode node3=new RandomListNode(3);
		RandomListNode node4=new RandomListNode(4);
		RandomListNode node5=new RandomListNode(5);
		
		node1.next=node2;
		node2.next=node3;
		node3.next=node4;
		node4.next=node5;
		
		node1.random=node3;
		node2.random=node5;
		node4.random=node2;
		
		RandomListNode node=new Solution().Clone(node1);
		System.out.println(" ---  ");
	}
	/*********************
     * 返回复制后的复杂链表头结点 
     * 实现思路为在复杂链表的基础上  在每一个节点之后复制一个相同的节点 最后再进行拆链
     * ABCDEFG ->AaBbCcDdEeFfGg -->abcdefg  新链用小写字母表示
     * @param pHead 源链表的头结点
     * @return 返回复制后链表的头结点
	 */
    public RandomListNode Clone(RandomListNode pHead)
    {
    	//非空判断
    	if(pHead==null)
    	{
    		return null;
    	}
    	//遍历节点
        RandomListNode traverseNode=pHead;
        //加链过程
        while(traverseNode!=null)
        {
        	//建立拷贝节点 保存拷贝节点所有值
        	RandomListNode copyNode=new RandomListNode(traverseNode.label);
        	copyNode.next=traverseNode.next;
        	copyNode.random=traverseNode.random;
        	
        	//临时节点用于保存当前节点
        	RandomListNode tempNode=traverseNode;
        	//当前节点后移至原链表中下一位置
        	traverseNode=traverseNode.next;
        	//当前位置的节点指向拷贝节点位置
        	tempNode.next=copyNode;
        }
        RandomListNode head=pHead.next;//因为题目中原链表会被删除 pHead不能使用 因此保存下新链表的头节点位置
        traverseNode=head;//将遍历指针移动到新链表的开始位置
        
        //拆链过程
        while(traverseNode.next!=null)
        {
        	//将其指针指向新节点的位置 即原来节点的下一位置
        	traverseNode.next=traverseNode.next.next;//AaBbCcDd  a连接到b
        	if(traverseNode.random!=null)//随机节点不为空 指向随机节点的复制节点
        	{
        		traverseNode.random=traverseNode.random.next;//更新随机节点的位置
        	}
        	traverseNode=traverseNode.next;//a后移到b
        }
        return head;
    }
    /********************
     * 返回复制后的复杂链表头结点 使用HashMap作为辅助
     * 实现思路:遍历源复杂链表 建立拷贝链表但是拷贝数据中特殊指针仍然指向原链表中的位置
     * 但是会在拷贝过程中将原链表节点和新链表节点以键值对的形式保存在HashMap中
     * 新链表建立完成后  ,将其特殊指针域的指向原链表的特殊指针值替换为新链表的位置
     * @param pHead 源链表的头结点
     * @return 返回复制后链表的头结点
     */
    public RandomListNode CloneWithHashMap(RandomListNode pHead)
    {
    	//非空检测
    	if(pHead==null)
    	{
    		return null;
    	}
    	//建立HashMap表存储源节点和对应位置的新节点 
    	HashMap<RandomListNode, RandomListNode> nodeMap=new HashMap<>();
    	
    	RandomListNode ergodicNode=pHead.next;//移动指针用于遍历源链表
    	RandomListNode newHead;//存储新建链表的头结点
    	RandomListNode newErgodicNode;//用于建立新链表
    	//新建链表头结点赋值 
    	newHead=new RandomListNode(pHead.label);
    	newHead.random=pHead.random;
    	newErgodicNode=newHead;
    	
    	nodeMap.put(pHead, newHead);
    	//循环遍历源链表
    	while(ergodicNode!=null)
    	{
    		//新建一个节点
    		RandomListNode newNode=new RandomListNode(ergodicNode.label);
    		newNode.random=ergodicNode.random;//新节点的随机值和源节点相同
    		//将新旧节点加入nodeMap中
    		nodeMap.put(ergodicNode, newNode);
    		//将新节点加入新建链表中
    		newErgodicNode.next=newNode;
    		newErgodicNode=newErgodicNode.next;//当前新链表节点指向新链表中最后一个节点
    		
    		//当前遍历节点后移
    		ergodicNode=ergodicNode.next;
    	}
    	//从新链表头结点开始访问 并修改随机节点指向
    	newErgodicNode=newHead;
    	while(newErgodicNode!=null)
    	{
    		//key存储源节点 value储存对应的新节点 
    		newErgodicNode.random=nodeMap.get(newErgodicNode.random);
    		newErgodicNode=newErgodicNode.next;
    	}
    	
    	return newHead;
    }
}
//数据结构
class RandomListNode {
    int label;
    RandomListNode next = null;
    RandomListNode random = null;

    RandomListNode(int label) {
        this.label = label;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值