C++:栈的实现和使用

目录

一、栈的简介

二、顺序栈的实现

三、链栈的实现

四、STL库中的栈


 

一、栈的简介

        栈(Stack)是一种重要的数据结构,它遵循“后进先出”(LIFO, Last In First Out)的原则。这意味着最后插入栈中的元素会最先被移除。栈的基本操作主要包括:

  1. 入栈(push):将一个元素添加到栈顶。
  2. 出栈(pop):移除栈顶的元素,并返回该元素。
  3. 取栈顶(top):返回栈顶的元素,但不移除它。
  4. 判空(empty):返回一个布尔值,指示栈是否为空。

        栈有两种存储结构,分别是顺序存储结构链接存储结构,对应称栈为顺序栈链栈。本文将介绍这两种栈的实现,并介绍STL库中的栈的使用。作为一般规律,当栈的使用过程中,元素个数变化较大时,建议使用链栈,反之,使用顺序栈。 

二、顺序栈的实现

  1. 构造函数:初始化一个空的顺序栈只需将栈顶指针top_index置为-1。
  2. 析构函数:顺序栈是静态存储分配,在顺序栈变量退出作用域时自动释放顺序栈所占存储单元,因此,顺序栈无需销毁,析构函数为空。
  3. 入栈操作:栈顶指针top_index+1,然后将数据存入栈顶位置即可。
  4. 出栈操作:取出栈顶元素,栈顶指针top_index-1即可。
  5. 取栈顶操作:取出栈顶元素,栈顶指针top_index不变。
  6. 判空操作:判断栈顶指针是否为-1即可。

template <typename T>                //使用模板,兼容各种数据类型
class SeqStack
{
public:
	SeqStack() {top_index = -1;}     //构造函数
	~SeqStack() {};                  //析构函数

	void push(T x)                   //入栈操作
	{
		if (top_index == size - 1)
		{
			throw "上溢";  //防止溢出
		}
		data[++top_index] = x;
	}

	T pop()                           //出栈操作
	{
		if (top_index == -1)
		{
			throw "下溢";  //防止溢出
		}
		T temp=data[top_index--];
		return temp;
	}

	T top() const                      //取栈顶操作
	{
		if (top_index == -1)
		{
			throw "下溢";  //防止溢出
		}
		T temp = data[top_index];
		return temp;
	}

	bool empty()                       //判空操作
	{
		return top_index==-1;
	}

private:
	const static int size = 100000;     //可存放的数据量
	T data[size];                       //用于存放数据的数组
	int top_index;                      //栈顶的索引
};

说明:

        上述代码中,T top()后面加上了const关键字,表示该成员函数是只读的,不会修改对象的任何成员变量。

        int size 前使用了const和static关键字,const确保size不会被修改,static确保size是类范围的静态变量,所有对象共享该变量,减少内存(不用每创建一个对象的同时都为size申请一块内存)的同时,使下一个语句T data[size]可以使用变量size。

三、链栈的实现

    链栈的实现相对复杂,可以的话建议使用顺序栈。 

  1. 构造函数:初始化一个空的链栈只需将栈顶指针top_index置为nullptr。
  2. 析构函数:链栈是动态存储分配,在链栈变量退出作用域前,要释放链栈的存储空间。
  3. 入栈操作:只需处理栈顶的情况。
  4. 出栈操作:只需处理栈顶的情况。
  5. 取栈顶操作:取出栈顶元素,不修改栈顶指针top_index。
  6. 判空操作:判断栈顶指针是否为nullptr即可。
template <typename T>                //使用模板,兼容各种数据类型
struct Node                          //结点
{
	T data;
	Node<T>* next;
};



template <typename T>                //使用模板,兼容各种数据类型
class LinkStack
{
public:
	LinkStack()                      //构造函数
    { 
        top_index = nullptr; 
    }

	~LinkStack()                     //析构函数
	{
		Node<T>* p = top_index;

		while (top_index != nullptr)
		{
			top_index = top_index->next;
            //栈顶指针指向下一个结点
			delete p;
            //释放前栈顶结点
			p = top_index;
            //指向新栈顶结点
		}
	};  

	void push(T x)                   //入栈操作
	{
		Node<T>* s = nullptr;
		s = new Node<T>;
        //生成一个新结点

		s->data = x;
		s->next = top_index;
        //连接前栈顶结点

		top_index = s;
        //成为新栈顶结点
	}

	T pop()                           //出栈操作
	{
		Node<T>* p = nullptr;
		
		if (top_index == nullptr)
		{
			throw "下溢";  //防止溢出
		}

		T temp = top_index->data;
        //取栈顶数据

		p = top_index;
        //指向栈顶结点

		top_index = top_index->next;
        //栈顶指针指向下一个结点

		delete p;
        //释放栈顶结点

		return temp;
	}

	T top() const                      //取栈顶操作
	{
		if (top_index == nullptr)
		{
			throw "下溢";  //防止溢出
		}

		T temp = top_index->data;
        //取栈顶数据        

		return temp;
	}

	bool empty()                       //判空操作
	{
		return top_index == nullptr;
	}

private:
	Node<T>* top_index;
};

        该链栈的操作基于链表结构,所有操作的时间复杂度均为 O(1),因为入栈、出栈和取栈顶操作都只涉及栈顶结点的操作,而无需遍历整个栈。链栈的优点是可以动态扩展栈的大小,避免固定大小的限制。

四、STL库中的栈

        栈这样的数据结构已经在STL库中定义好了,如果没有自行设计栈的要求,可以直接使用库中定义好的栈。现简单介绍其用法如下:

#include <stack>       //使用栈需要包含相应头文件



stack<int> s;          //定义一个int类型的栈,命名为s

s.push(666);           //入栈

s.pop();               //出栈

s.top();               //取栈顶,返回栈顶元素

s.empty();             //判空,返回bool值

s.size();              //查询栈大小,返回栈中元素个数

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值