三、栈的实现

栈的定义:栈是一种特殊的线性表(容器)。

栈仅能在线性表的一端进行操作:

栈顶(top):允许操作的一端;

栈底(bottom):不允许操作的一端。

栈的特性:后进先出(Last in First Out)

栈的操作(函数):创建(stack())、销毁(~stack())、清空(clear())、进栈(push())、出栈(pop())、获取栈顶元素(top())、获取栈的大小(size())。

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;
};


一、StaticStack顺序栈设计要点:

类模板:使用原生数组作为栈的存储空间

             使用模板参数(<T, N>)决定栈的最大容量


代码实现如下:

template <typename T, int N>
class StaticStack : public Stack<T>
{
protected:
    T m_space[N];  //栈存储空间,N为模板参数
    //此处已经涉及到泛指类型进行具体对象的构造了,所以效率不高。
    int m_top;  //栈顶标志
    int m_size; //当前栈的大小
    
public:
    StaticStack()
    {
        m_top = -1;
        m_size = 0;
    }
    
    int capacity() const
    {
        return N;
    }
    
    void push(const T& e)
    {
        if( m_size < N)
        {
            m_space[m_top + 1] = e;  //为了异常安全,在复制操作符出现异常的情况下,栈内部的数据并不会出现改变
            m_top++;     //e可能是一个类类型,如果真的这个类类型未进行复制操作符重载,抛出异常前不对m_top做任何改变
            m_size++;
        }
        else
        {
           //抛出异常
        }
    }
    
    void pop()
    {
        if( m_size > 0)
        {
          m_top--;
          m_size--;
        }
        else
        {
          //抛出异常
      }   
 }    
T top() const { if( m_size > 0) { return m_space[m_top]; //直接返回栈顶的值 } else { //抛出异常 } } void clear() { m_top = -1; m_size = 0; } int size() const { return m_size; } };

在主函数中测试如下代码:

int main()
{
    StaticStack<int, 5> ss;

    for(int i=0; i<5; i++)
    {
        ss.push(i);
    }

    while (ss.size() > 0)
    {
        cout << ss.top();

        ss.pop();
    }

    return 0;
}

输出效果为:


小结:栈只允许在线性表的一端进行操作。

注意:StaticStack使用原生数组作为内部存储空间

          StaticStack的最大容量由模板参数决定。


二、(LinkStack)链式栈的实现

问题提出:当存储的元素为类类型时,StaticStack的对象在创建时,会多次调用元素类型的构造函数,影响效率。原因在于使用原生数组作为存储空间,在创建栈对象的时候,会调用泛指类型的构造函数。

链式栈的设计要点(本质就是链表):

1、类模板,抽象父类Stack的直接子类;

2、在内部组合使用LinkList类,实现栈的链式存储;

3、只在单链表成员对象的头部进行操作


实现代码如下:

template <typename T>
class LinkStack : public Stack <T>
{
protected:
    LinkList<T> m_list;
public:
    void push(const T& e)  //O(1)  注:此处为头插法
    {
        m_list.insert(0,e);
    }

    void pop()   //O(1  )
    {
        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()  //O(n)
    {
        m_list.clear();
    }

    int size() const  //O(1)
    {
        return m_list.length();
    }
};

在主函数中编写如下代码:

class Test : public Object
{
  public:
    Test()
    {
        cout << "Test()" << endl;
    }

    ~Test()
    {
        cout << "~Test()" << endl;
    }
};

int main()
{
    LinkStack<Test> ls;

    cout << ls.size() << endl;

    return 0;
}
运行后发现,构造函数和析构函数均未执行,效率提升。


栈的应用之一:符号匹配问题:



bool scan(const char* code)
{
    LinkStack<char> stack;
    int i=0;
    bool ret = true;

    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()) && 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);
}

小结:链式栈的实现组合使用了单链表对象(又是不同的数据结构)。

在单链表的头部进行操作能够高效的入栈和出栈操作。

栈“后进后出”的特性适用于检测成对出现的符号。

栈非常适合于需要“就近匹配”的场合。



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值