数据结构--3.3栈的实现

基本操作

入栈、出栈相当于插入、删除

实现方式

链表、数组。
链表:可以通过继承链表来实现。本文略
数组实现:避免了指针,更流行,唯一的潜在危害是需要提前声明一个数组的大小,但是在典型的应用中,任一时刻栈元素的个数不会太大,所以此危害可忽略。

#include <iostream>
using namespace std;
/**********************************************************************
栈基本操作
用链表实现的栈结构的缺点是总是需要动态的分配资源,如果想解决这个问题可以
用另一个栈结构存储被删除的数据,而使用数组实现则效率更高一些,唯一的不足
就是就是需要提前的申请空间大小,这里只是实现了一些栈简答操作。
增加了find_min操作。
**********************************************************************/

typedef struct StackRecord
{
	int m_capcity;//栈容量
	int m_topIndex;//栈顶索引,空栈为-1
	int* m_pArray;//存放栈元素的数组
} *Stack;

Stack CreatStack(int capacity);//创建空栈
void push(Stack s, int x);
void pop(Stack s);
int top(Stack s);
void MakeEmpty(Stack s);
bool IsDisposeStack(Stack s);//释放栈
bool IsFull(Stack s);
bool IsEmpty(Stack s);
void Traverse(Stack s);//从栈顶到栈低遍历
int main()
{
	Stack s = CreatStack(5);
	push(s, 5);
	push(s, 19);
	push(s, 10);
	Traverse(s);
	cout << "一次出栈" << endl;
	pop(s);
	Traverse(s);
	int sTop = top(s);
	cout << "栈顶元素:" << top << endl;
	cout << "置空栈:";
	MakeEmpty(s);
	Traverse(s);
	if (IsDisposeStack(s))
		cout << "释放成功" << endl;
	else
		cout << "释放不成功" << endl;
	system("pause");
	return 0;
}


Stack CreatStack(int capacity)
{
	if (capacity < 0)
		cout << "栈太小" << endl;
	Stack stack = new StackRecord;
	stack->m_capcity = capacity;
	stack->m_pArray = new int[capacity];
	MakeEmpty(stack);
	return stack;
}

void push(Stack s, int x)
{
	if (!IsFull(s))
	{
		s->m_topIndex += 1;
		s->m_pArray[s->m_topIndex] = x;
	}
	else
		cout << "栈已满,入栈失败" << endl;
}

void pop(Stack s)
{
	if (!IsEmpty(s))
	{
		s->m_topIndex -= 1;
	}
	else
		cout << "空栈,弹出失败" << endl;
}

int top(Stack s)
{
	if (!IsEmpty(s))
		return s->m_pArray[s->m_topIndex];
	else
		cout << "空栈,栈顶元素不存在" << endl;
}

void MakeEmpty(Stack s)
{
	s->m_topIndex = -1;
}

bool IsDisposeStack(Stack s)
{
	if (s->m_pArray != nullptr)
	{
		delete[] s->m_pArray;
		s->m_pArray = nullptr;
	}
	delete s;
	s = nullptr;
	if (s == nullptr)
		return true;
}

bool IsFull(Stack s)
{
	if (s->m_topIndex == s->m_capcity - 1)
		return true;
	return false;
}

bool IsEmpty(Stack s)
{
	if (s->m_topIndex == -1)
		return true;
	return false;
}

void Traverse(Stack s)
{
	cout << "从栈顶到栈低遍历:";
	if (!IsEmpty(s))
	{
		int tmp = s->m_topIndex;
		while (tmp != -1)
		{
			cout << s->m_pArray[tmp] << " ";
			tmp--;
		}
		cout << endl;
	}
	else
		cout << "栈为空" << endl;
}

应用:

1.平衡符号:例如检验符号是否成对出现
读入字符直到文件尾,遇到左半边字符入栈,右半边字符出栈。如果到最后栈为空,则封闭,否则报错。复杂度为线性。
2.后缀表达式(逆波兰表达式):优点,当一个表达式以后缀形式给出时,无需知道任何优先规则。
3.将中缀表达式(标准)转化为后缀表达式:利用一个放操作符的栈,一个放输出的栈。
4.函数调用:

注意:

栈为了速度,一般不检查栈溢出,所以使用栈,当栈过大时(失控递归),会发生一些奇怪的事。

尾递归:

尾递归完全合法且看起来无害,但也会使你越出栈空间,eg:

//利用尾递归遍历(使用极端不当):尾递归设计在最后一行进行递归调用
//如果链表含有20000个元素,嵌套调用20000个活动记录的一个栈
//活动记录由于包含的全部信息特别庞大,可能会越过栈空间
void PrintList(List L)
{
        L = L->m_pNextNode;
	if (L != nullptr)
	{
		cout << L->m_element << "";
		PrintList(L->m_pNextNode);
	}
}


//使用goto语句消除尾递归
void PrintListGoto(List L)
{
	top:
	if (L != nullptr)
	{
		cout << L->m_element << "";
		L = L->m_pNextNode;
		goto top;
	}
}

猜你喜欢

转载自blog.csdn.net/vict_wang/article/details/83269007