我已经实现了一个带指针的堆栈,它的工作方式也是如此。现在,我需要它推送到堆栈,而不是推送副本。例如,如果我将'2'推入堆栈,那么推送另一个'2'仍会导致堆栈中只有一个'2',因为它已经存在。
以下是我尝试创建新推送功能的方法。我知道我想要遍历堆栈并检查它我正在添加的元素,但我想我做错了?任何人都可以帮助我吗?
typedef struct Node {
void *content;
struct Node *next;
} Node;
typedef struct Stack {
Node *head;
int count;
} Stack;
void push(Stack *stack, void *newElem) {
Node *newNode = (Node*) malloc(sizeof(Node));
if (stack->count > 0) {
int i;
for (i = 0, newNode = stack->head; i < stack->count; i++, newNode =
newNode->next) {
if (newNode->content == newElem) return;
}
} else {
newNode->next = stack->head;
newNode->content = newElem;
stack->head = newNode;
stack->count++;
}
}
答案 0 :(得分:3)
if (newNode->content == newElem)
您正在比较两个指针。我想你想检查他们的内容是否相同:
#include <string.h>
if (memcmp(newNode->content, newElem, size) == 0)
调用者可以指示值size
。在您的情况下,它应该是sizeof(int)
。
此外,一旦遍历了堆栈,就不会将元素添加到数据结构中。
答案 1 :(得分:2)
问题在于,如果您的筹码非空,并且您没有找到筹码中已有的元素,那么您就什么也做不了。您需要删除else
关键字并使该代码无条件。然后,在知道是否需要之前为新节点分配空间,更糟糕的是,在堆栈上迭代时覆盖新分配的指针,看看是否需要推送它。因此,在结束}
if
之后将malloc向下移动
答案 2 :(得分:1)
你已经有了工作
void push(Stack *stack, void *newElem);
正确?
那么,为什么不写一个新函数
int push_unique(Stack *stack, void *newElem) {
if (find_value(stack, newElem) != NULL) {
return 1; // indicate a collision
}
push(stack, newElem); // re-use old function
return 0; // indicate success
}
现在你已经把问题简化为写作
了Node *find_value(Stack *stack, void *value);
......你能这样做吗?
答案 3 :(得分:1)
我不确定您是否意识到这一点,但您提议的实施是在链接列表上执行线性搜索。如果您在堆栈上推送2,000个元素,每个元素值平均重复2个,那么对链接列表进行2,000次搜索,平均在500-750个链接之间(这取决于何时,IE:什么顺序,重复项呈现给搜索功能。这需要100万+比较。不漂亮。
上面的find_value()中更有效的重复检测可以使用搜索时间为O(1)的哈希表,或者搜索时间为O(log N)的树。前者如果您知道有多少值可能会进入堆栈,而后者如果数量未知,就像实时从套接字接收数据一样。 (如果前者你可以在一个数组中实现你的堆栈,而不是一个更慢,更详细的链表)
在任何一种情况下,为了正确维护哈希表,你的pop()函数需要与哈希表hashpop()函数配对,这将从哈希表中删除匹配值。
使用Hashtable,您的堆栈可以指向位于其哈希位置的元素值 - 从find_value()返回。但是,使用自平衡树,节点的位置以及元素值将一直在变化,因此您需要将元素的值存储在堆栈和树中。除非您在非常紧凑的内存环境中编写,否则第二个数据结构所能提供的性能将非常值得内存中的适度成本。