《C和指针》学习笔记之堆栈

堆栈是一种后进先出(LIFO)的数据结构。


1、堆栈接口

基本的堆栈操作通常是进栈push和出栈pop。push是把一个新值压入到堆栈的顶部,pop就是把堆栈顶部的值移出堆栈并返回这个值。另外一种堆栈接口提供三个基本操作:push、pop和top。push操作和前面描述的一样,pop只是把顶部元素从堆栈中移除,并不返回值,而top操作返回栈顶的元素,但不将其移除。第一种pop操作具有移除元素的副作用,而top操作没有副作用,第二种堆栈接口的功能分得更细,每种功能都不带副作用,所以第二种接口定义要更好一些。
堆栈的实现方式可以有三种:静态数组、动态数组和链表。如下的定义接口的头文件可用于所有的三种实现方式。
堆栈接口头文件stack.h:

/*
** 一个堆栈模块的接口
*/

#define STACK_TYPE int      /*堆栈所存储的值的类型*/

/*
** push
** 压入堆栈
*/
void push(STACK_TYPE value);

/*
** pop
** 弹出堆栈
*/
void pop(void);

/*
** top
** 返回堆栈顶部元素
*/
STACK_TYPE top(void);

/*
** is_empty
** 判断堆栈是否为空
*/
int is_empty(void);

/*
** is_full
** 判断堆栈是否已满
*/
int is_full(void);

/*
** create_stack
** 创建堆栈,参数指定堆栈长度
** 这个函数不用于静态数组版本的堆栈
*/
void create_stack(size_t size);

/*
** destroy_stack
** 销毁堆栈,释放所使用的内存
** 这个函数不用于静态数组版本的堆栈
*/
void destroy_stack(void);

在这个接口中,用户可以根据自己的需要修改堆栈中值的类型STACK_TYPE的定义。


2、静态数组实现堆栈

/*
** 用一个静态数组实现堆栈
*/
#include "stack.h"
#include <assert.h>

#define STACK_SIZE 100   /*堆栈长度*/

/*
** 存储堆栈中数据的数组和指向栈顶的指针
*/
static STACK_TYPE stack[STACK_SIZE];
static int        top_element = -1;

/*
** push
*/
void push(STACK_TYPE value)
{
    assert(!is_full());
    top_element += 1;
    stack[top_element] = value;
}

/*
** pop
*/
void pop(void)
{
    assert(!is_empty());
    top_element -= 1;
}

/*
** top
*/
STACK_TYPE top(void)
{
    assert(!is_empty());
    return stack[top_element];
}

/*
** is_empty
*/
int is_empty(void)
{
    return top_element == -1;
}

/*
** is_full
*/
int is_full(void)
{
    return top_element == STACK_SIZE - 1;
}

在这个实现中,所有不属于外部接口的内容都被声明为static,这是为了防止用户使用接口之外的其他方式改变堆栈中的值。
静态数组实现方式中,堆栈的长度是在编译之前就确定好的。


3、动态数组实现堆栈

/*
** 动态数组实现堆栈
** 堆栈的长度在创建堆栈的函数被调用时给出
*/
#include "stack.h"
#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
#include <assert.h>
#include <stddef.h>
/*
** 用于存储堆栈元素的数组和栈顶指针
*/
static STACK_TYPE *stack;
static size_t     stack_size;
static int        top_element = -1;

/*
** create_stack
*/
void create_stack(size_t size)
{
    assert(stack_size == 0);
    stack_size = size;
    stack = (STACK_TYPE *)malloc(stack_size * sizeof(STACK_TYPE));
    assert(stack != NULL);
}

/*
** destroy_stack
*/
void destroy_stack(void)
{
    assert(stack_size > 0);
    stack_size = 0;
    free(stack);
    stack = NULL;
}
/*
** push
*/
void push(STACK_TYPE value)
{
    assert(!is_full());
    top_element += 1;
    stack[top_element] = value;
}
/*
** pop
*/
void pop(void)
{
    assert(!is_empty());
    top_element -= 1;
}
/*
** top
*/
STACK_TYPE top(void)
{
    assert(!is_empty());
    return stack[top_element];
}
/*
** is_empty
*/
int is_empty(void)
{
    assert(stack_size > 0);
    return top_element == -1;
}
/*
** is_full
*/
int is_full(void)
{
    assert(stack_size > 0);
    return top_element == stack_size - 1;
}

在进行堆栈操作之前必须先调用void create_stack(size_t size)函数创建堆栈,同时指明堆栈长度。堆栈操作结束后需要调用void destroy_stack(void)函数释放内存。


4、链表实现堆栈

/*
** 用单相链表实现堆栈,这个堆栈没有长度限制
*/
#include "stack.h"
#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
#include <assert.h>

#define FALSE 0

/*
** 定义一个结构存储堆栈元素
*/
typedef struct STACK_NODE{
    STACK_TYPE value;
    struct STACK_NODE *next;
}StackNode;
/*
** 指向堆栈中第一个节点的指针
*/
static StackNode *stack;

/*
** create_stack
*/
void create_stack(size_t size)
{

}
/*
** destroy_stack
*/
void destroy_stack(void)
{
    while(!is_empty())
        pop();
}
/*
** push
*/
void push(STACK_TYPE value)
{
    StackNode *new_node;
    new_node = malloc(sizeof(StackNode));
    assert(new_node != NULL);
    new_node->value = value;
    new_node->next = stack;
    stack = new_node;
}
/*
** pop
*/
void pop(void)
{
    StackNode *first_node;
    first_node = stack;
    stack = first_node->next;
    free(first_node);
}
/*
** top
*/
STACK_TYPE top(void)
{
    assert(!is_empty());
    return stack->value;
}
/*
** is_empty
*/
int is_empty(void)
{
    return stack == NULL;
}
/*
** is_full
*/
int is_full(void)
{
    return FALSE;
}

create_stack是个空函数,因为不需要事先申请一定的内存,内存是随时要随时生成。链表实现的堆栈没有长度限制,所以int is_full(void)函数永远返回FALSE。
destroy_stack函数连续从堆栈中弹出元素,直到堆栈为空。这里的弹出元素与上面数组方式不一样,这里是真正的删除元素,连着该元素的内存一起释放。


参考文献

[1] Kenneth A. Reek. C和指针(第二版)[M]. 人民邮电出版社.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

巴普蒂斯塔

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值