数据结构(五)顺序栈 链式栈

一、概念

栈是一种先进后出的数据结构。FILO(firt in late out)

逻辑结构:线性结构

二、存储结构:

(一) 顺序存储——顺序栈

基于一个数组配合一个栈顶"指针(数组下标)–top"
顺序栈的本质就是对顺序表操作的一种约束:只能在一端进行插入和删除。

1. 结构体定义

//结构体定义
typedef struct node
{
    int data; //此处以int数据为例,可自行修改添加其他成员
}nd_t;

typedef struct stack
{
    int top; //顺序栈的"top指针"只需要一个int型数据就可以了,类似于数组下标
    nd_t st[N];    
}st_t;

2. 创建

(1)函数定义

int create_stack(stack_t **my_stack);

  1. 在内存中申请一块stack_t类型大小的空间存储栈的内容;
  2. 初始化栈的成员的数据:top置0
(2)注意点
  1. 进入函数就需要判断传入的参数是否为NULL,为空退出函数
  2. 在申请完内存空间后判断,申请空间是否成功,失败退出函数
(3)代码实现
int create_stack(st_t **my_stack){
    if(NULL==my_stack) return -1;
    *my_stack=(st_t *)malloc(sizeof(st_t));
    if(NULL==*my_stack) return -1;
    (*my_stack)->top=0;
    return 0;
}

3. 清空

(1)函数定义

int clean_stack(stack_t *my_stack);

count置0即可

(2)注意点
  1. 入参合理性检查
  2. count置0即可,原有内容没必要真的清空,之后写入内容会将其覆盖掉
(3)代码实现
int clean_stack(st_t *my_stack){
    if(NULL==my_stack) return -1;
    my_stack->top=0;
    return 0;
}

4. 销毁

(1)函数定义

int destroy_stack(stack_t **my_stack);

(2)注意点
  1. 入参合理性检测
  2. 传入二级指针
(3)代码实现
int destroy_stack(st_t **my_stack){
    if(NULL==my_stack||NULL==*my_stack) return -1;
    free(*my_stack);
    *my_stack=NULL;
    return 0;
}

5. 入栈、压栈——判断栈满

(1)函数定义

int is_full(st_t *my_stack);
int push_stack(stack_t *my_stack, int data);

  1. 在内存中申请一块node_t类型大小的数据空间
  2. count自加一
(2)注意点
  1. 需要检查传入参数是否为空,为空退出函数
  2. top指向栈顶最后一个元素的后一个空间
(3)代码实现
//满为1,不满为0
int is_full(st_t *my_stack){
    if(NULL==my_stack) return -1;
    return (N==my_stack->top)?1:0;
}

//入栈
int push_stack(st_t *my_stack, int data){
    if(NULL==my_stack) return -1;
    if(is_full(my_stack)){
        printf("栈已满\n");
        return -1;
    }
    my_stack->st[my_stack->top].data=data;
    my_stack->top++;
    return 0;
}

6. 出栈、弹栈——判断栈空

(1)函数定义

int is_empty(st_t *my_stack);
int pop_stack(stack_t *my_stack, int *num);

将栈顶的元素赋值给top
count自减

(2)注意点
  1. 需要检查传入指针参数和*num是否为空,为空退出函数
  2. 检查栈是否为空,为空退出函数
(3)代码实现
//空为1,不空为0
int is_empty(st_t *my_stack){
    if(NULL==my_stack) return -1;
    return (!(my_stack->top))?1:0;
}
int pop_stack(st_t *my_stack, int *num){
    if(NULL==my_stack||NULL==num) return -1;
    if(is_empty(my_stack)){
        printf("栈空\n");
        return -1;
    }
    *num=my_stack->st[my_stack->top-1].data;
    my_stack->top--;
    return 0;
}

7. 打印栈所有元素

(1)函数定义

int print_stack(stack_t *my_stack);

(2)注意点
  1. 入参合理性检查
  2. 判断栈是否为空
(3)代码实现
int print_stack(st_t *my_stack){
    if(NULL==my_stack) return -1;
    if(my_stack->top==0){
        printf("栈空\n");
        return -1;
    }
    for(int i=0;i<my_stack->top;i++){
        printf("%d ",my_stack->st[i].data);
    }
    putchar(10);
    return 0;
}

(二)链式存储——链式栈

1. 结构体定义

//链表节点结构体----数据元素
typedef struct _Node{
    int data;
    struct _Node *next;
}node_t;

//链式栈的结构体----数据对象
typedef struct _Stack{
    node_t *top;
    int count;//记录栈中元素个数
    //.....其他属性信息
}stack_t;

2.创建栈表

(1)函数定义

int create_stack(stack_t **my_stack);

  1. 在内存中申请一块stack_t类型大小的空间存储栈的内容;
  2. 初始化栈的成员的数据:将count置0,top置NULL
(2)注意点
  1. 进入函数就需要判断传入的参数是否为NULL,为空退出函数
  2. 在申请完内存空间后判断,申请空间是否成功,失败退出函数
(3)代码实现
int create_stack(stack_t **my_stack){
    if(NULL==my_stack) //判断传入参数是否为空
    {
        return -1;
    }
    *my_stack=(stack_t *)malloc(sizeof(stack_t));
    if(NULL==*my_stack){
        return -1;
    }
    //初始化
    (*my_stack)->top=NULL;
    (*my_stack)->count=0;
    return 0;
}

3. 入栈

(1)函数定义

int push_stack(stack_t *my_stack, int data);

  1. 在内存中申请一块node_t类型大小的数据空间
  2. 进行头插
  3. count自加一
(2)注意点
  1. 需要检查传入参数是否为空,为空退出函数
  2. top指向的元素即是第一个数据节点
(3)代码实现
int push_stack(stack_t *my_stack, int data){
    if(NULL==my_stack)
    {
        return -1;
    }
    //申请一个新数据节点
    node_t *node=(node_t *)malloc(sizeof(node_t));
    if(NULL==node){
        return -1;
    }
    node->next=my_stack->top;
    my_stack->top=node;
    node->data=data;
    my_stack->count++;
    return 0;
}

3. 出栈

(1)函数定义

int pop_stack(stack_t *my_stack, int *num);

  1. 头删
  2. count自减
(2)注意点
  1. 需要检查传入指针参数和*num是否为空,为空退出函数
  2. 检查栈是否为空,为空退出函数
(3)代码实现
//出栈
int pop_stack(stack_t *my_stack, int *num){
    if(NULL==my_stack||NULL==num)
    {
        return -1;
    }
    if(is_empty(my_stack)){
        return -1;
    }
    //头删
    node_t *pdel=my_stack->top;
    *num=pdel->data;

    my_stack->top=pdel->next;
    free(pdel);
    pdel=NULL;

    my_stack->count--;
    return 0;
}

4. 判断栈是否为空

(1)函数定义

int is_empty(stack_t *my_stack);

(2)注意点
  1. 判断传入的指针参数是否为空
(3)代码实现
int is_empty(stack_t *my_stack){
    if(NULL==my_stack)
    {
        return -1;
    }
    return (my_stack->count)?0:1; 
}

5. 清空栈

(1)函数定义

int clean_stack(stack_t *my_stack);

  1. 循环头删
  2. count置0
  3. 只要top的指向不为空,就一直循环
(2)注意点
  1. 入参合理性检查
  2. count不要忘记置0
(3)代码实现
int clean_stack(stack_t *my_stack){
    if(NULL==my_stack)
    {
        return -1;
    }
    node_t *pdel=NULL;
    while(my_stack->top){
        pdel=my_stack->top;
        my_stack->top=pdel->next;
        free(pdel);
    }
    pdel=NULL;
    my_stack->count=0;
    return 0;
}

6. 销毁栈

(1)函数定义

int destroy_stack(stack_t **my_stack);

(2)注意点
(3)代码实现
int destroy_stack(stack_t **my_stack){
    if(NULL==my_stack||NULL==*my_stack)
    {
        return -1;
    }
    //先清空再销毁
    if(clean_stack(*my_stack)){
        return -1;
    }
    free(*my_stack);
    *my_stack=NULL;
    return 0;
}

7. 打印栈

(1)函数定义

int print_stack(stack_t *my_stack);

(2)注意点
  1. 入参合理性检查
(3)代码实现
int print_stack(stack_t *my_stack){
    if(NULL==my_stack)
    {
        return -1;
    }
    if(is_empty(my_stack)){
        printf("栈空\n");
        return -1;
    }
    node_t *ptemp=my_stack->top;
    for(int i=0;i<my_stack->count;i++)
    {
        printf("%d ",ptemp->data);
        ptemp=ptemp->next;
    }
    putchar(10);

    return 0;
}

三、使用实例—判断字符串的括号是否配对

(一)功能需求:

在终端中输入一个字符串,判断字符串中的括号是否配对。
如果不配对,指出不配对的位置。

(二)需求分析

遇到左括号 ( [ { 就入栈
遇到右括号 ) ] } 就弹出栈顶元素 判断和当前的右括号是否配对
知道字符串遍历结束 如果栈中为 空 说明配对
记录下标

(三)代码实现

本代码实在链式栈基础上的应用实例,以下代码仅展示主函数以及部分修改后的链式栈

link_stack.h

//数据元素结构体,即用于存放入栈的左括号
typedef struct _Node{
    char data;  //此处修改为了char类型数据
    int index; //增加下标数据
    struct _Node *next;
}node_t;

link_stack.c

//入栈时不仅存储左括号本身,还存放左括号的下标
int push_stack(stack_t *my_stack, char data,int index){
    if(NULL==my_stack)
    {
        return -1;
    }
    //申请一个新数据节点
    node_t *node=(node_t *)malloc(sizeof(node_t));
    if(NULL==node){
        return -1;
    }
    node->data=data;  //左括号
    node->index=index;  //左括号下标

    node->next=my_stack->top;
    my_stack->top=node;
    my_stack->count++;
    return 0;
}

//出栈时不仅弹出左括号,还弹出它的下标
int pop_stack(stack_t *my_stack, char *num, int *index){
    if(NULL==my_stack||NULL==num||NULL==index)
    {
        return -1;
    }
    if(is_empty(my_stack)){
        return -1;
    }
    //头删
    node_t *pdel=my_stack->top;
    *num=pdel->data; //左括号
    *index=pdel->index; //下标
    my_stack->top=pdel->next;
    free(pdel);
    pdel=NULL;

    my_stack->count--;
    return 0;
}

main.c

#include "link_stack.h"

int main(int argc, const char *argv[])
{
	char str[128];
	//输入一个字符串
	printf("please input a string:\n");
	scanf("%s",str);
	//创建栈
	stack_t *my_stack=NULL;
	if(!create_stack(&my_stack))
	{
		printf("创建栈失败!\n");
		return -1;
	}

	int index=0;  //遍历字符串的下标
	int i=0;      //记录错误位置的下标
	int j=0;      //用于指出错误位置
	char c;       //记录当前取出的字符
	int flag=0;   //标记字符串中是否有括号,没有为0
	while(str[index])
	{//遍历字符串
		if(str[index]=='('||str[index]=='['||str[index]=='{')
		{//遇到左括号 (  [  { 就入栈
			flag=1;	
			push_stack(my_stack,str[index],index);
		}else if(str[index]==')'||str[index]==']'||str[index]=='}')
		{//遇到右括号 )  ]  } 就弹出栈顶元素  判断和当前的右括号是否配对
			flag=1;
			if(is_empty(my_stack)){
				goto ERR;
			}
			pop_stack(my_stack,&c,&i);
			switch(str[index]){
				case ')':
				if(c=='(')break;
				else{
					goto ERR;
				}
				case ']':
				if(c=='[')break;
				else{
					goto ERR;
				}
				case '}':
				if(c=='{')break;
				else{
					goto ERR;
				}
			}
		}
		index++;
	}

	if(flag==0){
		printf("无括号,无法配对\n");
		return -1;
	}
	//当字符串结束时,判断栈是否为空
	if(is_empty(my_stack)){
		printf("配对成功\n");
	}else{
		pop_stack(my_stack,&c,&i);
		index=i;
		goto ERR;
	}
	return 0;

ERR:
	for(j=0;j<index;j++)
		printf(" ");
	printf("^\n");
    printf("配对失败\n");
	return 0;
}

(四)实例代码已上传资源

下载链接:
判断字符串括号是否配对实例代码

  • 12
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值