目录
栈的概念及结构
概念
栈是一种特殊的线性表,其只允许在固定一端进行插入和删除操作。允许进行数据插入和删除的一端叫做栈顶,而不允许数据插入和删除的那一端叫做栈底。
如上图所示,n1为栈底元素,n5为栈顶元素。由于栈只能在栈顶进行插入删除操作,所以压栈的次序依次为n1,n2,n3,n4,n5;而出栈的次序为n5,n4,n3,n2,n1;由此可见,栈的特性可以概括为后进先出(Last In First Out , LIFO)。
结构
因为栈是一种操作受限的线性表,其逻辑结构是线性的,所以栈的物理结构有两种:一种是用顺序表实现的顺序栈,另一种是链表实现的链栈。
顺序表实现的顺序栈是在动态顺序表的尾部进行入栈与出栈的操作。链表实现的链栈是在带头单向非循环链表的头部进行入栈与出栈操作。相对而言顺序栈的结构实现更优一些,因为在动态数组尾上插入和删除数据的代价比较小。
顺序栈
初始化StackInit
销毁StackDestroy
压栈StackPush
出栈StackPop
获取栈顶元素StackTop
求栈的元素个数StackSize
判断栈是否为空栈StackEmpty
链栈
初始化StackInit
销毁StackDestroy
压栈StackPush
出栈StackPop
获取栈顶元素StackTop
求栈的元素个数StackSize
判断栈是否为空栈StackEmpty
代码
顺序栈
typedef int StackDataType;
typedef struct Stack
{
StackDataType* a;
int top;
int capacity;
}Stack;
void StackInit(Stack* ps); // 初始化
void StackDestroy(Stack* ps); // 销毁
void StackPush(Stack* ps, StackDataType x); // 压栈
void StackPop(Stack* ps); // 弹栈
StackDataType StackTop(Stack* ps); // 获取栈顶元素
int StackSize(Stack* ps); // 判空
bool StackEmpty(Stack* ps); // 求栈元素的个数
void StackInit(Stack* ps) // 初始化---先开辟两个元素的空间
{
assert(ps);
int newCapacity = 2;
StackDataType* tmp = (StackDataType*)malloc(sizeof(StackDataType) * newCapacity);
if (!tmp)
{
perror("malloc fail");
return;
}
ps->a = tmp;
ps->top = 0;
ps->capacity = newCapacity;
}
void StackDestroy(Stack* ps) // 销毁
{
assert(ps);
if (ps->a)
{
free(ps->a);
ps->a = NULL;
ps->top = ps->capacity = 0;
}
}
void StackPush(Stack* ps, StackDataType x) // 压栈
{
assert(ps);
if (ps->top == ps->capacity)
{
int newCapacity = 2 * ps->capacity; // 扩大为原来存储元素的两倍
StackDataType* tmp = (StackDataType*)realloc(ps->a, sizeof(StackDataType) * newCapacity);
if (!tmp)
{
perror("realloc fail");
return;
}
ps->a = tmp;
ps->capacity = newCapacity;
}
ps->a[ps->top] = x;
ps->top++;
}
void StackPop(Stack* ps) // 出栈
{
assert(ps);
assert(!StackEmpty(ps));
ps->top--;
}
StackDataType StackTop(Stack* ps) // 获取栈顶的元素
{
assert(ps);
assert(!StackEmpty(ps));
return ps->a[ps->top - 1];
}
int StackSize(Stack* ps) // 获取栈的元素个数
{
assert(ps);
return ps->top;
}
bool StackEmpty(Stack* ps) // 判断栈是否为空---空返回true否则返回false
{
assert(ps);
return ps->top == 0;
}
链栈
typedef int StackDataType;
typedef struct StackListNode
{
StackDataType data;
struct StackListNode* next;
}Node;
typedef struct Stack
{
Node* phead; // 头指针
int size;
}Stack;
Node* BuyNode(StackDataType x); // 开辟结点
void StackInit(Stack* ps, StackDataType x); // 初始化
void StackDestroy(Stack* ps); // 销毁
void StackPush(Stack* ps, StackDataType x); // 压栈
void StackPop(Stack* ps); // 弹栈
StackDataType StackTop(Stack* ps); // 获取栈顶元素
int StackSize(Stack* ps); // 求栈的元素个数
bool StackEmpty(Stack* ps); // 判空
Node* BuyNode(StackDataType x) // 开辟结点---开辟成功返回结点的地址
{
Node* newNode = (Node*)malloc(sizeof(Node));
if (!newNode)
{
perror("malloc fail");
return NULL;
}
newNode->data = x;
newNode->next = NULL;
return newNode;
}
void StackInit(Stack* ps, StackDataType x) // 初始化---开辟头结点
{
assert(ps);
ps->phead = BuyNode(x); // 因为栈存储元素的类型是可变的,所以头结点的元素需要自己随机给
ps->size = 0;
}
void StackDestroy(Stack* ps) // 销毁
{
assert(ps);
assert(ps->phead);
while (!StackEmpty(ps)) // 先将没有出栈的结点释放
{
StackPop(ps);
}
if (ps->phead) // 最后释放头结点
{
free(ps->phead);
ps->size = 0;
}
}
void StackPush(Stack* ps, StackDataType x) // 压栈---头插
{
assert(ps);
assert(ps->phead);
Node* newNode = BuyNode(x);
newNode->next = ps->phead->next;
ps->phead->next = newNode;
ps->size++; // 若压栈成功,栈的大小加一
}
void StackPop(Stack* ps) // 出栈---头删
{
assert(ps);
assert(ps->phead);
assert(!StackEmpty(ps));
Node* del = ps->phead->next;
ps->phead->next = del->next;
free(del);
del = NULL;
ps->size--; // 若出栈成功,栈的大小减一
}
StackDataType StackTop(Stack* ps) // 获取栈顶的元素
{
assert(ps);
assert(ps->phead);
assert(!StackEmpty(ps));
return ps->phead->next->data; // 返回第一个数据结点的元素
}
int StackSize(Stack* ps) // 求栈的元素个数
{
assert(ps);
assert(ps->phead);
return ps->size; // 因为每次的压栈与出栈都有size的加减,所以无须再遍历了
}
bool StackEmpty(Stack* ps) // 判空---空返回真否则返回假
{
return ps->phead->next == NULL; // 如果头结点的next为NULL则说明为空栈
}