220 likes | 373 Views
数据结构. (第五讲). 绍兴文理学院. 计算机系计算机应用教研室. 为什么在算术表达式中能 先 乘除 后 加减运算?. TKS. 2. 00:53. 第 3 章 栈和队列( 1 ). 一、教学目的: 明确栈的有关概念;掌握栈的逻辑结构和存储结构,掌握顺序和链式栈的基本操作;掌握栈的初步应用。. 二、教学重点: 栈的 LIFO 的结构和操作特点;栈的逻辑结构和存储结构,顺序和链式栈的基本操作;栈的初步应用;算法设计训练。. 三、教学难点: 栈的 LIFO 的有关概念和操作;栈的初步应用。算法实现 能力的训练。 四、教学过程:. §3.1 栈 (stack).
E N D
数据结构 (第五讲) 绍兴文理学院 计算机系计算机应用教研室
为什么在算术表达式中能先乘除后加减运算? TKS 2 00:53
第3章 栈和队列(1) 一、教学目的:明确栈的有关概念;掌握栈的逻辑结构和存储结构,掌握顺序和链式栈的基本操作;掌握栈的初步应用。 二、教学重点:栈的LIFO的结构和操作特点;栈的逻辑结构和存储结构,顺序和链式栈的基本操作;栈的初步应用;算法设计训练。 三、教学难点:栈的LIFO的有关概念和操作;栈的初步应用。算法实现能力的训练。 四、教学过程:
§3.1 栈(stack) an 栈顶 a2 a1 栈底 TKS 4 §3.1.1 栈的类型定义 1、定义:栈是限定仅在表尾进行插入或删除操作的线性表。 表尾端称为栈顶(top),表头端称为栈底(bottom),不含元素的空表称为空栈。 2、栈的逻辑结构及进出栈 S=(a1,a2,...,ai-1,ai,ai+1,…,an ) 删除 插入 出栈 进栈 栈的特点后进先出 LIFO 第一个进栈的元素在栈底, 最后一个进栈的元素在栈顶, 第一个出栈的元素为栈顶元素, 最后一个出栈的元素为栈底元素 00:53
3、栈的抽象数据类型定义(简讲) TKS 5 ADT Stack {数据对象:D={ai|ai ∈ElemSet, i=1,2,...,n, n≥0} 数据关系:R1={<ai-1, ai >| ai-1, ai∈D, i=2,...,n} 约定an端为栈顶,a1 端为栈底。 基本操作: InitStack(&S) 操作结果:构造一个空栈 S。 DestroyStack(&S) 初始条件:栈 S 已存在。 操作结果:栈 S 被销毁。 ClearStack(&S) 初始条件:栈 S 已存在。 操作结果:将 S 清为空栈。 00:53
StackEmpty(S) … … a1 a2 TKS 6 初始条件:栈 S 已存在。 操作结果:若栈 S 为空栈,则返回 TRUE,否则 FALE。 StackLength(S) 初始条件:栈 S 已存在。 操作结果:返回 S 的元素个数,即栈的长度。 GetTop(S, &e) 初始条件:栈 S 已存在且非空。 操作结果:用 e 返回 S 的栈顶元素。 an 00:53
Push(&S,e) … … a1 a2 an … … an-1 a2 a1 TKS 7 初始条件:栈 S 已存在。 操作结果:插入元素 e 为新的栈顶元素。 e Pop(&S, &e) 初始条件:栈 S 已存在且非空。 操作结果:删除 S 的栈顶元素,并用 e 返回其值。 a }ADT Stack 00:53
§3.1.2 顺序栈的表示和实现 TKS 8 1、结构定义 #define size 256 struct sqstack { selemtype *base; int top; int stacksize; }; 2、栈顶指针top与栈中数据元素的关系 top=-1 空栈 top=-1 空栈 top=0 1个元素 top=4 5个元素 top=2 3个元素 3、初始化 构造一个空栈:首先建立栈空间,然后初始化栈顶指针。 int InitSqStack(sqstack &s) { s.base=new selemtype[size]; s.top=-1; s.stacksize=size; return 1; } 00:53
4、入栈 5、出栈 TKS 9 int push(sqstack &s,selemtype e) { if(s.top==SIZE-1) return 0; // 栈满不能入栈 s.top++; s.base[s.top]=e; return 1; } int pop(sqstack &s, selemtype &e) { if(s.top==-1) return 0; // 栈空不能出栈 e=s.base[s.top] s.top--; return 1; } 顺序栈的基本操作S5_1 6、取栈顶元素 int gettop(sqstack s,selemtype &e) { if(s.top==-1) return 0; // 栈空 e=s.base[s.top]; } 00:53
§3.1.3 链栈的表示和实现 Data next top an 栈顶 an-1 a1 栈底 TKS 10 1、链栈概述 (1) 概念 用链式存储结构实现的栈称为链栈。通常链栈用单链表表示,因此其结点结构与单链表的结构相同。 (2)结构定义 typedef struct stacknode { datatype data; stacknode *next; } *linkstack; 说明 top为栈顶指针: linkStack top ; (3) 入栈和出栈操作 00:53
2、链栈的基本操作 (1) 初始化 构造一个不带头结点的空栈 int initstack(linkstack &s) { s=NULL; return 1; } an an-1 top 栈顶 a1 栈底 TKS 11 (2) 入栈 int push(linkstack &top, datatype e) { stacknode *s; s=new stacknode; s s->data=e; top e s->next=top; top=s; return 1; } 00:53
(3) 出栈 e an an-1 top 栈顶 a1 栈底 TKS 12 int pop(linkstack &top, datatype &e) { linkstack p; if(top==NULL) return 0; e=top->data; an p=top; top=top->next; p top delete p; 栈顶 return 1; } 00:53
§3.2 栈的应用举例 TKS 13 §3.2.1 数制转换 对于输入的任意一个非负十进制数,显示输出与其等值的八进制数。 1、转换原理 N = (N div d)×d + N mod d N:十进制数,div:整除运算,mod:求余运算;(1348)10=283+582+08+4=(2504)8 N N div 8 N mod 8 1348 168 4 168 21 0 21 2 5 2 0 2 输 出 顺 序 计 算 顺 序 00:53
2、算法描述 TKS 14 void conversion() {int n; sqstack s; s=initstack(); // 建空栈 cin>>n; // 输入一个非负十进制整数 while(n!=0) // n不等于零循环 {push(s,n%8); // n/8 余数进栈 n=n/8; // 整除运算 } printf("\n"); while(!stackempty(s)) // 输出存放在栈中的8进制数位 {pop(s,n); printf("%d",n); } } 算法3.8 对于输入的任意一个非负十进制 数,显示输出与其等值的 八进制数。S5_2 00:53
§3.2.2 括号的匹配 TKS 15 1、问题描述 假设在表达式中 ([ ]( ) )或[([ ][ ])]等为正确的格式,[ ( ])或 ( ( ) )或 ( ( ) ])均为不正确的格式。 则 检验括号是否匹配的方法可用“期待的急迫程度”这个概念来描述。 例如:考虑下列括号序列: [ ( [ ] [ ] ) ] 1 2 3 4 5 6 7 8 分析可能出现的不匹配的情况: • 到来的右括弧并非是所“期待”的; • 到来的是“不速之客”; • 直到结束,也没有到来所“期待”的括弧。 00:53
2、算法的设计思想 TKS 16 • 凡出现左括弧,则进栈; • 凡出现右括弧,首先检查栈是否空 • 若栈空,则表明该“右括弧”多余, • 否则和栈顶元素比较, • 若相匹配,则“左括弧出栈”, • 否则表明不匹配。 • 表达式检验结束时, • 若栈空,则表明表达式中匹配正确, • 否则表明“左括弧”有余。 3、算法描述 00:53
int matching(string exp) TKS 17 {LinkStack top=NULL; int state=1,i=0;char e; while(i<exp.size()&&state) {switch(exp[i]) {case '[': top=push(top,exp[i]);break; case '(': top=push(top,exp[i]);break; case ')': if(top!=NULL&&top->data=='(') top=pop(top,e); else state=0; break; case ']': if(top!=NULL&&top->data=='[') top=pop(top,e); else state=0; break; } i++; } 算法3.9 括号的匹配S5_3 if(top==NULL&&state) return 1; return 0; } 00:53
§3.2.3 表达式求值 TKS 18 1、分析 一般采用“算符优先法”。使用两个工作栈,一个称为OPTR栈,用来寄存运算符;另一个称为OPND栈,用来寄存操作数或运算结果。 操作数为常量或变量。 把运算符和界限符((、)、#)统称为运算符,任意两个相继出现的运算符θ1和θ2 之间的优先关系,至多是下面3种关系之一: θ1 < θ2 θ1的优先权低于θ2 θ1 = θ2 θ1的优先权等于θ2 θ1 > θ2 θ1的优先权高于θ2 下表定义了运算符之间的这种优先关系 00:53
运算符之间的优先关系 θ2 θ1 + - * / ( ) # + > > < < < > > - > > < < < > > * > > > > < > > / > > > > < > > ( < < < < < ) > > > > > > # < < < < < TKS 19 ▲ 说明:相同的运算符出现 θ1> θ2 的,表示表达式是从左向右运算,θ1是相对在左边的运算符,θ2是相对在右边的运算符。 2、算法思想 00:53
(1)建立并初始化OPTR栈和OPND栈,将表达式起始符“#”压入OPTR栈。(1)建立并初始化OPTR栈和OPND栈,将表达式起始符“#”压入OPTR栈。 TKS 20 (2)依次读入表达式中每个字符ch,循环执行(3)至(5),直至求出整个表达式的值为止。 (3) 取出OPTR的栈顶元素,当OPTR的栈顶元素和当前读入的字符ch均为“#”时,整个表达式求值完毕,这时OPND的栈顶元素为表达式的值。 (4) 若ch不是运算符,则压入OPND栈,读人下一字符ch。 (5) 若ch是运算符,则根据OPTR的栈顶元素和ch的优先权比较结果,做以下不同的处理。 ① 若是小于,则ch压入OPTR栈,读人下一字符ch。 ② 若是大于,则弹出OPTR栈顶的运算符,从OPND栈弹出两个数,进行相应运算,结果压入OPND栈。 ③ 若是等于,则OPTR的栈顶元素是“(”且ch是“)”,这时弹出OPTR栈顶的“(”,相当于去掉括号,然后读人下一字符ch。 00:53
3、例3.1 利用“算符优先法”计算算术表达式3*(7-2)值的操作过程 序号 OPTR栈 OPND栈 输入字符 操作 TKS 21 1 # 3*(7-2)# push(OPND,3) 2 # 3 *(7-2)# push(OPTR,’*’) 3 #*3 (7-2)# push(OPTR,’(’) push(OPND,7) 4 #*(3 7-2)# push(OPTR,’-’) 5 #*(3 7 -2)# push(OPND,2) 6 #*(-3 7 2)# 7 #*(-3 7 2 )# pop(OPND,2) pop(OPND,7) pop(OPTR,’-’) operate(’7’,’-’,’2’) push(OPND,5) pop(OPTR,’(’) {消去一对括号} 8 #*( 3 5 )# 9 #* 3 5 # pop(OPND,5) pop(OPND,3) pop(OPTR,’*’) operate(’3’,’*’,’5’) push(OPND,15) 10 #15 # RETURN(GETTOP(OPND)15) 4、算法3.10 表达式求值 (思考题) 00:53
TKS 22 五、作业: 1、书面作业:P69:1中:(1)、(2)、(4)、(5)、(6)、 (8)、(9)、(10) 2、上机编程: (数据结构编程练习)中 8831、8832、8833 ? 00:53