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