1. 栈、队列、线性表的区别与联系(异同)
答:
栈和队列联系:逻辑结构都是线性结构;存储结构都可以采用顺序存储结构和链式存储结构;他们的数据元素都呈线性关系,是一种的线性表,且只允许在端点处插入和删除元素
栈、队列和线性表联系:栈和队列都是一种操作受限的线性表。
区别:线性表可以在中间和两端任何地方插入和删除元素,而栈只能在同一端插入和删除元素,具有后进先出的特点、队列只允许在一段插入元素,另一端删除元素,具有先进先出的特点。
2. 顺序栈和链栈判空、满的条件?
答:
顺序栈(初始化top = -1);(初始化top = 0)
进栈:s[++top]=x ;s[top++]=x
出栈:x=s[top--] ;x=s[--top]
判空:top==-1 ; top == 0
判满:top==maxsize-1 ; top==maxsize (静态分配的)
链栈(带头结点初始化head->next=NULL) ----- 不考虑满的情况(因为是动态分配的)
栈空:head->next==NULL(出栈同理单链表删除第一个节点;进栈同理单链表头插入一个节点)
进出:注意是否带头结点
3. 顺序队列和链队列判空、满的条件?(循环队列)
顺序队列(循环队列)非循环队列会出现“假溢出”现象,不能很好的利用数组存储空间,但不会出现元素覆盖的情况,视情况选择是否使用
初始化r = f = 0 ; r = f = 0 and size=0 ; 增加tag标识最近一次操作是出/入队
进队:r=(r+1)%maxs; size++ ; tag=1
出队:f=(f+1)%maxs; size-- ; tag=0
队空:r==f; size==0 ; r==f and tag==0
队满:(r+1)%maxs==f; size=maxsize; r==f and tag==1
循环队列(f指向首元素前一个,r指向尾元素)元素个数=(r-f+maxs)%maxs
链队:单链表+表头指针+表尾指针(不考虑满)
初始化:q->front=q->rear=NULL
队空:q->rear==NULL
进出:注意是否带头结点
4. 何时用哪种(栈/队列)数据结构?
答:在实际应用中,一般栈和队列都是用来存放临时数据的,如果先保存的元素先处理,应该采用队列;如果后保存的元素先处理,应该采用栈。
实际应用:
栈的应用:实现递归(函数调用栈);用于计算后缀表达式的值;括号匹配;判断回文;求迷宫路径(非最优)。
队列的应用:树的层次遍历;图的广度优先遍历;求迷宫最短路径;操作系统中的进程调度(先来先服务FCFS):当进程被创建完成后变为就绪状态,加入就绪队列。当进程请求某一资源(如外设)的使用或等待某一事件的发生(如 I/O 操作的完成)时,它就从运行态转换为阻塞态,根据阻塞原因的不同会设置多个阻塞队列。
5. 循环队列一定优于非循环队列吗?什么时候用非循环队列?
答:不一定。队列主要用于保存中间数据,且保存的数据有先产生先处理的特点。非循环队列存在数据假溢出现象,即队列中有空间,可是队满条件成立,为此改为循环队列可以克服假溢出现象。
但循环队列中出队元素的空间可能被后来进队的元素覆盖,如果算法要求在队列操作结束后利用进队的所有元素实现某种功能时,此时循环队列就不适合了。
例如,求解迷宫路径问题时,应该使用非环形队列。
6. 简述使用栈进行“括号匹配”的步骤
答:从左向右依次扫描每个括号字符,遇到左括号则入栈;遇到右括号则取出栈顶元素,此时若栈为空,则匹配失败;反之检查栈顶元素是否与之匹配,若不匹配则匹配失败,若匹配继续扫描,当扫描完整个括号串后,如果栈不空,则匹配失败,反之则匹配成功。
7. 函数调用栈
8. 用栈实现中缀表达式转后缀、后缀表达式的计算、中缀表达式的计算
答:
计算机将中缀转后缀算法步骤:
初始化一个栈,用于保存暂时还不确定运算顺序的运算符。
从左到右处理各个元素,直到最后一个元素,当遇到:
① 遇到操作数。直接加入后缀表达式
② 遇到界限符。遇到"("(左括号)直接入栈;遇到")"(右括号)则依次弹出栈内运算符并加入后缀表达式,直到弹出“(”为止,“(”不加入后缀表达式。
③ 遇到运算符。依次弹出栈中优先级高于或等于当前运算符的所有运算符,并加入后缀表达式,若遇到“(”或栈空则停止。之后再把当前运算符入栈。
按上述方法处理完所有字符后,将栈中剩余的运算符依次弹出,并加入后缀表达式中。
计算机计算后缀表达式算法步骤:
① 从左向右扫描后缀表达式,直到扫描到最后一个字符
② 如果扫描到操作数,则进栈,继续执行①;否则,执行③
③ 如果扫描到运算符,则出栈两次栈顶,第一次出栈的为右操作数,第二次出栈的为左操作数,计算的结果进栈,继续①
计算机计算中缀表达式算法步骤(前两个的结合):
初始化两个栈,操作数栈 和 运算符栈
① 若扫描到操作数,进入操作数栈
② 若扫描到运算符或界限符,按照“中转后”相同逻辑进入运算符栈(期间每弹出一个运算符时,就需要弹出两个操作数栈中的栈顶元素执行相应运算,运算结果再压回操作数栈)