在C ++中使用多重功能对两个链表进行并集

时间:2019-06-14 11:25:50

标签: c++ list linked-list union find-occurrences

我需要使用“多重性”定义来对从输入传递来的两个无序多重集进行并集:元素的多重性(也称为绝对频率)是元素“ x”在无序中出现的次数多集“ s”。 在multiSetUnion中,元素的多重性是两个多重集中其多重性的最大值。

我已经正确实现了int multiplicity(const Elem e,const MultiSet&s)函数(返回多重集中的出现次数)。

多重集是单链表。

这是我想出的算法:

for as long as the first list isn't empty
   if elem of the first list (multiset) is not in the second list (multiset)
      add elem in unionlist
   if elem of the first list (multiset) is in the second list (multiset)
      if multiplicity of elem is bigger in the first list than in the second one
         add elem in unionlist as many times as its multiplicity in list1
      if multiplicity of elem is bigger in the second list than in the first one
         add elem in unionlist as many times as its multiplicity in list2  
analyze the second element of the first list 

这是我对算法的实现,但是当两个列表都不为空并且不知道为什么时,它给我错误:

MultiSet multiset::multiSetUnion(const MultiSet& s1, const MultiSet& s2)
{
    if (isEmpty(s1) && isEmpty(s2))
        return emptySet;
    if (isEmpty(s1) && !isEmpty(s2))
        return s2;
    if (!isEmpty(s1) && isEmpty(s2))
        return s1;
    MultiSet s3 = emptySet;    
    MultiSet aux2 = s2;            //THE FUNCTION DOESN'T WORK FROM HERE ON
    for (MultiSet aux1 = s1; !isEmpty(aux1); aux1 = aux1->next) { 
        if (!isIn(aux1->elem, aux2))
            insertElemS(aux1->elem, s3);
        if (isIn(aux1->elem, aux2)) {
            if (multiplicity(aux1->elem, aux1) > multiplicity(aux1->elem, aux2)) {
                for (int n = 0; n < multiplicity(aux1->elem, aux1); ++n)
                    insertElemS(aux1->elem, s3);
            }
            else {
                for (int m = 0; m < multiplicity(aux1->elem, aux2); ++m)
                    insertElemS(aux1->elem, s3);
            }
        }
    }
    return s3;
}

有人可以指出我在哪里做错了吗?我是否忘记了算法中的某些内容,或者这是一个实现问题?

编辑:这是我实现函数IsIn(const Elem x,MultiSet&s)和multiplicity(const Elem e,MultiSet&s)的方式:

bool isIn(const Elem x, MultiSet& s) {
    if (s->elem == x) return true;
    while (!isEmpty(s)) {
        if (s->elem!=x)
            s = s->next;
        else    return true;
    }
    return false;
}

int multiset::multiplicity(const Elem e, const MultiSet& s)
{
    if (isEmpty(s))    return 0;
    int count = 0;
    MultiSet aux = s;
    while (!isEmpty(aux)) {
        if (aux->elem==e) {
            ++count;
        }
        aux = aux->next;
    }
    return count;
}

不幸的是,我无法使用向量库(或与此有关的任何STL库)。 我提出的算法故意是解决方案的一半(我遇到问题的部分)。 我没有收到任何特定的错误,但是程序只是停顿了(它应该打印两个多重集的第一个,第二个和并集-打印功能正确并且直接在主函数中调用;至于现在我只得到了一个或两个多集为空时,请更正输出),并返回以下内容:“过程返回了-1073741819”(我目前在Windows上进行调试)。

1 个答案:

答案 0 :(得分:3)

考虑以下示例:

MultiSet s1({7, 7});
MultiSet s2({5});

如果您现在遍历s1:

1st iteration:        7    7
                      ^
                     aux1

2nd iteration:        7    7
                           ^
                          aux1

如果s1中有多个相等的元素,则将不止一次发现它们,最终导致增加多重平方(如果s2之一较大,则为两个多重乘积)。

另一方面,由于s1中不包含5,因此您也不会尝试在s2中查找它–仍然存在...

要解决第一个问题,您需要检查当前元素是否已包含在s3中,如果已经包含,则跳过它。

要解决第二个问题,您还需要遍历s2,添加s3中尚未包含的所有那些元素。

按原样,最终结果将是相当差的性能(应该在O(n²)O(n³)之间,而后者应该在后者之间)。不幸的是,您选择了一个数据结构(一个简单的单链列表–显然未排序!),无法为您想要的操作(尤其是您选择的算法)提供很好的支持。

如果您对两个列表进行排序,则可以创建具有线性运行时间的算法。它将与合并排序中的合并步骤类似地工作:

while(elements available in both lists):
    if(left element < right element):
        append left element to s3
        advance left
    else
        append right element to s3
        if(left element == right element):
            advance left // (too! -> avoid inserting sum of multiplicities)
        advance right
append all elements remaining in left
append all elements remaining in right
// actually, only in one of left and right, there can be elements left
// but you don't know in which one...

在插入过程中对列表进行排序非常简单:

while(current element < new element):
    advance
insert before current element // (or at end, if no current left any more)

但是,当直接暴露列表的节点时,总是有危险,插入不会从head元素开始–排序顺序可能会中断。

您应该适当封装:

  • 将当前的MultiSet重命名为e。 G。 “节点”并创建一个新的类MultiSet
  • 使节点类成为新集合类的嵌套类。
  • 列表中的所有修饰符应仅是set类的成员。
  • 您可能公开了节点类,但是用户必须不能修改它。然后它将只是一种迭代器。