何为栈?栈的状态ADT设计C语言实现两种类型栈
顺序栈
代码实现 非连续栈
代码实现 相关经典题目
何为栈?栈(Stack):就是只允许在一端(限定只在表尾)进行插入或删除操作的线性表。
所以,对于栈而言,是有所区分栈顶(top)和栈底(bottom) 的。具体就如下图:
所以,在使用栈的存储时,是存在先进后出的一个规律。
当我们将元素依次存储入栈后,最先进栈储存的元素在取出(出栈)时,是需要等到后入栈压在其上的元素被全部取出后,才能出栈。
一个栈它是有着四种不同的状态
空栈满栈入栈(进栈、压栈push)出栈 (弹栈pop)
这也就对应着最基础的几个栈的操作API。
对于栈的程序设计,我们主要编写这几个对栈的操作
| 栈方法名 | 操作 |
|---|---|
| initStack(*S) | 初始化栈,建立一个空栈 |
| destoryStack(*S) | 若栈S存在,销毁栈 |
| is_Full(S) | 栈是否已满 |
| clearStack(*S) | 将栈中元素清空 |
| getTop(S,*e) | 若栈S非空,用e获取栈顶元素 |
| push(*S,e) | 若栈S存在,将元素e压入到栈中 |
| pop(*S,*e) | 删除栈S的栈顶元素,并用e返回被删除的值 |
| stackLength(S) | 得到栈的长度 |
顺序栈是利用连续的内存空间(数组)进行存储栈内元素,并实现栈的功能特性。
使用顺序栈的优点:
构造简单,存储地址连续,便于操作
缺点:
内存空间固定,可拓展性差且需要占用整块内存 代码实现
# include非连续栈# include # define MaxSize 50 // 定义栈的深度 typedef int ElemType; // 定义栈储元素的类型 // 结构体构造栈的结构 typedef struct { ElemType data[MaxSize]; // 构造存储的栈内存结构 int top; // 定义栈顶指针 } SeqStack; // 初始化栈 SeqStack* initStack(SeqStack* s){ // 上面已经使用结构体构造了栈的结构 // 这里要给定义好的栈结构进行内存的开辟 s = (SeqStack*)malloc(sizeof(SeqStack)); // 将栈顶指针设置到栈底 // 这里是按照数组进行储存,所以栈首是从0开始的 // 所以这里的初始化,要设置为-1 s->top = -1; return s; } // 判断栈是否为空 int is_Full(s){ if(s->top == MaxSize-1){ return 0; } return -1; } // 入栈 void push(SeqStack* s, Elemtype e){ if(is_Empty){ printf("Stack is Fulln"); }else{ s->top ++; s->data[s->top] = e; } } // 出栈 void pop(SeqStack* s){ int fetchElem; //若栈内无元素 if(s->top == -1){ printf("Stack is Emptyn"); }else{ fetchElem = s->data[s->top]; s->top --; printf("%dn",fetchElem); } } // 获取栈顶元素 // 这里是进行查看栈顶元素,而非出栈 void getTop(SeqStack s, Elemtyep e){ // 若栈为空 if(s->top == -1){ printf("Stack is Emptyn"); }else{ e = s->data[s->top]; printf("%dn", e); } } // 获取栈的长度 void stackLength(SeqStack s){ int length; length = s->top + 1; printf("%dn", length); }
非连续栈是指在栈的结构构造上,不依赖于固定连续的内存空间,而是使用指针将分散的栈储元素进行连接,实现栈的功能。
非连续栈的优点:
存储的元素分散,不限制大小,可任意拓宽深度不需要使用整块内存
缺点:
元素间使用指针连接,操作复杂 代码实现
# include相关经典题目# include typedef int ElemType; // 定义单个栈储节点 typedef struct Node { // 定义数据域,用于存放栈储元素 int data; // 定义指针域,指向下一个栈储元素 struct Node* next; } linkStack; // 初始化栈 void initStack(linkStack* s){ // 一次先开辟一个节点的内存空间 s = (linkStack*)malloc(sizeof(linkStack)); // 将指针清空 s->Next = NULL; } // 判断是否为空 int is_Empty(linkStack* s){ return(s->next == NULL) } // 销毁栈 void destroyStack(linkStack* s){ Node *h = s; // 先遍历到栈的最后一个栈储空间 // 然后释放掉,再从头遍历到最后一个人栈储空间 while(s != NULL){ s = s->next; free(p); p = s; } } // 入栈 void push(linkStack* s, ElemType e){ linkStack* p; p = (linkStack*)malloc(sizeof(linkStack)); p->data = e; // 将待压栈栈储的指针指向首栈元素 p->next = s->next; // 再使首栈元素为待插入的元素 s->next = p; } // 出栈 void pop(linkStack* s){ // 判断栈是否为空 if(s->next == NULL){ printf("Stack is Emptyn"); }else{ // 暂存待删首栈储 linkStack* temp = s->next; // 使首栈为原首栈的下一栈 s->next = temp->next; // 释放原首栈的存储空间 free(temp); } }
关于数据结构的栈在PTA中有一些经典的习题,这里将进行解决
将十进制转换为二进制,使用初中学习的短除法,进行循环取2余后,在从底往上书写结果,这一过程恰好是符合我们栈的FILO的原则。所以如下:
#include#include #define M 100 typedef int ElemType; typedef struct { ElemType data[M]; int top; }Stack; //初始化栈 void InitStack(Stack *s) { s->top = -1; } int Push(Stack *s,ElemType e) { if (s->top == M-1) { printf("栈满n"); return 0; } s->top++; s->data[s->top]=e; return 1; } //判断是否为空 int Empty(Stack *s) { return(s->top==-1); } //出栈 int Pop(Stack *s,ElemType *e) { if(Empty(s)) { printf("n Stack is free"); return 0; } *e=s->data[s->top]; s->top--; return 1; } void Conversion(int N) { int e; Stack *s = (Stack *)malloc(sizeof(Stack)); InitStack(s); while(N) { Push(s,N%2); N=N/2; } while(!Empty(s)) { Pop(s,&e); printf("%d",e); } } int main() { int m; scanf("%d",&m); Conversion(m); }



