数据结构:栈

1、栈的表示

顺序栈的表示

存储方式:利用一组地址连续的存储单元依次存放自栈底到栈顶的数据元素。

栈底一般在低地址。

top:指示栈顶元素位置

base:指示栈底元素位置

stacksize:表示栈的最大容量

接下来,我们用更详细的一幅图来描述顺序栈:

起始状态,top和base都指向0的位置,此时是空栈:base==top,且栈的容量stacksize=4。

接下来为空的栈添加元素(入栈),将新的元素添加到top所指位置,再将top移向下一位置,我们最终可以观察到top并没有指向D,而是栈的外面,即4的位置。

因此栈的容量stacksize=top-base。

注意:top的最初指向位置是人为规定的,可以指向-1,也可以指向0,具体根据题目判断。

接下来,外面根据代码加深对顺序栈的理解:

typedef struct
{
	SELemType* base;//栈底指针
	SELemType* top;//栈顶指针
	int stacksize;//栈可用最大容量
}sqStack;
sqStack S;//定义了一个名为S的顺序栈

根据代码,我们首先定义了一个顺序栈的结构体类型,包括栈底指针和栈顶指针,同时包含栈的容量。接着创建了一个S的顺序栈。

2、顺序栈的实现

2.1初始化

Status InitStack(SqStack& S)
{
	S.base = new SElemType[MAXSIZE];
	if (!S.base)
	{
		return OVERFLOW;//空间分配失败
	}
	S.top = S.base; //栈顶指针=栈底指针
	S.stackSize = MAXSIZE;
	return OK;
}

这串代码的功能就是创建了一个顺序栈,并对顺序栈初始化,使top和base都指向0的位置。

2.2入栈

入栈的含义就是在原有的栈中插入新的元素。我们把新的元素插入在栈顶指针的位置。因此需要经历下面几个步骤:

1、判断是否栈满,栈满就无法进行插入了。

2、栈顶指针指向要插入的元素,并将栈顶指针移向下一位置。

通过图示,大家可以进一步理解上述步骤。

基于前面创建好的顺序栈,我们就可以用代码实现入栈:

Status Push(SqStack& S, SElemType)
{
	if (S.top - S.base == S.stacksize)//判断栈满
		return ERROR;
	*S.top = e;//栈顶指针top指向的元素为e
	S.top++;//将栈顶指针移向下一位置
}

2.3出栈

出栈可以理解为从栈顶移除一个元素,有以下步骤:

1、判断是否栈空,栈空就不能移除元素。

2、栈顶指针往下移动,再将所指元素赋给e。

通过图示,我们可以进一步理解:

Status Pop( SqStack &S, SElemType e) 
{
if( S.top == S.base) // 栈空
 return ERROR; 
--S.top;
e=*S.top;
return OK;
}

3、链栈的表示与实现

3.1链栈的表示

我们可以类比顺序表与链表的关系理解链栈的概念。与链表不同的是链栈没有头指针的,栈顶指针就是链表的头指针。同时每一项包含数据域和指针域,指针域指向下一个元素的地址。

typedef struct StackNode 
{
	int data;//数据域
	struct StackNode* next;//指针域
}stackNode, * LinkStack;
LinkStack S;

3.2链栈的实现

3.2.1初始化

由于链栈不需要头节点,我们基于创建好的链栈,使栈顶指针指向空即可。

void initStack(LinkStack& s)
{
	s = NULL;//不需要头节点
}

3.2.2判空

根据链栈初始化的内容,我们可以根据栈顶指针指向的内容判断是否为空。

int stackEmpty(LinkStack s)
{
	if (s == NULL)
		return ok;
	return error;
}

3.2.3求链栈长度

与顺序栈不同,链栈的元素是随机存放的,无法根据top-base的方法得到长度。因此,我们需要设置一个计数器,通过边累加,边让栈顶指针往下移动,直到指向空停止循环,得出链栈的长度。 

int stackLength(LinkStack s)
{
	int sum = 0;
	stackNode* temp = s;
	while (temp != NULL)
	{
		sum++;
		temp = temp->next;
	}
	return sum;
}

3.2.4入栈

入栈可以类比在链表中插入元素。我们根据代码做进一步解释。 

void push(LinkStack& s, int e)
{
	stackNode* p = new stackNode;
	p->data = e;//创建一个包含数据域和指针域的项
	p->next = NULL;
	if (s == NULL)//将问题分为两种情况
		s = p;//s指针指向p
	else
	{
		p->next = s;//p指针的前驱指向s
		s = p;//s指针指向p
	}
}

首先我们创建一个包含数据域和指针域的项并用P指向它。接着分情况讨论,如果链表为空,那么指针s 直接指向p,如果不为空则让p的后继指向s,再将s挪至p的位置。

3.2.5出栈

出栈可以类比在链表中删除元素。我们根据代码做进一步解释。

void pop(LinkStack& s, int& e)
{
	stackNode* p = new stackNode;
	if (s == NULL)//如果链栈为空则无法出栈
	{
		cout << "栈为空" << endl;
	}
	else
	{
		p = s;//用p记录指针s的位置
		e = p->data;//将指针s指向的元素赋值给e
		s = s->next;//将s移至下一位置
		delete p;//删除p
		cout << "成功弹出栈顶元素" << endl;
	}
}

首先判断是否为空栈,如果是空栈则无法移除元素。如果不是空栈我们创建指针p用于记录s的位置,并将指针s指向的元素赋给e。接着我们将s挪至s的后继,再将p删除即可实现出栈操作。 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值