栈的定义及基本操作

栈的定义和特点


      栈是一个特殊的线性表,是限定在一端进行插入和删除操作的线性表
      插入到栈顶称作入栈(PUSH) 
      从栈顶删除最后一个元素称作出栈 (POP)

图1 栈的表示

假设三个元素a,b,c入栈顺序为a,b,c,那么出栈顺序有几种?

                                   一般表示一个栈都是竖着列表表示

                                                           栈顶

          c
 b
          a
                                                            栈底

       
cba

表尾                                                                               表头

出栈可以等a,b,c都存放进去在依次出栈,出栈结果为:

a
b
c

也可以放完a,然后a出栈,b和c都入栈后再依次出栈,结果为:

b
c
a

当然也可以a,b先入栈,然后依次出栈,最后c入栈,结果为:

c
a
b

还有几种情况,就不一一举例了

那么会出现b,c,a的情况吗?显然是不可能的,因为栈的特点就是只能在栈顶进行入栈和出栈操作,以上这个例子可以很好反应栈的这个特点。


顺序栈的表示和实现

与链表相同栈的存储方式也分为两种:顺序存储结构和链式存储结构


顺序栈的特点:简单,方便,但容易溢出
顺序栈的存储方式:同一般线性表的顺序存储结构完全相同

用一组连续的存储单元依次顺序放置,从栈底到栈顶的数据元素,栈底一般存放在低地址端

几个重要概念:
//栈满:top-base==stacksize;
/*栈满处理方法:
      报错返回系统
      分配更大的存储空间*/
//空栈:base=top 
      
//上溢:栈已满,又要压入元素 (通常是一种错误)
//下溢:栈已空,又要弹出元素 (通常被用作结束条件) 

 

顺序栈的表示

base表示指向栈底的指针

top表示指向栈顶的指针

//顺序栈的表示
#define MAXSIZE 100;
typedef struct{
	SElemType *base;        //栈底 
	SElemType *top;         //栈顶
	int stacksize;          //最大容量 
}SqStack; 

 

 顺序栈的初始化

相当于建立一个空栈即top=base,两个指针指向相同

//顺序栈的初始化
Status InitStack(SqStack S){
	S.base=(SElemType *)malloc(sizeof(SElemType)*MAXSIZE);//分配存储空间
	if(!S.base){
		printf("OVERLOW");
	} 
	else{
		S.top=S.base;                            //顶指针和底指针指向相同,相当于建立一个空栈 
		S.stacksize=MAXSIZE;
		return OK;
	}
} 

 

判断顺序栈是否为空

空栈的标志性条件top=base,两个指针有相同的指向

如果是空栈返回TURE,如果不是空栈返回FALSE

//判断顺序栈是否为空
Status StackEmpty(SqStack S){
	if(S.top==S.base){                  //判断栈为空的标志base=top; 
		teturn TURE;
	}
	else{
		return FALSE;
	}
} 

 

求顺序栈的长度

这里直接用两个指针相减即可

//求顺序栈的长度
int StackLength(SqStack S){
	return S.top-S.base;         //两个指针相减可以算出中间隔了多少个数据元素,也就是栈的长度 
} 

 

清空顺序栈

这里与清空单链表类似

//清空顺序栈
/*与链表相同,就是把该表置空,但保留表的头结点,栈里的top指针就相当于链表里的头结点*/ 
Status ClearStack(SqStack S){
	if(S.base){
		S.base=S.top;                  //相当与把当前栈变成一个空栈 
	}
} 

看一下单链表的清空


/*清空单链表*/
Status ClearList(LinkList &L){
	Lnode *p,*q;
	p=L->next;                       //p指向首元结点 
	while(p){
		q=p->next;                   //q指向p后面的结点 
		free(p);                     //释放p 
		p=q;                         //p,q指向同一结点 
	}
	L->next=NULL;
	return OK;
}

 销毁顺序栈

与销毁单链表类似

//销毁顺序栈
Status DestoryStack(SqStack S){
	if(S.base){
		S.stacksize=0;                //表长为空 
		S.base=S.top=NULL;            //指针为空 
	}
	return OK; 
}

 销毁单链表

/*销毁单链表(头结点,头指针都不存在)*/
Status DestoryList_L(LinkList &L){     //L为指向头结点的指针 
	Lnode * p;                         //或者LinkList p;
	while(L){                          
		p=L;                           //p和L指向同一个结点 
		L=L->next;                     //L向后移动一个 
		free(p);                       //释放p 
	} 
	return OK;
} 

顺序栈的入栈(注意:栈只能在栈顶进行入栈和出栈操作)

具体步骤
/*判断是否栈满
  将元素e压入栈顶
  栈顶指针加一*/

这里注意栈满的条件:S.top-S.base==stacksize

//顺序栈的入栈
/*判断是否栈满
  将元素e压入栈顶
  栈顶指针加一*/
Status Push(SqStack S,SElemType e){
	if(S.top-S.base==stacksize){         //这里的top指针指向的是栈顶元素的下一个位置 
		return ERROR;                    //栈满 
	}              
	*S.top++=e;
	return OK; 
}  

*S.top++=e;

这一句其实是先将数据元素e放入栈中,然后栈顶指针top移向下一个位置。

如果top指针指向当前表的最后一个数据元素(也就是栈顶元素),即表尾,那么要先将top指针向后移动一位,然后再进行赋值,该语句就变为*++S.top=e;

顺序栈的出栈(注意:栈只能在栈顶进行入栈和出栈操作)

具体步骤
/*判断是否栈空
  获取栈顶元素e
  栈顶指针减一*/

这里的top指针同样也是指向栈顶元素的下一个位置

//顺序栈的出栈
/*判断是否栈空
  获取栈顶元素e
  栈顶指针减一*/
Status Pop(SqStack S,SElemType e){
	if(S.top==S.base){
		return ERROR;
	}
	e=*--S.top;
} 

e=*--S.top;

这一句是先将top指针向下移动一个位置,然后将该位置的数据元素(也就是栈顶元素)赋值给e,

就可以完成出栈。

如果top指针指向当前表的最后一个数据元素(也就是栈顶元素),即表尾,那么就可以先直接将S.top赋值给e,然后将top指针向下移动一个位置,即e=*S.top--;


链栈的表示和实现


链栈是运算受限的单链表,只能在表头进行插入删除操作

与单链表相比较链栈的插入和删除操作就很简单了,相当于只表头进行

图2 链栈的表示



链栈与链表的比较
/*链表的头结点就是栈顶指针top
  链栈里不需要头结点
  链栈基本不存在栈满情况
  空栈相当于头指针指向为空
  插入和删除操作仅存在于栈顶*/

链栈的表示

与单链表的表示很像

//链栈的表示
typedef struct StackNode{
	SElemType data;
	struct StackNode *next;
}StackNode,*LinkStack; 

 

链栈的初始化

相当于建立空栈

 //链栈的初始化
void InitStack(LinkStack S){
	S=NULL;                           //相当与头结点 
	return OK;
}


判断链栈是否为空

如果是空栈返回TURE,如果不是空栈返回FALSE

//判断链栈是否为空
Status StackEmpty(LinkStack S){
	if(S==NULL){
		return TRUE;
	}
	else{
		return FALSE;
	}
} 

链栈的入栈

相当于在S的前面插入新的数据元素,新的数据元素成为栈顶元素

新的数据元素的next域指向S

//链栈的入栈
Status Push(LinkStack S,SElemType e){              //S指向栈顶元素 
	p=(StackNode *)malloc(sizeof(StackNode));      //分配存储空间
	p->data=e;
	p->next=S;
	S=p;
	return OK;
} 

 

链栈的出栈

出栈只需要先保存top指针的内容,然后向下移动一个位置即可

//链栈的出栈
Status Pop(LinkStack S,SElemType e){
	if(S==NULL){
		return ERROR;                  //与顺序栈一样要先判断栈是否为空 
	}
	else{
		e=S->data;
		p=S;
		S=S->next;
		free(p);
		return OK;
	}
} 


取出栈顶元素

直接保存top指针的内容即可

//取出栈顶元素
SElemType GetTop(LinkStack S){
	if(S!=NULL){
		return S->data;
	}
}

  • 13
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值