clinked-listsingly-linked-listintersectionfunction-definition

problem while taking the intersection of a list with another one


this function intersects the first list with the second, and it has to return a new list, I've used elemtype.h and list.h, (of course with elemtype.c and list.c)

this is elemtype.c:

#define _CRT_SECURE_NO_WARNINGS
#include "elemtype.h"

#include <string.h>
#include <stdlib.h>

#define _unused(x) ((void)(x))

int ElemCompare(const ElemType *e1, const ElemType *e2) {
    return (*e1 > *e2) - (*e1 < *e2);
}

ElemType ElemCopy(const ElemType *e) {
    return *e;
}

void ElemSwap(ElemType *e1, ElemType *e2) {
    ElemType tmp = *e1;
    *e1 = *e2;
    *e2 = tmp;
}

void ElemDelete(ElemType *e) {

    _unused(e);
}

int ElemRead(FILE *f, ElemType *e) {
    return fscanf(f, "%d", e);
}

int ElemReadStdin(ElemType *e) {
    return ElemRead(stdin, e);
}

void ElemWrite(const ElemType *e, FILE *f) {
    fprintf(f, "%d", *e);
}

void ElemWriteStdout(const ElemType *e) {
    ElemWrite(e, stdout);
}

this is elemtype.h:

#ifndef ELEMTYPE_INT_H_
#define ELEMTYPE_INT_H_

#include <stdbool.h>
#include <stdio.h>

typedef int ElemType;


int ElemCompare(const ElemType *e1, const ElemType *e2);


ElemType ElemCopy(const ElemType *e);


void ElemSwap(ElemType *e1, ElemType *e2);


void ElemDelete(ElemType *e);


int ElemRead(FILE *f, ElemType *e);


int ElemReadStdin(ElemType *e);


void ElemWrite(const ElemType *e, FILE *f);


void ElemWriteStdout(const ElemType *e);

#endif // ELEMTYPE_INT_H_

this is list.c:

#define _CRT_SECURE_NO_WARNINGS
#include "list.h"

#include <string.h>
#include <stdlib.h>

/*****************************************************************************/
/*                           Item & Primitives                               */
/*****************************************************************************/

Item *ListCreateEmpty(void) {
    return NULL;
}

Item *ListInsertHead(const ElemType *e, Item *i) {
    Item *n = malloc(sizeof(Item));
    n->value = ElemCopy(e);
    n->next = i;
    return n;
}

bool ListIsEmpty(const Item *i) {
    return i == NULL;
}

const ElemType *ListGetHeadValue(const Item *i) {
    if (ListIsEmpty(i)) {
        printf("ERROR: null list\n");
        exit(1);
    }
    else {
        return &i->value;
    }
}

Item *ListGetTail(const Item *i) {
    if (ListIsEmpty(i)) {
        printf("ERROR: null list \n");
        exit(2);
    }
    else {
        return i->next;
    }
}

Item *ListInsertBack(Item *i, const ElemType *e) {

    Item *n = ListInsertHead(e, ListCreateEmpty());

    if (ListIsEmpty(i)) {
        return n;
    }

    Item *tmp = i;
    while (!ListIsEmpty(ListGetTail(tmp))) {
        tmp = ListGetTail(tmp);
    }

    tmp->next = n;
    return i;
}

void ListDelete(Item *i) {
    while (!ListIsEmpty(i)) {
        Item *tmp = i;
        i = i->next;
        ElemDelete(&tmp->value);
        free(tmp);
    }
}

/*****************************************************************************/
/*                            Non Primitives                                 */
/*****************************************************************************/

void ListWrite(const Item *i, FILE *f) {
    fprintf(f, "[");
    while (!ListIsEmpty(i)) {
        ElemWrite(&i->value, f);
        i = ListGetTail(i);
        if (!ListIsEmpty(i)) {
            fprintf(f, ", ");
        }
    }
    fprintf(f, "]\n");
}

void ListWriteStdout(const Item *i) {
    ListWrite(i, stdout);
}

and this is list.h:

#ifndef LIST_H_
#define LIST_H_

#include "elemtype.h"

#include <stdbool.h>
#include <stdio.h>

/*****************************************************************************/
/*                           Item & Primitives                               */
/*****************************************************************************/


struct Item {
    ElemType value; 
    struct Item *next; 
};

typedef struct Item Item;


Item *ListCreateEmpty(void);
Item *ListInsertHead(const ElemType *e, Item *i);


bool ListIsEmpty(const Item *i);


const ElemType *ListGetHeadValue(const Item *i);


Item *ListGetTail(const Item *i);



Item *ListInsertBack(Item *i, const ElemType *e);


void ListDelete(Item *i);

/*****************************************************************************/
/*                             Non Primitives                                */
/*****************************************************************************/

void ListWrite(const Item *i, FILE *f);


void ListWriteStdout(const Item *i);

#endif // LIST_H_

this is my implementation of intersect.c:

#include "elemtype.h"
#include "list.h"

Item* Intersect(const Item* i1, const Item* i2) {
    Item* ris = ListCreateEmpty(); 
    for (; !ListIsEmpty(i1); i1 = ListGetTail(i1)) {
        for (const Item* tmp2 = i2; !ListIsEmpty(tmp2); tmp2 = ListGetTail(i2)) {
            if (ElemCompare(ListGetHeadValue(i1), ListGetHeadValue(tmp2))) {
                ris = ListInsertBack(ris, ListGetHeadValue(i1)); 
                break; 
            }
        }
    }
    return ris; 
}



   int main(void) {
    ElemType v1[] = { 0, 1, 2};
    Item* i1 = ListCreateEmpty();
    for (size_t i = 0; i < 3; i++) {
        i1 = ListInsertHead(v1 + i, i1);
    }
    ElemType v2[] = { 4, 0, 2 }; 
    Item* i2 = ListCreateEmpty(); 
    for (size_t i = 0; i < 3; i++) {
        i2 = ListInsertHead(v2 + i, i2); 
    }
    Item* i3 = Intersect(i1, i2); 
    ListDelete(i3); ListDelete(i1); 
    ListDelete(i2); 
    return 0; 
} 

this solution works fine, but it returns only first list (i.e i1), and not only the common values even if it does the elemcompare and it inserts each value correctly.

(side note: there are 2 warnings located in the other files, but you can ignore them)


Solution

  • It seems the problem is this if statement

    if (ElemCompare(ListGetHeadValue(i1), ListGetHeadValue(tmp2))) {
    

    The condition of the if statement evalautes to logical true when two elements are not equal each other.

    Actually you need to write

    if (ElemCompare(ListGetHeadValue(i1), ListGetHeadValue(tmp2)) == 0 ) {
    

    And there is a typo also in the inner for loop.

    Instead of

    for (const Item* tmp2 = i2; !ListIsEmpty(tmp2); tmp2 = ListGetTail(i2)) {
    

    you have to write

    for (const Item* tmp2 = i2; !ListIsEmpty(tmp2); tmp2 = ListGetTail(tmp2)) {
    

    Pay attention to that the function in any case is wrong because for example for lists { 0, 0 } and { 0, 1 } the value 0 will be inserted in the new list two times while it should be inserted only one time.

    The function can look the following way

    Item* Intersect( const Item* i1, const Item* i2 ) 
    {
        Item *ris = ListCreateEmpty(); 
    
        if ( !ListIsEmpty( i1 ) && !ListIsEmpty( i2 ) )
        {
            for ( const Item *tmp1 = i1; !ListIsEmpty( tmp1 ); tmp1 = ListGetTail( tmp1 ) ) 
            {
                size_t n = 1;
    
                for ( const Item *prev = i1; prev != tmp1; prev = ListGetTail( prev ) )
                {
                    n += ElemCompare( ListGetHeadValue( tmp1 ), ListGetHeadValue( prev ) ) == 0;
                }
     
                for ( const Item *tmp2 = i2; n != 0 && !ListIsEmpty( tmp2 ); tmp2 = ListGetTail( tmp2 ) ) 
                {
                    if ( ElemCompare( ListGetHeadValue( tmp1 ), ListGetHeadValue( tmp2 ) ) == 0 ) --n;
                }
           
                if ( n == 0 ) ris = ListInsertBack( ris, ListGetHeadValue( tmp1 ) ); 
            }
        }
    
        return ris; 
    }