链接列表问题

时间:2010-08-11 21:45:04

标签: c++ linked-list

  

可能重复:
  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");
}

3 个答案:

答案 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);
}

现在为了提高效率,您只需要将递归转换为循环。应该是比较琐碎的。完成后,您可以将三个功能合并为一个。