【问题标题】:Merging two linked lists at alternate position在交替位置合并两个链表
【发布时间】:2015-03-26 17:49:29
【问题描述】:

我正在合并两个链接列表,第三个列表由交替位置的元素组成,但将合并的功能不起作用

void insert2()
{
    //node ptr-pointer of first linked list<br>
    //node1 ptr1-pointer of second list<br>
    //node2 ptr2 -pointer of the merged linked list

    node *ptr=head;
    node1 *ptr1=head1;
    node2 *ptr2=(node2*)malloc(sizeof(node2));
    node *ptr3;

    while(ptr!=NULL&&ptr1!=NULL)
    {
        //Entering the element of first linked list

        ptr2->info=ptr->info;
        if(head2==NULL)
        {
            ptr->next=NULL;
            head=ptr;
        }
        else
        {
            ptr3=head2;
            while(ptr3->next!=NULL)
            {
                ptr3=ptr3->next;
            }
            ptr3->next=ptr2;
            ptr2->next=NULL;
        }
        //Entering the element of second linked list

        ptr2->info=ptr1->info;
        while(ptr3->next!=NULL)
        {
            ptr3=ptr3->next;
        }
        ptr3->next=ptr2;
        ptr2->next=NULL;
    }
}

【问题讨论】:

  • 问题是什么?
  • Input-2 3 5 6 7// list 1 Input- 8 9 10 11 Output 应该是-2 8 3 9 5 10 7 11 但我上面给出的功能不起作用跨度>
  • 如果列表长度不同怎么办?有许多相关的问题,其中一些列在右侧。 Merging two sorted linked lists 接近你所追求的;您的数据未明确排序,因此您的比较更容易。关于简单地合并两个列表中的替代值,我还没有发现其他一些问题。
  • 你的代码的输出是什么?
  • 您既没有提供输入函数也没有提供输出函数,也没有提供调用您提供的函数的代码,因此我们很难确定可能出了什么问题。此外还不清楚为什么您有三种不同的节点类型。

标签: c data-structures linked-list


【解决方案1】:

假设我们要在第二个列表中交替添加节点。所以第二个列表将成为新列表。这个想法是

  • 保留 2 个指向当前节点的指针。最初是原始列表 p 和 q。

  • 虽然它们不为空(两者都不为空),但您存储在两个节点的下一个地址中。

  • 现在你会怎么做?您将 p 的下一个指向 q 的当前,q 的当前指向 p 的下一个。

  • 当前指针现在将正确更改为下一个节点,因为它们现在将被处理。

 --------             ----------
| p_curr|------------>|        |--------->NULL
|-------|    p_next-->|--------|

 --------             ----------
| q_curr|------------>|        |--------->NULL
|-------|    q_next-->|--------|

 //After an iteration in the while loop.
 --------                ----------
|       |----|       --> |  p_curr| --------->NULL
|-------|  _ |______|    |--------|
          |  | 
 -------- |  |        ----------
|       |_|  |------->| q_curr |--------->NULL
|-------|             |--------|

代码将是这样的(更多信息请查看link

void merge(struct node *p, struct node **q)
{
     struct node *p_curr = p, *q_curr = *q;
     struct node *p_next, *q_next;

     // While therre are avialable positions in p
     while (p_curr != NULL && q_curr != NULL)
     {
         // Save next pointers
         p_next = p_curr->next;
         q_next = q_curr->next;

         // Make q_curr as next of p_curr
         q_curr->next = p_next;  // Change next pointer of q_curr
         p_curr->next = q_curr;  // Change next pointer of p_curr

         // Update current pointers for next iteration
         p_curr = p_next;
         q_curr = q_next;
    }

    *q = q_curr; // Update head pointer of second list
}

创建第三个链表作为结果

  • 您可以像以前的方法一样执行此操作。现在您需要进行哪些更改?

  • 您只需复制list Alist B,然后将它们作为参数传递给列表,您将获得上一个函数的第三个列表。

    李>
  • 但这是一个相当原始的解决方案。您还可以在函数中以线性时间动态构建列表。

struct node * getnode()
{
    struct node *temp=(struct node*)malloc(sizeof(struct node));
    if(temp==NULL)
    {
         printf("\n Error in allocation\n");
         exit(0);
    }
    return temp;
 }

 void merge(struct node *p, struct node *q,struct node **n)   
 {
    struct node *p_curr = p, *q_curr = q;
    struct node **store;
    struct node *n1;   
 // While therre are avialable positions in p
 while (p_curr != NULL || q_curr != NULL)
 {

    if (p_curr) 
    {
        if(first)
        {
             store=&n1;first=0;
        }
        n1=getnode();
        n1->info=p_curr->info;
        n1->next = p_curr->next;
        n1=n1->next;
        p_curr=p_curr->next;
    }
    if (q_curr) 
    {
        if(first)
        {
             store=&n1;first=0;
        }
        n1=getnode();
        n1->info=q_curr->info;
        n1->next = q_curr->next;
        n1=n1->next;
        q_curr=q_curr->next;
     }
  }
  *n=*store;
 }

请记住,在这种情况下,两个 if 语句正在检查其中是否有任何一个是 NULL。如果是这种情况,则在结果节点中添加其他列表的节点。 store 存储第一个节点的地址。毕竟我们需要指向第三个节点的头部。

【讨论】:

  • 实际上我正在尝试使用备用节点创建第三个列表,并且我没有修改现有列表
【解决方案2】:

试试这个:

NODE * AlternateListMerge(NODE *pSrc1, NODE *pSrc2)
{
NODE *pDst = NULL;                      /* destination head ptr */
NODE **ppDst = &pDst;                   /* ptr to head or prev->next */
NODE *pNode;                            /* ptr to node */
    while(pSrc1 || pSrc2){
        if(pSrc1){
            pNode = malloc(sizeof(NODE));
            pNode->info = pSrc1->info;
            pSrc1 = pSrc1->next;
            *ppDst = pNode;
            ppDst = &pNode->next;
        }
        if(pSrc2){
            pNode = malloc(sizeof(NODE));
            pNode->info = pSrc2->info;
            pSrc2 = pSrc2->next;
            *ppDst = pNode;
            ppDst = &pNode->next;
        }
    }
    *ppDst = NULL;
    return pDst;
}

或者这个(更少的代码,更多的时间):

NODE * AlternateListMerge(NODE *pSrc1, NODE *pSrc2)
{
NODE *pDst = NULL;                      /* destination head ptr */
NODE **ppDst = &pDst;                   /* ptr to head or prev->next */
NODE *pNode;                            /* ptr to node */
NODE *pSwap;                            /* used for swap */
    while(pSrc1 || pSrc2){
        if(pSrc1){
            pNode = malloc(sizeof(NODE));
            pNode->info = pSrc1->info;
            pSrc1 = pSrc1->next;
            *ppDst = pNode;
            ppDst = &pNode->next;
        }
        pSwap = pSrc1;
        pSrc1 = pSrc2;
        pSrc2 = pSwap;
    }
    *ppDst = NULL;
    return pDst;
}

【讨论】:

    【解决方案3】:

    没有涉及类型的声明,没有关于如何初始化列表的信息,也没有关于如何尝试输出结果的详细信息,我只能笼统地说。但是,鉴于您确实说过要避免修改原始列表,可以肯定的是,您需要为每个列表中的每个节点制作一个 副本。这是您可以做到的一种方法:

    struct node {
        void *data;
        struct node *next;
    };
    
    #define COPY(from, to, error_label) do { \
        to = malloc(sizeof(struct node));    \
        if (! to) {                          \
            /* allocation error */           \
            goto error_label;                \
        }                                    \
        to->data = from->data;               \
        to->next = NULL;                     \
    } while (0)
    
    int merge(struct node *head1, struct node *head2, struct node **result) {
        struct node dummy = { NULL, NULL };
        struct node *merge_tail = dummy;
        int node_count = 0;
    
        while (head1 || head2) {
            if (head1) {
                COPY(head1, merge_tail->next, allocation_error);
                head1 = head1->next;
                merge_tail = merge_tail->next;
                node_count += 1;
            }
            if (head2) {
                COPY(head2, merge_tail->next, allocation_error);
                head2 = head2->next;
                merge_tail = merge_tail->next;
                node_count += 1;
            }
        }
        *result = dummy->next;
        return node_count;
    
        allocation_error:
        while (dummy->next) {
            struct node *temp = dummy->next;
    
            dummy->next = dummy->next->next;
            free(temp);
        }
    
        return -1;
    }
    

    基本思想是同时遍历两个输入列表,或者将节点从一个输入和另一个输入复制到输出列表。此特定实现返回合并列表中节点总数的计数,或 -1 错误;合并列表的头部通过第三个参数返回。如果输入列表具有不同的长度(较长列表中剩余的节点附加在末尾),或者输入列表中的一个或两个为空,则不会触发它。复制节点的大部分血腥细节都被分解到COPY() 宏中。 dummy 节点避免了合并列表的头部成为特殊情况。

    不管怎样,如果构建三个列表的节点是不同类型的,那么这样做是没有意义的。

    【讨论】:

      猜你喜欢
      • 2018-05-25
      • 2021-02-26
      • 2015-08-03
      • 2012-10-26
      • 1970-01-01
      • 2016-10-14
      • 1970-01-01
      相关资源
      最近更新 更多