图解数据结构(2)——栈

转载自http://www.cppblog.com/guogangj/archive/2009/10/14/98565.html

前一篇讲解了最基本的东西,这篇就稍微前进一点点,讲一下栈,栈在英文中叫Stack,翻译成中文又叫“堆栈”,但决不能称为“堆”,这个要搞清楚,我们说的“栈”和“堆栈”指的都是Stack这种数据结构,但“堆”却是另外一个概念了,这里且不提。

栈最大特点是先进后出,如图:

可以看出,栈有几个最常见的方法,或者说必备的方法,Push,Pop和Top,即进栈,出栈和取最顶元素。从代码上看,栈如何实现呢?用数组好还是用单向链表好呢?其实都可以,我下面的例子是用数组实现的。

说了那么多,栈有什么用呢?下面就举一个最经典的例题——逆波兰表达式(RPN,Reversed Polish Notation)的求解。

什么是逆波兰表达式?我们表述一个算式通常是这样:X+Y,即:“操作数1 操作符 操作数2”,当然也有比较特别的,比如“sqrt(N)”,sqrt是操作符,N是操作数,而逆波兰表达式则很统一,先操作数,后操作符,为什么叫“逆波兰表达式”?因为有一个波兰人发明了波兰表达式,而逆的波兰表达式就叫“逆波兰表达式”了。看下图就能很好理解了:

所有的算式都可以用逆波兰表达式写出来,只是我这里的举例是为了方便起见,限制在整数的四则运算里。

那假如现在我们有一个逆波兰表达式,那我们如何求出它的值呢?这里我们的“栈”就要派上用场了,由于操作数在操作符前面,所以我们按顺序遍历这个表达式,遇到操作数的时候进栈,遇到操作符时候让操作数出栈并运算,然后把运算结果进栈。过程如下图所示:

遇到第一个操作符,“+”的时候,由于需要两个操作数,所以出栈两次,4和3出栈,执行加法运算,结果是7,7进栈……依此类推。

下面我给出参考代码,我的代码使用很简单,复制,粘贴到一个cpp文件中,编译此cpp文件即可,没别的依赖。

#include "stdio.h"
struct Cell
{
    int iType; // 0 - number, 1 - '+', 2 - '-', 3 - '*', 4 - '/'
    int iData;
};

class Stack
{
public:
    Stack(int iAmount = 10);
    ~Stack();

    //return 1 means succeeded, 0 means failed.
    int Pop(int& iVal);
    int Push(int iVal);
    int Top(int& iVal);
private:
    int *m_pData;
    int m_iCount;
    int m_iAmount;
};

Stack::Stack(int iAmount)
{
    m_pData = new int[iAmount];
    m_iCount = 0;
    m_iAmount = iAmount;
}

Stack::~Stack()
{
    delete m_pData;
}

int Stack::Pop(int& iVal)
{
    if(m_iCount>0)
    {
        --m_iCount;
        iVal = m_pData[m_iCount];
        return 1;
    }
    return 0;
}

int Stack::Push(int iVal)
{
    if(m_iCount<m_iAmount)
    {
        m_pData[m_iCount] = iVal;
        ++m_iCount;
        return 1;
    }
    return 0;
}

int Stack::Top(int& iVal)
{
    if(m_iCount>0 && m_iCount<=m_iAmount)
    {
        iVal = m_pData[m_iCount-1];
        return 1;
    }
    return 0;
}

int main(int argc, char* argv[])
{
    //12 3 4 + * 6 - 8 2 / +
    Cell rpn[11] = {
        0, 12,
        0, 3,
        0, 4,
        1, 0,
        3, 0,
        0, 6,
        2, 0,
        0, 8,
        0, 2,
        4, 0,
        1, 0};

    Stack st;

    // I won't check the return value for this is just a demo.
    int i, iOpt1, iOpt2;
    for(i=0; i<sizeof(rpn)/sizeof(Cell); i++)
    {
        switch(rpn[i].iType)
        {
        case 0: // number
            st.Push(rpn[i].iData);
            break;
        case 1: // +
            st.Pop(iOpt2);
            st.Pop(iOpt1);
            st.Push(iOpt1 + iOpt2);
            break;
        case 2: // -
            st.Pop(iOpt2);
            st.Pop(iOpt1);
            st.Push(iOpt1 - iOpt2);
            break;
        case 3: // *
            st.Pop(iOpt2);
            st.Pop(iOpt1);
            st.Push(iOpt1 * iOpt2);
            break;
        case 4: // /
            st.Pop(iOpt2);
            st.Pop(iOpt1);
            st.Push(iOpt1 / iOpt2);
            break;
        }
    }

    int iResult;
    st.Pop(iResult);
    printf("The result is %d\n", iResult);
    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
数据结构是计算机科学中非常重要的概念之一,它用于组织和存储数据以便有效地操作和访问。Java语言提供了丰富的数据结构库,包括数组、链表、、队列、树、图等。我将为你图解一些常见的数据结构及其在Java中的实现。 1. 数组(Array):数组是一种线性数据结构,它按照顺序存储相同类型的元素。在Java中,数组的大小在创建时就确定,并且可以通过索引访问和修改其中的元素。 2. 链表(Linked List):链表是一种动态数据结构,它由节点组成,每个节点包含数据和指向下一个节点的引用。在Java中,有单向链表和双向链表两种常见的实现方式。 3. (Stack):是一种后进先出(LIFO)的数据结构,类似于我们生活中的一叠盘子。在Java中,可以使用Stack类或者使用LinkedList类来实现。 4. 队列(Queue):队列是一种先进先出(FIFO)的数据结构,类似于我们日常生活中排队等待的情况。在Java中,可以使用Queue接口或者使用LinkedList类来实现队列。 5. 树(Tree):树是一种非线性的数据结构,它由节点和边组成,每个节点可以有多个子节点。在Java中,常见的树结构包括二叉树、二叉搜索树(BST)、AVL树、红黑树等。 6. 图(Graph):图是一种由节点和边组成的数据结构,节点表示实体,边表示实体之间的关系。在Java中,可以使用邻接矩阵或邻接表来表示图,并通过深度优先搜索(DFS)或广度优先搜索(BFS)等算法来遍历图。 这些只是数据结构中的一部分,Java还提供了其他更复杂的数据结构和算法库,可以根据具体需求选择合适的数据结构。希望以上图解能够帮助你更好地理解数据结构在Java中的实现。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值