数据结构 栈的实现

一、栈——顺序存储结构

顺序栈的定义
typedef struct sq {
Elemtype* base;
Elemtype* top;
int stacksize;
}SqStack;
其中stacksize指示栈的当前可使用的最大容量,base表示栈底指针,top表示栈顶指针。

二、栈——顺序存储结构1

1.栈的初始化过程

动态分配一个连续的所需要存储的数据类型的内存空间,栈底指针存放这个连续的内存空间的地址,再将栈底指针赋值给栈顶指针,最后将栈当前的最大容量改变为所开辟的内存空间的大小。在初始化的过程中,可以判断一下所内存分配是否成功。
代码如下:

Status int_SqStack(SqStack& s)
{
	s.base = (Elemtype*)(malloc(sizeof(Elemtype) * STACK_INT_SIZE));
	if (s.base == NULL) return ERROR;
	s.stacksize = STACK_INT_SIZE;
	s.top = s.base;
	return OK;
}

2.栈的输出流重载

可以分为两种情况,一种是栈是空栈,还有一种是栈不是空栈。当栈是空栈的时候,就输出提示“栈是空栈”,判断栈是空栈可以通过栈顶指针和栈底指针相等(可以通过调用判断栈是不是空栈的函数来实现);而当栈不是空栈时,可以通过将栈底指针赋值给一个新的指针,通过新的指针来遍历整个栈,循环的条件是新的指针小于栈顶指针。
代码如下:

ostream &operator<<(ostream& output, SqStack s)
{
	Elemtype* q;
	empty_SqStack(s);
	if(s.base!=s.top)
	{
		q = s.base;
		cout << "(";
		while (q < s.top)
		{   cout << *q << ",";
			q++;
		}
		cout << '\b';
		cout << ")" << endl;

	}
	return output;
}

3.判断栈是不是空栈

要判断栈是不是空栈要通过栈顶指针和栈尾指针是否相等来实现,若栈是空栈则输出“该栈为空栈”的提示,若不是空栈则不提示。
代码如下:

Status empty_SqStack(SqStack s)
{
	if (s.top == s.base)
		cout << "该栈为空栈" << endl;
	return OK;
}
在主函数中验证123函数是否成功,主函数的代码如下:
int main()
{
	SqStack s;     
	int_SqStack(s);    //验证初始化
	cout << "初始化后的栈为:"<<s;      
	return 0;
}

4.判断栈是否满栈

判断栈是否满栈是通过栈顶指针是否等于栈的最大存储空间即该实验中的stacksize,如果是相等的话则输出“栈已满”的提示,并且开辟新的内存空间,若直接将realloc()后的结果强制类型转换后赋值给base指针会出现警告,出现警告的原因则是realloc()分配失败时,会返回NULL。但是参数中的base的内存是没有释放的,如果直接将realloc()后的强制类型转换后的值赋给base,那么当申请内存失败时,就会造成base原来指向的内存丢失,造成内存的游离和泄露,为了避免这一情况,可以先realloc()后的值赋给一个新的ELemtype类型的指针,再将该指针赋值给base指针,然后再改变top指针,因为base指针的地址可能会发生改变,这是由于需要再开辟的内存空间可能再原本的内存后已经没有连续的内存空间了,这时候需要找到一个拥有这个存储内存空间大小的连续的空间来存放,最后再改变栈当前的最大容量,若不是满栈则不提示。
代码如下:

Status full_SqStack(SqStack& s)
{
	Elemtype* q;
	if (s.top - s.base == s.stacksize)
	{
		cout << "栈已满" << endl;
		q = (Elemtype*)realloc(s.base, sizeof(Elemtype) * (s.stacksize + STACKADDSIZE));
		if (s.base == NULL) exit(OVERFLOW);
		s.base = q;
		s.top = s.base + s.stacksize;
		s.stacksize = s.stacksize + STACKADDSIZE;
	}
	return OK;
}

5.进栈功能(插入功能)

进栈的话存在着两种情况,一种是栈满了,此时就要开辟新的空间来实现进栈功能,而此时可以调用判断栈是否满栈的函数来实现,另外一种则是栈没满,栈没满的话,也有可能存在清除栈后栈底指针被释放了的情况。这时候就需要重新动态分配内存空间,就可以直接进行进栈了。而进栈的实现将需要存放的数据存放到base指针所指向的内存空间中,再将base指针加1。
代码如下:

  Status insert_SqStack(SqStack& s, Elemtype e)
{
	full_SqStack(s);
    *s.top = e;
	s.top++;
	return OK;
}
在主函数中验证45函数是否成功,主函数的代码如下:
int main()
{
	SqStack s;     
	Elemtype e;
	e = 1;
	int_SqStack(s);    //验证初始化
	cout << "初始化后的栈为:"<<s;      
	insert_SqStack(s, e);  
	cout <<"插入后的栈为:"<< s;         //验证进栈
	return 0;
}

6.实现从键盘上输入的功能

先让用户输入所要存储的数据的个数,需要判断一下用户所输入的个数与现在所有的内存空间的大小,若内存空间不够存放这些数据则需要先开辟新的内存空间(在进栈功能时,也提到了这点),再将所要存放的数据进栈。
代码如下:

Status input_SqStack(SqStack& s)
{
	int i,j,m;
	Elemtype e,*q;
	cout << "请输入所需要存储的数据的个数:" << endl;
	cin >> i;
	m = s.top - s.base;
	if (s.stacksize-m<i)
	{
		cout << "栈的空间不够" << endl;
		q = (Elemtype*)realloc(s.base, sizeof(Elemtype) * (s.stacksize + STACKADDSIZE));
		if (s.base == NULL) exit(OVERFLOW);
		cout << "已成功开辟新的空间" << endl;
		s.base = q;
		s.top = s.base + m;
		s.stacksize = s.stacksize + STACKADDSIZE;
	}
	cout << "请输入所要存储的数据:" << endl;
	for (j = 0; j < i;j++)
	{
		cin >> e;
		*s.top = e;
		s.top++;
	}
	return OK;
}

在主函数中验证6的函数是否成功,主函数的代码如下:

int main()
{
	SqStack s;     
	Elemtype e;
	e = 1;
	int_SqStack(s);    //验证初始化
	cout << "初始化后的栈为:"<<s;      
	insert_SqStack(s, e);  
	cout <<"插入后的栈为:"<< s;         //验证进栈
	input_SqStack(s);
	cout <<"实现从键盘上输入后的栈:"<<s; //手动输入的数据量大点,验证首次开辟的内存不够的情况
	delete_SqStack(s,e);
	return 0;
}

7.退栈(实现删除功能)

要进行退栈,首先要判断这个栈是不是空栈,如果是空栈,就没有退栈的意义了,如果栈不是空栈的话,将栈顶指针减1,并且将指针指向的值赋值给主函数传入的参数。再退栈中的判断是不是空栈可以调用栈是不是空栈的函数。
代码如下:

   Status delete_SqStack(SqStack& s, Elemtype& e)
{
	empty_SqStack(s);
	if (s.top != s.base)
	{
		s.top--;
		e = *s.top;
	}
	return OK;
}

8.获取栈顶元素的功能

要获取栈顶元素和退栈的操作类似,相同的是需要判断是不是空栈,如果空栈获取栈顶元素是没有意义的,不同的是退栈的时候栈顶指针需要做出改变,而在获取栈顶的元素的函数中,栈顶指针是不需要减1的,需要将栈顶指针减1的指向的值赋值给所传入的参数。
代码如下:

void   getTop_SqStack(SqStack s, Elemtype& e)   //获取栈顶元素
{   
	empty_SqStack(s);
	if (s.top != s.base)
		e = *(s.top - 1);

}

9.清除栈的功能

因为在本次实验中所用的是顺序栈的动态分配,所以在清除栈时,不仅要将栈底指针赋值给栈顶指针,还需要将栈底指针释放,释放完后,为了方式野指针的出现,将NULL赋值给栈顶指针和栈底指针。
代码如下:

Status free_SqStack(SqStack& s)   //实现清空栈
{
	empty_SqStack(s);
	if (s.top != s.base)
		s.top = s.base;
	free(s.base);
    s.base = NULL;
	s.top  = s.base;
	return OK;
}

在主函数中验证7,8,9的函数是否成功,主函数的代码如下:

int main()
{
	SqStack s;     
	Elemtype e;
	e = 1;
	int_SqStack(s);    //验证初始化
	cout << "初始化后的栈为:"<<s;      
	insert_SqStack(s, e);  
	cout <<"插入后的栈为:"<< s;         //验证进栈
	input_SqStack(s);
	cout <<"实现从键盘上输入后的栈:"<<s; //手动输入的数据量大点,验证首次开辟的内存不够的情况
	delete_SqStack(s,e);
	cout << "将最后一个元素退栈" << endl;
	cout << "实现退栈后的栈为:" << s;   //验证退栈
	cout <<"退栈的数据为:"<<e<<endl;
	getTop_SqStack(s, e);               //验证获取栈顶元素
	cout << "栈顶元素的数据为:"<<e << endl;
	free_SqStack(s);   //验证清空栈功能
	cout << "清空栈后:"<<s;
	insert_SqStack(s, e);   //验证清栈后的插入功能
	cout << s;
	return 0;
}

三、栈——顺序存储结构2

typedef struct SqStack_array
{
Elemtype data[MAXSIZE];
int top;
int base;

} SqStack_a;
顺序栈的定义:其中top为栈顶指针,MAXSIZE为顺序栈的数组空间的大小。

1.栈的初始化过程

这次实验中所采用的是用数组来存储栈的数据元素,所以只要将栈底和栈顶指针都指向数组的0下标的位置,就能将栈进行初始化。
代码如下:

Status int_SqStack(SqStack_a& s)   //初始化栈
{
	s.base = s.top = 0;
	return OK;
}

2.输出流重载

可以分为两种情况,一种是栈是空栈,还有一种是栈不是空栈。当栈是空栈的时候,就输出提示“该栈为空栈”,判断栈是空栈则是通过栈顶指针和栈位指针相等(可以通过调用判断栈是不是空栈的函数来实现);而当栈不是空栈时,可以通过将栈底指针赋值给一个int变量,通过变量这个来遍历整个栈,循环的条件是这个变量小于栈顶指针。

ostream& operator<<(ostream& output, SqStack_a s)  //输出流重载
{
  int j;
  if (s.base == s.top)
  	cout << "该栈为空栈" << endl;
  else
  {
  	j = s.base;
  	cout << "(";
  	while (j < s.top)
  	{
  		cout << s.data[j] << ",";
  		j++;

  	}
  	cout << '\b' << ")" << endl;
  }
  return output;
}

3.判断是否空栈

如果栈底指针和栈顶指针相等,那么这个栈就是空栈,空栈的时候返回ERROR,否则这个栈就不是空栈,栈不空的时候返回OK。

Status empty_SqStack(SqStack_a s) //判断栈是否为空栈
{
  if (s.top == s.base)
  {
  	return ERROR;
  }
  else
  	return OK;
}

3.判断是否满栈
如果栈顶指针刚好等于栈的最大存储量,那么这个栈满,栈满的时候返回ERROR;否则就返回OK。

Status full_SqStack(SqStack_a s)   //判断是否为栈满
{
  if (s.top == MAXSIZE)
  {
  	cout << "栈满" << endl;
  	return ERROR;
  }
  else
  	return OK;

}

4.实现进栈功能

如果栈不满的时候就可以实现进栈功能,否则就输出提示“无法实现进栈功能”。
代码如下:

Status insert_SqStack(SqStack_a& s, Elemtype e)  //实现插入功能(进栈)
{
	if (full_SqStack(s))
	{
		s.data[s.top++] = e;
	}
	else
	{
		cout << "无法实现进栈功能" << endl;
	}
	return OK;
}

5.实现退栈功能

如果栈不空的时候就可以实现退栈功能,并且将退栈的元素的值传给e,通过引用将e返回到主函数中,栈为空的时候就输出“无法实现退栈功能”。
代码如下:

Status delete_SqStack(SqStack_a& s, Elemtype& e)  //实现删除功能(退栈)
{
	if (empty_SqStack(s))
	{
		e = s.data[--s.top];
	}
	else
		cout << "无法实现退栈功能";
	return OK;
}

6.获取栈顶元素

如果栈不为空的时候就可以实现获取栈顶元素功能,并且将栈顶元素的值传给e,通过函数返回值将栈顶元素返回给主函数,栈为空的时候就输出“无法实现获取栈顶元素功能”。
代码如下:

Elemtype getTop_SqStack(SqStack_a s)  //获取栈顶元素
{
	Elemtype e;
	if (empty_SqStack(s))
	{
		e = s.data[s.top - 1];
     }
	else
	{
		cout << "无法实现获取栈顶元素功能" << endl;

	}
	return e;
}
```c

## 7.实现从键盘上输入功能

  让用户从键盘上输入所要存储的数据个数(且元素个数不超过所能存储的最大存储量),此次实验中没有调用进栈功能的函数,而是直接用一个for循环实现这个从键盘上输入的功能。
代码如下:
```c
Status input_SqStack(SqStack_a& s)  //实现从键盘上输入功能
{
	int i,j;
	Elemtype e;
	cout << "请用户输入所需要存储的数据个数(元素个数不超过" <<MAXSIZE-s.top<<")"<< endl;
	cin >> i;
	for (j = 0; j < i; j++)
	{
		cin >> e;
		s.data[s.top++] = e;
	}
	return OK;
}

7.实现清除栈功能

如果栈不是空栈的话,就将栈底指针赋值给栈顶指针,如果栈是空栈的话就输出提示“无需清除,原本已是空栈”。
代码如下:

Status free_SqStack(SqStack_a& s)  //实现清除栈功能
{
	if (empty_SqStack(s))
	{
		s.top = s.base;
	}
	else
		cout << "无需清除,原本已是空栈" << endl;

	return OK;
}
int main()
{
	SqStack_a s;
	Elemtype e;
	e = 2;
	int_SqStack(s);   //实现初始化功能
	cout <<"执行初始化功能后:"<< s;   //验证初始化是否成功
	insert_SqStack(s, 2);   //实现插入功能
	cout << "执行插入功能后:" << s;  //验证进栈是否成功
	delete_SqStack(s, e);   //实现删除功能
	cout << "执行删除功能后:" << s; //验证退栈是否成功
	cout << "退栈的数据元素为:" << e<<endl;
	input_SqStack(s);//实现从键盘上获取数据功能
	cout << "执行从键盘上获取数据功能后:" << s;  //验证从键盘上获取数据功能是否成功
	e = getTop_SqStack(s);  //实现获取栈顶元素功能
	cout << "执行获取栈顶元素功能后:" << s;  //验证获取栈顶元素功能是否成功
	insert_SqStack(s, 10);   //实现插入功能
	cout << "执行插入功能后:" << s;  //验证进栈是否成功
	free_SqStack(s);//实现清除栈功能
	cout <<"执行清除栈功能后:"<<s; //验证清楚栈功能是否成功
	return 0;
}
```c

转载请申明~


     




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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值