数据结构之栈

栈、队列、优先级队列和双端队列是特殊的线性表,逻辑结构与线性表相同

栈是先进后出的线性表,只能在表的末端进行插入删除操作,最开始加进去的叫做栈底,最后加进去的是栈顶,只能在栈顶进行操作

栈的存储表示有两种:顺序栈(基于数组的存储)和链式栈(基于链表的存储)


 1.顺序栈

顺序栈的头指针是*elements,存放最大元素个数是maxSize,栈顶元素的位置由下标指针top指定

当top=-1时,置栈为空,在插入时,先让栈顶指针加一,指到当前可加入新元素的位置,再将新元素插入

top==maxSize-1,表明栈已满,再加入新的元素会出现栈溢出

进栈 elements[++top] = x;把x进栈,先让指针+1在进栈,注意是前缀自加

当退栈时相反,先取指针在自减 x=elements[top--];后缀自减

当程序同时需要两个栈的时候,我们可以定义一个足够的栈空间,两端分别设为栈底,用b[0]=-1和b[1]=maxSize表示,让栈顶t[0]和t[1]分别向中间扩展,直到两栈相遇才会发生溢出。进栈时t[0]+1,t[1]-1,退栈时t[0]-1,t[1]+1,这里的0和1是指左栈和右栈,并不是下标

数据结构之栈_第1张图片

在双栈的情况下,初始化为b[0]=t[0]=-1;t[1]=b[1]=maxSize

栈满条件为指针相遇,即t[0]+1=t[1],而不是t[0]+t[1]=maxSize

栈空为t[0]=b[0]或者t[1]=b[1]


2.链式栈

链式栈便于节点的插入和删除,链式栈的栈顶在链表的表头,新结点的插入和删除都是在表头进行的

进栈时top=new LinkNode(x,top);建立一个x的结点,该结点的指向是top的指向,即指向原来top指向的表头结点,再用top来指向该节点

退栈时LinkNode *p=top;top=top->link;x=p->data;delete p;

同时使用n个链表栈 LinkNode *s = new LinkNode[n]


栈的出栈顺序有很多种,有时候进栈和退栈交替发生,导致顺序多种,但是比出栈项顺序靠前的一定在栈内,比如序列ABCDEFGH,依次进栈,可能ABC进栈之后在C出栈之后D在进栈,这样导致了出栈顺序的多元化,但是C出栈时,在C前面进栈的AB一定压在栈中  


栈的应用

1.表达式的计算

表达式有三种表示方法:前缀、中缀、后缀,我们平时常用的是中缀表达式

中缀:数+符+数 A+B;前缀:符+数+数 +AB;后缀:数+数+符 AB+

因为后缀表达式只用一个栈,而前缀和中缀需要两个栈,而且中缀表达式设计操作符优先级的问题,所以一般程序选用后缀表达式

后缀表达式计算:从左到右扫描表达式,并使用一个栈保存操作数或者计算结果 ,如果是操作数就将其压入栈中,如果是操作符就连续从栈中退出两个操作数Y和X,并进行计算XY的操作,(注意操作顺序,取得时候先取的是右值再取左值,计算的时候是左值<符号>右值)最后将计算结果重新压入栈中,最后栈顶存放的就是计算结果

中缀表达式转化为后缀表达式:

想要实现转化,要考虑各种符号的优先级

数据结构之栈_第2张图片

isp叫做栈内优先数,icp叫做栈外优先数,优先数越大,优先级越高

 转化过程:

1.操作符栈初始化,结束符#进栈,读入首字符ch

2.ch是操作数就直接输出,读取下一字符ch,如果ch是操作符判断ch优先级icp和当前在栈顶的操作符op的isp优先级

icp(ch)>isp(op),ch进栈,读取下一字符ch

icp(ch)

icp(ch)==isp(op),退栈但是不输出,如果退出的是‘(’,读取下一字符ch

重复,直到ch=”#“,同时栈顶操作符也是”#“,停止

 

栈与递归

递归通俗点讲就是从上而下到底,把大问题转化为子问题,只要子问题解决了,那么大问题也就解决了,子问题解决的时候也依靠他自己的子问题,这样一层一层的探下去,直到遇见问题自己可以解决的时候,接着在一层一层向上调用回归,最终问题得以解决。这是一种分而治之的策略,也叫作分治法。

递归必须要有结束条件,否则就会出现一直递归的现象

递归和递推是不同的,递归是想知道第一个,得先知道第二个,知道第二个得先知道第三个,这样一直往下找直到第N个自己就知道,然后一层一层返回,最终第一个知道了;而递推则是知道了第一个,通过第一个推出了第二个,一次类推,推出了第N个的结果。这样解释应该还算通俗易接受

递推的问题可以用递归解决,也可以用迭代的方法解决


递归在设计算法中的应用

1.分治法和减治法

这里再说一下分治法和减治法

分治法采用分而治之的思想,就是将一个大问题分解为两个小问题,在对子问题求解,子问题合并起来就是整体的解,常用递归来实现,如果要变成非递归的就用栈来辅助实现

减治法就是将将原来的问题降低一个等级求解,在将子问题的解回头求原来的解

分治法:快速排序、归并排序、二叉树遍历

减治法:B树求给定值、折半查找、斐波那契查找、插值查找、二叉树求最大最小值给定值、线性表求最大最小值给定值长度等

2.回溯法

回溯法类似于深度优先搜索,先假设一条路径可以,然后一步一步走下去,当走不下去的时候,返回上一点在重新选择尝试回溯法常使用递归来求解,并且使用栈来保存回退路径

回溯法:二叉树遍历、深度优先搜索、根到节点路径、八皇后问题、迷宫问题  

3.动态规划

在问题分解的时候可能有多个相同的子问题需要解决,就可以把这些相同的子问题解保留在一个表格中,遇到相同的时候就直接拿出来使用,就像求解斐波那契数列,可以把子问题的解保留在一个表格中,就不需要每次都求一遍子问题的解

动态规划:二叉查找树构造算法、Huffman树构造算法、小根堆大根堆构造算法、最优二叉查找树构造算法、最短路径、拓扑排序算法、直接插入排序、胜者树败者树算法

4.贪心算法

要求最优解的时候,可以将问题分为若干步骤,每次都是求当前眼下最优解,这样不一定求下来就是问题的最优解,他不需要回溯,速度很快,但是不能保证整体最优,是求比较满意的解

贪心算法:带权连通图最小生成树、带权有向图Dijkstra算法求单源最短路径和单目标最短路径、背包问题、多村庄医疗站问题

5.分枝限界法

分枝限界法类似于广度优先搜索,在查找的过程中利用最优解的限制,减去不必要的分枝

分枝限界法:求树根到节点距离、指定节点深度、两节点间距离



你可能感兴趣的:(数据结构+算法,栈,递归)