Bootstrap

C语言实现数据结构之栈

一. 栈的概念及结构

栈:一种特殊的线性表,其只允许在固定的一端进行插入和删除元素操作。进行数据插入和删除操作的一端称为栈顶另一端称为栈底
栈中的数据元素遵守后进先出LIFO(Last In First Out)的原则。

压栈:栈的插入操作叫做进栈/压栈/入栈,入数据在栈顶
出栈:栈的删除操作叫做出栈。出数据也在栈顶
栈的后进先出
栈的入栈和出栈

二. 栈的实现

栈的实现一般可以使用数组或者链表实现,相对而言数组的结构实现更优一些。因为数组在尾上插入数据的代价比较小。
数组实现栈
链表实现栈

1. 静态栈

// 下面是定长的静态栈的结构,实际中一般不实用,所以我们主要实现下面的支持动态增长的栈
typedef int STDataType;
#define N 10
typedef struct Stack
{
	STDataType _a[N];
	int _top; // 栈顶
}Stack;

2. 动态栈的实现

2.1 要实现的功能
// 支持动态增长的栈
typedef int STDataType;
typedef struct Stack
{
STDataType* _a;
int _top; // 栈顶
int _capacity; // 容量
}Stack;
// 初始化栈
void StackInit(Stack* ps);
// 入栈
void StackPush(Stack* ps, STDataType data);
// 出栈
void StackPop(Stack* ps);
// 获取栈顶元素
STDataType StackTop(Stack* ps);
// 获取栈中有效元素个数
int StackSize(Stack* ps);
// 检测栈是否为空,如果为空返回非零结果,如果不为空返回0
int StackEmpty(Stack* ps);
// 销毁栈
void StackDestroy(Stack* ps);
2.2 具体实现

本次栈的实现我们基于顺序表,实现了动态扩容。

2.2.1 结构体

为了适配多种数据类型,这里使用typedef对数据类型进行重命名,便于进行统一修改。

typedef int STDataType;

typedef struct Stack
{
	STDataType* a;
	int top;
	int capacity;
}ST;
2.2.2 初始化

由于涉及到操作数组的下标,top就有了两种表示方式,这里让top指向栈顶数据的下一位,否则无法分辨栈内是否有一个元素。或者让top最开始指向-1。

void STInit(ST* pst)
{
	assert(pst);

	pst->a = NULL;
	pst->capacity = 0;
	// top指向栈顶数据的下一个位置
	pst->top = 0;

	 top指向栈顶数据
	//pst->top = -1;
}
2.2.3 销毁

释放动态申请的空间,将top和容量置空即可。

void STDestroy(ST* pst)
{
	assert(pst);

	free(pst->a);

	pst->a = NULL;
	pst->capacity = 0;
	pst->top = 0;
}
2.2.4 入栈

入栈应当将数据插入到数组尾部,然后top增加。

void STPush(ST* pst, STDataType x)
{
	assert(pst);

	//扩容
	if (pst->top == pst->capacity)
	{
		int newcapacity = (pst->capacity == 0) ? 4 : (2 * pst->capacity);
		STDataType* tmp = (STDataType*)realloc(pst->a, newcapacity * sizeof(STDataType));
		if (tmp == NULL)
		{
			perror("realloc failed");
			exit(1);
		}

		pst->a = tmp;
		pst->capacity = newcapacity;
	}

	//存放数据
	pst->a[pst->top] = x;
	pst->top++;
}
2.2.5 出栈

出栈应当将数组尾部的数据删除,具体就是top前移。

void STPop(ST* pst)
{
	assert(pst);
	assert(pst->top > 0);
	pst->top--;
}
2.2.6 返回栈顶元素

返回数组的top位置的前一个元素即可。如果top初始为-1,返回下标为top位置的数据即可。

STDataType STTop(ST* pst)
{
	assert(pst);
	assert(pst->top > 0);

	return pst->a[pst->top - 1];
}
2.2.7 判空

返回top是否为0。如果top初始为-1,返回top是否为-1即可。

_Bool STEmpty(ST* pst)
{
	assert(pst);
	return pst->top == 0;
}
2.2.8 栈元素个数

返回top即可。如果top初始为-1,返回top+1即可。

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

三. 栈相关OJ题

有效的括号

题目链接:有效的括号

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->capacity = 0;
	// top指向栈顶数据的下一个位置
	pst->top = 0;

	 top指向栈顶数据
	//pst->top = -1;
}

void STDestroy(ST* pst)
{
	assert(pst);

	free(pst->a);

	pst->a = NULL;
	pst->capacity = 0;
	pst->top = 0;
}

void STPush(ST* pst, STDataType x)
{
	assert(pst);

	//扩容
	if (pst->top == pst->capacity)
	{
		int newcapacity = (pst->capacity == 0) ? 4 : (2 * pst->capacity);
		STDataType* tmp = (STDataType*)realloc(pst->a, newcapacity * sizeof(STDataType));
		if (tmp == NULL)
		{
			perror("realloc failed");
			exit(1);
		}

		pst->a = tmp;
		pst->capacity = newcapacity;
	}

	//存放数据
	pst->a[pst->top] = x;
	pst->top++;
}

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

STDataType STTop(ST* pst)
{
	assert(pst);
	assert(pst->top > 0);

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

四. 概念选择题

  1. 一个栈的初始状态为空。现将元素1、2、3、4、5、A、B、C、D、E依次入栈,然后再依次出栈,则元素出栈的顺序是( )。
    A 12345ABCDE
    B EDCBA54321
    C ABCDE12345
    D 54321EDCBA
  2. 若进栈序列为 1,2,3,4 ,进栈过程中可以出栈,则下列不可能的一个出栈序列是()
    A 1,4,3,2
    B 2,3,4,1
    C 3,1,4,2
    D 3,4,2,1

答案:

  1. B
  2. C

五. 参考代码

Stack.h

#pragma once

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

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->capacity = 0;
	// top指向栈顶数据的下一个位置
	pst->top = 0;

	 top指向栈顶数据
	//pst->top = -1;
}

void STDestroy(ST* pst)
{
	assert(pst);

	free(pst->a);

	pst->a = NULL;
	pst->capacity = 0;
	pst->top = 0;
}

void STPush(ST* pst, STDataType x)
{
	assert(pst);

	//扩容
	if (pst->top == pst->capacity)
	{
		int newcapacity = (pst->capacity == 0) ? 4 : (2 * pst->capacity);
		STDataType* tmp = (STDataType*)realloc(pst->a, newcapacity * sizeof(STDataType));
		if (tmp == NULL)
		{
			perror("realloc failed");
			exit(1);
		}

		pst->a = tmp;
		pst->capacity = newcapacity;
	}

	//存放数据
	pst->a[pst->top] = x;
	pst->top++;
}

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

STDataType STTop(ST* pst)
{
	assert(pst);
	assert(pst->top > 0);

	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"

int main()
{
	ST s;
	STInit(&s);

	STPush(&s, 1);
	printf("%d ", STTop(&s));
	STPush(&s, 2);
	printf("%d ", STTop(&s));
	STPush(&s, 3);
	printf("%d ", STTop(&s));
	STPush(&s, 4);
	printf("%d ", STTop(&s));
	STPush(&s, 5);
	printf("%d ", STTop(&s));

	//printf("%d ", STTop(&s));
	//STPop(&s);
	//printf("%d ", STTop(&s));
	//STPop(&s);
	//printf("%d ", STTop(&s));
	//STPop(&s);
	//printf("%d ", STTop(&s));
	//STPop(&s);
	//printf("%d ", STTop(&s));
	//STPop(&s);

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

	STDestroy(&s);
	return 0;
}
;