您的位置:首页 > 运维架构

LeetCode之Copy List with Random Pointer

2015-04-18 09:46 399 查看
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表,确实比我这个要健全多了。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息