栈及栈的基本操作

栈(stack)是限定仅在表尾进行插入和删除操作的线性表。

       我们把允许插入和删除的一端称为顶 (top)另一端为底(bottom)不含任何数据元素的栈称为空。又称为后进先出(Last Im First out)的性表简称LIFO结构。

       首先它是一个线性表,也就是说,栈元素具有线性关系,即前驱后继关系。只不过它是一种特殊的线性表而已。定义中说是在线性表的表尾进行插入和删除操作,这里表尾是指栈顶,而不是栈底。
       它的特殊之处就在于限制了这个线性表的插入和删除位置,它始终只在栈顶进行。这也就使得:栈底是固定的,最先进栈的只能在栈底。

栈的插入操作,叫作进栈,也称压栈、入栈。类似子弹入弹夹,如图所示
栈的删除操作,叫作出栈,也有的叫作弹栈。如同弹夹中的子弹出夹,如图所示。

栈的存储方式有两种:

    顺序栈和链栈,即栈的顺序存储和链式存储。
 采用顺序存储的栈称为顺序栈,它利用一组地址连续的存储单元存放自栈底到栈顶的元素,同时附设一个指针(top)指示当前栈顶的位置。 

    采用链式存储的栈称为链栈,链栈便于多个栈共享存储空间和提高其效率,且不存在栈满上溢的情况。通常采用单链表实现,并且所有操作都是在单链表的表头进行的。在本文中主要是介绍了顺序栈下的一些基本操作,关于链栈的实现与单链表类似。

栈的基本操作包括:

1)初始化

2)入栈

3)出栈

4)销毁栈

5)构造一个空栈;

6)置为空栈;

7)返回栈的元素个数,即栈的长度;

8)若栈为空栈,则返回TRUE,否则返回FALSE;

9)若栈为满栈,则返回TRUE,否则返回FALSE;

10)若栈不空,则用pVal返回栈顶元素,并返回OK,否则返回ERROR;

11)若栈不空,则删除栈顶元素,用pval返回其值,并返回OK,否则返回ERROR  

详细代码与注释 

// 栈.cpp 
#include<stdio.h>
#include<stdlib.h>           //malloc free   malloc申请空间失败的时候返回一个空指针
#include<assert.h>

#define TRUE    1
#define FALSE   0   
#define OK      1
#define ERROR   0
#define INFEASIBLE -1
#define OVERFLOW   -2

typedef int Status;              //状态的重命名规则

#define STACK_INIT_SIZE 10         //初始化栈的大小为10
#define STACKINCREMENT  2          //栈的增容操作
typedef int SElemType;            //入栈元素  char类型
typedef struct
{
	SElemType* base;     // 栈底指针
	int        top;      // 栈顶指针         // int top      //0 //-1
	int  stacksize;      // 栈的当前最大容量
}SeqStack;
//构造一个空栈 
Status InitStack(SeqStack* ps)            //ps指向的是顺序栈的首地址
{
	assert(ps != nullptr);             //形参是指针 第一步就要断言
	ps->top = 0;                // 
	ps->stacksize = STACK_INIT_SIZE;  //栈的初始大小 
	ps->base = (SElemType*)malloc(sizeof(SElemType) * ps->stacksize);//malloc 从堆区申请空间 申请 元素的大小乘以ps所占的大小
	if (nullptr == ps->base)               
	{
		return ERROR;            //申请空间失败
	}
	return OK;
}
//销毁栈
void DestroyStack(SeqStack* ps) 
{
	assert(ps != nullptr);
	free(ps->base);           //base指的是连续的空间              
	ps->base = nullptr; 
	ps->top = 0;
	ps->stacksize = 0;
}
//置为空栈
void ClearStack(SeqStack* ps)
{
	assert(ps != nullptr);
	ps->top = 0;
}
//返回栈的元素个数,即栈的长度
int StackLength(const SeqStack* ps)
{
	assert(ps != nullptr);
	return ps->top;               //top是一个指针    top值是元素的个数
}
//若栈为空栈,则返回TRUE,否则返回FALSE
bool StackEmpty(const SeqStack* ps)
{
	assert(ps != nullptr);
	return StackLength(ps) == 0;        //如果栈的长度为0
}
//若栈为满栈,则返回TRUE,否则返回FALSE
bool StackFull(const SeqStack* ps)
{
	assert(ps != nullptr);
	return ps->top==ps->stacksize;          //栈的长度=ps指向的栈的大小
}

bool IncMem(SeqStack* ps)
{
	assert(ps != nullptr);
	SElemType* newdata = (SElemType*)realloc(ps->base, sizeof(SElemType) * ps->stacksize * STACKINCREMENT);
	if (newdata == nullptr)            //realloc会自动管理ps->base的空间
	{
		return false;
	}
	ps->stacksize = ps->stacksize * STACKINCREMENT;      
	ps->base = newdata;
	return true;
}
//入栈val , val为栈顶数据元素 
Status Push(SeqStack* ps, SElemType val)
{
	assert(ps != nullptr);               //判断栈满
	if (StackFull(ps)&&!IncMem(ps))      //如果栈满
	{ 
	 	return OVERFLOW;      //内存溢出      
	}
	ps->top++;             //栈顶指针加一
	ps->base[ps->top] = val;              //将新插入的元素赋值给栈顶空间
	return OK;
}

//若栈不空,则用pVal返回栈顶元素,并返回OK,否则返回ERROR
Status GetTop(const SeqStack* ps, SElemType* pval)
{
	assert(ps != nullptr&&pval!= nullptr);
	if (StackEmpty(ps))
	{
		return ERROR;

	}
	*pval = ps->base[ps->top - 1];
	return OK;
}

//若栈不空,则删除栈顶元素,用pval返回其值,并返回OK,否则返回ERROR 
Status Pop(SeqStack* ps, SElemType* pval)
{
	assert(ps != nullptr && pval != nullptr);
	if (StackEmpty(ps))
	{
		return ERROR;

	}
	*pval = ps->base[--ps->top];
	return OK;
}



int main()
{
	SeqStack mys;
	InitStack(&mys);       //对栈进行初始化(构建一个栈)

	for (int i = 1; i <= 20; ++i)
	{
		Push(&mys, i);
	}
	int x;
	while (Pop(&mys, &x) != ERROR)
	{
		printf("%d \n", x);
	}

	DestroyStack(&mys);

	return 0;
}

链栈

栈的链式存储结构,简称为链栈。

代码以及详细注释 

#include<stdio.h>
#include<stdlib.h>   // malloc free
#include<assert.h>
#define TRUE    1
#define FALSE   0
#define OK      1
#define ERROR   0
#define INFEASIBLE -1
#define OVERFLOW   -2

typedef int Status;
typedef int ElemType;
typedef struct StackNode         //栈的节点类型
{
    ElemType data;               
    struct StackNode* next;      
}StackNode, * PStackNode;             //结点类型  指针类型
typedef struct
{
    PStackNode top;        //栈顶指针
    int cursize;           //元素个数
}LinkStack;     //链栈 

StackNode* Buynode(ElemType val, StackNode* narg = nullptr)
{
    StackNode* s = (StackNode*)malloc(sizeof(StackNode));
    if (nullptr == s)
    {
        exit(EXIT_FAILURE);
    }
    //memset(s, 0, sizeof(StackNode));
    s->data = val;
    s->next = narg;
    return s;
}
void Freenode(StackNode* p)
{
    free(p);
}

//构造一个空栈 
Status InitStack(LinkStack* ps)
{
    assert(ps != nullptr);
    ps->cursize = 0; 
    ps->top = nullptr;
}

//置为空栈
void ClearStack(LinkStack* ps)
{
    assert(ps != nullptr);
    while (ps->top != nullptr)
    {
        StackNode* q = ps->top;
        ps->top = q->next;
        Freenode(q);
    }
}
//销毁栈
void DestroyStack(LinkStack* ps)
{
    assert(ps != nullptr);
    ClearStack(ps);

}
//返回栈的元素个数,即栈的长度
int StackLength(const LinkStack* ps)
{
    assert(ps != nullptr);
    return ps->cursize;
}
//若栈为空栈,则返回TRUE,否则返回FALSE
bool StackEmpty(const LinkStack* ps)
{
    assert(ps != nullptr);
    return ps->cursize == 0;
}

//入栈val , val为栈顶数据元素 
Status Push(LinkStack* ps, ElemType val)
{
    assert(ps != nullptr);
    StackNode* s = Buynode(val, ps->top);
    ps->top = s;
    ps->cursize += 1;
    return OK;
}
//若栈不空,则用pVal返回栈顶元素,并返回OK,否则返回ERROR
Status GetTop(const LinkStack* ps, ElemType* pval)
{
    assert(ps != nullptr);
    if (StackEmpty(ps))
    {
        return ERROR;
    }
    *pval = ps->top->data;
    return OK;
}
//Status GetTop(const LinkStack *ps,ElemType &val);
//若栈不空,则删除栈顶元素,用pval返回其值,并返回OK,否则返回ERROR 
Status Pop(LinkStack* ps, ElemType* pval)
{
    assert(ps != nullptr);
    if (StackEmpty(ps))
    {
        return ERROR;
    }
    *pval = ps->top->data;
    StackNode* q = ps->top;
    ps->top = q->next;
    Freenode(q);
    ps->cursize -= 1;
    return OK;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值