在两个列表取交集时遇到问题。

huangapple go评论121阅读模式
英文:

problem while taking the intersection of a list with another one

问题

这个函数将第一个列表与第二个列表进行交集操作,返回一个新的列表。请注意,该解决方案仅返回第一个列表(即i1),而不仅仅是公共值,即使它正确地进行了ElemCompare并正确插入每个值。

(附注:其他文件中有2个警告,但您可以忽略它们)

如果需要更正该问题,您可以修改Intersect函数以确保它只返回包含公共元素的列表。一种方法是使用一个标志来跟踪是否找到了公共元素,并只在找到时插入元素。以下是一个可能的修改:

Item* Intersect(const Item* i1, const Item* i2) {
    Item* ris = ListCreateEmpty();
    
    for (; !ListIsEmpty(i1); i1 = ListGetTail(i1)) {
        bool found = false; // 用于跟踪是否找到公共元素
        for (const Item* tmp2 = i2; !ListIsEmpty(tmp2); tmp2 = ListGetTail(tmp2)) {
            if (ElemCompare(ListGetHeadValue(i1), ListGetHeadValue(tmp2)) == 0) {
                ris = ListInsertBack(ris, ListGetHeadValue(i1));
                found = true; // 找到了公共元素
                break;
            }
        }
        if (!found) {
            // 如果未找到公共元素,则释放资源
            ElemDelete((ElemType *)ListGetHeadValue(i1));
        }
    }
    
    return ris;
}

此修改将确保仅返回包含公共元素的列表,并释放未找到的元素。请记得在使用此修改后再次测试您的程序。

英文:

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)

答案1

得分: 2

以下是翻译好的内容:

看起来问题出在这个if语句上:

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

当两个元素不相等时,if语句的条件评估为逻辑真。

实际上,你需要写成:

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

而且内部的for循环也有个拼写错误。

不是这样写:

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

你应该这样写:

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

要注意的是,这个函数无论如何都是错误的,因为例如对于列表 { 0, 0 } 和 { 0, 1 },值 0 将会被插入新列表两次,而应该只插入一次。

这个函数可以如下修改:

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; 
}
英文:

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

huangapple
  • 本文由 发表于 2023年5月7日 16:20:50
  • 转载请务必保留本文链接:https://go.coder-hub.com/76192855.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定