我需要编写一个程序来查找模式。或者最多出现一个整数或整数。 所以,
1,2,3,4,1,10,4,23,12,4,1将具有1和4的模式。
我不确定我应该使用哪种算法。我很难想到能够奏效的东西。
我正在考虑某种频率表,也许我可以通过数组,然后通过创建一个链表。如果链接不包含该值,则将其添加到链接,如果是,则将值1添加。
所以,如果我从上面有同样的事情。依次通过 1,2,3,4,1,10,4,23,12,4,1
然后list为空,因此添加number = 1且value = 1的节点。 2不存在所以添加number = 2和value = 1的节点,依此类推。 到1和1已经存在,所以值= 2现在。
我必须循环遍历数组,然后每次循环遍历链表以找到该值。
完成后,请浏览链接列表并创建一个新的链接列表来保存模式。所以我将头设置为第一个元素1.然后我浏览包含出现的链接列表并比较值。如果当前节点的出现是>当前最高然后我设置头到这个节点。如果它=到最高,那么我将节点添加到模式链表。
完成后,我循环浏览模式列表并打印值。
不确定这是否有效。有没有人看到这个有什么问题?有更简单的方法吗?我也在考虑哈希表,但不确定如何在C中做到这一点。
感谢。
答案 0 :(得分:5)
如果可以将整个整数列表保留在内存中,则可以先对列表进行排序,这样可以使重复的值彼此相邻。然后,您可以对排序列表执行单次传递以查找模式。这样,您只需要跟踪到目前为止看到的模式的最佳候选者,以及到目前为止看到当前值的次数。
答案 1 :(得分:2)
您所拥有的算法适用于家庭作业。您可以采取各种措施来优化代码,例如:
但我认为你会发现在这种情况下他们没有必要。对于家庭作业,目的只是为了表明你理解如何编程,而不是你知道各种各样的技巧来榨取最后一盎司的表现。您的教育工作者将更多地寻找可读,结构化的代码,而不是棘手的优化。
我将在下面描述我的所作所为。你显然可以根据自己的意愿尽可能多地使用我的建议,这取决于你自己想要获得多少满足感。我只会提供伪代码,这是我的家庭作业问题的标准做法。
我会从一个包含数字,计数和下一个指针(用于链接列表)的结构和指向第一个指针的全局指针开始:
typedef struct sElement {
int number;
int count;
struct sElement *next;
} tElement;
tElement first = NULL;
然后创建一些用于创建和使用列表的函数:
tElement *incrementElement (int number);
tElement *getMaxCountElement (void);
tElement *getNextMatching (tElement *ptr, int count);
这些功能将分别为:
每个伪代码:
def incrementElement (number):
# Find matching number in list or NULL.
set ptr to first
while ptr is not NULL:
if ptr->number is equal to number:
return ptr
set ptr to ptr->next
# If not found, add one at start with zero count.
if ptr is NULL:
set ptr to newly allocated element
set ptr->number to number
set ptr->count to 0
set ptr->next to first
set first to ptr
# Increment count.
set ptr->count to ptr->count + 1
def getMaxCountElement (number):
# List empty, no mode.
if first is NULL:
return NULL
# Assume first element is mode to start with.
set retptr to first
# Process all other elements.
set ptr to first->next
while ptr is not NULL:
# Save new mode if you find one.
if ptr->count is greater than retptr->count:
set retptr to ptr
set ptr to ptr->next
# Return actual mode element pointer.
return retptr
def getNextMatching (ptr, number):
# Process all elements.
while ptr is not NULL:
# If match on count, return it.
if ptr->number is equal to number:
return ptr
set ptr to ptr->next
# Went through whole list with no match, return NULL.
return NULL
然后您的主程序变为:
# Process all the numbers, adding to (or incrementing in) list .
for each n in numbers to process:
incrementElement (n)
# Get the mode quantity, only look for modes if list was non-empty.
maxElem = getMaxCountElement ()
if maxElem is not NULL:
# Find the first one, whil exists, print and find the next one.
ptr = getNextMatching (first, maxElem->count)
while ptr is not NULL:
print ptr->number
ptr = getNextMatching (ptr->next, maxElem->count)
答案 2 :(得分:1)
如果数字的范围是事先知道的,并且是一个合理的数字,你可以为计数器分配一个足够大的数组,然后只做count[i] += 1
。
如果数字范围未提前知道,或者对于天真使用数组而言太大,您可以维护一个二进制值树来维护计数器。这将使您的搜索量远远低于链接列表。无论哪种方式,您都必须遍历数组或树并构建从最高到最低计数的顺序。我再次推荐一棵树,但你的列表解决方案也可以。
另一个有趣的选择可能是使用priority queue进行提取阶段。完成计数器列表后,遍历树并以优先级等于其计数的值插入每个值。然后,您只需从优先级队列中提取值,直到计数结束。
答案 3 :(得分:1)
我会选择基于hash table的简单解决方案。
包含数字和相应频率的哈希表的结构。还有一个指向下一个用于在哈希桶中链接的元素的指针。
struct ItemFreq {
struct ItemFreq * next_;
int number_;
int frequency_;
};
处理从
开始max_freq_so_far = 0;
它通过数字列表。对于每个number
,哈希表会查找ItemFreq
元素x
,以便x.number_ == number
。
x
,则会将ItemFreq
元素创建为{ number_ = number, frequency_ = 1}
并插入到哈希表中。x
,则其frequency_
会递增。frequency_ > max_freq_so_far
则max_freq_so_far = frequency
遍历完成的数字列表后,我们遍历哈希表并打印ItemFreq
frequency_ == max_freq_so_far
个项目
算法的复杂性为O(N)
,其中N
是输入列表中的项目数。
有关哈希表的简单优雅构造,请参阅K&R (The C Programming Language)的第6.6节。
答案 4 :(得分:0)
这个回答是Paul Kuliniewicz想法的样本:
int CompInt(const void* ptr1, const void* ptr2) {
const int a = *(int*)ptr1;
const int b = *(int*)ptr2;
if (a < b) return -1;
if (a > b) return +1;
return 0;
}
// This function leave the modes in output and return the number
// of modes in output. The output pointer should be available to
// hold at least n integers.
int GetModes(const int* v, int n, int* output) {
// Sort the data and initialize the best result.
qsort(v, v + n, CompInt);
int outputSize = 0;
// Loop through elements while there are not exhausted.
// (look there is no ++i after each iteration).
for (int i = 0; i < n;) {
// This is the begin of the new group.
const int begin = i;
// Move the pointer until there are no more equal elements.
for (; i < n && v[i] == v[begin]; ++i);
// This is one-past the last element in the current group.
const int end = i;
// Update the best mode found until now.
if (end - begin > best) {
best = end - begin;
outputSize = 0;
}
if (end - begin == best)
output[outputSize++] = v[begin];
}
return outputSize;
}