说明
栈是最常见基础的一种数据结构,在算法的实现上,经常会使用到栈。本文主要目标是实现一个可以存储多种数据类型的栈,并提供常用的栈方法。本文采用三种方式来创建栈:定长数组、创建时指定长度数组、链式栈,提供的栈方法:
- 创建栈
- 栈空判断
- 栈满判断
- 入栈
- 出栈
- 获取栈顶元素
- 栈销毁
1、定长数组栈
1.1、栈结构定义
栈结构 即是栈对象,其内包含数据对象数组、栈容量、栈长度、栈顶指针信息。为了存储不指定类型的数据,这里采用void*
数组来存储,void*
不指定指针的类型,实际上存储的是数据的地址,从而实现不指定数据类型。使用时,只需将出栈后的指针强转位需要的类型即可正常使用。这里需要自己注意存入与取出类型的区分,不要因为转型错误产生问题。
#define STACK_FIX_LEN 50
//栈对象(固定长度)
typedef struct ArrayStackFix{
void* datas[STACK_FIX_LEN]; //数据内容,长度固定
int size; //最大容量
int length; //当前长度
int top; //栈顶指针
}ArrayStackFix;
1.2、创建栈
初始化栈对象,包括 分配栈对象空间、基础信息设置。
//创建栈,传入栈的接收数据空间地址(事先分配好), 传入栈最大容量
ArrayStackFix* createArrayStackFix(){
ArrayStackFix *stack = (ArrayStackFix*)malloc(sizeof(ArrayStackFix));
stack->length = 0;
stack->size = STACK_FIX_LEN;
stack->top = 0;
return stack;
}
1.3、栈空判断
为空返回1,否则返回0
//栈空判断
int fixStackIsEmpty(ArrayStackFix *stack){
if(stack->length == 0){
return 1;
}else{
return 0;
}
}
1.4、栈满判断
栈满则返回1,否则返回0
//栈满判断
int fixStackIsFull(ArrayStackFix *stack){
if(stack->length == stack->size){
return 1;
}else{
return 0;
}
}
1.5、入栈
传入数据对象 和 栈对象,在栈未满时将数据入栈。
void fixStackPush(void* data,ArrayStackFix *stack){
if(fixStackIsFull(stack) == 1){
printf("入栈失败,栈已满!\n");
}else{
stack->datas[stack->top] = data;
stack->top = stack->top+1;
stack->length = stack->length+1;
}
}
1.6、出栈
传入栈对象,将栈顶元素出栈。
//出栈
void* fixStackPop(ArrayStackFix *stack){
if(fixStackIsEmpty(stack) == 1){
printf("出栈失败,栈已空!\n");
return NULL;
}else{
stack->top = stack->top-1;
stack->length = stack->length-1;
return (stack->datas[stack->top]);
}
}
1.7、获取栈顶元素
传入栈对象,返回栈顶元素。这里不会移动栈顶指针
void* fixStackPeek(ArrayStackFix *stack){
if(fixStackIsEmpty(stack) == 1){
printf("出栈失败,栈已空!\n");
return NULL;
}else{
return (stack->datas[stack->top -1]);
}
}
1.8、销毁栈
释放栈空间
void fixStackDestroy(ArrayStackFix *stack){
free(stack);
}
2、指定长度数组栈
2.1、栈结构定义
栈结构 即是栈对象,其内包含数据对象数组、栈容量、栈长度、栈顶指针信息。为了存储不指定类型的数据,这里采用void*
数组来存储,void*
不指定指针的类型,实际上存储的是数据的地址,从而实现不指定数据类型。使用时,只需将出栈后的指针强转位需要的类型即可正常使用。这里需要自己注意存入与取出类型的区分,不要因为转型错误产生问题。
//栈对象(动态长度)
typedef struct ArrayStackDynamic{
void** datas; //数据内容,长度动态
int size; //最大容量
int length; //当前长度
int top; //栈顶
}ArrayStackDynamic;
2.2、创建栈
初始化栈对象(传入栈长度),包括分配栈对象空间、数据对象数组空间分配、基础信息设置。
//创建栈,传入栈的接收数据空间地址(事先分配好), 传入栈最大容量
ArrayStackDynamic* createArrayStackDynamic(int size){
ArrayStackDynamic *stack = (ArrayStackDynamic*)malloc(sizeof(ArrayStackDynamic));
stack->datas = (void**) malloc(sizeof(void*) * size);
stack->length = 0;
stack->size = size;
stack->top = 0;
return stack;
}
2.3、栈空判断
为空返回1,否则返回0
//栈空判断
int dynamicStackIsEmpty(ArrayStackDynamic *stack){
if(stack->length == 0){
return 1;
}else{
return 0;
}
}
2.4、栈满判断
栈满则返回1,否则返回0
//栈满判断
int dynamicStackIsFull(ArrayStackDynamic *stack){
if(stack->length == stack->size){
return 1;
}else{
return 0;
}
}
2.5、入栈
传入数据对象 和 栈对象,在栈未满时将数据入栈。
void dynamicStackPush(void* data,ArrayStackDynamic *stack){
if(dynamicStackIsFull(stack) == 1){
printf("入栈失败,栈已满!\n");
}else{
stack->datas[stack->top] = data;
stack->top = stack->top+1;
stack->length = stack->length+1;
}
}
2.6、出栈
传入栈对象,将栈顶元素出栈。
//出栈
void* dynamicStackPop(ArrayStackDynamic *stack){
if(dynamicStackIsEmpty(stack) == 1){
printf("出栈失败,栈已空!\n");
return NULL;
}else{
stack->top = stack->top-1;
stack->length = stack->length-1;
return (stack->datas[stack->top]);
}
}
2.7、获取栈顶元素
传入栈对象,返回栈顶元素。这里不会移动栈顶指针
void* dynamicStackPeek(ArrayStackDynamic *stack){
if(dynamicStackIsEmpty(stack) == 1){
printf("出栈失败,栈已空!\n");
return NULL;
}else{
return (stack->datas[stack->top -1]);
}
}
2.8、销毁栈
释放栈空间
void dynamicStackDestroy(ArrayStackDynamic *stack){
free(stack->datas);
free(stack);
}
3、链式栈
3.1、栈结构定义
栈结构 包含栈节点(采用单向链表).
/**
* 链式栈
*/
//栈节点
typedef struct StackNode{
void* data;
struct StackNode *next;//单向链表
}StackNode;
//栈对象(固定长度)
typedef struct LinkedStack{
StackNode *top; //数据内容,长度固定
int size; //当前长度
}LinkedStack;
3.2、创建栈
初始化栈对象(传入栈长度),包括分配栈对象空间、基础信息设置。
//创建栈,传入栈的接收数据空间地址(事先分配好), 传入栈最大容量
LinkedStack* createLinkedStack(){
LinkedStack *stack = (LinkedStack*)malloc(sizeof(LinkedStack));
stack->size = 0;
stack->top = NULL;
return stack;
}
3.3、栈空判断
为空返回1,否则返回0
//栈空判断
int linkedStackIsEmpty(LinkedStack *stack){
if(stack->size == 0){
return 1;
}else{
return 0;
}
}
3.4、栈满判断
链栈不会满
3.5、入栈
传入数据对象 和 栈对象,分配栈节点空间存储当前数据。
void linkedStackPush(void* val,LinkedStack *stack){
StackNode *node = (StackNode*)malloc(sizeof(StackNode));
node->data = val;
node->next = stack->top;
stack->top = node;
stack->size = stack->size + 1;
}
3.6、出栈
传入栈对象,将栈顶元素出栈,释放栈顶元素所在栈节点空间。
//出栈
void* linkedStackPop(LinkedStack *stack){
if(linkedStackIsEmpty(stack) == 1){
printf("出栈失败,栈已空!\n");
return NULL;
}else{
StackNode *node = stack->top;
stack->top = node->next;
stack->size = stack->size - 1;
void* val = node->data;
free(node);
return val;
}
}
3.7、获取栈顶元素
传入栈对象,返回栈顶元素。这里不会移动栈顶指针
void* linkedStackPeek(LinkedStack *stack){
if(linkedStackIsEmpty(stack) == 1){
printf("出栈失败,栈已空!\n");
return NULL;
}else{
return stack->top->data;
}
}
3.8、销毁栈
释放栈空间
void linkedStackDestroy(LinkedStack *stack){
free(stack);
}
源码地址:https://download.csdn.net/download/Waiting_Love/89510372