YAZONG 我的开源

(数据结构)第二讲-线性结构(2.2.2堆栈的顺序存储实现)

  , ,
0 评论0 浏览

image.png

/*
表示堆栈的结构
*/
#define MaxSize//存储数据元素的最大个数
typedef struct SNode *Stack;
struct SNode{
	//数组的分量
	ElementType Data[MaxSize];
	//栈顶位置其数组下标位于哪里,但Top不是一个地址.
	int Top;
}

入栈

/*
入栈
PtrS是Stack类型的一种结构指针
item准备入栈的对象

用数组表示堆栈时:
Top=0,表示分量下标为0的地方有一个元素。
Top=-1,表示堆栈空,在最下面的位置。
Top>0且<=MaxSize-1,表示堆栈不为空,且至少有两个元素。
*/
void Push(Stack PtrS, ElementType item){
	/*
	入栈操作首先判断堆栈是否满,即:最多放MaxSize这些元素。
	因为数组的下标是从0开始的,所以从0一直到MaxSize-1。
	所以当Top指向MaxSize-1的时候,意味着n个元素全部放满了。
	*/
	if(PtrS->Top == MaxSize-1){
		//这里用数组表示,说明数组是有界限的。
		printf("堆栈满");
		return;
	}else{
		/*
		此语句做了两件事情:
		item放在Top+1的一个位置。
		++放在Top上面,实现入栈操作。
		*/
		PtrS->Data[++(PtrS->Top)] = item;
		return;
	}
}

image.png

出栈

/*
出栈
PtrS是Stack类型的一种结构指针

用数组表示堆栈时:
Top=0,表示分量下标为0的地方有一个元素。
Top=-1,表示堆栈空,在最下面的位置。
Top>0且<=MaxSize-1,表示堆栈不为空,且至少有两个元素。
*/
ElementType Pop(Stack Ptrs){
	if(Ptrs->Top == -1){
		printf("堆栈空!");
		/*
		ERROR是ElementType的特殊值,标识错误.
		*/
		return ERROR;
	}else{
		return (Ptrs->Data[(Ptrs->Top)--]);
	}
}

image.png

案例

image.png

首先把数组对分,左边一半是个堆栈,右边一半是另一堆栈,这样的话,一个数组就实现了两个堆栈。看下这样有什么问题?

image.png

堆栈都是往右边涨,都空出来的右边是空的。

假如,第二个堆栈继续涨,那么第二个堆栈就再也放不进去了。

但此时,数组还是有空间的,第一个堆栈还有地方没放。

image.png

此时,TOP1的位置指向堆栈的第一块最右边的位置,TOP2的位置指向数组末尾的位置。

所以,简单的把一个数组对分来做两个堆栈就会有问题:一个堆栈满了,另一个堆栈没满。

那么我们的要求是,只要数组有剩余空间,那么就入栈。

image.png

此时,换一种思路,数组依然做两个堆栈,但是不是都往右边涨了,而是都往中间涨,第一个堆栈有数据时往右挪动,第二个堆栈有数据时往左挪动,删除的话,二者就往相反方向挪动,这样只要数组有空间,那么就可以执行入栈操作。

如何判断堆栈满了呢?

第一个堆栈TOP1(数组下标),第二个堆栈TOP2(数组下标)。

但并不是TOP1+TOP2=堆栈满。

image.png

image.png

有且仅当两个堆栈的指针相遇的时候,堆栈就满了,而不是TOP1+TOP2=堆栈满。

/*
最大地利用数组空间:基础结构

一个数组实现两个堆栈,使这两个堆栈分别从数组的两头开始向中间生长。
当两个栈顶指针相遇时,表示两个栈都满了。
*/
#define MaxSize<存储数据元素的最大个数>
struct DStack{
	ElementType Data[MaxSize];
	int Top1;//堆栈1的栈顶指针
	int Top2;//堆栈2的栈顶指针
} S;
/*
Top1代表Data数组的下标
第1个堆栈空的条件/位置:Top1 = -1
数组的第一个位置是:0
*/
S.Top1 = -1;
/*
Top2代表Data数组的下标
第2个堆栈空的条件/位置:Top1 = MaxSize
数组的最后一个位置是:MaxSize-1
*/
S.Top2 = MaxSize;
/*
最大地利用数组空间:push操作

一个数组实现两个堆栈,使这两个堆栈分别从数组的两头开始向中间生长。
当两个栈顶指针相遇时,表示两个栈都满了。

PtrS是Stack类型的一种结构指针
Tag作为区分两个堆栈的标识,1和2.
*/
void Push(struct DStack *Ptrs, ElementType item, int Tag){
	//堆栈满,两个指针挨在一起了
	if(Ptrs->Top2 - Ptrs->Top1 == 1){
		printf("堆栈满");
		return;
	}
	//对第1个/左边的堆栈操作(从低位到高位)
	else if(Tag == 1){
		//入栈
		Ptrs->Data[++(Ptrs->Top1)] = item;
	}
	//对第2个/右边的堆栈操作(从高位到低位)
	else{
		//入栈
		Ptrs->Data[--(Ptrs->Top2)] = item;
	}
}
/*
最大地利用数组空间:pop操作

一个数组实现两个堆栈,使这两个堆栈分别从数组的两头开始向中间生长。
当两个栈顶指针相遇时,表示两个栈都满了。

PtrS是Stack类型的一种结构指针
Tag作为区分两个堆栈的标识,1和2.
*/
ElementType Pop(struct DStack *Ptrs, int Tag){
	//对第1个/左边的堆栈操作(从高位到低位)
	if(Tag == 1){
		if(Ptrs->Top1 == -1){
			printf("堆栈1空");
			return NULL;
		}else{
			//出栈
			return Ptrs->Data[(Ptrs->Top1)--];
		}
	}
	//对第2个/右边的堆栈操作(从低位到高位)
	else{
		if(Ptrs->Top2 == MaxSize){
			printf("堆栈空");
			return NULL;
		}else{
			//出栈
			return Ptrs->Data[(Ptrs->Top2)++];
		}
	}

}

标题:(数据结构)第二讲-线性结构(2.2.2堆栈的顺序存储实现)
作者:yazong
地址:https://blog.llyweb.com/articles/2023/08/15/1692030057400.html