我在C中有一个字符串数组,一个整数表示数组中有多少个字符串。
char *strarray[MAX];
int strcount;
在此数组中,最高索引(其中10大于0)是添加的最新项目,最低索引是添加的最远项目。 数组中项目的顺序很重要。
我需要一种快速方法来检查数组是否有重复项,删除除最高索引重复项之外的所有内容,然后折叠数组。
例如:
strarray[0] = "Line 1";
strarray[1] = "Line 2";
strarray[2] = "Line 3";
strarray[3] = "Line 2";
strarray[4] = "Line 4";
会变成:
strarray[0] = "Line 1";
strarray[1] = "Line 3";
strarray[2] = "Line 2";
strarray[3] = "Line 4";
原始数组的索引1被删除,索引2,3和4向下滑动以填补空白。
我对如何做到这一点有一个想法。它是未经测试的,我目前正在尝试对其进行编码,但仅仅从我的微弱理解来看,我确信这是一个可怕的算法。
每次将新字符串添加到strarray时,都会运行下面给出的算法。
为了表明我正在尝试,我将在下面提出我提出的算法:
再一次,这是未经测试的(我现在正在实施它)。我希望那里的人能有更好的解决方案。
项目的顺序很重要,代码必须使用C语言(而不是C ++)。应删除最低索引重复项并保留单个最高索引。
谢谢!
答案 0 :(得分:3)
典型的高效独特功能是:
我相信您可以将qsort
与strcmp
结合使用来完成第一部分;写一个有效的remove
将会在你身上。
不幸的是我这里没有具体的想法;这对我来说是一个灰色区域,因为我通常使用C ++,这很简单:
std::vector<std::string> src;
std::sort(src.begin(), src.end());
src.remove(std::unique(src.begin(), src.end()), src.end);
我知道你不能使用C ++,但实现应该基本相同。
因为您需要保存原始订单,所以可以使用以下内容:
typedef struct
{
int originalPosition;
char * string;
} tempUniqueEntry;
对string
进行第一次排序,删除排序集上的唯一元素集,然后依靠originalPosition
求助。这样你仍然可以获得O(n lg n)性能,但你不会丢失原始订单。
EDIT2:
std::unique
的简单C实现示例:
tempUniqueEntry* unique ( tempUniqueEntry * first, tempUniqueEntry * last )
{
tempUniqueEntry *result=first;
while (++first != last)
{
if (strcmp(result->string,first->string))
*(++result)=*first;
}
return ++result;
}
答案 1 :(得分:1)
你可以控制进入数组的输入吗?如果是这样,请执行以下操作:
int addToArray(const char * toadd, char * strarray[], int strcount)
{
const int toaddlen = strlen(toadd);
// Add new string to end.
// Remember to add one for the \0 terminator.
strarray[strcount] = malloc(sizeof(char) * (toaddlen + 1));
strncpy(strarray[strcount], toadd, toaddlen + 1);
// Search for a duplicate.
// Note that we are cutting the new array short by one.
for(int i = 0; i < strcount; ++i)
{
if (strncmp(strarray[i], toaddlen + 1) == 0)
{
// Found duplicate.
// Remove it and compact.
// Note use of new array size here.
free(strarray[i]);
for(int k = i + 1; k < strcount + 1; ++k)
strarray[i] = strarray[k];
strarray[strcount] = null;
return strcount;
}
}
// No duplicate found.
return (strcount + 1);
}
您总是可以使用上面的函数循环遍历现有数组的元素,构建一个没有重复的新数组。
PS:如果你经常进行这种类型的操作,你应该远离数组作为你的存储结构,而是使用链表。它们可以更有效地从末端以外的位置删除元素。
答案 2 :(得分:1)
我不太明白你提出的算法(我不明白在步骤5中将字符串添加到索引意味着什么),但我要做的是:
unsigned int i;
for (i = n; i > 0; i--)
{
unsigned int j;
if (strarray[i - 1] == NULL)
{
continue;
}
for (j = i - 1; j > 0; j--)
{
if (strcmp(strarray[i - 1], strarray[j - 1]) == 0)
{
strarray[j - 1] = NULL;
}
}
}
然后你只需要从数组中过滤掉空指针(我将把它留作练习)。
另一种方法是在数组上向后迭代并将每个项目插入到(平衡的)二进制搜索树中。如果该项目已在二叉搜索树中,则标记该数组项(例如将数组元素设置为NULL
)并继续。处理完整个数组后,像以前一样过滤掉标记的元素。这会有更多的开销,并且会消耗更多的空间,但是它的运行时间将是O(n log n)而不是O(n ^ 2)。
答案 3 :(得分:0)
使用终端中的qsort
(man 3 qsort
)算法对数组进行排序以查看应如何使用该算法,然后使用函数strcmp
比较字符串并查找重复项< / p>
如果你想保留原始顺序,可以使用嵌套两个for
的O(N ^ 2)复杂度算法,第一次选择一个元素与另一个进行比较,第二个将用于扫描数组的其余部分以查找所选元素是否重复。