数据结构与算法—栈

目录

一、栈的概念及结构

二、栈的实现 

1、声明栈结构体

2、初始化

3、 销毁

4、 入栈(压栈)

5、出栈(弹栈)

6、栈的大小

 OJ练习

 完整版:

Stack.h声明

Stack.c函数

test.c参考测试用例


一、栈的概念及结构

栈(Stack)是一种常见的数据结构,它遵循一种特定的数据存储和访问方式,通常用于管理数据的后进先出(Last-In-First-Out,LIFO)的操作顺序。这意味着最后压入栈的元素将首先被弹出,类似于一叠盘子,你总是在最上面放入和拿出盘子。

栈通常支持以下两种基本操作:

  1. 压栈(Push):将元素添加到栈的顶部。这个操作通常叫做“入栈”。
  2. 弹栈(Pop):从栈的顶部移除元素。这个操作通常叫做“出栈”。

 数据结构与算法—栈_第1张图片

二、栈的实现 

栈的实现一般可以使用数组或者链表实现,相对而言数组的结构实现更优一些。因为数组在尾上插入数据的代价比较小,(CPU高速缓存命中率会更高)

1、声明栈结构体

typedef int STDataType;
typedef struct Stack
{
	STDataType* a;
	int top;
	int capacity;
}ST;
  • 将栈的数据类型设置别名STDataType,方便后续修改。
  • 定义结构体名称的别名为ST。
  •  结构体成员*a用于指向存储栈元素的动态数组。
  • top为栈顶的位置。
  • capacity为当前栈的容量。

2、初始化

void STInit(ST* pst)
{
	assert(pst);
	pst->a = NULL;
	pst->top = 0;
	pst->capacity = 0;
}
  • assert判断栈的地址是否为空,为空则报错。
  • 将指针a初始化为空,栈顶位置top初始化为0,容量capacity初始化为0。

3、 销毁

void STDestroy(ST* pst)
{
	assert(pst);
	free(pst->a);
	pst->a = NULL;
	pst->top = 0;
	pst->capacity = 0;
}
  •  assert判断栈的地址是否为空,为空则报错。
  • free释放结构体成员a的空间,以避免内存泄漏,然后将a置空。
  • 将栈顶位置top赋值为0,表示栈已空。
  • 将容量capacity赋值为0,表示容量为0.

4、 入栈(压栈)

void STPush(ST* pst,STDataType x)
{
	if (pst->top == pst->capacity) {
		int newCapacity = pst->capacity == 0 ? 4 :pst-> capacity * 2;
		STDataType* tmp = (STDataType*)realloc(pst->a, newCapacity * sizeof(STDataType));
		if (tmp == NULL) {
			perror("realloc fail");
			return;
		}
		pst->a = tmp;
		pst->capacity = newCapacity;
	}
	pst->a[pst->top] = x;
	pst->top++;
}
  • 每次数据入栈都先检查栈的容量,top与capacity相等分为两种情况:第一次入栈或栈已满
  1. 第一次入栈时,新栈newCapacity的容量为4,然后为其开辟相应大小的空间,
  2. 如果已满即top与capacity相等,则新栈newCapacity的大小为当前的两倍,然后对当前空间进行扩容。
  • 用中间变量接收扩容的空间,防止扩容失败丢失数据。
  •  如果扩容失败则调用perror打印错误信息。
  • 将中间变量赋值给 a。
  • 更新容量为newCapacity的值。
  • 将接收的参数 x 入栈到top位置,然后更新top位置向上移动一位。

5、出栈(弹栈)

出栈需要三个函数,STPop 用于弹出元素,STTop 用于获取栈顶元素的值,而 STEmpty 用于检查栈是否为空。

void STPop(ST* pst)
{
	assert(pst);
	assert(!STEmpty(pst));
	pst->top--;
}

STDataType STTop(ST* pst)
{
	assert(pst);
	assert(!STEmpty(pst));
	return pst->a[pst->top - 1];
}

bool STEmpty(ST* pst)
{
	assert(pst);
	return pst->top == 0;
}

void STPop(ST* pst) 函数:

  • 这个函数用于弹出栈顶元素,也就是将栈顶位置 pst->top 的值减一,相当于将栈顶元素从栈中移除。
  • assert(pst) 确保传入的 pst 指针不为空。
  • assert(!STEmpty(pst)) 确保栈不为空,因为如果栈已经为空,就不应该执行弹出操作,否则会导致错误。
  • pst->top--; 将栈顶位置减一,以实现弹出操作。

STDataType STTop(ST* pst) 函数:

  • 这个函数用于获取栈顶元素的值,但不将其从栈中移除。
  • assert(pst) 确保传入的 pst 指针不为空。
  • assert(!STEmpty(pst)) 确保栈不为空,因为如果栈为空,就不能安全地访问栈顶元素。
  • return pst->a[pst->top - 1]; 返回栈顶位置 pst->top 上的元素值,由于栈是从0开始索引的,所以需要减一。

bool STEmpty(ST* pst) 函数:

  • 这个函数用于检查栈是否为空。
  • assert(pst) 确保传入的 pst 指针不为空。
  • return pst->top == 0; 返回一个布尔值,表示栈是否为空。如果栈顶位置 pst->top 等于0,说明栈为空,返回 true;否则返回 false

6、栈的大小

int STSize(ST* pst)
{
	assert(pst);
	return pst->top;
}
  •   assert判断栈的地址是否为空,为空则报错。
  • 返回栈的大小,即栈顶位置 pst->top 的值。栈顶位置表示栈中元素的数量,因为栈是从0开始索引的,所以 pst->top 的值等于栈中元素的数量。

 OJ练习

20. 有效的括号

 数据结构与算法—栈_第2张图片

由于我们用C语言做这道题,所以代码前要加上咱们实现的栈的代码,同时要将数据类型STDataType改为char类型。

typedef char STDataType;
typedef struct Stack
{
	STDataType* a;
	int top;
	int capacity;
}ST;

void STInit(ST* pst);
void STDestroy(ST* pst);
void STPush(ST* pst, STDataType x);
void STPop(ST* pst);
STDataType STTop(ST* pst);
bool STEmpty(ST* pst);
int STSize(ST* pst);

void STInit(ST* pst)
{
	assert(pst);
	pst->a = NULL;
	pst->top = 0;
	pst->capacity = 0;
}

void STDestroy(ST* pst)
{
	assert(pst);
	free(pst->a);
	pst->a = NULL;
	pst->top = 0;
	pst->capacity = 0;
}

void STPush(ST* pst,STDataType x)
{
	if (pst->top == pst->capacity) {
		int newCapacity = pst->capacity == 0 ? 4 :pst-> capacity * 2;
		STDataType* tmp = (STDataType*)realloc(pst->a, newCapacity * sizeof(STDataType));
		if (tmp == NULL) {
			perror("realloc fail");
			return;
		}
		pst->a = tmp;
		pst->capacity = newCapacity;
	}
	pst->a[pst->top] = x;
	pst->top++;
}

void STPop(ST* pst)
{
	assert(pst);
	assert(!STEmpty(pst));
	pst->top--;
}

STDataType STTop(ST* pst)
{
	assert(pst);
	assert(!STEmpty(pst));
	return pst->a[pst->top - 1];
}

bool STEmpty(ST* pst)
{
	assert(pst);
	return pst->top == 0;
}

int STSize(ST* pst)
{
	assert(pst);
	return pst->top;
}

bool isValid(char* s) {
    ST st;
    STInit(&st);
    while (*s) {
        if (*s == '(' || *s == '[' || *s == '{') {
            STPush(&st, *s);
        }
        else {
            if (STEmpty(&st)) {
                STDestroy(&st);
                return false;
            }
            char top = STTop(&st);
            STPop(&st);
            if ((top != '(' && *s == ')') ||
                (top != '{' && *s == '}') ||
                (top != '[' && *s == ']')) {
                STDestroy(&st);
                return false;
            }
        }
        s++;
    }
    bool ret = STEmpty(&st);
    STDestroy(&st);
    return ret;
}
  • 创建栈结构体ST变量 st,然后进行初始化。
  • 以*s为循环进行条件
  • 首先,创建一个名为 st 的 ST 结构体实例,并使用 STInit 初始化它。

  • 然后,遍历输入字符串 s 中的每个字符。
  • 对于每个字符,如果是左括号 '(','[','{' ,则将其推入栈中。
  • 如果是右括号 ')',']','}' ,则执行以下操作:

检查栈是否为空,如果为空,表示没有对应的左括号,则销毁栈,返回 false

否则,弹出栈顶元素,将其与当前右括号进行匹配。如果不匹配,则销毁栈,返回 false

  • 最后,遍历完整个字符串后,检查栈是否为空。如果栈为空,表示所有括号都成功匹配,返回 true,否则返回 false
  • 最后,调用 STDestroy 销毁栈,并返回最终的匹配结果。

 完整版:

Stack.h声明

#include 
#include 
#include 
#include 
typedef int STDataType;
typedef struct Stack
{
	STDataType* a;
	int top;
	int capacity;
}ST;

void STInit(ST* pst);
void STDestroy(ST* pst);
void STPush(ST* pst, STDataType x);
void STPop(ST* pst);
STDataType STTop(ST* pst);
bool STEmpty(ST* pst);
int STSize(ST* pst);

Stack.c函数

#include "Stack.h"

void STInit(ST* pst)
{
	assert(pst);
	pst->a = NULL;
	pst->top = 0;
	pst->capacity = 0;
}

void STDestroy(ST* pst)
{
	assert(pst);
	free(pst->a);
	pst->a = NULL;
	pst->top = 0;
	pst->capacity = 0;
}

void STPush(ST* pst,STDataType x)
{
	if (pst->top == pst->capacity) {
		int newCapacity = pst->capacity == 0 ? 4 :pst-> capacity * 2;
		STDataType* tmp = (STDataType*)realloc(pst->a, newCapacity * sizeof(STDataType));
		if (tmp == NULL) {
			perror("realloc fail");
			return;
		}
		pst->a = tmp;
		pst->capacity = newCapacity;
	}
	pst->a[pst->top] = x;
	pst->top++;
}

void STPop(ST* pst)
{
	assert(pst);
	assert(!STEmpty(pst));
	pst->top--;
}

STDataType STTop(ST* pst)
{
	assert(pst);
	assert(!STEmpty(pst));
	return pst->a[pst->top - 1];
}

bool STEmpty(ST* pst)
{
	assert(pst);
	return pst->top == 0;
}

int STSize(ST* pst)
{
	assert(pst);
	return pst->top;
}

test.c参考测试用例

#include "Stack.h"

void test1()
{
	ST st;
	STInit(&st);
	STPush(&st, 999);
	STPush(&st, 99);
	STPush(&st, 9);
	//printf("%d ", STTop(&st));
	//STPop(&st);
	//printf("%d ", STTop(&st));

	while (!STEmpty(&st)) {
	    printf("%d ", STTop(&st));
	    STPop(&st);
    }
	STDestroy(&st);
}

int main()
{
	test1();
	return 0;
}

你可能感兴趣的:(数据结构,数据结构,c语言)