Stack(堆栈):一种操作受限制的线性表,只允许在一头进行添加和删除
定义:
· “栈”也叫“堆栈”,是一种操作受限的线性表,栈只允许在线性表的一端进行插入/删除等操作,不允许其他位置插入/删除
· 线性表中可以进行插入/删除的一端称为:栈顶(top),栈顶保存的元素为“栈顶元素”,相对另一端称为“栈底”(bottom)
· 如果栈中没有数据称为“空栈”
· 向栈中插入元素,称为“进栈/入栈/压栈”,从栈中删除元素称为“退栈/出栈/弹栈”;
· 栈的插入/删除操作只允许在栈顶进行,后进栈的元素必定先出栈,称为:后进先出表LIFO;
堆栈抽象数据类型的定义:
ADT Stack{
数据对象 : D={a0,a1,a2...,an, 其中ai(i=1,2..n)是同一种数据类型的元素}
数据关系 : R={<ai,ai+1>}
基本操作:
InitStack(&S): 初始化栈,分配内存空间
DestroyStack(&S): 销毁并释放栈的内存
ClearStack(&S): 清空栈
IsEmpty(S): 判断栈是否为空
GetSize(S): 返回栈元素个数
Peek(S): 偷看栈顶元素
Push(&S,e): 压栈、入栈
Pop(&S,&e): 弹栈、出栈
Traverse(S): 从栈底到栈顶依次遍历
}ADT Stack;
卡特兰数:如果有n个不同元素进栈,出栈元素不同的排列的个数为:1/(n+1) * Cⁿ2n
(还有一种栈叫“共享栈”,逻辑上是2个栈,物理上共享一片连续的内存)
--------------------------
栈的顺序实现:顺序栈一般通过数组实现;堆栈的操作都在栈顶完成,选择数组中索引值较大的一端作为栈顶,也就是数组尾部作为栈顶;
#include <stdlib.h>
#include <stdio.h>
#define ElemType int
#define MAXSIZE 10
typedef struct Stack{
int capacity;
int top;
ElemType* data;
}Stack;
// 空指针异常,用于判断表指针是否为NULL
static void NullPointerException(Stack *s){
if(s == NULL){exit(1);}
}
//栈扩容(2倍扩容)
static void ExpandSize(Stack *s){
NullPointerException(s);
// 临时指针old,保存旧栈的基地址
ElemType* old = s->data;
// 申请一片新的空间,是原容量的2倍
s->capacity *= 2;// 先设置表容量为原来的2倍
// 直接将表指针指向新容量的地址
s->data = (ElemType*)malloc(s->capacity * sizeof(ElemType));
// 如果申请失败,程序直接终止
if(s->data == NULL){ exit(1); }
// 申请成功,将旧表的内容进行拷贝
int i;
for(i=0; i<s->top; i++){
s->data[i] = old[i];
}
// 销毁旧表
free(old);
}
//InitStack(&S): 初始化栈,分配内存空间
void InitStack(Stack* s){
NullPointerException(s);
s->data = (ElemType*) malloc(MAXSIZE * sizeof(ElemType));
if(s->data == NULL){ exit(1); }else{//分配成功
s->capacity = MAXSIZE;
s->top = 0;
}
}
//DestroyStack(&S): 销毁并释放栈的内存
void DestroyStack(Stack* s){
NullPointerException(s);
s->capacity = 0;
s->top = 0;
free(s->data);
s->data = NULL;
}
//ClearStack(&S): 清空栈
void ClearStack(Stack* s){
NullPointerException(s);
s->top = 0;
}
//IsEmpty(S): 判断栈是否为空
int IsEmpty(Stack s){
return s.top == 0;
}
// GetSize(S): 返回栈元素个数
int GetSize(Stack s){
return s.top;
}
// Peek(S): 偷看栈顶元素
ElemType Peek(Stack s){
if(s.top == 0){ exit(1); }
return s.data[s.top-1];
}
// Push(&S,e): 将e压栈
void Push(Stack* s, ElemType e){
NullPointerException(s);
//容量不够,2倍扩容
if(s->top > s->capacity){
ExpandSize(s);
}
s->data[s->top] = e;
s->top ++;
}
// Pop(&S,&e): 弹栈
void Pop(Stack* s, ElemType* e){
NullPointerException(s);
if(s->top == 0){
printf("弹栈失败:栈空!\n");
exit(1);
}
s->top --;
*e = s->data[s->top];
}
// Traverse(S): 从栈底到栈顶依次遍历
void Traverse(Stack s){
printf("\n");
int i;
for(i=0; i<s.top; i++){
printf("%d ", s.data[i]);
}
printf("\n");
}
//=============测试程序==============================================================
int main(int argc, char const *argv[])
{
Stack s;
InitStack(&s);
Push(&s, 8);
Push(&s, 18);
Push(&s, 28);
ElemType value;
Pop(&s, &value);
//看下弹出的东西
printf("%d\n", value);
Push(&s, 38);
Push(&s, 48);
//看下栈顶
printf("%d\n", Peek(s));
Traverse(s);
printf("栈中元素个数为:%d\n", GetSize(s));
Pop(&s, &value);
Pop(&s, &value);
Traverse(s);
printf("%d\n", value);
ClearStack(&s);
printf("栈是否为空:%d\n", IsEmpty(s));
Traverse(s);
DestroyStack(&s);
return 0;
}
运行结果:
部分代码还可以完善,欢迎指正~_~