我正在寻找实现快速排序整数数组交集/联合操作的C算法(或代码)。越快越好。
换句话说,在C中实现两个整数数组之间的并集和交集操作的有效方法是什么?
答案 0 :(得分:2)
这不是最快的,但它展示了正确的算法。
//List is an output variable, it could be a
//linked list or an array list or really anything you can add at end to.
void intersection(int A[], int B[], int aLen, int bLen, List output)
{
int i = 0;
int j = 0;
while (i < aLen && j < bLen)
{
a = A[i];
b = B[j];
if (a == b)
{
add(output, a);
i++;
j++;
}
else if (a < b)
{
i++;
}
else
{
j++;
}
}
}
以上算法为O(aLen + bLen)
你可以做得更好,特别是当遇到交叉超过2个列表的问题时。
对于交集,基本算法是迭代遍历所有已排序的列表,同时进行交叉。如果所有列表的头部匹配,则移动到所有列表中的下一个元素,并将头部添加到交叉点。如果没有,找到可见的最大元素,并尝试在所有其他列表中找到该元素。
在我的代码示例中,我只是继续迭代,但由于这些是排序列表,如果您希望A是数字1到10000而B是集合{7777},您还可以二进制搜索到正确的索引。使用多个列表查找最大元素意味着如果要正确执行,请使用堆。
如果你进行二进制搜索更改,最坏的情况将会达到O((aLen + bLen)*(lg(aLen + bLen)),但根据数据,你的平均情况可能会大幅改善。
当将多个集合交叉时,堆更改将是必要的,因为上述算法变为O(numLists *(所有列表中的元素总数))并且可以减少为O(lg(numLists)*(总数)所有列表中的元素))
void union(int A[], int B[], int aLen, int bLen, List output)
{
int i = 0;
int j = 0;
while (i < aLen && j < bLen)
{
a = A[i];
b = B[j];
if (a == b)
{
add(output, a);
i++;
j++;
}
else if (a < b)
{
add(output, a);
i++;
}
else
{
add(output, b);
j++;
}
}
//Add any leftovers.
for (;i < aLen; i++)
{
add(output, A[i]);
}
for (;j < bLen; j++)
{
add(output, B[j]);
}
}
Union基本上是相同的算法,除了你总是添加每个元素,因此,在二进制搜索中没有任何意义。将其扩展到多个列表可以使用实现查看的堆来完成,基本规则是始终添加最小元素,并在前面具有该元素的每个列表中前进。
答案 1 :(得分:2)
假设这些是实际的集(因为具有重复项的数组上的交集最多是有问题的),以下代码可能有所帮助。
首先,一些必要的标题:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
和一些强制性文件:
// Description:
// Will give back the union or intersection of two sorted integer
// sets (only one copy of each element).
// Caller responsible for freeing memory.
// Input:
// Union ('u') or intersection (anything else).
// arr1 and arr2 are pointers to the arrays.
// sz1 and sz2 are the number of integers in each array.
// psz3 as the pointer to the variable to receive the
// size of the returned array.
// Returns:
// A pointer to the array, or NULL if malloc failed.
// Memory allocated even if result set is empty, so
// NULL return indicates ONLY malloc failure.
// psz3 receives the size of that array, which is
// zero for an empty set.
然后功能正确:
int *arrUnionIntersect ( int type,
int *arr1, size_t sz1,
int *arr2, size_t sz2,
size_t *psz3
) {
int *arr3, *ptr1, *ptr2;
*psz3 = 0;
// If result will be empty, just return dummy block.
if ((sz1 == 0) && (sz2 == 0))
return malloc (1);
// Otherwise allocate space for real result.
if (type == 'u')
arr3 = malloc ((sz1 + sz2) * sizeof (*arr1));
else
if (sz1 > sz2)
arr3 = malloc (sz1 * sizeof (*arr1));
else
arr3 = malloc (sz2 * sizeof (*arr1));
if (arr3 == NULL)
return NULL;
直到那里,它主要是初始化功能。此跟随位遍历两个输入集,选择添加到结果中的内容。这是最好的(在我看来)作为三个阶段,第一个是当两个输入集仍然有一些元素时选择一个元素。请注意这里对于联合和交叉点的不同行为,特别是交叉点只有在两个输入集中添加了元素:
// Set up pointers for input processing.
ptr1 = arr1;
ptr2 = arr2;
// Phase A: select appropriate number from either, when both
// have remaining elements.
while ((sz1 > 0) && (sz2 > 0)) {
if (*ptr1 == *ptr2) {
arr3[(*psz3)++] = *ptr1++;
sz1--;
ptr2++;
sz2--;
continue;
}
// We don't copy for intersect where elements are different.
if (*ptr1 < *ptr2) {
if (type == 'u')
arr3[(*psz3)++] = *ptr1;
ptr1++;
sz1--;
continue;
}
if (type == 'u')
arr3[(*psz3)++] = *ptr2;
ptr2++;
sz2--;
}
其他两个阶段(其中只有一个阶段将针对工会运行,而没有针对交叉点运行),只是从非空输入集中获取剩余的项目:
// Phase B and C are only for unions.
if (type == 'u') {
// Phase B: process rest of arr1 if arr2 ran out.
while (sz1 > 0) {
arr3[*psz3++] = *ptr1++;
sz1--;
}
// Phase C: process rest of arr2 if arr1 ran out.
while (sz2 > 0) {
arr3[*psz3++] = *ptr2++;
sz2--;
}
}
// Return the union.
return arr3;
}
测试程序:
int main (void) {
int x1[] = {1, 3, 5, 7, 9, 11, 13, 15, 17, 19};
int x2[] = {2, 3, 5, 7, 11, 13, 17, 19};
size_t i, sz3;
int *x3;
x3 = arrUnionIntersect ('u', x1, sizeof(x1)/sizeof(*x1),
x2, sizeof(x2)/sizeof(*x2), &sz3);
printf ("union =");
for (i = 0; i < sz3; i++)
printf (" %d", x3[i]);
free (x3);
printf ("\n");
x3 = arrUnionIntersect ('i', x1, sizeof(x1)/sizeof(*x1),
x2, sizeof(x2)/sizeof(*x2), &sz3);
printf ("intersection =");
for (i = 0; i < sz3; i++)
printf (" %d", x3[i]);
free (x3);
printf ("\n");
return 0;
}
及其输出,如预期:
union = 1 2 3 5 7 9 11 13 15 17 19
intersection = 3 5 7 11 13 17 19