数据结构--链式栈LinkStack

上一讲学习了栈以及顺序栈的实现,本讲我们继续学习另一种栈--链式栈

什么叫链式栈,就是和链表类似,不过它需要遵守栈的特性,只能操作其中一端,我们不需要从头创建一个链式栈,只在单链表的基础上进行实现即可。

链式栈的设计要点:

类模板编程。

继承自抽象父类Stack。

在内部组合使用LinkList类实现链式存储。

只在单链表的其中一端进行操作。

具体实现如下:

template< typename T>
class LinkStack : public Stack<T>
{
protected:
    LinkList<T> m_list;

public:

    void push(const T& obj)
    {
        m_list.insert(0,obj);//操作d单链表的第0个节点。
    }
    void pop()
    {
        if(m_list.length() > 0)
            m_list.remove(0);
        else
            THROW_EXCEPTION(InvalidOperationException, "mo element to pop...");
    }

    int size()const//const对象调用
    {
        return m_list.length();
    }

    T top()const//const 对象调用
    {
        if(m_list.length() > 0)
            return m_list.get(0);
        else
            THROW_EXCEPTION(InvalidOperationException, "mo element to top...");
    }


    void clear()
    {
        m_list.clear();
    }

};

总体看来实现其实比顺序栈更简单,借用了单链表的实现,单链表的实现具体请看单链表那一篇文章。


小算法

既然文章已经开始了,又不能就这么匆匆结束,所以接下来实现一个小算法,具体要求如下:

扫描一串代码,进行左右操作符匹配,返回匹配结果,使用链式栈实现。

算法思路:

一、从第一个字符开始扫描

1、扫描到普通符号时忽略

2、扫描到左操作符时让符号入栈

3、扫描到右操作符时将栈顶符号并与之进行匹配,成功匹配进行出栈操作,失败直接可以返回。

二、扫描结束

成功:所有字符扫描完毕且栈的状态为空。

失败:匹配失败或者扫描完成后栈不为空。


实现

在实现之前需要一些辅助函数,对左右操作符进行判断,由于单引号和双引号左右都一样,需要单独处理,以及实现操作符之间匹配函数。


操作符判定:

bool isLeft(char c)//左操作符
{
    return ( c == '(' ) || ( c == '{' ) || ( c == '[' ) || ( c == '<' );
}

bool isRight(char c)//右操作符
{
    return ( c == ')' ) || ( c == '}' ) || ( c == ']' ) || ( c == '>' );
}

bool isQuot(char c)//引号
{
    return (c == '\'') || (c == '\"');
}



操作符匹配:

bool isMatch(char l, char r)
{
    return  ( (l == '(')  && (r == ')') ) ||
            ( (l == '{')  && (r == '}') ) ||
            ( (l == '[')  && (r == ']') ) ||
            ( (l == '<')  && (r == '>') ) ||
            ( (l == '\'') && (r == '\'') ) ||
            ( (l == '\"') && (r == '\"') );
}



最后根据算法思路实现扫描函数:

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

    if(str != NULL)
    {
        while(ret && str[i] != '\0')
        {
            if( isLeft(str[i]) )//处理左操作符
            {
                stack.push(str[i]);
            }
            else if( isRight(str[i]) )//处理右操作符
            {
                if( (stack.size() > 0) && isMatch(stack.top(), str[i]) )
                {
                    stack.pop();
                }
                else
                {
                    ret = false;
                }

            }
            else if( isQuot(str[i]) )//处理引号
            {
                if( (stack.size() == 0) || (!isMatch(stack.top(), str[i])) )
                {
                    stack.push(str[i]);
                }
                else if(isMatch(stack.top(),str[i]))
                {
                    stack.pop();
                }
            }
            i++;
        }
    }
    else
    {
        ret = false;
    }

    return (ret && stack.size() == 0);

}


程序分析:

遇到左操作符时直接入栈。

遇到右操作符先判断栈是否为空且匹配是否成功,要是成功的话就直接弹出栈顶元素

遇到引号先判断栈是否为空或者匹配是否成功,如果栈为空或者匹配失败就将当前扫描到的引号入栈,如果匹配成功了就将栈顶元素弹出。

然后自增循环变量i扫描下一个字符。
当扫描完毕后判断条件变量和栈的状态是否满足要求,当条件变量为真且栈为空时就返回匹配结果为真,否则就匹配失败,返回假。


总结:

链式栈实现组合使用了单链表类。

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

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

栈非常适合于就近匹配场合


最后的测试代码请大家自行实现,在此处不占用篇幅。


栈的学习到此为止,下一阶段学习队列,在此感谢狄泰唐老师。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值