目录
1、栈的概念及实现
栈的定义
-栈是一种特殊的线性表
-栈仅能在线性表的—端进行操作
栈顶(Top) : 允许操作的—端
栈底(Bottom) : 不允许操作的—端
栈的特性
-后进先出( Last In First Out)
栈的操作
-创建栈( Stack() )
- 销毁栈( ~Stack() )
-清空栈( clear() )
-进栈( push() )
-出栈( pop() )
-获取栈顶元素( top() )
-获取栈的大小( size() )
栈的实现
//Stack.h
#ifndef STACK_H
#define STACK_H
#include "Object.h"
namespace DTLib
{
template <typename T>
class Stack : public Object
{
public:
virtual void push(const T& e) = 0;
virtual void pop() = 0;
virtual T top() const = 0;
virtual void clear() = 0;
virtual int size() const = 0;
};
}
#endif // STACK_H
2、基于顺序存储结构的栈
栈的顺序实现
StaticStack设计要点
-使用原生数组作为栈的存储空间
-使用模板参数决定栈的最大容量
3、编程实验
基于顺序存储结构的栈 StaticStack.h
#ifndef STATICSTACK_H
#define STATICSTACK_H
#include "Stack.h"
#include "Exception.h"
namespace DTLib
{
template <typename T, int N>
class StaticStack : public Stack<T>
{
protected:
T m_space[N];
int m_top;
int m_size;
public:
StaticStack()
{
m_top = -1;
m_size = 0;
}
void push(const T& e)
{
if(m_size < N)
{
m_space[m_top+1] = e;
m_top++;
m_size++;
}
else
{
THROW_EXCEPTION(InvalidOperationException, "No space in current stack ...");
}
}
void pop()
{
if(m_size > 0)
{
m_top--;
m_size--;
}
else
{
THROW_EXCEPTION(InvalidOperationException, "No element in current stack ...");
}
}
T top() const
{
if(m_size > 0)
{
return m_space[m_top];
}
else
{
THROW_EXCEPTION(InvalidOperationException, "No element in current stack ...");
}
}
void clear()
{
m_size = 0;
m_top = -1;
}
int size() const
{
return m_size;
}
int capacity() const
{
return N;
}
};
}
#endif // STATICSTACK_H
main.cpp
#include <iostream>
#include "StaticStack.h"
using namespace std;
using namespace DTLib;
int main()
{
StaticStack<int, 5> stack;
try
{
stack.pop();
}
catch(const Exception& e)
{
cout << e.message() << endl;
cout << e.location() << endl;
}
for(int i = 0; i < 5; i++)
{
stack.push(i);
}
while(stack.size() > 0)
{
cout << stack.top() << " ";
stack.pop();
}
return 0;
}
StaticStack的效率缺陷
#include <iostream>
#include "StaticStack.h"
using namespace std;
using namespace DTLib;
class Test : public Object
{
public:
Test()
{
cout << "Test" << endl;
}
~Test()
{
cout << "~Test" << endl;
}
};
int main()
{
StaticStack<Test, 5> stack;
cout << stack.size() << endl;
return 0;
}
多次调用元素构造函数
3、基于链式存储结构的栈
链式栈的存储实现
top始终指向第一个结点
链式栈的设计要点
-类模板,抽象父类Stack的直接子类
-在内部组合使用LinkList类,实现栈的链式存储
-只在单链表成员对象的头部进行操作
链式栈的设计要点
4、编程实验
基于链式存储结构的栈 LinkStack.h
#ifndef LINKSTACK_H
#define LINKSTACK_H
#include "Stack.h"
#include "LinkList.h"
#include "Exception.h"
namespace DTLib
{
template <typename T>
class LinkStack : public Stack<T>
{
protected:
LinkList<T> m_list;
public:
void push(const T& e)
{
m_list.insert(0, e);
}
void pop()
{
if(m_list.length() > 0)
{
m_list.remove(0);
}
else
{
THROW_EXCEPTION(InvalidOperationException, "No element in current stack ...");
}
}
T top() const
{
if(m_list.length() > 0)
{
return m_list.get(0);
}
else
{
THROW_EXCEPTION(InvalidOperationException, "No element in current stack ...");
}
}
void clear()
{
m_list.clear();
}
int size() const
{
return m_list.length();
}
};
}
#endif // LINKSTACK_H
main.cpp
#include <iostream>
#include "LinkStack.h"
using namespace std;
using namespace DTLib;
class Test : public Object
{
public:
Test()
{
cout << "Test" << endl;
}
~Test()
{
cout << "~Test" << endl;
}
};
int main()
{
LinkStack<Test> stack;
cout << stack.size() << endl;
return 0;
}
5、栈的应用实践
符号匹配问题
在C语言中有一些成对匹配出现的符号
括号 :( ),[ ],{ },< >
引号 :' '," "
问题
如何实现编译器中的符号成对检测?
算法思路
-从第—个字符开始扫描
当遇见普通字符时忽略
当遇见左符号时压入栈中
当遇见右符号时弹出栈顶符号,并进行匹配
-结束
成功:所有字符扫描完毕,且栈为空
失败:匹配失败或所有字符扫描完毕但栈非空
6、编程实验
利用栈实现符号的成对匹配 main.cpp
#include <iostream>
#include "LinkStack.h"
using namespace std;
using namespace DTLib;
bool is_left(char c)
{
return (c == '(') || (c == '{') || (c == '[') || (c == '<');
}
bool is_right(char c)
{
return (c == ')') || (c == '}') || (c == ']') || (c == '>');
}
bool is_quot(char c)
{
return (c == '\'') || (c == '\"');
}
bool is_match(char l,char r)
{
return ((l == '(') && (r == ')')) ||
((l == '{') && (r == '}')) ||
((l == '[') && (r == ']')) ||
((l == '<') && (r == '>')) ||
((l == '\'') && (r == '\'')) ||
((l == '\"') && (r == '\"'));
}
bool scan(const char* code)
{
LinkStack<char> stack;
bool ret = true;
int i =0;
code = (code == NULL) ? "" : code;
while(ret && (code[i] != '\0'))
{
if(is_left(code[i]))
{
stack.push(code[i]);
}
else if(is_right(code[i]))
{
if( (stack.size() > 0) && is_match(stack.top(), code[i]) )
{
stack.pop();
}
else
{
ret = false;
}
}
else if(is_quot(code[i]))
{
if(stack.size() == 0 || !is_match(stack.top(), code[i]))
{
stack.push(code[i]);
}
else if(is_match(stack.top(), code[i]))
{
stack.pop();
}
}
i++;
}
return ret && (stack.size() == 0);
}
int main()
{
cout << scan("abcd") << endl;
cout << scan("a{b()c}\'d\'e") << endl;
cout << scan("a\"bcd") << endl;
cout << scan("(") << endl;
cout << scan("else if(is_quot(code[i])){if(stack.size() == 0 || !is_match(stack.top(), code[i])){stack.push(code[i]);}else if(is_match(stack.top(), code[i])){ stack.pop();}}") << endl;
return 0;
}
7、小结
栈是—种特殊的线性表
栈只允许在线性表的—端进行操作
StaticStack使用原生数组作为内部存储空间
StaticStack的最大容量由模板参数决定
链式栈的实现组合使用了单链表对象
在单链表的头部进行操作能够实现高效的入栈和出栈操作
栈 "后进先出" 的特性适用于检测成对出现的符号
栈非常适合于需要“就近匹配”的场合
8、深度思考
开放性问题
使用单链表对象实现链式栈时,为什么选择在单链表的头部进行操作?
如果选择在尾部进行操作是否也能实现栈的功能?