本系列文章将学习一种常见的数据结构——Stack,具体内容包括:Stack基类、StackAsArray、StackAsLinkedList以及Stack的应用(计算infix expression)。
一、栈(stack)
栈(也可翻译为堆叠)是一种LIFO(for last in, first out)的元素集合体。栈支持两种基本的操作:push——将新元素加入到栈顶,pop——从栈顶取出一个元素。(参考Wikipedia)
栈主要用于“缓存”。比如:(场景1)桌上有一叠文件,(最方便的情况下)你可以将新文件放到这叠文件顶部或者从这叠文件顶部取走一份文件。(场景2)你正在进行几项项task1、task2、task3,这时老板跑过来又给你下了一个临时的紧急tmp task,你需要现将task1、task2、task3缓存,先完成tmp task,再完成task1、task2、task3。
计算机程序中的函数调用也要用到栈,需要先将主函数入栈,先执行被调函数,再出栈,恢复主函数后续执行步骤。
由上图可知,栈的基本操作有三个。接口定义如下:
#pragma once
#include "Container.h"
class Stack : public virtual Container
{
public:
virtual Object & Top() const= 0;
virtual void Push(Object &) = 0;
virtual Object & Pop() = 0;
};
注:这里的“虚继承”是为了后续的“多继承”。
二、StackAsArray(点击打开链接)
我们先用数组来实现栈,这里用到之前“基础数据结构之数组与链表”系列文章的动态数组。
#pragma once
#include "Stack.h"
#include "DynamicArray.h"
using namespace FoundationalDataStructure;
class StackAsArray : public Stack
{
private:
Array<Object*> array;
class Iter;
protected:
int CompareTo(Object const &) const;
public:
StackAsArray(unsigned int);
~StackAsArray();
void Purge();
void Accept(Visitor &) const;
Iterator & NewIterator() const;
Object & Top()const;
void Push(Object &);
Object & Pop();
friend class Iter;
};
class StackAsArray::Iter : public Iterator
{
public:
Iter(const StackAsArray &);
void Reset();
bool IsDone() const;
Object& operator * () const;
void operator ++();
private:
const StackAsArray & stack;
unsigned int position;
};
迭代器与容器伴生。
#include "stdafx.h"
#include "StackAsArray.h"
#include "NullObject.h"
StackAsArray::StackAsArray(unsigned int size)
: array(size)
{
}
StackAsArray::~StackAsArray()
{
Purge();
}
void StackAsArray::Purge()
{
if (IsOwner())
{
for (unsigned int i = 0; i < count; ++i)
delete array[i];
}
count = 0;
}
void StackAsArray::Accept(Visitor & visitor) const
{
for (unsigned int i = 0; i < count && !visitor.IsDone(); ++i)
visitor.Visit(*array[i]);
}
Iterator & StackAsArray::NewIterator() const
{
return *new Iter(*this);
}
void StackAsArray::Push(Object & object)
{
if (count == array.Length())
array.SetLength(2 * count);//throw std::domain_error("stack is full");
array[count++] = &object;
}
Object & StackAsArray::Pop()
{
if (count == 0)
throw std::domain_error("stack is empty");
else if (count == array.Length() / 2)
array.SetLength(count);
return *array[--count];
}
Object & StackAsArray::Top() const
{
if (count == 0)
throw std::domain_error("stack is empty");
return *array[count - 1];
}
int StackAsArray::CompareTo(Object const & object) const
{
//const StackAsArray & stack =
// dynamic_cast<const StackAsArray &>(object);
//return ::Compare(array, stack.array);
return -1;
}
// The implementation of Iter
StackAsArray::Iter::Iter(const StackAsArray & _stack)
: stack(_stack)
{
Reset();
}
bool StackAsArray::Iter::IsDone() const
{
return position >= stack.count;
}
Object& StackAsArray::Iter::operator * () const
{
if (position < stack.count)
return *stack.array[position];
else
return NullObject::Instance();
}
void StackAsArray::Iter::operator++()
{
if (position < stack.count)
++position;
}
void StackAsArray::Iter::Reset()
{
position = 0;
}