复制一个带random指针的链表

一个单链表,其中除了next指针外,还有一个random指针,指向链表中的任意某个元素。

如何复制这样一个链表呢?

通过next来复制一条链是很容易的,问题的难点在于如何恰当地设置新链表中的random指针。从这个目的出发,我们要在旧链表和新链表的对应节点之间建立联系。除了在链表之外来另外开辟空间存储的方法之外,我们可以利用链表中多余的指针来连接起来。

不扯淡了,上代码。这里的只是一种可能,不一定要某个指针一定要某种用途,但是思想是类似的。

#include <cstdio>
#include <cstdlib>
#include <ctime>
#include <cassert>
using namespace std;

struct Node {
    int val;
    struct Node *next;
    struct Node *random;
    Node(int val_, Node *next_, Node *random_)
        : val(val_), next(next_), random(random_) { }
    Node (int val_)
        : val(val_), next(NULL), random(NULL) { }
    Node () // for the head nodes.
        : val(-1), next(NULL), random(NULL) { }
};

#define NR_NODES    10

// Setup a linked-list with random pointer
void setup_random_linked_list(struct Node *head)
{
    Node *curr;
    Node *all_nodes[NR_NODES];
    int i;

    // allocate all the nodes.
    for (i = NR_NODES - 1; i >= 0; i--) {
        curr = new Node(i, head->next, NULL);
        head->next = curr;
        all_nodes[i] = curr;
    }
    // setup the random pointers in each node.
    srand(time(0));
    curr = head->next;
    while (curr) {
        curr->random = all_nodes[rand() % NR_NODES];
        curr = curr->next;
    }
}

// free the list
void free_random_linked_list(struct Node *head)
{
    Node *curr, *temp;

    curr = head->next;
    while (curr) {
        temp = curr->next;
        delete curr;
        curr = temp;
    }
}

void print_random_linked_list(struct Node *head)
{
    Node *curr;
    curr = head->next;
    while (curr) {
        printf("%d ", curr->val);
        curr = curr->next;
    }
    printf("\n");
    curr = head->next;
    while (curr) {
        printf("%d ", curr->random->val);
        curr = curr->next;
    }
    printf("\n");
}

// copy from list @src to list @dst.
void copy_random_linked_list(struct Node *dst, struct Node *src)
{
    // Image that there're 4 parallel lists...

    Node *curr_src, *curr_dst;
    // 1, duplicate the list.
    curr_src = src->next;
    while (curr_src) {
        // copy the node
        curr_dst = new Node(curr_src->val);
        // 'random' vertically goes down, while 'next' goes up to original's random.
        curr_dst->next = curr_src->random;
        curr_src->random = curr_dst;
        // move forward
        curr_src = curr_src->next;
    }
    // 2, Now that 'random' comes vertically form the original list to the duplicated list, 
    // and that 'next' points to the random node in the old list,
    // use that to setup the 'random' pointer in the new list.
    curr_src = src->next;
    dst->next = curr_src->random; // follow the head node.
    while (curr_src) {
        curr_dst = curr_src->random;
        // setup 'random' relationship via the original list.
        curr_dst->random = curr_dst->next->random;
        // move forward
        curr_src = curr_src->next;
    }
    // 3, now the vertical links still exist, and 'next's in the new list point to 'random' 
    // in the original list, go through the lists to repair both.
    curr_src = src->next;
    while (curr_src) {
        curr_dst = curr_src->random;
        // setup 'next' relationship via the original list.
        curr_src->random = curr_dst->next;
        curr_dst->next = curr_src->next ? curr_src->next->random : NULL;
        // move forward
        curr_src = curr_src->next;
    }
}

int main(int argc, char *argv[])
{
    Node head, head2;

    setup_random_linked_list(&head);
    printf("the original list before copying: \n");
    print_random_linked_list(&head);

    copy_random_linked_list(&head2, &head);
    printf("finished copying random linked list.\n");

    printf("the original list after copying: \n");
    print_random_linked_list(&head);
    printf("and the duplicated list: \n");
    print_random_linked_list(&head2);

    free_random_linked_list(&head);
    free_random_linked_list(&head2);
    return 0;
}

转载于:https://www.cnblogs.com/qsort/archive/2011/07/15/2107829.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值