一个单链表,其中除了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;
}