顺序栈的问题
当存储的元素类型为类类型,StaicStack 的对象在创建时会多次调用元素类型的构造函数,影响效率!
文件:main.cpp
#include <iostream>
#include "StaitcStack.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() = " << stack.size() << endl;
return 0;
}
输出:
Test()
Test()
stack.size() = 0
~Test()
~Test()
~Test()
~Test()
~Test()
原因: T m_space[N];
链式栈的存储实现
链式栈的设计要点
- 类模板,抽象父类 Stack 的直接子类
- 在内部组合使用 LinkList 类,实现栈的链式存储
- 只在单链表成员对象的头部进行操作
编程实验:基于链式存储结构的栈
文件: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>
{
public:
void push(const T &e) override // O(1)
{
m_list.insert(0, e);
}
void pop() override // O(1)
{
if (m_list.length() > 0)
{
m_list.remove(0);
}
else
{
THROW_EXCEPTION(InvalidOpertionExcetion, "No element in current LinkStack ...");
}
}
T top() const override // O(1)
{
if (m_list.length() > 0)
{
return m_list.get(0);
}
else
{
THROW_EXCEPTION(InvalidOpertionExcetion, "No element in current LinkStack ...");
}
}
void clear() override // O(n)
{
m_list.clear();
}
int size() const override // O(1)
{
return m_list.length();
}
~LinkStack() // O(n)
{
clear();
}
protected:
LinkList<T> m_list;
};
}
#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_1;
cout << "stack_1.size() = " << stack_1.size() << endl;
cout << "-------" << endl;
LinkStack<int> stack_2;
for (int i=0; i<5; ++i)
{
stack_2.push(i);
}
while (stack_2.size() > 0)
{
cout << stack_2.top() << endl;
stack_2.pop();
}
return 0;
}
输出:
stack_1.size() = 0
-------
4
3
2
1
0
栈的应用实践
符号匹配问题
在 C 语言中有一些成对匹配出现的符号
括号: (), [], {}, <>
引号: '', ""
问题: 如何实现编译器中的符号成对检测?
算法思路
从第一字符开始扫描
- 当遇见普通字符时忽略
- 当遇见左符号时压入栈中
- 当遇见右符号时弹出栈顶符号,并进行匹配
结束
- 成功:所有字符扫描完毕,且栈为空
- 失败:匹配失败或所有字符扫描完毕但栈非空
编程实验:符号匹配问题
文件: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_macth(char l, char r)
{
return ((l == '(') && (r == ')')) ||
((l == '{') && (r == '}')) ||
((l == '[') && (r == ']')) ||
((l == '<') && (r == '>')) ||
((l == '\'') && (r == '\'')) ||
((l == '\"') && (r == '\"'));
}
bool scan(const char *code)
{
bool ret = true;
int i = 0;
LinkStack<char> stack;
code = (code == nullptr) ? "" : 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_macth(stack.top(), code[i]))
{
stack.pop();
}
else
{
ret = false;
}
}
else if (is_quot(code[i]))
{
if (stack.size() == 0 || !is_macth(stack.top(), code[i]))
{
stack.push(code[i]);
}
else if (is_macth(stack.top(), code[i]))
{
stack.pop();
}
}
++i;
}
return ret && (stack.size() == 0);
}
int main()
{
cout << scan("<a{b(\'x\')c}d>") << endl;
return 0;
}
输出:
1
小结
- 链式栈的实现组合使用了单链表对象
- 在单链表的头部进行操作能够实现高效的入栈和出栈操作
- 栈 “后进先出” 的特性适用于检测成对出现的括号
- 栈非常适合于需要 “就近匹配” 的场合
以上内容整理于狄泰软件学院系列课程,请大家保护原创!
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。