链式栈
链式栈(Linked Stack)是一种基于链表的数据结构,用于实现栈(后进先出,LIFO)的特性。与基于数组的栈不同,链式栈通过动态分配内存来存储数据,这使得它更加灵活,能够在运行时根据需要动态调整栈的大小。
以下是链式栈的基本结构和操作:
- 节点结构
链式栈的每个节点通常包含两个部分:数据域和指针域。数据域用于存储数据,指针域用于指向下一个节点。
typedef struct StackNode {int data; // 数据域struct StackNode* next; // 指针域,指向下一个节点
} StackNode;
- 栈结构
栈结构通常包含一个指向栈顶节点的指针(即头指针)。
typedef struct {StackNode* top; // 指向栈顶节点的指针
} Stack;
- 初始化栈
初始化栈时,通常将栈顶指针设置为NULL,表示栈为空。
int LStack_init(LinkStack *st, int num){st -> pHead = NULL;st -> size = num;st -> num = 0;return 0 ;}
- 入栈操作(Push)
入栈操作是在栈顶添加一个新的节点。
int LStack_push(LinkStack *st,DATA data){if(LStack_isfull(st))return -1;NODE* p = (NODE*)malloc(sizeof(NODE));if(!p)return -1;p -> data = data;p -> next = st -> pHead;st -> pHead = p;(st -> num)++;return 0;}
- 出栈操作(Pop)
出栈操作是移除栈顶的节点,并返回其数据。
int LStack_pop(LinkStack *st,DATA *data){if(LStack_isempty(st))return -1;NODE* p = st -> pHead;if(!p)return -1;*data = p -> data;st -> pHead = p -> next;free(p);(st -> num)--;return 0;}
linkstack.h
#ifndef __LINKSTACK_H#define __LINKSTACK_H// 数据类型
typedef int DATA;
// 链式栈节点
typedef struct _node{DATA data; // 数据
struct _node *next; // 指向下一个栈的节点
}NODE;// 链式栈管理结构体
typedef struct{NODE *pHead;// 链式栈栈顶指针
int size; // 链式栈当前元素个数
int num;
}LinkStack;// 初始化链式栈
int LStack_init(LinkStack *s, int num);// 判断栈是否已满
int LStack_isfull(LinkStack *st);// 判断栈是否为空
int LStack_isempty(LinkStack *st);// 压栈/入栈
int LStack_push(LinkStack *st,DATA data);// 弹栈/出栈
int LStack_pop(LinkStack *st,DATA *data);// 回收栈
int LStack_free(LinkStack *st);#endif
linkstack.c
#include "linkstack.h"#include <stdio.h>#include <stdlib.h>// 初始化栈
int LStack_init(LinkStack *st, int num){st -> pHead = NULL;st -> size = num;st -> num = 0;return 0 ;}// 判断栈是否已满
int LStack_isfull(LinkStack *st){return st -> num == st -> size;}// 判断栈是否为空
int LStack_isempty(LinkStack *st){return st -> num == 0;}// 入栈
int LStack_push(LinkStack *st,DATA data){if(LStack_isfull(st))return -1;NODE* p = (NODE*)malloc(sizeof(NODE));if(!p)return -1;p -> data = data;p -> next = st -> pHead;st -> pHead = p;(st -> num)++;return 0;}// 出栈
int LStack_pop(LinkStack *st,DATA *data){if(LStack_isempty(st))return -1;NODE* p = st -> pHead;if(!p)return -1;*data = p -> data;st -> pHead = p -> next;free(p);(st -> num)--;return 0;}// 回收栈
int LStack_free(LinkStack *st){NODE* p = st -> pHead, *q = NULL;while(p){q = p;p = p -> next;free(q); }st -> pHead = NULL;st -> num = 0;return 0;}
LStack_init: 初始化栈,将栈的头指针指向空,设置栈的最大容量和当前元素个数为0。
LStack_isfull: 判断栈是否已满,即判断当前元素个数是否等于最大容量。
LStack_isempty: 判断栈是否为空,即判断当前元素个数是否为0。
LStack_push: 入栈操作,首先判断栈是否已满,如果已满则返回-1表示入栈失败。否则,创建一个新的节点,将数据放入节点的data字段,将节点的next指针指向原来的栈顶节点,并更新栈顶指针为新节点,同时将当前元素个数加1。
LStack_pop: 出栈操作,首先判断栈是否为空,如果为空则返回-1表示出栈失败。否则,将栈顶节点的数据存入指定的data变量中,更新栈顶指针为原栈顶的下一个节点,并释放原栈顶节点的内存,同时将当前元素个数减1。
LStack_free: 回收栈,释放栈中所有节点的内存,将栈的头指针指向空,将当前元素个数设置为0。
linkstack_main.c
#include "linkstack.h"#include <stdio.h>int main(void){LinkStack st;LStack_init(&st,10);register int i = 1;for(; i <= 10; i++)LStack_push(&st,i);if(-1 == LStack_push(&st,1024))fprintf(stderr,"满栈,插入失败\n");while(!LStack_isempty(&st)){DATA data = 0;LStack_pop(&st,&data);printf("%4d",data); }printf("\n");LStack_free(&st);return 0;
}
练习 2 」
使用链式栈,实现十进制转八进制:键盘输入一个十进制数,经过链式栈的相关算法,输出八进制 数。
解析: 首先需要构建一个链式栈,链式栈实际上就是一条链表,只不过只能对栈顶操作。然后再将与栈相 关的数据封装在一个统一的结构体中,方便管理,比如可以这样设计链栈的节点和链栈的管理结构 体:
#include <stdio.h>#include <stdlib.h>#include <stdbool.h>// 链栈的节点(实际上就是单链表节点)
struct node{int data;struct node *next;};// 链栈管理结构体
typedef struct{struct node *top;int size;}linkstack;// 初始化空栈
linkstack *init_stack(void){linkstack *s = malloc(sizeof(linkstack));if(s != NULL){s->top = NULL;s->size = 0;}return s;}}// 入栈
void push(int data, linkstack *s){struct node *new = malloc(sizeof(struct node));if(new != NULL){new->data = data;}new->next = s->top;s->top = new;s->size++;// 判断栈是否为空
bool is_empty(linkstack *s){return s->size == 0;}// 出栈
bool pop(linkstack *s, int *pm){if(is_empty(s))return false;*pm = s->top->data;struct node *tmp = s->top;s->top = s->top->next;free(tmp);s->size--;return true;}int main(int argc, char const *argv[]){linkstack *s = init_stack();int n;scanf("%d", &n);while(n > 0){push(n%8, s);n /= 8;}int m;printf("0");while(1){if(is_empty(s))break;pop(s, &m);printf("%d", m);}printf("\n");return 0;}
首先定义了一个链栈的节点结构体,包含数据和指向下一个节点的指针。
然后定义了链栈管理结构体,包含了栈顶指针和栈的大小。
接着实现了初始化空栈的方法,通过动态分配内存来创建一个链栈管理结构体,并初始化栈顶指针为空,栈的大小为0。
然后实现了入栈的方法,首先动态分配内存来创建一个新的节点,然后将数据赋值给节点的data成员,将当前栈顶指针赋值给节点的next成员,最后将新节点设置为栈顶指针,并将栈的大小加1。
接着实现了判断栈是否为空的方法,通过判断栈的大小是否为0来确定栈是否为空。
然后实现了出栈的方法,首先判断栈是否为空,如果为空则返回false,否则将栈顶节点的数据赋值给传入的指针变量pm,并将栈顶指针指向下一个节点,释放原来的栈顶节点的内存,最后将栈的大小减1,返回true表示出栈成功。
最后在main函数中,首先调用init_stack方法初始化一个空栈,然后读取输入的十进制数n,将n转换为八进制数并依次入栈,最后循环出栈并打印栈中的数据,直到栈为空。