数据结构与算法(七) 栈以及栈的应用

栈的应用非常的广泛,在C++的STL中,提供了用数组实现的栈。把线性表的插入和删除操作都限制在同一端,就得到栈的数据结构。是一个后进先出的数据结构。

因为栈是一种特殊的线性表,所以可以从线性表类派生出stack类。通过派生的方法可以降低栈的开发难度,但是代码的执行效率也会降低。

定义和应用:

栈:一种特殊的线性表,插入和删除操作都限制在表的同一端进行,这端称为栈顶,另一端称为栈底。

应用: 计算机执行递归函数就用到了栈。

1.直接创建基于数组的栈:
arrayStack类:

arraystack.h文件

#ifndef ARRAY_STACK_H
#define ARRAY_STACK_H
#include <iostream>
#include "E:\back_up\code\c_plus_code\sparseMatrix\external_file\stackemptyException.h"   // 异常类 
using namespace std;

template<typename T=int>
class arrayStack
{
	private:
	T* element;
	int elem_number;    // 栈中元素的个数 
	int capacity;     // 栈的容量 
	void ensureCaoacity();
	
	// stack ADT
	public:
    arrayStack(int init_capacity=10);
    ~arrayStack();
    arrayStack(const arrayStack& stack);   // 拷贝构造函数
	bool empty() const;
	int size() const;    // 返回栈中元素的个数 
    T top() const;   // 返回栈顶元素的值
	void pop();      // 删除栈顶元素
	void push(T x);  // 入栈 
	void print_stack() const;
	// 定义友元函数; 
	 
};

// arrayStack实现
template<typename T>
arrayStack<T>::arrayStack(int init_capacity)
{
	elem_number = 0;
	capacity = init_capacity;
	element = new T[capacity];
} 

template<typename T>
arrayStack<T>::~arrayStack()
{
	delete []element;
}

template<typename T>
arrayStack<T>::arrayStack(const arrayStack& stack)
{
	elem_number = stack.elem_number;   // 栈中的元素个数
	capacity = stack.capacity;
	element = new T[capacity];
	// 赋值元素
	for(int i=0; i<elem_number; i++)
	{
		element[i] = stack.element[i];
	} 
}

template<typename T>
void arrayStack<T>::ensureCaoacity()
{
	if(elem_number>=capacity)
	{
		T* old = element;
		// delete element;   
		// delete的本质是: delete之后,下次再重新申请的时候可以
		// 再申请这块内存地址,对于这块地址的内容,没有进行清空处理(也没有必要) 
		capacity = elem_number*2;
		element = new T[capacity];
		for(int i=0; i<elem_number; i++)
		{
			element[i] = old[i];   
		}
		delete []old;
	}
	
	// 还可以添加栈中数组大小动态减小的代码 
}

template<typename T>
bool arrayStack<T>::empty() const
{
	return elem_number==0;
} 

template<typename T>
int arrayStack<T>::size() const   // 返回栈中元素的个数 
{
	return elem_number;
}

template<typename T>
T arrayStack<T>::top() const
{
	if(empty())
	   throw stack_empty_exception(0); 
	return element[elem_number-1];    // 返回栈顶元素的值 
}

template<typename T>
void arrayStack<T>::pop()
{
	if(empty())
	   throw stack_empty_exception(0);
	elem_number--;
} 

template<typename T>
void arrayStack<T>::push(T x)
{
	ensureCaoacity();
	element[elem_number++] = x;
} 

template<typename T>
void arrayStack<T>::print_stack() const
{
	if(empty())
	{
		cout << "The stack is empty" << endl;
	}
	else
	{
		for(int i=0; i<elem_number; i++)
		{
			cout << element[i] << " ";
		}
		cout << endl;
	}	
}

#endif
 

在栈为空的时候,不能进行出栈操作,这一功能由异常类实现:

stackemptyException.h文件

// 自定义异常类:
#ifndef STACK_EMPTY_EXCEPTION
#define STACK_EMPTY_EXCEPTION
#include <stdexcept>
using namespace std;    // 因为stdexcept
class stack_empty_exception : public runtime_error
{
	private:
	int current_stack_size;
	
	public:
	stack_empty_exception(int stack_size):runtime_error("Stack is empty")
	{
		this->current_stack_size = stack_size;
	}
	void display_error_info()
	{
		cout << "----------------------------" << endl;
		cout << "The stack size is " << current_stack_size << endl;
		cout << "----------------------------" << endl;
	}
};
#endif


 

测试文件

main.cpp

#include <iostream>
#include "E:\back_up\code\c_plus_code\sparseMatrix\external_file\arraystack.h"
using namespace std;

int main(int argc, char *argv[])
{
	arrayStack<int> stack(10);
	try    // 异常测试 
	{
		stack.pop();
	}
	catch(stack_empty_exception& ex)
	{
		cout << ex.what() << endl;
		ex.display_error_info();
	}
	
	try    // 异常测试 
	{
		stack.pop();
	}
	catch(stack_empty_exception& ex)
	{
		cout << ex.what() << endl;
		ex.display_error_info();
	}
	
	stack.print_stack(); 
	for(int i=0; i<13; i++)
	{
		stack.push(i+1);
	}
	stack.print_stack();
	cout << "stack size: " << stack.size() << endl;
	while(!stack.empty())   // 出栈 
	{
		cout << stack.top() << " ";
		stack.pop();
	}
	cout << endl;
}

运行结果:

2

添加新的方法,将stack中的数据分为a,b两部分:

template<typename T>
void arrayStack<T>::split_stack(arrayStack& stack_a, arrayStack& stack_b)
{
	if(elem_number<2)
	   throw stack_empty_exception(2); 
	int criterion = elem_number/2;
	int count = 0;
	while(elem_number>0)
	{
		if(count < criterion)
		{
			stack_a.push(element[elem_number-1]);
			count++;
			elem_number--;
		}
		else
		{
			stack_b.push(element[elem_number-1]);
			count++;
			elem_number--;
		}
		
	}
}

测试函数:

main.cpp

#include <iostream>
#include "E:\back_up\code\c_plus_code\sparseMatrix\external_file\arraystack.h"
using namespace std;

int main(int argc, char *argv[])
{
	arrayStack<int> stack(10);
	//stack.print_stack(); 
	for(int i=0; i<10; i++)
	{
		stack.push(i+1);
	}
	stack.print_stack();
	
	arrayStack<int> a;
	arrayStack<int> b;
	try
	{
		stack.split_stack(a, b);
		cout << "split stack into two parts" << endl;
		cout << "stack_a: ";
		a.print_stack();
		cout << "stack_b: ";
	    b.print_stack();
	}
    catch(stack_empty_exception& ex)
    {
    	cout << ex.what() << endl;
    	ex.display_error_info();
    }
}

运行结果:

2. 此外栈和可以由线性表的类派生而来,如arrayLIst类和chain类

3.栈的应用:

(a). 括号匹配:

例如:(a*(b+c)+d)进行括号匹配:从左到右扫描字符串,没哟个右括号都与最近扫描到的未匹配的左括号进行匹配

#include <iostream>
#include "E:\back_up\code\c_plus_code\sparseMatrix\external_file\arraystack.h"
#include <string>
using namespace std;


void printMatchedPairs(string expr)
{
	arrayStack<int> s;
	int expr_length = (int)expr.size();
	// 扫描表达式
	for(int i=0; i<expr_length; i++)
	{
		if(expr.at(i)=='(')
		{
			s.push(i);    // 左括号的位置 
		}
		else
		{
			if(expr.at(i)==')')    // 如果是右括号,则进行匹配 
			try
			{
				cout << s.top() << " " << i << endl;
				s.pop();
			}
			
			catch(stack_empty_exception& ex)
			{
				cout << "NO match for ) at " << i << endl;
			}
		} 
	} 
	
	while(!s.empty())
	{
		cout << "NO match for left bracket" << s.top() << endl;
		s.pop();
	}
	
}


int main(int argc, char *argv[])
{
	string expression("((a+b)*2)+3");
	printMatchedPairs(expression);

}

输出:
1 5

0 8
 

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值