如何从堆栈中删除重复项?

时间:2019-01-29 10:48:20

标签: c

任务:假设存在一个包含M个元素的整数堆栈S。给出一种算法,该算法将从出现两次或多次的堆栈S中删除所有这些数字。 (使用C / C ++编写任务)

注意::我们不允许使用std::stack来解决此任务。

首先,我决定使用C语言,这是我使用的堆栈实现。

int* stack = (int*)malloc(10 * sizeof(int));
int size = 10;
int sp = -1;

bool isempty() {
    return (sp == -1);
}

bool isfull() {
    return (sp == size - 1);
}

void push(int x) {
    if (isfull()) {
        printf("Full!");
    }
    else {
        sp++;
        stack[sp] = x;
    }
}

int pop() {
    int x;
    if (isempty()) {
        printf("Empty!");
    }
    else {
        x = stack[sp];
        sp--;
    }
    return x;
}

void peek() {
    if (!isempty()) {
        printf("%d", stack[sp]);
    }
}

void clear() {
    while (!isempty()) {
        pop();
    }
}

void print() {
    if (!isempty()) {
        for (int i = 0; i < sp+1; i++) {
            printf("%d ", stack[i]);
        }
    }
    printf("\n");
}

我解决此任务的想法是制作另一个 temp 堆栈并将主 stack 复制到其中,而不是使用两个 for 循环进行比较我使用 if 语句检查所有元素和内部是否相同,如果不相同,我只是将它们推回到先前已清除的堆栈中,通过这种方式跳过所有重复的元素,但是由于某些原因,此代码无法正常工作,它使我发垃圾邮件的状态为“满!”消息。

void removeDuplicates() {
    int* temp = (int*)malloc(10 * sizeof(int));
    int temp_size = 10;
    int temp_sp = -1;

    for (int i = 0; i < sp + 1; i++) {
        temp[i] = stack[i];
    }
    temp_sp = sp;
    clear();

    for (int i = 0; i < temp_sp+1; i++) {
        for (int j = i + 1; j < temp_sp+1; i++) {
            if (!(temp[i] == temp[j])) {
                push(temp[i]);
            }
        }
    }
}

这是我用来测试功能的主要功能:

int main() {
    push(1);
    push(2);
    push(3);
    push(4);
    push(3);
    push(5);

    removeDuplicates();

    print();

    return 0;
}

如果有使用C ++(而非std::stack)解决此问题的简单方法,请告诉我。

2 个答案:

答案 0 :(得分:2)

  

该代码本应适用于普通数组,但不确定是否适合堆栈,因为我们可能使用动态内存

您的代码对堆栈是否正确与动态分配无关,而与堆栈接口无关。你知道那是什么吗解决问题绝对是必不可少的,而且我看不到任何暗示您知道堆栈的行为或试图对其进行研究的提示。

您在这里,stack abstract datatype

  • 保留后进先出的顺序
  • 允许您将新元素压入堆栈顶部
  • 允许您从堆栈顶部弹出最近推送的元素(尚未弹出)。

这就是一切,并且没有随机访问权限(即stack[j]永远不会是有效的表达式),因此,显然对于您展示的算法来说是不可能的。

如果您还没有堆栈实现,请编写一个!无论如何,您将需要一个堆栈来编译和测试算法。您显示的定义描述的是存储空间,而不是接口。

只有两个函数要编码(加上两个函数来创建和销毁堆栈,还有一个用于查询大小)。

现在使用该算法-您只能访问堆栈的顶部元素,因此您需要考虑对pop不重复的元素进行处理。它们必须走到某个地方,因为当它们在您的主堆栈上时您看不到它们的下方,并且您一定不能丢掉它们。


您的编辑显示您确实有一个堆栈数据类型,它是:它使用三个全局变量,您必须小心不要破坏它们,并且您不能为临时堆栈重用任何函数,因为它们在这些全局变量。

即使在C语言中,我也希望看到类似这样的内容(根据上面的内容,未经测试,未经编译的示例代码)

struct Stack {
    int size;
    int sp;
    int data[];
};

struct Stack* stack_create(int elements) {
    struct Stack *s = malloc(sizeof(*s) + elements * sizeof(int));
    s->size = elements;
    s->sp = -1;
    return s;
}

bool stack_isEmpty(struct Stack *s) { return s->sp == -1; }
bool stack_isFull(struct Stack *s) { return s->sp == s->size - 1; }
void stack_push(struct Stack *s, int x)
{
    assert(!stack_isFull(s));
    s->data[++s->sp] = x;
}
int stack_pop(struct Stack *s)
{
    assert(!stack_isEmpty(s));
    return s->data[(s->sp)--];
}

因为这样您就可以在主堆栈和临时堆栈上使用相同的操作。

如果removeDuplicates消息应该按照堆栈抽象来实现,则需要一种可以根据stack_push,{{1} }等。

如果stack_pop消息被假定为是直接在堆栈实现上运行的内部函数,而不是在堆栈抽象方面实现,那么您的基本方法可能就可以了(如果距离最佳状态还差得很远),则只需学习调试代码。

我仍然不知道其中哪一个是正确的(因此我不会投票重新开放),但是它们是完全不同的问题。

答案 1 :(得分:1)

我发现您当前的代码存在一些问题:

循环中

for (k = j; k < size; k++)
{
    stack[k] = stack[k + 1];
}

您超出限制是因为您使用stack[k+1]。您将如何解决?

但是在将所有元素下移1之后,新的stack[j]可能是stack[i]的另一个副本。您将如何解决?您可以考虑使用while循环。

您使用全局变量size,即堆栈大小。但是还有一个变量sp,它是堆栈指针,指示正在使用的堆栈部分。因此,除了循环size之外,还应该循环sp

请注意堆栈指针所指向的内容:值-1表示堆栈为空,因此任何其他值都指向堆栈顶部的当前值。 (这很重要,因为对堆栈指针的另一种解释是它指向堆栈的下一个空闲元素。)

sp当然会随着您从堆栈中删除的每一个重复项而减少。