复制带随机指针的链表

复制带随机指针的链表

问题

一种特殊链表节点描述如下

class Node():
    def __init__(self, val):
        self.val = val
        self.next = None
        self.rand = None

next跟正常链表一样,rand是一个指针可以指向任意节点,也可能指向NULL,复制一个链表。

测试方法

为了简化测试,我们用0~n生成一个序列,随机打乱作为链表的顺序,然后rand维护一个有序的序列

class LinkList():
    def __init__(self):
        self.head = None
        self.sorted_head = None


    def make_linklist(self, datas):
        if not datas:
            return

        tail = None
        for d in datas:
            node = Node(d)
            if not self.head:
                self.head = node
                self.sorted_head = node
                tail = node
            else:
                tail.next = node
                tail = node

                prev = None
                cur = self.sorted_head
                while cur and cur.val < d:
                    prev = cur
                    cur = cur.rand

                if not prev:
                    node.rand = self.sorted_head
                    self.sorted_head = node
                else:
                    prev.rand = node
                    node.rand = cur


    def to_list(self):
        l = []
        p = self.head
        while p:
            l.append(p.val)
            p = p.next

        return l


    def sorted_to_list(self):
        l = []
        p = self.sorted_head
        while p:
            l.append(p.val)
            p = p.rand

        return l
def test_copy_linklist(count):
    datas = []
    for i in range(count):
        datas.append(i)
    random.shuffle(datas)

    ll = LinkList()
    ll.make_linklist(datas)
    l1 = ll.to_list()
    l2 = ll.sorted_to_list()

    datas_sorted = sorted(datas)
    if not operator.eq(l2, datas_sorted):
        raise Exception('Error')

    cp = ll.copy()
    cp_l1 = cp.to_list()
    if not operator.eq(l1, cp_l1):
        raise Exception('Error')

    cp_l2 = cp.sorted_to_list()
    if not operator.eq(l2, cp_l2):
        raise Exception('Error')

    cp2 = ll.copy2()
    cp2_l1 = cp2.to_list()
    if not operator.eq(l1, cp2_l1):
        raise Exception('Error')

    cp2_l2 = cp2.sorted_to_list()
    if not operator.eq(l2, cp2_l2):
        raise Exception('Error')

思路1

使用Hash表做一个node->copy_node的映射,根据node->rand设置copy_node->rand

实现

    def copy(self):
        cp = LinkList()
        if not self.head:
            return cp

        node_map = {}
        p = self.head
        while p:
            node = Node(p.val)
            node_map[p] = node
            p = p.next

        p = self.head
        while p:
            if p.next:
                node_map[p].next = node_map[p.next]
            if p.rand:
                node_map[p].rand = node_map[p.rand]
            p = p.next

        cp.head = node_map[self.head]
        cp.sorted_head = node_map[self.sorted_head]
        return cp

思路2

在链表中每个节点后面加一个节点,如
1->3->2->5
=>
1->1’->3->3’->2->2’->5->5’
则可以根据前面节点的rand设置后面节点的rand

实现

    def copy2(self):
        cp = LinkList()
        if not self.head:
            return cp

        # copy node, and add to list
        p = self.head
        while p:
            node = Node(p.val)
            next = p.next
            p.next = node
            node.next = next
            p = next

        # copy rand
        p = self.head
        while p:
            next = p.next.next
            copy_node = p.next
            if p.rand:
                copy_node.rand = p.rand.next
            p = next

        cp.head = self.head.next
        cp.sorted_head = self.sorted_head.next

        # split from list
        p = self.head
        head = None
        tail = None
        while p:
            next = p.next.next
            copy_node = p.next
            p.next = next
            copy_node.next = None
            if not head:
                head = copy_node
                tail = copy_node
            else:
                tail.next = copy_node
                tail = copy_node
            p = next

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值