制作多个堆栈

时间:2013-12-30 23:05:29

标签: c stack

我想在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;
    }

4 个答案:

答案 0 :(得分:2)

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

从@ 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而忽略了你。你可能想要更好地处理它。

答案 1 :(得分: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)那么,从物理上讲,一个{ {1}}指针实际上是指向指针的指针。我们可以使用struct stack *名称来编写代码,以便我们可以使用任何定义:

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 */ 方面的API都是这样的:

stack_t

或其他什么。如果void stack_init(stack *s); int stack_push(stack *s, int item); 是一个指针(上面的替代“A”),则stack是一个指向指针的指针,因此你的代码将充满指向指针的操作。

如果你对指针到指针的语法都不熟悉,那么你可以给自己一个宏来假装它是一个结构。

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; 访问器,现在可以在替代“A”和“B”之间翻转堆栈类型的表示,而无需重写任何代码(仅重新编译它)。

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

答案 2 :(得分: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;
}

答案 3 :(得分:0)

C中单个数组中两个堆栈的静态实现看起来像这样...堆栈结构将具有两个top变量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");

下溢条件变得非常明显。由于我们可能会用完阵列中的存储空间,因此此方法可能不会提高内存效率,但这是单个阵列中多个堆栈的基本原理。