【问题标题】:Alternating split of a given Singly Linked List给定单链表的交替拆分
【发布时间】:2014-08-29 14:08:13
【问题描述】:

编写一个函数 AlternatingSplit(),它接受一个列表并将其节点划分为两个较小的列表“a”和“b”。子列表应由原始列表中的交替元素组成。因此,如果原始列表为 0->1->0->1->0->1,则一个子列表应为 0->0->0,另一个应为 1->1->1。

有关问题的更多详细信息 - http://www.geeksforgeeks.org/alternating-split-of-a-given-singly-linked-list/

现在我编写了这段代码,它运行成功了

#include<stdio.h>
#include<stdlib.h>
struct node
{
    int num;
    node *next;
};

node *start1 = NULL, *start2 = NULL, *start3 = NULL;

void push()
{
    node *temp = (node *)malloc(sizeof(node));
    printf("Enter number = ");
    scanf("%d", &temp->num);
    temp -> next = start1;
    start1 = temp;
}

void split()
{
    while(start1 != NULL)
    {
        node *temp1 = (node *)malloc(sizeof(node));
        temp1 ->num = start1 ->num;
        temp1->next = start2;
        start2 = temp1;
        start1 = start1 -> next;

        if(start1 != NULL)
        {
            node *temp2 = (node *)malloc(sizeof(node));
            temp2 ->num = start1 ->num;
            temp2->next = start3;
            start3 = temp2;
            start1 = start1 -> next;
        }
    }
}

int main()
{
    int n;
    scanf("%d", &n);

    while(n--)
        push();

    split();

    node *temp = start2;

    while(temp != NULL)
    {
        printf("%d  ", temp ->num);
        temp = temp ->next;
    }

    printf("\n");
    temp = start3;

    while(temp != NULL)
    {
        printf("%d  ", temp ->num);
        temp = temp ->next;
    }

    return 0;
}

问题提供的代码是 -

/*Program to alternatively split a linked list into two halves */
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>

/* Link list node */
struct node
{
    int data;
    struct node* next;
};

/* pull off the front node of the source and put it in dest */
void MoveNode(struct node** destRef, struct node** sourceRef) ;

/* Given the source list, split its nodes into two shorter lists.
If we number the elements 0, 1, 2, ... then all the even elements
should go in the first list, and all the odd elements in the second.
The elements in the new lists may be in any order. */

void AlternatingSplit(struct node* source, struct node** aRef, struct node** bRef) 
{
    /* split the nodes of source to these 'a' and 'b' lists */
    struct node* a = NULL; 
    struct node* b = NULL;

    struct node* current = source;

    while (current != NULL) 
    {
        MoveNode(&a, &current); /* Move a node to list 'a' */

        if (current != NULL) 
        {
            MoveNode(&b, &current); /* Move a node to list 'b' */
        }
    }

    *aRef = a;
    *bRef = b;

}

/* Take the node from the front of the source, and move it to the front of the dest.
It is an error to call this with the source list empty. 

Before calling MoveNode():
source == {1, 2, 3}   
dest == {1, 2, 3}

Affter calling MoveNode():
source == {2, 3}      
dest == {1, 1, 2, 3}      
*/

void MoveNode(struct node** destRef, struct node** sourceRef) 
{
    /* the front source node  */
    struct node* newNode = *sourceRef; 
    assert(newNode != NULL);

    /* Advance the source pointer */
    *sourceRef = newNode->next;

    /* Link the old dest off the new node */
    newNode->next = *destRef; 

    /* Move dest to point to the new node */
    *destRef = newNode; 
}

/* UTILITY FUNCTIONS */
/* Function to insert a node at the beginging of the linked list */

void push(struct node** head_ref, int new_data)
{
    /* allocate node */
    struct node* new_node = (struct node*) malloc(sizeof(struct node));

    /* put in the data  */
    new_node->data  = new_data;

    /* link the old list off the new node */
    new_node->next = (*head_ref);     

    /* move the head to point to the new node */
    (*head_ref)    = new_node;
}

/* Function to print nodes in a given linked list */

void printList(struct node *node)
{
    while(node!=NULL)
    {
        printf("%d ", node->data);
        node = node->next;
    }
} 

/* Drier program to test above functions*/
int main()
{
    /* Start with the empty list */
    struct node* head = NULL;
    struct node* a = NULL;
    struct node* b = NULL;  

    /* Let us create a sorted linked list to test the functions
    Created linked list will be 0->1->2->3->4->5 */
    push(&head, 5);
    push(&head, 4);
    push(&head, 3);
    push(&head, 2);
    push(&head, 1);                                    
    push(&head, 0);  

    printf("\n Original linked List:  ");
    printList(head); 

    /* Remove duplicates from linked list */
    AlternatingSplit(head, &a, &b); 

    printf("\n Resultant Linked List 'a' ");
    printList(a);            

    printf("\n Resultant Linked List 'b' ");
    printList(b);            

    getchar();

    return 0;

}

我的问题是,考虑到时间复杂度、空间复杂度和其他所有因素,这两个代码中哪一个更有效、更正确? 为什么? 详细的解释会更有帮助。

【问题讨论】:

  • 没有一个例子检查内存错误,这是我的第一反应:)

标签: c linked-list


【解决方案1】:

当你只是拆分一个链表时,你不需要任何内存分配,只需要围绕指针进行洗牌就足够了。

您的代码在拆分时进行内存分配,因此效率较低,模型答案代码要好得多。

但更糟糕的是,您的代码会泄漏内存。它会丢失指向原始列表元素的指针而不释放它们。所以你的代码实际上是错误的,而且方式很糟糕。


要仅修复内存泄漏,这是一个实际的错误,您需要将两个 start1 = start1 -&gt; next; 行更改为:

node *tmp_next =  start1->next;
free(start1);
start1 = tmp_next;

对于其他更改,模型答案是一个很好的示例,但最重要的是:摆脱额外的 malloc 调用,并通过移动节点进行拆分,而不是分配新节点和复制数据(并在上述错误修复之后,释放旧节点)。然后摆脱全局变量,而是向函数添加参数,就像在模型答案中一样。

【讨论】:

  • 谢谢@hyde 我要做的就是让它没有错误,我不太确定这个过程,如果你只是调试代码 sn-p 并添加到它会很有帮助这里的评论。
  • 好吧,我在答案中添加了如何修复内存泄漏(但我重复一遍:那是多余的,您实际上应该摆脱额外的 malloc 调用,而不是仅仅让它们不泄漏记忆)。模型答案很好地涵盖了其余要修复的问题。
【解决方案2】:

只是另一个快速拆分,没有新的分配,并保持原始列表减少为奇数元素,同时为偶数元素形成新列表,以及对每个关键步骤的评论

void split_in_evenodd(node *orig)
{
    if(!orig)
        return;

    node *e, *cur, *e_hd;

    e = orig->next; // point first even member
    e_hd = e; // keep a head pointer to even list

    if(!e) // covers the case of list with single element
        return;

    orig->next = e->next; // make orig skip the even node
    cur = orig->next; // cur moves to next odd node

    while(cur && cur->next) {
        e->next = cur->next; // even pointing to next even node
        e = e->next; // move even list forward

        cur->next = e->next; // update odds next
        cur = e->next;// move current forward (to next odd)
    }
}

【讨论】:

    【解决方案3】:

    在解决这个问题时,我想出了这种方法,我为两个拆分创建了单独的头节点,然后在计数变量的帮助下,所有奇数链表节点都被发送到拆分链表 1 和所有偶数计数链表节点被发送到拆分链表 2。 希望能帮助到你!这段代码是 C 语言的。

    #include <stdio.h>
    #include <stdlib.h>
    struct node *add_at_end(struct node *ptr,int item);
    struct node{
    int data;
    struct node *next;
    };
    
    void main(){
    
    struct node *head=malloc(sizeof(struct node));
    head->data=1;
    head->next=NULL;
    // first node gets created
    struct node *ptr=head;
    //now we will add other nodes at the end
    
    ptr=add_at_end(ptr,2);
    ptr=add_at_end(ptr,3);
    ptr=add_at_end(ptr,4);
    ptr=add_at_end(ptr,5);
    //the nodes get added to the linked list.Now let's print the data of all these nodes
    ptr=head;
    while(ptr!=NULL){
        printf("%d ",ptr->data);
        ptr=ptr->next;
    }
    printf("\n");
    int count;
    struct node *splitNode=malloc(sizeof(struct node));
    struct node *forward=malloc(sizeof(struct node));
    forward=head;
    
    //now we will create the 1st split linked list
    struct node *headll1=malloc(sizeof(struct node));
    splitNode=forward;
    forward=forward->next;
        headll1->data=splitNode->data;
        headll1->next=NULL;
        struct node *ptr1=headll1;
        count=1;
         
    //now we will create the 2nd split linked list
    struct node *headll2=malloc(sizeof(struct node));
    splitNode=forward;
    forward=forward->next;
        headll2->data=splitNode->data;
        headll2->next=NULL;  
        struct node *ptr2=headll2;
        count++;
        
    //head nodes of both the split linked lists is ready    
    while(forward!=NULL){
        splitNode=forward;
        forward=forward->next;
        count+=1;
        if(count%2==1){
          ptr1->next=splitNode;
          splitNode->next=NULL;
          ptr1=ptr1->next;
        }else{
          ptr2->next=splitNode;
          splitNode->next=NULL;
          ptr2=ptr2->next;
        }
    }
    //we have finished adding the nodes to linked list 1 and 2 alternatively based on count.
    
    //now let's print both the linked lists.
    ptr1=headll1;
    while(ptr1!=NULL){
        printf("%d ",ptr1->data);
        ptr1=ptr1->next;
    }
    printf("\n");
    ptr2=headll2;
    while(ptr2!=NULL){
        printf("%d ",ptr2->data);
        ptr2=ptr2->next;
    }
    
    
    }
    struct node *add_at_end(struct node *ptr,int item){
    struct node *temp=malloc(sizeof(struct node));
    temp->data=item;
    ptr->next=temp;
    temp->next=NULL;
    
    return temp;
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-12-12
      • 1970-01-01
      • 1970-01-01
      • 2010-09-24
      • 1970-01-01
      • 2016-08-07
      • 1970-01-01
      相关资源
      最近更新 更多