链表问题

发布于 2024-09-14 10:22:18 字数 2699 浏览 3 评论 0原文

可能的重复:
复制链接列表

你好 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");
}

Possible Duplicate:
Copy a linked list

Hello stackoverflow! I am trying to learn more about linked lists so I am trying to create a function that deep copies a linked list. I've got this under control. The hard part is that the input list is going to contain nodes that reference other random nodes within the list.

First problem is that I don't know how to create the 'random' nodes within the list. As of now, I just have the 'random' nodes equal to the 'next' nodes.

For example... pNext references the next value, but pReference will reference a random node in the list. Like pReference 1 references 3, 2 references 4, 3 references 1, and 4 references 1.

Second problem is that my code is coping the 'random' node values but it is dependent on the original copy. I want it to be a deep copy and not dependent on the original.

#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");
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

前事休说 2024-09-21 10:22:18

使用 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;
}

Use a std::map to store the conversion between the original and the new pointers.

Walk the list two times: one time to create the new nodes (with pReference set to NULL) and to populate the map, a second time to fill in the pReference member by looking them up in the map.

Untested code:

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;
}
无声情话 2024-09-21 10:22:18

这是一个非常巧妙的算法,当你没有列表的大小时,我学会了在 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;
}

因此,您只需使用每个节点的列表头调用此函数即可获得均匀分布的随机节点。

至于深度复制问题,您只需分配一个新节点并将节点的值复制到其中即可。

Here is a very slick algorithm I learned to get a random element from a list in O(N) time when you don't have the size of the list.

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;
}

So you can just call this function with the head of your list for each node to get a uniformly distributed random node.

As for your deep copy problem, you just have to allocate a new node and copy the value of your node into it.

晨曦慕雪 2024-09-21 10:22:18

简化一下怎么样。
我通常先编写递归解决方案,然后将其转换为循环:

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

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

How about simplifying.
I usually write the recursive solution first then translate that into a loop:

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

Now to make it efficient you just need to translate the recursion into a loop. Should be relatively trivial. Once you have done that you can merge the three functions into one.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文