可能重复:
Copy a linked list
Hello stackoverflow!我正在尝试了解有关链表的更多信息,因此我尝试创建一个深层复制链表的函数。我控制住了这个。困难的部分是输入列表将包含引用列表中其他随机节点的节点。
第一个问题是我不知道如何在列表中创建“随机”节点。截至目前,我只是让“随机”节点等于“下一个”节点。
例如... pNext引用下一个值,但pReference将引用列表中的随机节点。与pReference 1引用3,2引用4,3引用1和4引用1。
第二个问题是我的代码正在处理“随机”节点值,但它依赖于原始副本。我希望它是一个深层复制而不依赖于原始版本。
#include <iostream>
#include <stdio.h>
using namespace std;
struct Node
{
int Number; // An integer value.
Node *pNext; // A pointer to the next node within the list.
Node *pReference; // A pointer to a random node within the list.
};
void push(Node** head, int data, Node* reference)
{
Node* newNode = new Node;
newNode->Number = data;
newNode->pNext = *head;
newNode->pReference = reference;
*head = newNode;
}
Node* DuplicateLinkedList(Node *head)
{
Node* current = head;
Node* newHead = NULL;
Node* newTail = NULL;
while(current != NULL)
{
if(newHead == NULL)
{
push(&newHead, current->Number, (current->pReference));
newTail = newHead;
}
else
{
push(&(newTail->pNext),current->Number, (current->pReference));
newTail = newTail->pNext;
}
current = current->pNext;
}
return newHead;
}
int main()
{
Node* headOfList= NULL;
//Creating List for verification.
for(int i=6; i>=1;i--)
{
push(&headOfList, i, headOfList);
}
//Call duplicate function.
Node* copiedList = DuplicateLinkedList(headOfList);
//Output for verification
cout << endl << "Original: " << endl;
while(headOfList != NULL)
{
cout << "Number: " << headOfList->Number << " ";
cout << "pNext: " << headOfList->pNext << " ";
cout << "pReference: " << headOfList->pReference << " " << endl;
headOfList = headOfList->pNext;
}
cout << endl << endl;
cout << endl << "Copied: " << endl;
while(copiedList != NULL)
{
cout << "Number: " << copiedList->Number << " ";
cout << "pNext: " << copiedList->pNext << " ";
cout << "pReference: " << copiedList->pReference << " " << endl;
copiedList = copiedList->pNext;
}
cout << endl << endl;
system("pause");
}
答案 0 :(得分:4)
使用std :: map存储原始指针和新指针之间的转换。
两次走动列表:一次创建新节点(pReference设置为NULL)并填充地图,第二次通过在地图中查找来填充pReference成员。
未经测试的代码:
Node* CopyNode(Node* src)
{
if (src == NULL) return NULL;
Node* newNode = new Node;
newNode->number = src->number;
newNode->pNext = NULL;
newNode->pReference = NULL;
return newNode;
}
Node* DeepCopy(Node* head)
{
if (head == NULL) return NULL;
std::map<Node*, Node*> mappings;
Node* newHead = copyNode(head);
mappings[head] = newHead;
Node* newCurrent = newHead;
for (Node* next = head->pNext; next != NULL; next = next->pNext)
{
Node* copy = CopyNode(next);
mappings[next] = copy;
newCurrent->pNext = copy;
newCurrent = copy;
}
for (Node* current = head; current != NULL; current = current->pNext)
{
Node* newCurrent = mappings[current];
newCurrent->pReference = mappings[current->pReference];
}
return newHead;
}
答案 1 :(得分:1)
这是一个非常灵巧的算法,我学会了在没有列表大小的情况下在O(N)时间从列表中获取随机元素。
Node* GetRandomNode(Node* head)
{
int i = 1;
srand ( time (NULL) );
Node* temp = head;
while ( head != NULL )
{
if ( rand() % i == 0 ) temp = head;
head = head->pNext;
i++;
}
return temp;
}
因此,您可以使用列表头部为每个节点调用此函数,以获得均匀分布的随机节点。
至于深层复制问题,您只需分配一个新节点并将节点的值复制到其中。
答案 2 :(得分:1)
如何简化。
我通常首先编写递归解决方案,然后将其转换为循环:
Node* DuplicateLinkedList(Node* list)
{
std::map<Node*,Node*> nodeMap;
Node* result = DuplicateNode(nodeMap, list);
resetRandomNodes(nodeMap, result);
return result;
}
Node* DuplicateNode(std::map<Node*,Node*>& nodeMap, Node *node)
{
if (node== NULL)
{ return NULL;
}
Node* result = new Node(node->Number,
// Recursively copy the next element
DuplicateNode(nodeMap, node->pNext),
// For now store the original rand element
// We will fix this by iterating over the list again
node->pReference
);
// Keep a record of which node maps to which new node.
nodeMap[node] = result;
return result;
}
void resetRandomNodes(std::map<Node*,Node*>& nodeMap, Node *node)
{
if (node== NULL)
{ return;
}
// Remember we stored the original random node (from the src list) in pReference.
// Now we must replace this with the correct value. We can look this up in the
// nodeMap we created when we copied the loop.
node->pReference = nodeMap[node->pReference];
// Recursively go through list.
resetRandomNodes(nodeMap, node->pNext);
}
现在为了提高效率,您只需要将递归转换为循环。应该是比较琐碎的。完成后,您可以将三个功能合并为一个。