一、原理
栈通常从数据结构和内存空间两个角度解释,从数据结构的角度,栈是一种线性结构表,只允许在固定的一端进行插入和删除元素,从内存空间角度,操作系统为函数和变量分配的内存空间通常在栈区,但是无论是从数据结构还是内存空间角度来看,栈都遵从的原则是:后进先出原则。
栈的特性是顺序存储(随机访问)和后进先出(LIFO:Last In First Out)
- 压栈:栈的插入操作叫做进栈、压栈、入栈,入数据在栈顶
- 出栈:栈的删除操作叫做出栈,出数据也在栈顶
栈的缺陷:
- 栈空间有容量限制,实现动态扩容的栈在每次插入时都需要检查是否需要扩容,降低了效率。
- 栈空间的扩容策略可能会导致内存空间浪费。
- 数据只能从栈顶进行增删,不支持随机增删。
二、Stack.h
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <stdlib.h>
#define CAPACITY 4 // 初始容量为4
typedef int DataType;
typedef struct Stack
{
DataType* data;
int size;
int capacity;
}Stack;
void Init(Stack* s)
{
s->data = (DataType*)malloc(sizeof(DataType) * CAPACITY);
s->size = 0;
s->capacity = CAPACITY;
}
void CheckCapacity(Stack* s)
{
if (s->size == s->capacity)
{
// 栈已满,需要扩容
s->data = (DataType*)realloc(s->data, sizeof(DataType) * (s->size + 4));
s->capacity += 4;
}
}
int Empty(Stack* s)
{
return s->size == 0;
}
void Push(Stack* s, DataType x)
{
CheckCapacity(s);
s->data[s->size] = x;
++s->size;
}
void Pop(Stack* s)
{
if (Empty(s))
{
printf("栈为空,pop失败\n");
return;
}
--s->size;
}
DataType Head(Stack* s)
{
if (Empty(s))
{
printf("栈为空,无栈顶元素\n");
return NULL;
}
return s->data[s->size - 1];
}
void Destroy(Stack* s)
{
free(s->data);
s->data = NULL;
printf("栈已销毁\n");
}
void Print(Stack* s)
{
if (Empty(s))
{
printf("栈为空!\n");
return;
}
int i = 0;
for (; i < s->size; ++i)
{
printf("%2d ", s->data[i]);
}
printf(",栈顶元素为:%2d\n", Head(s));
}
三、test.c
#define _CRT_SECURE_NO_WARNINGS 1
#include "Stack.h"
int main()
{
Stack s;
Init(&s);
Push(&s, 1);
Push(&s, 3);
Push(&s, 5);
Push(&s, 7);
Push(&s, 2);
Push(&s, 4);
Push(&s, 6);
Push(&s, 8);
Print(&s);
Pop(&s);
Pop(&s);
Pop(&s);
Print(&s);
Push(&s, 20);
Print(&s);
Pop(&s);
Pop(&s);
Pop(&s);
Pop(&s);
Pop(&s);
Pop(&s);
Pop(&s);
Pop(&s);
Print(&s);
Destroy(&s);
}