目录
前言:暑期复习之栈的简单理解
经过这两天对链表和顺序表的简单复习,接下来是对栈的基本见解。
一·栈的设计思路
栈是一种基于先进后出(FILO)的数据结构,是一种只能在一端进行插入和删除操作的特殊线性表。它按照先进后出的原则存储数据,先进入的数据压入栈底,最后的数据在栈顶,需要读数据的时候从栈顶开始弹出数据(最后一个数据被第一个读出来)。
我们称数据进入到栈的动作为压栈,数据从栈中出去的动作为弹栈。栈仅限在表尾进行插入删除,表头其实也可以进行插入删除但是比较麻烦,且复杂。
逻辑图示:
#define TRUE 1
#define FALSE 0
#define OK 1
#define ERROR 0
#define OVERFLOW -2
typedef int Status;
#define STACK_INIT_SIZE 100 //栈的初始大小
#define STACKINC 1.5 //栈的扩容倍数
typedef int SElemType;
typedef struct
{
SElemType* base;//栈底指针
SElemType* top;//栈顶指针
int stacksize; //栈的容量
}SeqStack;
二·栈的具体代码详解
栈的基本操作除了在栈顶进行插入或删除外,还有栈的初始化,判空及取栈顶元素等。
1.栈的初始化操作
利用malloc操作进行开辟空间,也就是开辟栈,并将栈结构体中的成员变量赋予一个是初始值。
Status是我们定义的一个状态变量,在结构体设计时利用宏定义。
//初始化栈
Status InitStack(SeqStack* ps)
{
assert(ps != NULL);
ps->base = (SElemType*)malloc(sizeof(SElemType)*STACK_INIT_SIZE);
if (NULL == ps->base)
{
return OVERFLOW;
}
ps->top = ps->base;
ps->stacksize = STACK_INIT_SIZE;
return OK;
}
2.入栈和出栈
(1)入栈:将将要入栈的数据赋值给top指针,然后top指针向后挪动一格。
//入栈
Status Push(SeqStack* ps, SElemType val)
{
assert(ps != NULL);
if (StackFull(ps))
{
return ERROR;
}
*ps->top = val;
ps->top += 1;
return OK;
}
(2)出栈:将将要出栈的数据元素赋值给pr指针,然后top指针挪动一格。
//出栈
Status Pop(SeqStack* ps, SElemType* pr)
{
assert(ps != NULL);
if (pr == NULL)
{
return NULLPTR;
}
if (StackEmpty(ps))
{
return ERROR;
}
ps->top -= 1;
*pr = *ps->top;
}
3.取栈顶元素
将top指针指向的值给准备好的变量,只是想知道栈顶元素的数据值,并不是将栈顶元素取出,并删除,所以top指针不挪动。
//取栈顶元素
Status GetPop(SeqStack* ps, SElemType* pr)
{
assert(ps != NULL);
if (pr == NULL)
{
return NULLPTR;
}
if (StackEmpty(ps))
{
return ERROR;
}
*pr = *(ps->top - 1);
return OK;
}
4.获取栈中元素个数
利用逻辑图示可以清楚的看到,栈顶指针-栈底指针就是栈中元素的个数
//栈中元素个数
int StackLenth(const SeqStack* ps)
{
assert(ps != NULL);
return(ps->top - ps->base);
}
5.判空判满
(1)判空
利用获取元素个数函数进行判空操作
//判空
bool StackEmpty(SeqStack* ps)
{
assert(ps != NULL);
return StackLenth(ps) == 0;
}
(2)判满
利用获取元素个数函数和栈的最大容量来进行判满
//判满
bool StackFull(SeqStack* ps)
{
assert(ps != NULL);
return StackLenth(ps) == ps->stacksize;
}
6.栈的增容
栈的增容:这里用到的是realloc,因为realloc可以将原来空间中的数据一个个放入新开辟的空间,并使之自动释放掉。将开辟好的newdata赋给base,然后top就是基础的栈底指针加上增容前的容量,增容成功返回true.
//增容
bool IncSize(SeqStack* ps)
{
assert(ps != NULL);
int total = ps->stacksize * STACKINC;
SElemType* newdata = (SElemType*)realloc(ps->base, sizeof(SElemType) * total);
if (NULL == newdata)
{
return NULLPTR;
}
ps->base = newdata;
ps->top = ps->base + ps->stacksize;
ps->stacksize = total;
return true;
}
7.清空与销毁
(1)清空操作:
逻辑上当栈顶指针和栈底指针相同时,此栈为空栈。
//清空栈
void ClearStack(SeqStack* ps)
{
assert(ps != NULL);
ps->top = ps->base;
}
(2)销毁操作:
销毁栈就是释放开辟的这一片空间,并初始化其中的成员变量。
//销毁栈
void DestroyStack(SeqStack* ps)
{
assert(ps != NULL);
free(ps->base);
ps->base = NULL;
ps->top = NULL;
ps->stacksize = 0;
}
三·栈的总结
(1)定义:栈是限定仅在表尾进行插入或删除操作的线性表。
(2)逻辑结构:与线性表相同,一对一关系,数据元素存储。
(3)物理存储结构:顺序栈和链栈
(4)运算规则:插入数据和删除数据按照后进先出的规则运算(在栈顶入栈和出栈)
(5)栈与线性表的区别:运算规则不同