制作多个堆栈

问题描述 投票:0回答:4

我想在C中创建一个堆栈数组,在那里我应该能够保留单独的堆栈及其各自的信息。我目前有以下实现,它只适用于一个堆栈。如何修改push和pop函数以实现多个堆栈,每个堆栈使用相同的功能。 (我很容易用Java做到这一点,因为我可以创建一个类,但我不知道在C中)

    #include <stdio.h>
    #include <stdlib.h>

    struct node {
        int data;
        struct node *next;
    };

    struct node *first = NULL;

    void push(int x) {
        struct node *newnode = malloc(sizeof(struct node));
        newnode->data = x;
        newnode->next = first;
        first = newnode;
    }

    int pop() {
        int temp = first->data;
        first = first->next;
        return temp;
    }
c stack
4个回答
2
投票

pop()函数中的代码中存在内存泄漏。你应该释放你拥有malloc的内存。

从@Jongware的评论中获取建议。

这是push()pop()函数的新版本。

#include <stdlib.h>

struct node {
    int data;
    struct node *prev;
};

void push(struct node **stack, int x) {
    if (stack != NULL)
    {
        struct node *newnode = malloc(sizeof(struct node));
        newnode->data = x;
        newnode->prev = *stack;
        *stack = newnode;
    } else
    {
        // You didn't give me a valid pointer to a stack, so I'm ignoring you!
    }
}

int pop(struct node **stack) {
    int temp = 0; // This is the default value that is returned when there is an error.
    struct node *oldnode;

    if (stack != NULL)
    {
        if (*stack != NULL)
        {
            oldnode= *stack;
            temp = oldnode->data;
            (*stack) = oldnode->prev;
            free(oldnode);
        } else
        {
            // The stack is empty. I will just ignore you and return the default value for temp.
        }
    } else
    {
        // You didn't give me a valid pointer to a stack so I'm ignoring you and returning the default value of 0 for temp!
    }

    return temp;
}

以下是如何使用它们的示例:

#include <stdio.h>

int main()
{
    struct node *stack1 = NULL, *stack2 = NULL;
    int value;

    // Push some values onto the stacks
    printf("Pushing 7 and then 8 onto stack1\n");
    push(&stack1, 7);
    push(&stack1, 8);

    printf("Pushing 3 onto stack2\n");
    push(&stack2, 3);

    // Pop and print both stacks
    value = pop(&stack2);
    printf("Popped %d from stack2\n", value);

    value = pop(&stack1);
    printf("Popped %d from stack1\n", value);
    value = pop(&stack1);
    printf("Popped %d from stack1\n", value);

    return 0;
}

至于你应该在哪里声明你的堆栈指针,以及你打算如何使用它们。

阅读有关C variable scope的一些选项以及如何使用它们。

此外,我将必须包含一个警告,在函数内声明这些指针。在您声明指针的任何函数中,必须确保在退出函数之前弹出堆栈中的所有内容,否则将丢失指针并泄漏所有已分配的内存。如果这不是您想要的,或者您希望指针比该函数更长,那么您可以全局声明指针或传递它,确保在程序存在之前将所有内容从堆栈中弹出或丢失指针。

您可能想要考虑的另一件事是当您在空堆栈上使用pop()时会发生什么?我给你的实现只返回0而忽略了你。你可能想要更好地处理它。


2
投票

您只能拥有一个堆栈,因为您将其定义为全局变量:

struct node *first = NULL;

在Java中,您将使用一个类。在C中,您同样可以通过定义保存实例变量的抽象数据类型来执行“基于对象”的编程,而不是使用全局变量:

struct stack {
  struct node *first;
};

没有像构造函数或析构函数这样的类功能,所以你编写函数来初始化堆栈,销毁堆栈等等。要实现多实例化,请将stack *参数显式传递给堆栈模块中的每个函数。您可能希望以一致的方式命名您的函数,如stack_initstack_cleanupstack_push等。

有一些设计问题需要解决,例如:调用者是否分配struct stack,为此你提供stack_init函数?或者你提供一步一步的stack_alloc函数来分配和返回一个堆栈?或者两者兼而有之,用户可以选择性能还是方便?

void stack_init(struct stack *);
void stack_cleanup(struct stack *);

struct stack *stack_alloc(void); /* also calls stack_init on new stack */
void stack_free(struct stack *); /* calls stack_cleanup, then frees */

可以在C中隐藏信息,从而可以完全隐藏客户端代码(使用堆栈模块)struct stack

但是,如果你提供stack_init,那么客户端必须知道堆栈有多大,因为它为它提供了内存。通常,完全隐藏实现的模块也会隐藏它的大小,因此只提供stack_allocstack_free类型的接口。

这样做的一个优点是,如果更改堆栈模块并且结构更大,则不必重新编译客户端代码。如果您正在编写一个广泛使用的库,这非常好:用户可以轻松升级或降级。

但是,揭示实现允许更高效的代码,因为客户端可以自由选择堆栈的内存管理。堆栈可以在自动存储中声明为局部变量(“在堆栈中”,可以这么说),静态地作为全局变量,或打包到数组中。

用户可以执行以下操作:

{
  struct stack temp_stack;

  stack_init(&temp_stack); /* stack is good to go! */

  /* ... use stack ... */

  stack_cleanup(&temp_stack); /* don't forget to clean up */
}

和类似的东西:

struct stack array_of_stacks[42];
int i;

for (i = 0; i < 42; i++)
  stack_init(&array_of_stacks[i]); /* no memory allocation taking place */

所有这些代码都具有struct stack定义的编译时依赖性;每当触及struct stack时,都必须重新编译。

注意,如果上面的struct stack定义是堆栈的确切定义(堆栈的唯一属性是它有一个指向顶部节点的指针,它可以为null)那么,从物理上讲,struct stack *指针实际上是指向a的指针指针。我们可以使用typedef名称来编写代码,以便我们可以使用以下任一定义:

/* Alternative "A" */
typedef struct node *stack_t; /* a stack_t type is a pointer to a node */

/* Alternative "B" */
typedef struct stack {
  struct node *top;
} stack_t; /* stack_t is a structure containing a pointer to a node */

无论哪种方式,根据stack_t的API然后看起来像这样:

void stack_init(stack *s);
int stack_push(stack *s, int item);

管他呢。如果stack是一个指针(上面的替代“A”),那么stack *s是一个指向指针的指针,所以你的代码将充满指针到指针的操作。

如果你对指针到指针的语法不太满意,那么你可以给自己一个宏来假装它仍然是一个结构。

/* Alternative "A" */
typedef struct node *stack_t; /* a stack_t type is a pointer to a node */
#define stack_top(s) (*(s))   /* dereference stack s to obtain the top pointer */

/* Alternative "B" */
typedef struct stack {
  struct node *top;
} stack_t; /* stack_t is a structure containing a pointer to a node */
#define stack_top(s) ((s)->top)  /* dereference struct pointer to get top pointer */

在代码中,您可以执行以下操作:

/* push new_node onto stack */

new_node->next = stack_top(s);
stack_top(s) = new_node;

如果您始终使用stack_top访问器,则现在可以在替代“A”和“B”之间翻转堆栈类型的表示,而无需重写任何代码(仅重新编译它)。

一些挑剔的C程序员会在stack_top(s) = new_node畏缩,因为它看起来像是一个函数调用(这在C中是不可能的,不使用宏来弯曲语言),并且更喜欢stack_top_set(s, new_node)的“setter”函数。这大多只是过时的,狭隘的思维。


1
投票
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>

typedef int Item;

#define ItemFormat "%d"

struct node {
    Item data;
    struct node *next;
};

typedef struct node *Stack;

void push(Stack *st, Item x){
    struct node *newnode = malloc(sizeof(struct node));
    newnode->data = x;
    newnode->next = *st;
    *st = newnode;
}

bool isEmpty(Stack st){
    return st == NULL;
}

Item pop(Stack *st) {
    if(!isEmpty(*st)){
        struct node *p = *st;
        Item value = p->data;
        *st = p->next;
        free(p);
        return value;
    }
    fprintf(stderr, "Stack is Empty!\n");
    return (Item)0;
}

bool inputItem(Item *x){
    int stat;
    if(1==(stat=scanf(ItemFormat, x)))
        return true;
    if(stat == EOF)
        return false;
    scanf("%*[^\n]");
    return false;
}

void printItem(Item x){
    printf(ItemFormat, x);
}

int main(void){
    Stack st = NULL, array[5] = { NULL };
    Item x;
    while(inputItem(&x)){
        push(&array[1], x);
    }
    while(!isEmpty(array[1])){
        x = pop(&array[1]);
        printItem(x);
        printf("\n");
    }
/*
    while(inputItem(&x)){
        push(&st, x);
    }
    while(!isEmpty(st)){
        x = pop(&st);
        printItem(x);
        printf("\n");
    }
*/
    return 0;
}

0
投票

C中单个数组中两个堆栈的静态实现看起来像这样......堆栈结构将有两个顶部变量top1和top2。

struct stack
{
  int data[MAX];
  int top1,top2;
}s;

top1初始化为-1,而top2初始化为MAX

溢出条件:1]

if((s->top1)+1==s->top2)
    printf("Stack 1 overflow\n");

2]

 if((s->top2)-1==s->top1)
    printf("Stack 2 overflow\n");

下溢情况变得非常明显。此方法可能不具有内存效率,因为我们可能会耗尽阵列中的存储空间,但它是单个阵列中多个堆栈的基本基础。

© www.soinside.com 2019 - 2024. All rights reserved.