一道奇妙的链表复制问题

最近看到一道有关链表复制的算法题,解法很是奇妙。

题目:已知一链表,每个节点除了有一个指向下一节点的指针外,还有一随机指针指向链表中的任意节点(可能为空,也有可能为自身),请复制一个链表,要求节点的顺序以及节点上的随机指针指向的节点位置和原链表一致。

解法一:

空间换时间,利用数组、链表等数据结构存储Random指针位置信息,这里样例代码使用Hash表,这样空间利用率是O(n),时间效率也是O(n)。

  1. #include <hash_map>
  2. using namespace std;
  3. using namespace stdext;
  4. struct Node
  5. {
  6.     Node* pNext;
  7.     Node* pRandom;
  8. };
  9. Node* Copy(Node* pHead)
  10. {
  11.     if (pHead = NULL)
  12.         return NULL;
  13.     // 额外存储空间,利用Hash方法达到常数级的查找开销
  14.     hash_map<Node*, int> NodeMap;
  15.     int nIndex = 0;
  16.     Node* pNode = pHead;
  17.     // 将链表存入map中,并记录下编号
  18.     while (pNode != NULL)
  19.     {
  20.         if (NodeMap.insert(hash_map<Node*, int>::value_type(pNode, nIndex)).second)
  21.         {
  22.             nIndex++;
  23.             pNode = pNode->pNext;
  24.         }
  25.         else // 到达环的交点
  26.             break;
  27.     }
  28.     Node* pNewNodes = new Node[NodeMap.size()];
  29.     // 顺序复制每个节点的指针
  30.     nIndex = 0;
  31.     for (hash_map<Node*, int>::iterator it = NodeMap.begin(); it != NodeMap.end(); it++, nIndex++)
  32.     {
  33.         int nNext = 0, nRandom = 0;
  34.         Node* pOriginal = it->first;
  35.         // 复制Next
  36.         if (pOriginal->pNext != NULL)
  37.         {
  38.             hash_map<Node*, int>::iterator temp = NodeMap.find(pOriginal->pNext);
  39.             pNewNodes[nIndex].pNext = &pNewNodes[temp->second];
  40.         }
  41.         else
  42.             pNewNodes[nIndex].pNext = NULL;
  43.         // 复制Random
  44.         if (pOriginal->pRandom != NULL)
  45.         {
  46.             hash_map<Node*, int>::iterator temp = NodeMap.find(pOriginal->pRandom);
  47.             pNewNodes[nIndex].pRandom = &pNewNodes[temp->second];
  48.         }
  49.         else
  50.             pNewNodes[nIndex].pRandom = NULL;
  51.     }
  52.     return pNewNodes;
  53. }

解法二:

此方法的中心思想是把原始链表和复制链表先合并为一个有固定顺序的链表,然后给复制链表中每个节点的随机指针复制,最后再打断链表恢复原样。和解法一相比,空间效率上更佳。

代码如下:

  1. typedef struct __Node {
  2.     int nData;
  3.     __Node* pNext;
  4.     __Node* pRandom;
  5. } Node;
  6. Node* DuplicateList(Node* pSrcListHead)
  7. {
  8.     if (pSrcListHead == NULL)
  9.         return NULL;
  10.     
  11.     Node* pNode = pSrcListHead;
  12.     while (pNode != NULL)
  13.     {
  14.         Node* pNewNode = new Node;
  15.         pNewNode->nData = pNode->nData;
  16.         pNewNode->pNext = pNode->pNext;
  17.         pNewNode->pRandom = pNode->pRandom;
  18.         pNode->pNext = pNewNode;
  19.         pNode = pNewNode->pNext;
  20.     }
  21.     
  22.     Node* pDestListHead = pSrcListHead->pNext;
  23.     pNode = pSrcListHead;
  24.     while (pNode != NULL)
  25.     {
  26.         pNode->pNext->pRandom = pNode->pRandom->pNext;
  27.         pNode = pNode->pNext->pNext;
  28.     }
  29.     pNode = pSrcListHead;
  30.     Node* pNode2 = pNode->pNext;
  31.     while (pNode != NULL)
  32.     {
  33.         pNode->pNext = pNode2->pNext;
  34.         pNode = pNode->pNext;
  35.         if (Node)
  36.             pNode2->pNext = pNode->pNext;
  37.         else
  38.             pNode2->pNext = NULL;
  39.         pNode2 = pNode2->pNext;
  40.     }
  41.     return pDestListHead;
  42. }

不过目前还未考虑到原始链表有环的情况,如果原始链表有环,则应该先求出环的入口点,然后利用上面的方法进行链表复制,在这里就不详细列出代码了。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值