交替拆分给定的单链表

时间:2014-08-29 14:08:13

标签: c linked-list

编写一个AlternatingSplit()函数,它接受一个列表并将其节点分成两个较小的列表'a'和'b'。子列表应该由原始列表中的交替元素构成。因此,如果原始列表是0-> 1-> 0-> 1-> 0-> 1,那么一个子列表应该是0-> 0-> 0而另一个子列表应该是1-> 0。 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;

}

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

3 个答案:

答案 0 :(得分:4)

当你刚刚拆分一个链表时,你不需要任何内存分配,只需在指针之间移动即可。

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

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


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

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

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

答案 1 :(得分:0)

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

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

答案 2 :(得分:0)

在解决此问题的同时,我想到了这种方法,即为两个拆分创建了单独的头节点,然后借助count变量,将所有奇数链接列表节点发送到拆分链接列表1,甚至所有偶数count个链表节点发送到拆分链表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;
}