在C中创建一个没有重复的新数组

Posted

技术标签:

【中文标题】在C中创建一个没有重复的新数组【英文标题】:Making a new array without duplicates in C 【发布时间】:2022-01-13 17:01:51 【问题描述】:

据我所知,我的代码有效.. 我想知道它是否可以以更好的方式完成(更好的时间复杂度)以及我的代码的时间复杂度是多少,因为我不确定如何计算它。 无法更改问题中的当前数组,但如果有更快的方法通过删除我也想知道,非常感谢。

    int i = 1, j = 0, count = 1;
int arrNew[SIZE] =  NULL ; 
arrNew[0] = arr1[0]; 
while(i<size)
    if (arr1[i] == arrNew[j])  // if the element of arr1 is already added, resets j for next iteration and moves to the next element.
        j = 0;
        i++;
    
    else 
        if (j == count - 1)  // checks if we reached the end of arrNew and adds missing element.
            arrNew[count] = arr1[i];
            j = 0;
            count++; // this variable makes sure we check only the assigned elements of arrNew.
            i++;
        
        else // if j < count -1 we didnt finish checking all of arrNew.
            j++;
    

【问题讨论】:

不,我在 3 个未排序的数组上检查了它,它运行良好.. 嗯。很确定这适用于未排序的数组,但是:这将退化为 n^2 最坏的情况(数组已经填充了不同的唯一值)。对于大型数组,您最好对原始数组进行排序,然后单次传递以丢弃重复项。但是,这样做会丢失原始顺序,这可能会破坏该方法的交易。根据领域的不同,计数标志指示器阵列也是可选的,如果模型合适,它会快速咆哮。无关,VLA 是大型阵列的灾难,可能也需要考虑。 但是我使用了 count 变量来确保我只检查数组中分配的空格,它仍然是 n^2 吗? SIZE 是方法外的变量(使用#define SIZE),因为我们还没有学习如何制作动态数组.. 更糟糕的情况(已经不同的唯一值),运行将是 O(n^2)。考虑每次通过会发生什么。 j 上的每个新项目都将与新数组中的 每个 已经分类的项目进行比较。由于它们都是独一无二的,这意味着扫描将是 1、2、3、4... (n-2)、(n-1) 次比较。这是最坏的情况 O(n^2) 结果。仅供参考,最好的情况是整个原件都填充了相同的值。这意味着在每次迭代的第一次比较后立即放弃,导致数组中只有一个最终值和 O(n) 最佳情况。 1.你的循环写得很混乱,因为它有条件地增加ij,隐藏了循环的复杂性。 2. 如果允许,最明智的方法是进行“排序到新数组”(即O(n log n)),然后在第二遍中删除重复项(或者,这可以使用“部分排序”逐步完成,但这复杂性更差:AFAICT O((n/m)n log(m)) 如果以 m 大小的块完成,3. 如果您想保留原始顺序,您可以将 #2 方法放入临时缓冲区,然后分配一个位集并再次传递输入,进行二分搜索并标记它。 【参考方案1】:

我想知道是否可以以更好的方式完成(更好的时间复杂度)

一开始有点难以判断发生了什么,但看起来您基本上是在使用一个循环来完成两项工作。您正在循环 i 以逐步浏览原始数组,但也使用 j 扫描每个新元素的新数组。实际上,嵌套循环的大小可能相同,因此复杂度为 O(n2)。

我建议重写您的代码,以便两个循环是明确的。让一个循环执行双重任务并没有节省任何时间,如果一个月后你回到这段代码,你将浪费大量时间试图记住它是如何工作的。让你的代码显而易见——它与你未来的自己或你的同事交流,就像与编译器交流一样。

你能改进 O(n2) 复杂度吗? 是的,当然。 一种方法是对数组进行排序,使重复值最终在数组中彼此相邻。然后很容易不复制任何与前一个值相同的值。我知道您无法修改原始数组,但您可以复制整个内容,对其进行排序,然后在复制该数组的同时删除重复项。这会给你 O(n log n) 复杂度(如果你选择一个有效的排序算法)。事实上,你可以通过结合排序和复制来加快速度——但你最终还是会得到 O(n log n) 的复杂度。另一种方法是使用哈希表:检查表中是否存在该值,如果存在则将其扔掉,或者将其添加到表中,如果不存在则复制到新数组中。这将接近 O(n)。

【讨论】:

请记住,组合的sort_and_copy 实现通常比单独的copysort_in_place 更有效——尤其是在需要稳定性的情况下。遗憾的是,C 标准库仅提供就地不稳定排序。但幸运的是,大多数人都知道要使用第三方库。 排序是nlogn,不是吗?之后我仍然需要通过数组来删除重复项。除非数组中的重复项很少,否则不会花费更多时间吗? 实际上,大多数通用的就地稳定排序算法是O(n log² n) 或更糟(据说“块合并排序”是一个例外,但在查找之前我从未听说过它)现在 - 甚至它表明首选额外的内存,因为否则它的“最佳情况”会更少)。如果您放弃“稳定”或“就地”要求,或者可以对您的输入施加严格的限制,则已知更多算法。 就地删除重复项只是O(n),它在排序的复杂性旁边消失了。只需使用两个索引对数组进行一次迭代:无条件地增加“source”,但只有在您实际找到新值时才增加“dest”。然后在最后做一个realloc 来缩小它。 @technical 我描述的想法是:复制数组,将其排序,然后在删除重复项的同时复制它。因此,您将数组复制两次(均为 O(n))并将其排序一次(O(n log n)),因此总体复杂度为 O(n log n)。当我们谈论大 O 复杂性时,我们真正感兴趣的是性能如何随问题的大小而变化。

以上是关于在C中创建一个没有重复的新数组的主要内容,如果未能解决你的问题,请参考以下文章

在Objective C中创建JSON数组[重复]

如何在mysql中创建具有旧数据库中一些表的新数据库[重复]

在C中创建n个项目的k和m个组合的所有可能子集[重复]

在 C++ 中创建一个大数组 [重复]

在 C++ 中创建一个大数组 [重复]

创建没有重复的新 SQL 表