A linked list is given such that each node contains an additional random pointer which could point to any node in the list or null.
Return a deep copy of the list.
结构体定义如下:
struct RandomListNode {
int label;
struct RandomListNode *next;
struct RandomListNode *random;
};
函数定义如下
struct RandomListNode *copyRandomList(struct RandomListNode *head)
看到此题的标签是HashTable,知道应该用hash表,但是如何使用呢?
设原先的链表为list1,新的链表为list2
如果可以通过list1中的node1的random指针,找到list2中的node2的指针,
也就是说,假如random指向了list1中的第三个节点,那么random对应的node2也应该是第三个
如何建立node1和node2之间的联系呢?hash表
建立联系的过程如下:
struct RandomListNode newhead = {0, NULL, NULL};
struct RandomListNode* p = head;
struct RandomListNode* q = &newhead;
Hashtable* ht = createHashTable(1023);
while(p){
q->next = (struct RandomListNode*)malloc(sizeof(struct RandomListNode));
q->next->label = p->label;
insert(ht, (Key)p, (Value)q->next);
q = q->next;
p = p->next;
}
可以看到将list1中的节点指针,和list2中的节点指针,通过一个hash表联系起来。
现在已经构建了新的链表和hash表,剩余的工作就是添加random指针。
就是使用random指针作为key,在hash表中查找对应的value,也就是list2中对应的节点指针。
但是,第一步的构建过程好像没有添加random指针,添加的是节点本身的指针,这么查找真的对吗?
仔细想一下,random指针其实是节点指针的子集。即以random为key的hash节点肯定是存在的。
添加random指针的过程如下:
q = newhead.next;
p = head;
while(q){
q->random = NULL;
if(p->random){
node* n1 = find(ht, (Key)p->random, comp);
if(n1){
q->random = (struct RandomListNode*)n1->value;
}
}
p = p->next;
q = q->next;
}
为此,我还特意写了一个hash表,其实没有必要。
直接用STL中的unordered_map就行,为了练手,就自己写了一个。(其实是为了准备线上笔试,怕时间来不及,提前写好)
template<class Key, class Value>
class Hashtable;
template<class Key, class Value>
class node{
private:
friend class Hashtable<Key, Value>;
Key key;
Value value;
node* next;
public:
node(const Key& k, const Value& v):key(k),value(v),next(NULL){}
node():key(),value(),next(NULL){}
Value& data(){ return value; }
Key& index(){return key;}
~node(){ }
};
template<class Key, class Value>
class Hashtable{
private:
node<Key,Value>* listheads;
int size;
public:
Hashtable(int size);
~Hashtable();
void insert(const Key& key, const Value& value);
node<Key, Value>* find(const Key& key);
};
template<class Key, class Value>
Hashtable<Key, Value>::Hashtable(int __size)
{
listheads = new node<Key,Value>[__size]; //表头节点
size = __size;
}
template<class Key, class Value>
Hashtable<Key, Value>::~Hashtable()
{
node<Key, Value>* nd;
node<Key, Value>* p;
for(int i = 0;i<size;i++){
nd = (listheads + i)->next;
while(nd){
p = nd;
nd = nd->next;
delete p;
}
}
delete [] listheads;
}
template<class Key, class Value>
void Hashtable<Key, Value>::insert(const Key& key, const Value& value)
{
node<Key,Value>* listhead = listheads + (key % size);
node<Key,Value>* nd = new node<Key,Value>(key, value);
nd->next = listhead->next;
listhead->next = nd; //后进先出式进链
}
template<class Key, class Value>
node<Key, Value>* Hashtable<Key, Value>::find(const Key& key){
node<Key,Value>* nd = listheads + (key % size);
while(nd && key != nd->key){
nd = nd->next;
}
return nd;
}
功能很不完善,没有删除和修改功能,没有实现rehash,没有提供迭代器,更没有考虑线程安全性,更像是一个玩具。
想想项目中用到的hash表,确实比我这个要健全多了。