C复习-堆栈和队列

参考: 里科《C和指针》- 经典抽象数据类型

本章涉及堆栈、队列、二叉搜索树、泛型等,代码太多,应该参考leetcode题目。本文只包含栈的数组实现(静态数组和动态数组)和链表实现,以及队列的数组实现。


堆栈 stack

1)使用静态数组实现堆栈

  • 把不属于外部接口的内容都声明为static,可以防止用户越界访问。
  • 使用assert防止非法操作,针对的是用户可以自己检查的内容
  • 使用is_full和is_empty是为了之后可以修改测试空堆栈和满堆栈的情况
/*
* 堆栈的接口 stack.h
*/
#define STACK_TYPE int

/* 把一个新值压到堆栈中 */
void push(STACK_TYPE value);

/* 从堆栈中弹出一个值,并将其丢弃 */
void pop(void);

/* 返回栈顶元素,但不对堆栈进行修改*/
STACK_TYPE top(void);

/* 如果堆栈为空,返回TRUE,否则FALSE */
int is_empty(void);

/* 如果堆栈已满,返回TRUE,否则FALSE */
int is_full(void);

/* ************************** */
/* 用一个静态数组实现堆栈,数组的长度只能通过修改#define定义,并重新编译实现 */
#include "stack.h"
#include <assert.h>

/* 堆栈中值数量的最大限制 */
#define STACK_SIZE 100

/* 存储堆栈中值的数组和一个指向堆栈顶部元素的指针 */
static STACK_TYPE stack[ STACK_SIZE ];
static int top_element = -1;

/* 把一个新值压到堆栈中 */
void push(STACK_TYPE value) {
	assert( !is_full() );
	top_element += 1;
	stack[top_element] = value;
}

/* 从堆栈中弹出一个值,并将其丢弃 */
void pop(void) {
	assert( !is_empty() );
	top_element -= 1;
}

/* 返回栈顶元素,但不对堆栈进行修改*/
STACK_TYPE top(void) {
	assert( !is_empty() );
	return stack[top_element];
}

/* 如果堆栈为空,返回TRUE,否则FALSE */
int is_empty(void) {
	return top_element == -1;
}

/* 如果堆栈已满,返回TRUE,否则FALSE */
int is_full(void) {
	return top_element == ( STACK_SIZE - 1 );
}

2)使用动态数组实现堆栈

  • 内存有限的环境中,使用assert检查内存是否分配成功不合适,因为失败的话直接停止了。可以让create_stack返回一个值,提示内存是否分配成功,如果失败的话,用户可以换小一点的值再试。

/* 创建堆栈,size指定可以保存多少个元素 */
void create_stack( size_t size);
/* 销毁堆栈,释放内存 */
void destroy_stack( void );

/* 相比静态数组实现,需要添加和修改的地方如下,其他函数不变 */
#include <malloc.h>

/* 存储堆栈中值的数组和一个指向堆栈顶部元素的指针 */
static STACK_TYPE *stack;
static size_t stack_size;
static int top_element = -1;

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 );
}

void destroy_stack(void) {
	assert( stack_size > 0 );
	stack_size = 0; // 设置size
	free(stack); // 释放空间
	stack = NULL; // 指针设为NULL
}

/* 如果堆栈为空,返回TRUE,否则FALSE */
int is_empty(void) {
	assert( stack_size > 0 ); // 增加
	return top_element == -1;
}

/* 如果堆栈已满,返回TRUE,否则FALSE */
int is_full(void) {
	assert(stack_size > 0); // 增加
	return top_element == ( stack_size - 1 );
}

3)链式堆栈

  • stack指针一直指向栈顶
  • 因为链式堆栈不会满,所以is_full始终是FALSE,且创建时不需要做工作
  • destroy_stack使用了is_empty和pop
#define FALSE 0

typedef struct STACK_NODE {
	STACK_TYPE value;
	struct STACK_NODE *next;
} StackNode;

/* 指向堆栈中第一个节点的指针 */
static StackNode *stack;

void create_stack(size_t size) {}

void destroy_stack(void) {
	while (!is_empty())
		pop();
}

/* 把一个新值压到堆栈中 */
void push(STACK_TYPE value) {
	StackNode* new_node;
	new_node = (StackNode*)malloc(sizeof(StackNode));
	assert(new_node != NULL);
	new_node->value = value;
	new_node->next = stack;
	stack = new_node;
}

/* 从堆栈中弹出一个值,并将其丢弃 */
void pop(void) {
	StackNode* first_node;
	assert( !is_empty() );
	first_node = stack; // 改指向
	stack = first_node->next; 
	free(first_node); // 释放
}

/* 返回栈顶元素,但不对堆栈进行修改*/
STACK_TYPE top(void) {
	assert( !is_empty() );
	return stack->value;
}

/* 如果堆栈为空,返回TRUE,否则FALSE */
int is_empty(void) {
	return stack == NULL;
}

/* 如果堆栈已满,返回TRUE,否则FALSE */
int is_full(void) {
	return FALSE;
}

队列

队列的接口:

/*
* 队列的接口 queue.h
*/
#define QUEUE_TYPE int

/* 只适用于动态分配数组的队列 */
void create_queue(size_t size);

/* 只适用于链式和动态分配数组的队列 */
void destroy_queue(void);

void insert(QUEUE_TYPE value);

void _delete(void);

QUEUE_TYPE first(void);

/* 如果堆栈为空,返回TRUE,否则FALSE */
int is_empty(void);

/* 如果堆栈已满,返回TRUE,否则FALSE */
int is_full(void);

为了尽可能利用空间,使用循环数组

  • 留一个空间不用,使得队列“满”时front和rear的值不同
  • front和rear可以用任何值初始化
  • 队列空的条件是(rear + 1) % QUEUE_SIZE == front
  • 队列满的条件是(rear + 2) % QUEUE_SIZE == front
#define QUEUE_SIZE 100 /* 队列中元素的最大数量 */
#define ARRAY_SIZE (QUEUE_SIZE + 1)

static QUEUE_TYPE queue[ ARRAY_SIZE ];
static size_t front = 1; // 从1开始.当只有1个元素时都指向1
static size_t rear = 0;

void insert(QUEUE_TYPE value) {
	assert( !is_full() );
	rear = (rear + 1) % ARRAY_SIZE;
	queue[rear] = value;
}

/*
* 删除元素时只要移动front即可
*/
void _delete(void) {
	assert( !is_empty() );
	front = (front + 1) % ARRAY_SIZE; 
}

QUEUE_TYPE first(void) {
	assert( !is_empty() );
	return queue[front];
}

int is_empty(void) {
	return (rear + 1) % ARRAY_SIZE == front;
}

int is_full(void) {
	return (rear + 2) % ARRAY_SIZE == front;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值