数据结构之栈

栈的简介

今天给大家介绍另一种常用的数据结构——栈。(注意,栈从不同的角度定义有不同的定义,从内存分配的角度定义是指变量由系统分配内存,今天讲的是一种数据结构)它是一种先进后出的结构即FILO(first in last out)。如下图所示,数据的插入(压栈)删除(出栈)都从栈顶操作。
![栈示意图]( https://img-blog.csdnimg.cn/20200327174934854.png?x-oss-process=image/watermark ,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80Mzk1ODYxMA==,size_16,color_FFFFFF,t_70#pic_center)
栈通常具有以下接口:

  1. 判断栈是否为空
  2. 移除栈顶元素
  3. 在栈顶增加元素
  4. 返回栈中元素数目
  5. 返回栈顶元素

栈的应用十分的广泛,如逆序输出、数制转换和特殊符号匹配等,函数的调用就是很好的栈的应用,下面我们进行顺序栈和链栈的代码实现。

顺序栈

![在这里插入图片描述]( https://img-blog.csdnimg.cn/20200327183655904.png?x-oss-process=image/watermark ,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80Mzk1ODYxMA==,size_16,color_FFFFFF,t_70#pic_center)
如上图所示,顺序栈使用数组存储数据,读取写入数据时用游标操作。空表时top=-1,表满时top=MAXSIZE-1,MAXSIZE为栈容量。

顺序栈类声明

声明时采用模版,可以适应处理多种类型数据。

#define MAXSIZE 10

template<typename T>			
class stack
{
public:
	stack() :_index(-1) {};		        //初始化空表
	~stack() {};

	bool empty() const;			//堆栈为空则返回真
	void pop();				//移除栈顶元素
	void push(T value);			//在栈顶增加元素
	int size() const;			//返回栈中元素数目
	T top() const;				//返回栈顶元素

private:
	int _index;				//游标
	T data[MAXSIZE];			//数组容量为MAXSIZE
};

顺序栈各接口实现

template<typename T>
inline bool stack<T>::empty() const
{
	if (_index == -1)
		return true;
	return false;
}

template<typename T>
inline void stack<T>::pop()
{
	if (_index == -1)
		return;
	_index--;
}

template<typename T>
inline void stack<T>::push(T value)
{
	if (_index == MAXSIZE - 1)
		return;
	data[++_index] = value;
}

template<typename T>
inline int stack<T>::size() const
{
	return _index + 1;
}

template<typename T>
inline T stack<T>::top() const
{
	if (_index == -1)
		return 0;
	return data[_index];
}

顺序栈的操作实现较为简单,需要注意的是,在压栈和出栈时首先要判断栈是否空或满。

测试

int main()
{
	stack<int> s;
	int num[] = { 1,2,3,4,5,6 };
	for (int i = 0; i < sizeof(num)/sizeof(int); i++)
	{
		s.push(num[i]);
	}
	cout << "栈容量:" << s.size() << endl;
	while (!s.empty())
	{
		int value = s.top();
		printf("%d ", value);
		s.pop();
	}
	getchar();
}

输出:

压栈:1 2 3 4 5 6
栈容量:6
出栈:6 5 4 3 2 1

链栈

在这里插入图片描述
如图所示,链栈采用链式结构,每个节点包括一个数据元素和一个指向下一层节点的指针,栈底节点指针指向空。链栈没有最大容量限制。

链栈类声明

仍然使用模版。

/**********节点定义*********/
template<typename T>
struct ListNode
{
	T m_nValue;
	ListNode* m_pNext;
};
/**********链栈类**********/
template<typename T>
class LStack
{
public:
	LStack();
	~LStack();
private:
	ListNode<T>* p_Top;			//指向下一层节点指针
	int _size;				//节点数量
public:
	bool empty() const;			//堆栈为空则返回真
	void pop();				//移除栈顶元素
	void push(T value);			//在栈顶增加元素
	int size() const;			//返回栈中元素数目
	T top() const;				//返回栈顶元素
};

链栈类实现

与顺序栈不同,链栈压栈时不需要判断栈是否满。

template<typename T>
LStack<T>::LStack()		//构造空栈
{
	_size = 0;
	p_Top = nullptr;
}

template<typename T>
LStack<T>::~LStack()
{
}

template<typename T>
inline bool LStack<T>::empty() const
{
	if (p_Top == nullptr)
		return true;
	return false;
}

template<typename T>
inline void LStack<T>::pop()
{
	if (p_Top == nullptr)		//判断栈是否空
		return;
	ListNode<T>* r = p_Top;
	p_Top = p_Top->m_pNext;
	delete r;
}

template<typename T>
inline void LStack<T>::push(T value)
{
	ListNode<T>* r = new ListNode<T>;
	r->m_nValue = value;
	r->m_pNext = p_Top;
	p_Top = r;
	_size++;
}

template<typename T>
inline int LStack<T>::size() const
{
	return _size;
}

template<typename T>
inline T LStack<T>::top() const
{
	if (!p_Top)
		return 0;
	return p_Top->m_nValue;
}

测试

int main()
{
	LStack<int> s;
	int num[] = { 1,2,3,4,5,6 };
	cout << "压栈:";
	for (int i = 0; i < sizeof(num)/sizeof(int); i++)
	{
		s.push(num[i]);
		cout << num[i] << " ";
	}
	cout << endl;
	cout << "栈容量:" << s.size() << endl<<"出栈:";
	while (!s.empty())
	{
		int value = s.top();
		printf("%d ", value);
		s.pop();
	}
	getchar();
}

输出:

压栈:1 2 3 4 5 6
栈容量:6
出栈:6 5 4 3 2 1

操作与效果和顺序栈一样。

总结

栈分为顺序栈和链栈,在需要逆序使用或操作数据时非常方便。但因为栈通常不处理特别大量的数据,所以栈通常是定长的即有最大容量。所以我们一般使用顺序栈。但理解链栈的实现也非常有必要。(最后声明本文所有图片皆引用网络)

posted @ 2020-05-29 16:19  睡觉觉了哦  阅读(82)  评论(0)    收藏  举报