ADT 栈(Stack)
Data
栈的数据对象集合为{a1, a2,..., an},每个元素的类型均为DataType。其中除第一个元素a1以外,每个元素有且只有一个直接前驱元素;除了最后一个
元素an以外,每个元素有且只有一个直接后继元素。数据元素之间的关系是一对一的关系。
Operation
initStack(*S): 初始化操作,建立一个空栈S
destoryStack(*S): 若栈存在,则销毁它
stackEmpty(*S): 若栈为空,则返回true,否则返回false
clearStack(*S): 将栈清空,栈本身还存在
getTop(S, *e): 若栈存在且非空,用e返回S的栈顶元素
push(*S, e): 若栈存在,插入新元素e到栈S中,并成为栈顶元素
pop(*S, *e): 删除栈S中栈顶元素,并用e返回其值
stackLength(L): 返回栈S的元素个数
endADT
先写一个Element.h的头文件:
1 #ifndef ELEMENT_H_INCLUDED 2 #define ELEMENT_H_INCLUDED 3 #define MAX_SIZE 255 4 #define TRUE 1 5 #define FALSE 0 6 7 8 9 typedef struct ElementType 10 { 11 int id; 12 char *name; 13 }ElementType;
定义顺序栈数据结构及常用操作,以下是关于顺序栈的头文件(SeqStack.h):
1 #ifndef SEQSTACK_H_INCLUDED 2 #define SEQSTACK_H_INCLUDED 3 4 #include <stdio.h> 5 #include <stdlib.h> 6 #include "Element.h" 7 8 typedef struct SeqStack{ 9 ElementType elements[MAX_SIZE]; 10 int top; //栈顶,如果为-1,则栈为空 11 int length; //当前栈的长度 12 }SeqStack; 13 14 /** 初始化栈*/ 15 void InitSeqStack (SeqStack *seqStack); 16 17 /** 压栈操作:向栈中压入元素,返回压如结果*/ 18 int PushSeqStack (SeqStack *seqStack, ElementType element); 19 20 /** 以指针的方式返回出栈的元素,返回值为出栈结果*/ 21 int PopSeqStack (SeqStack *seqStack, ElementType *element); 22 23 /** 清空栈*/ 24 void ClearSeqStack (SeqStack *seqStack); 25 26 /** 判断栈是否为空*/ 27 int SeqStackEmpty (SeqStack *seqStack); 28 29 /** 返回栈顶元素*/ 30 void GetTopSeqStack (SeqStack *seqStack, ElementType *element); 31 32 #endif // SEQSTACK_H_INCLUDED 33
以下是关于顺序栈的.c文件(SeqStack.c):
1 #include "SeqStack.h" 2 3 /** 初始化栈*/ 4 void InitSeqStack (SeqStack *seqStack){ 5 seqStack->top = -1; //当top指向-1时表明栈内没有元素 6 seqStack->length = 0; //同样的初始化时,栈的长度为0 7 } 8 9 /** 入栈操作:向栈中压入元素,返回压如结果*/ 10 int PushSeqStack (SeqStack *seqStack, ElementType element) 11 { 12 if (seqStack->top == MAX_SIZE -1){ //压栈的过程当中需要先判断栈内元素是否是满的 13 printf("满栈,压栈操作失败!"); 14 return FALSE; 15 } 16 /** 17 1 将顺序栈的栈顶指到下一个空间 18 2 将元素赋给新的栈顶 19 3 将栈的长度加1 20 4 最后若是压栈成功则返回TRUE 21 */ 22 seqStack->top++; 23 seqStack->elements[seqStack->top] = element; 24 seqStack->length++; 25 return TRUE; //由于事先define了TRUE和FALSE的值是1和0所以返回值用int来接收,下同 26 } 27 28 /** 以指针的方式返回出栈的元素,返回值为出栈结果*/ 29 int PopSeqStack (SeqStack *seqStack, ElementType *element) 30 { 31 if (seqStack->top == -1){ 32 printf("空栈,出栈失败!"); 33 return FALSE; 34 } 35 *element = seqStack->elements[seqStack->top]; 36 seqStack->top--; 37 seqStack->length--; 38 return TRUE; 39 } 40 41 /** 清空栈*/ 42 void ClearSeqStack (SeqStack *seqStack) 43 { 44 seqStack->top = -1; 45 seqStack->length = 0; 46 } 47 48 /** 判断栈是否为空*/ 49 int SeqStackEmpty (SeqStack *seqStack) 50 { 51 if (seqStack->top == -1){ 52 return TRUE; 53 } 54 return FALSE; 55 } 56 57 /** 返回栈顶元素*/ 58 void GetTopSeqStack (SeqStack *seqStack, ElementType *element) 59 { 60 if (seqStack->top == -1){ 61 printf("空栈,栈顶元素为空!"); 62 element = NULL; 63 return; 64 } 65 *element = seqStack->elements[seqStack->top]; 66 } 67
接下来在main.c中实现:
1 #include <stdio.h> 2 #include <stdlib.h> 3 #include "SeqStack.h" 4 5 ElementType datas [] = { 6 {1, "小A"}, 7 {2, "小B"}, 8 {3, "小C"}, 9 {4, "小D"}, 10 }; //由于是检测一下功能,就只取4个数据 11 12 void TestSeqStack(); 13 14 void TestSeqStack(){ 15 SeqStack *stack = (SeqStack *)malloc(sizeof(SeqStack)); 16 ElementType *element = (ElementType *)malloc(sizeof(ElementType)); 17 InitSeqStack(stack); 18 for (int i=0; i<4; i++){ 19 printf("当前入栈的是:%d\t%s\n", datas[i].id, datas[i].name); 20 PushSeqStack(stack, datas[i]); 21 } 22 printf("\n"); 23 PopSeqStack(stack, element); 24 printf("当前出栈元素是:%d\t%s\n", element->id, element->name); 25 printf("\n"); 26 for (int i=0; i<stack->length; i++){ 27 printf("当前栈内的元素是: %d\t%s\n", stack->elements[i].id, stack->elements[i].name); 28 } 29 free(stack); 30 } 31 32 int main() 33 { 34 TestSeqStack(); 35 return 0; 36 }
栈是按照FILO(先入后出)或者LIFO(后入先出)的原则,关于链栈的一些笔记在之后给出
根据栈的一些特性,我们可以用来实现一些信息的有序存储,例如在一些回合制的游戏当中可以运用这种栈的结构,可以按照一定的顺序来存入玩家的操作数据,来方便对玩家的操作进行回撤。