合并两个排序的圆形单链表

时间:2015-02-25 20:50:18

标签: c algorithm singly-linked-list circular-list

我在C语言课程考试之前练习了一些算法问题而且我在这个问题上陷入困境(至少3小时甚至4小时),我不知道如何回答:

您有两个已经排序的循环单链接列表,您必须将它们合并并返回新循环链接列表的头部,而不创建任何新的额外节点。返回的列表也应该排序。

节点结构是:

typedef struct Node {
   int data;
   struct Node* next;
} Node;

我尝试了很多方法(递归和非递归)但没有解决问题。

感谢您的帮助。

4 个答案:

答案 0 :(得分:2)

这基本上是merge sort的合并步骤。

在链接列表中,可以在适当的位置完成。

我们的想法是为每个列表设置一个迭代器,直到合并列表中的数据用完为止,将list1中的节点与list2中的节点进行比较,如果list2_iterator

通过维护额外的prev迭代器,在当前节点完成之前插入节点。

请注意,在此算法的整个过程中 - 没有创建单个新节点,您所做的只是"移动"从list2list1的节点。

如果此程序为O(n),则为复杂性。

答案 1 :(得分:1)

首先维护一个包含两个链表的队列。以下是伪代码: -

 queue* merge_queues (queue* first, queue* second)
       {

           queue* merged_queue = create_queue(first->capacity + second->capacity);
           if (first != NULL && second != NULL){
              while ( !is_empty (first) && !is_empty (second)){
           int max;
           if ( peekqueue (first) > peekqueue (second)){
               max = peekqueue (first);
               dequeue (first);
           }
           else{
                max = peekqueue (second);
                dequeue (second);
           }
           enqueue( merged_queue, max);
        }
         while ( !is_empty (first)){
              enqueue( merged_queue, peekqueue(first));
              dequeue (first);
         }
         while (!is_empty (second)){
             enqueue (merged_queue, peekqueue(second));
             dequeue (second);
        }
    }
    return merged_queue;
}

答案 2 :(得分:0)

合并两个已排序列表的示例代码。要检查循环列表的结束节点,检查指向列表头节点的指针而不是NULL,并且在到达一个列表的末尾之后,您需要从另一个列表中一次链接其余节点因为终结符不是NULL。合并之后,您需要设置最后一个节点的指向头节点的下一个指针,使其成为循环列表。代码检查Src2< Src1类似于C ++标准库排序比较使用<而不是< =。

NODE * MergeLists(NODE *pSrc1, NODE *pSrc2)
{
NODE *pDst = NULL;                      /* destination head ptr */
NODE **ppDst = &pDst;                   /* ptr to head or prev->next */
    while(1){
        if(pSrc1 == NULL){              /* if end of Src1 */
            *ppDst = pSrc2;             /*   append remainder of Src2 */
            break;                      /*   and break out of loop */
        }
        if(pSrc2 == NULL){              /* if end of Src2 */
            *ppDst = pSrc1;             /*   append remainder of Src1 */
            break;                      /*   and break out of loop */
        }
        if(pSrc2->data < pSrc1->data){  /* if Src2 < Src1 */
            *ppDst = pSrc2;             /*   append node from Src2 */
            pSrc2 = *(ppDst = &(pSrc2->next));
            continue;
        } else {                        /* else Src1 <= Src2 */
            *ppDst = pSrc1;             /*   append node from Src1 */
            pSrc1 = *(ppDst = &(pSrc1->next));
            continue;
        }
    }
    return pDst;
}

答案 3 :(得分:0)

这合并了两个循环链表。该代码假设两个列表已经排序并开始正​​确的点。

#include <stdio.h>

struct llist {
        struct llist *next;
        int value;
        };

struct llist wheel[] =
{{ wheel+1, 0 }
,{ wheel+2, 2 }
,{ wheel+3, 4 }
,{ wheel+0, 6 }
};
struct llist cycle[] =
{{ cycle+1, 0 }
,{ cycle+2, 3 }
,{ cycle+3, 6 }
,{ cycle+0, 9 }
};

struct llist *mergelists(struct llist *one, struct llist *two)
{
struct llist *einz, *zwei;
struct llist *result ,**pp;

if (!one) return two;
if (!two) return one;

result = NULL; pp= &result;

for (einz=one, zwei=two; einz || zwei; pp = &(*pp)->next ) {
        if ( !zwei || einz && einz->value <= zwei->value) {
                *pp = einz; einz = einz->next == one ? NULL : einz->next;
                }
        else    {
                *pp = zwei; zwei = zwei->next == two ? NULL : zwei->next;
                }
        }
*pp = result; /* close the loop */
return result;
}

int main(void)
{
struct llist *p;

        /* This loops.  forever ... */
for(p = mergelists( wheel, cycle); p ; p = p->next) {
        printf("%p = %d\n", (void*) p, p->value );
        }
return 0;
}