KimiZ님의 프로필SEIZE THE DAY사진블로그리스트기타 ![]() | 도움말 |
|
11월 24일 特殊链表的拷贝--一道面试题面IBM时候被问到,死在这道题上了。标记一下。 struct node { int data; struct node * next; struct node * random; }; 本题来源是ms的一道面试题,要求是将一条有特殊结构的链表进行复制,链表的结构如上,除了正常的2个域之外,多了一个random,它代表一个指向链表 上某一任意节点的指针,要求将该链表复制。如图,其中实线表示next域,虚线表示random域。 ![]() 难点分析:本题最难的部分就在于如何将random域完好无损的完全拷贝复制到新的链表之上,对于普通链表一个while循环拷贝就可以搞定,但是这里似乎不可行。 突破点:如何保存或记录random域可以作为一个思考的参考点,下面提供2种解法: 1. hash缓存: 我们可以定义一个hash表,key为被拷贝链表中Node的地址,value为新的拷贝链表中Node的值。下面将在伪代码中进一步说明 伪代码如下: struct node * old_list; struct node * new_list; hash ht; while( old_list != NULL ) { if( ht.get(old_list) == NULL ) // 当前节点没有被复制过,则拷贝节点,同时将原节点的地址作为key,插入hash表 { new_node = copy(*old_list); ht.set(old_list, new_node); } else // 已经存在则直接将该节点读出 { new_node = ht.get(old_list); } // 并将新复制的节点插入链表 insert(new_list, new_node); if( ht.get(old_list->random) == NULL ) // 如果ht的random不存在,那么产生一个random node,并放入hash表 { random_node = copy(*(old_list->random)); ht.set(old_list->ramdon,random_node); } else //否则从hash表中读出random { random_node = ht.get(old_list->random); } // 将random域进行填充 new_node->random = random_node; } 这样可以看出,因为地址值是唯一存在的,所以Hash函数的设计可以保证每个节点的值都会被一一映射,并且由于每一个节点都只会被复制一次,并且在代码的遍历过程中就已经完全复制好,空间复杂度为O(n),时间复杂度为O(n) 2. 用一个图的方法看的比较清楚,首先在遍历原来链表的过程中,插入新的节点,比如A_N是copy(A_O)的,同时将A_N->next = A_O->next; A_O->next = A_N;通过一个遍历,我们就可以将链表复制成图中的样子。在完成next域的链接后,需要开始做random域的复制。 ![]() 在实现了next的结构之后,我们需要开始对new_list的random域和next域进行赋值。 那么有: A_N->random = A_O->random->next; 入图所示:A_O->random为C_O,C_O的next为C_N,这样A_N->random = C_N; 对于 A_N->next = A_N->next->next;即B_N; 该算法复杂度为O(N),空间复杂度为O(1),除了新拷贝的空间之外没有额外地址; |
|
|