数据结构
1. 组成
- 一组存储区用来存放数字
- 一组函数用来操作存储区
2. 栈 (最简单的数据结构)
- 2.1 特点
- 每次只能加入一个数字,每次只能拿出一个数字。
- 栈里的数字有前后顺序,先进入的数字在最前,后进入的数字在最后。
- 每次从栈里获得的数字一定是最后放进去的数字(后进先出)
- 2.2 实现方法
- 可使用宏 SIZE,在编译的时候临时决定栈里需要多少个存储区
- 有了数字个数 qty,随时就可以知道最后一个数字放在哪个下标里,同时也可以知道下一个数字往哪个下标的存储区里放
typedef struct {
int buf[SIZE]; //存放数字的数组
int qty; //栈里的数字个数
} stack;
-
- 除了这个结构体外,还需要为这个栈编写一组相关的关联函数
- 栈的初始化函数用来把一个没有使用过的栈设置成可使用的状态
- void stack_init(stack *p_stack) {…}
- 栈的清理函数 用来把一个使用过的栈里的所有数字删除
- void stack_deinit(stack *p_stack){…}
- 获得栈里的数字个数的函数
- int stack_size(const stack *p_stack){…}
- 判断栈是否是空的函数
- int stack_empty(const stack *p_stack){…}
- 判断栈是否满的函数
- int stack_full(const stack *p_stack){…}
- 向栈里加数字的函数(用整数类型返回值表示是否把数字加进了栈里)
- int stack_push(stack *p_stack, int val){…}
- 从栈里获得数字的函数(同时删除数字)
- int stack_pop(stack *p_stack, int *p_val){…}
- 从栈里获得数字的函数(不会删除数字
- int stack_top(const stack *p_stack, int *p_val){…}
/
//stack_1.h
//头尾加上条件编译预处理指令
#ifndef __STACK_1_H__
#define __STACK_1_H__
typedef struct {
int buf[SIZE];
int qty;
} stack;
void stack_init(stack *);
void stack_deinit(stack *);
int stack_size(const stack *);
int stack_empty(const stack *);
int stack_full(const stack *);
int stack_push(stack *, int);
int stack_pop(stack *, int *);
int stack_top(const stack *, int *);
#endif //__STACK_1_H__
/
//stack_1.c
#include "stack_1.h"
//栈的初始化函数(处理一个没有使用过的栈),用结构体指针形参来代表一个栈
//要修改这个栈,所以不用加const关键字
void stack_init(stack *p_stack) {
//qty = 0 表示栈里没有数字,所有存储区的数字都是无效的
//所以可以不用管数组内容
p_stack->qty = 0;
}
//栈的清理函数(处理一个使用过的栈)
void stack_deinit(stack *p_stack) {
//栈里没有数字就相当于把数字都删了
p_stack->qty = 0;
}
//获得栈里数字个数的函数
int stack_size(const stack *p_stack) {
return p_stack->qty;
}
//判断栈是否空的函数
int stack_empty(const stack *p_stack) {
return !p_stack->qty;
}
//判断栈是否是满的
int stack_full(const stack *p_stack) {
return p_stack->qty >= SIZE;
}
//向栈里加入数字, val 表示要加的数字
int stack_push(stack *p_stack, int val) {
//先判断栈是否已经满了
if(p_stack->qty >= SIZE) {
//如果栈满了就不可能加入新数字
return 0;
}
//栈的数组有两种使用方法,第一种是先加入的数字放在小下标的存储区里
//第二种是先加入的数字放在大下标的存储区里,这里用第一种
//以 qty 为下标到数组里找到第一个存储区,把数字赋值给这个存储区
p_stack->buf[p_stack->qty] = val;
p_stack->qty++;
return 1;
}
//从栈里获得数字的函数
//返回值用来表示是否成功的获得了数字
//这里用 整数类型指针形参 把获得的数字从 被调函数 传递给 调用函数
int stack_pop(stack *p_stack, int *p_val) {
//检查栈是否是空的
if (p_stack->qty == 0)
{
//如果栈里没有数字就无法获得数字
return 0;
}
//找到以 qty - 1 作下标的存储区,它里面就是最后面的数字
//把这个数字传递给调用函数,然后数字个数减一
*p_val = p_stack->buf[p_stack->qty - 1];
p_stack->qty--;
return 1;
}
//从栈里获得数字的函数(不会删除这个数字)
int stack_top(const stack *p_stack, int *p_val) {
if (p_stack->qty == 0)
{
return 0;
}
*p_val = p_stack->buf[p_stack->qty - 1];
return 1;
}
/*
//验证这个没有主函数的源文件能不能编译过
gcc -DSIZE=5 stack.cc -c
*/
/
//stack_main.c
#include <stdio.h>
//如果一个源文件里使用了某个头文件里声明的函数,那这个头文件也是这个源文件的必要头文件
#include "stack_1.h"
int main() {
stack stk = {0};
int val = 0;
//使用数据结构的代码框架
//首先做初始化, 最后做清理
stack_init(&stk);
printf("数字个数是%d\n", stack_size(&stk));
printf("判断栈是空的结果是%d\n", stack_empty(&stk));
printf("判断栈是满的结果是%d\n", stack_full(&stk));
stack_push(&stk, 10);
stack_push(&stk, 20);
stack_push(&stk, 30);
printf("数字个数是%d\n", stack_size(&stk));
printf("判断栈是空的结果是%d\n", stack_empty(&stk));
printf("判断栈是满的结果是%d\n", stack_full(&stk));
stack_push(&stk, 40);
stack_push(&stk, 50);
printf("数字个数是%d\n", stack_size(&stk));
printf("判断栈是空的结果是%d\n", stack_empty(&stk));
printf("判断栈是满的结果是%d\n", stack_full(&stk));
//拿到的一定是最后放进去的数字
stack_top(&stk, &val);
printf("最后的数字是%d\n", val);
//把栈里所有数字拿出来,并删除
while (1) {
if(!stack_pop(&stk, &val)) {
//负责处理不能从栈里获得数字的情况
break;
}
printf("%d ", val);
}
printf("\n");
printf("数字个数是%d\n", stack_size(&stk));
printf("判断栈是空的结果是%d\n", stack_empty(&stk));
printf("判断栈是满的结果是%d\n", stack_full(&stk));
//最后做清理
stack_deinit(&stk);
return 0;
}
/*
gcc -DSIZE=5 stack_main.c stack_1.c
./a.out
数字个数是0
判断栈是空的结果是1
判断栈是满的结果是0
数字个数是3
判断栈是空的结果是0
判断栈是满的结果是0
数字个数是5
判断栈是空的结果是0
判断栈是满的结果是1
最后的数字是50
50 40 30 20 10
数字个数是0
判断栈是空的结果是1
判断栈是满的结果是0
*/