1 / 81

引入栈和队列

引入栈和队列. 4. 3. 2. 1. 栈和队列是 操作受限 的线性表. 第 8 章 栈和队列. 主要内容. 堆栈的概念及其抽象类 顺序栈 链式栈 队列的概念及其抽象类 循环队列 链式队列. 8.1 堆栈的概念及其 抽象类. 堆栈的定义 堆栈的特点 堆栈的有关运算 堆栈的抽象类. 进栈. 出栈. a n. 栈顶. a 2. a 1. 栈底. 栈的示意图. 堆栈的定义. 堆栈是一种只允许在 表的一端进行插入和删除运算 的线性表; 允许进行运算的一端称为 栈顶 ,另一端则称为 栈底 ; 当表中没有元素时,称为 空栈 ;

Download Presentation

引入栈和队列

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. 引入栈和队列 4 3 2 1 栈和队列是操作受限的线性表

  2. 第8章 栈和队列

  3. 主要内容 • 堆栈的概念及其抽象类 • 顺序栈 • 链式栈 • 队列的概念及其抽象类 • 循环队列 • 链式队列

  4. 8.1 堆栈的概念及其抽象类 • 堆栈的定义 • 堆栈的特点 • 堆栈的有关运算 • 堆栈的抽象类

  5. 进栈 出栈 an 栈顶 a2 a1 栈底 栈的示意图 堆栈的定义 • 堆栈是一种只允许在表的一端进行插入和删除运算的线性表; • 允许进行运算的一端称为栈顶,另一端则称为栈底; • 当表中没有元素时,称为空栈; • 堆栈的插入运算简称为入栈或进栈,删除运算简称为出栈或退栈。

  6. 进栈 出栈 an 栈顶 a2 a1 栈底 栈的示意图 堆栈的特点 栈的特点 后进先出 第一个进栈的元素在栈底 最后一个进栈的元素在栈顶 第一个出栈的元素为栈顶元素 最后一个出栈的元素为栈底元素

  7. 堆栈的有关运算 • 进栈运算:在堆栈的顶端插入一个新元素,相当于在线性表最后的元素之后再插入一个新元素; • 出栈运算:删除栈顶的元素,在实际应用中,经常要用到栈顶元素。所以,栈顶元素一般应先保存,再删除栈顶结点; • 清栈运算:用来将栈清空; • 测试栈空:测试当前栈是否为空,栈空时,不能进行出栈运算。下溢; • 测试栈满:测试当前栈是否为满,栈满时,不能进行入栈运算。上溢。

  8. 栈的抽象类定义 template<class type> //定义一个抽象的模板堆栈类 class abstack { public: bool IsEmpty( ) //判断堆栈是否为空 { return (height==0)?true:false; } //进栈函数,将一元素压入栈中 virtual void Push(type&)=0; //出栈函数,从栈中取一元素 virtual bool Pop(type&)=0; //清栈函数,用于释放栈所占的内存空间 virtual void Clear( )=0; protected : unsigned height; }; //栈高

  9. 小结 • 堆栈的定义 • 堆栈的特点 • 堆栈的有关运算 • 堆栈的抽象类

  10. 8.2 顺序栈的定义及其实现 • 顺序栈的定义 • 顺序栈类的定义 • 典型成员函数的实现

  11. 顺序栈的定义 SATCK • 设一维数组为STACK[maxsize] ; • 再设一个整型变量top表示栈顶指针:当堆栈不空时,top的值就是栈顶元素的下标值;当堆栈为空时,有top= -1; • top最大取值为maxsize-1。 • STACK[0]为第一个进入堆栈的元素,当没有删除运算时,STACK[i-1]为第i个进入堆栈的元素,STACK[top]为栈顶元素; M-1 … 2 1 0 top B A

  12. 顺序栈的示意图 top E D C top B B top A A A top 空栈 E D C出栈 A进栈 B C D E进栈 称为:栈满

  13. 顺序栈的定义 • 堆栈是动态结构,存在溢出问题。当堆栈中已经有M个元素时,如果再做进栈运算就会产生溢出,称之为上溢;对空栈进行删除运算也会产生溢出,称之为下溢。 • 为了避免溢出,在对堆栈进行进栈运算和退栈运算之前都应该分别测试堆栈“是否已满”或者“是否已空”。

  14. 顺序栈类的定义 template<class type>//定义一个顺序栈类模板 class SeqStack: pubilc abstack<type> {public: SeqStack(int i); //构造函数,i用来设置栈的最大高度 SeqStack(SeqStack & s) //拷贝构造函数,用于同 { copy(s); } 类型栈的赋值 ~ SeqStack( ) //析构函数,调用Clear( )函数释放栈所 { Clear( ); } 占的内存空间 void Push(type & x); //进栈: 将元素x压入栈中 bool Pop(type & x); //出栈: 将栈顶元素值放入x中

  15. //清栈函数,用于释放栈所占的内存空间 void Clear( ){ delete elements; } SeqStack & Copy(SeqStack & s); //拷贝函数:同类型栈赋值 //重载赋值运算符“=”,用于同类型栈赋值 SeqStack & operator=(SeqStack & s) {delete elements; Copy(s); return *this;} bool IsFull( ) //判断栈是否为满 {return top= =maxsize-1;} // top= =maxsize-1为关系表达式 protected: int top; //栈顶指针 type *elements; //一维数组指针,用于存放栈中元素 int maxsize; //栈的最大高度 };

  16. 顺序栈类典型成员函数的实现 • 构造函数 • 进栈函数 • 出栈函数

  17. 构造函数 • 用于建立栈的对象,为栈的数据成员赋初值。 • 首先将栈高置为0,将栈顶指针top置为-1,设置一个空栈; • 然后,根据参数值,设置最大栈高,并为此栈分配内存空间。

  18. template<class type> SeqStack<type>::SeqStack(int i) { height = 0; //abstack抽象类的数据成员 top = -1; maxsize = i>10 ? i:10; //最大栈高最小为10 elements = new type[maxsize]; assert (elements!=0); //条件满足,继续执行;否则终止 }

  19. 进栈函数

  20. template<class type> //函数模板 void SeqStack<type>::Push(type & x ) { assert(!IsFull( )); //栈满警告,出错处理 elements[++top] = x; //将栈顶指针加1,将元素 放入栈顶 height++; //栈高加1 }

  21. 出栈函数

  22. template<class type> bool SeqStack<type>::Pop(type & x) { if(IsEmpty( )) //栈空警告,出错处理 return false; else { x = elements[top]; //取出栈顶元素, 将其值放入x 中 top- -; //栈顶指针减1 height- -; //栈高减1 } return true; }

  23. 顺序栈的缺点 • 容易产生栈满。

  24. 小结 • 顺序栈的定义 • 顺序栈类的定义 • 典型成员函数的实现

  25. 8.3 链式栈 • 链式栈的定义 • 链式栈类的定义 • 链栈中典型成员函数的实现 • 堆栈的应用

  26. 链式栈的定义 • 链式栈就是用一个线性链表来实现一个堆栈结构。栈中每个元素用一个链结点表示,同时,设置一个指针变量,指出当前栈顶元素所在结点的存储位置,当栈为空时,有top==NULL,下图就是链接栈的一般形式:

  27. 链栈的特点 • 链表的第一个结点就是栈顶元素的结点; • 根据堆栈的定义,新结点的插入和栈顶结点的删除都在表头进行 ; • 插入一个新元素,相当于在第一个结点之前插入一个新结点; • 删除链接栈的栈顶元素,就是删除链表的第一个结点。 • 一般不会有栈满而产生溢出的问题。

  28. 链式栈类的定义 • 定义一个结点结构: template<class type> struct StackNode//定义一个结点模板-结构 { type data; //结点的数据元素值 StackNode *next; //指向下一结点的指针 };

  29. 链式栈类的定义:链栈模板 template<class type> //定义一个栈类模板 class LinkStack: public abstack<type> { protected: StackNode<type>*top; //栈顶指针 • //复制函数,将堆栈g复制给本链式栈 LinkStack & Copy(LinkStack & g); public: LinkStack( ); //无参构造函数 LinkStack(LinkStack & g) //拷贝构造函数 { top=NULL; Copy(g); }

  30. ~ LinkStack( ) //析构函数,调用Clear()函数释 • { Clear( ); }放内存空间 void Clear( ); //清空当前栈中元素 void Push(type & x); //进栈函数 bool Pop(type & x); //出栈函数 //重载赋值运算符,用于同类型栈对象的赋值 LinkStack & operator=(LinkStack & g) { Copy(g); return *this; } };

  31. 链栈中典型成员函数的实现 • 构造函数 • 清栈函数 • 进栈函数 • 出栈函数

  32. 构造函数 初始化数据成员值,构造一个空栈。 template<class type> LinkStack<type>:: LinkStack( ) { height=0; top=NULL; }

  33. 清栈函数 释放链式栈中各结点元素所占的存储空间。循环调用Pop( )函数,删除当前栈顶结点,直到栈空为止。 template<class type> viod LinkStack<type>::Clear( ) { type x; while(Pop(x)); //循环调用Pop( )函数,出栈, 直到栈空为止 }

  34. 进栈函数:将x压入堆栈中 template<class type> viod LinkStack<type>::Push(type & x) { StackNode<type>*p; if(top) //若栈非空 { p =new StackNode<type>; //为x分配一个结点n assert(p); //内存分配失败,设置出错信息,返回 • p->data=x; //将x赋给结点数据元素 • p->next=top;//将结点插入链式栈前端,成为栈顶元素 • top=p; //修改栈顶指针 • } //else…

  35. else //若为空栈 { top = new StackNode<type>; //为栈顶元素分配内存 assert(top); //分配失败,设置出错信息,返回 top->data=x; //将x赋给栈顶数据元素 top->next=NULL; } height++; //栈高加1 }

  36. 出栈函数 template<class type> bool LinkStack<type>::Pop(type& x) { StackNode<type>*p; if(height) //若栈中有元素 { x=top->data; //将栈顶结点的数据元素赋给x p=top; //将栈顶指针赋给p top=top->next; //修改栈顶指针,下移一个位置 delete p; //删除原栈顶结点 height--; //栈高减1 return true; } return false; }

  37. 堆栈应用举例 • 数制转换 在计算机中,常需要将十进制的数转换为其他进制的数,或将其他进制的数转换为十进制的数,将十进制数转换为其他进制数的基本方法是辗转相除法。

  38. 例如:要将十进制数1348转换为8进制数, 运算过程如下: N N/8 N%8 1348 168 4 168 21 0 21 2 5 2 0 2 十进制1348对应的八进制数是2504。 计算时从低位到高位顺序产生八进制数的各个数位 输出显示时按从高位到低位的顺序输出 计算顺序 输出顺序

  39. 2+3*(5-4)=5 堆栈应用举例 1)问题的提出从键盘一次性输入一串算术表达式,给出计算结果。

  40. 如何确定运算符的运算顺序? ? 11.4 堆栈应用举例 常数 +、-、*、/ ( )、# 2)表达式的构成操作数+运算符+界符 3)表达式的求值: 例:5+6(1+2)-4 按照四则运算法则,上述表达式的计算过程为: 5+6(1+2)-4 = 5+63-4 = 5+18-4 = 23-4 = 19 1 2 3 4

  41. θ2 θ1 + -* / () # + > > < < < > > - > > < < < > > * > > > > < > > / > > > > < > > ( < < < < < = ) > > > > > > < < < < < = # 11.4 堆栈应用举例 4)算符优先关系表 表达式中任何相邻运算符 1、2 的优先关系有:1 < 2:1的优先级 低于 21 = 2:1的优先级 等于 21 > 2:1的优先级 高于 2 注:θ1、θ2是相邻算符,θ1在左,θ2在右

  42. 11.4 堆栈应用举例 用两个栈分别保存扫描过程中 遇到的操作数和运算符 5)算符优先算法 5 + 4  (1 + 2) - 6 后面也许有优先级更高的算符 从左向右扫描表达式: 遇操作数——保存; 遇运算符号j——与前面的刚扫描过的运算符i比较: 若i<j则保存j(因此已保存的运算符的优先关系为1<2<3<4…) 若i>j则说明i是已扫描的运算符中优先级最高者,可进行运算 若i=j则说明括号内的式子已计算完,需要消去括号 +  ( + 后保存的算符优先级高

  43. 11.4 堆栈应用举例 在算符优先算法中,建立了两个工作栈。一个是OPTR栈,用以保存运算符;一个是OPND栈,用以保存操作数或运算结果。 算法的基本思想是: 1、首先置操作数栈为空栈,表达式起始符“#”为运算符栈的栈底元素。 2、依次读入表达式中每个字符,若是操作数,则进OPND栈;若是运算符,则与OPTR栈的栈顶运算符比较优先级后作相应操作。 直至整个表达式求值完毕(即OPTR栈的栈顶元素和当前读入的字符均为“#”)。

  44. 3.2 栈的应用举例 base OPTR栈 OPND栈 top top top top top top top top top top top top top top top top top top top top top top top top top top top top top top top top base 表达式求值示意:5 + 6  ( 1 + 2 ) - 4 = 19 6 ( 1 + 2 ) - 4 # × 读入表达式过程: 5 + 1+2=3 6×3=18 5+18=23 23-4=19 + ( 2 3 1 × + - 18 4 6 # 19 23 5

  45. 小结 • 链式栈的定义 • 链式栈类的定义 • 链栈中典型成员函数的实现 • 堆栈的应用

  46. 8.4 队列的概念及其抽象类 • 队列的概念及其运算 • 队列的抽象类

  47. 队列的概念 • 队列简称队,是一种只允许在表的一端进行插入操作而在表的另一端进行删除操作的线性表。 • 允许进行插入的一端称为队尾,允许删除的一端称为队头。队列的插入运算也简称进队,删除运算简称为出队。 • 队列也称为先进先出表(FIFO)。

  48. 队列的概念 • 假设Q=(a1,a2,…,an-1,an)为一个队结构,则队头为a1,队尾为an。该队列是按a1,a2,…,an-1,an的顺序进入的,退出该队列也只能按这个顺序进行。 • 队列和堆栈一样,也是动态结构,同样存在溢出问题,在进行插入、删除运算之前,应进行队满、队空的判断。

  49. 队列的有关运算 • 进队:在队列的尾部插入一个新元素 • 出队:删除队列的队头元素 • 测试队空:测试队列是否为空 • 测试队满:测试队列是否为满 • 清队:创建一个空队列

  50. 抽象队列类 template<class type> class abque//定义抽象队列类模板 { protected : int qsize; //队列长度 public: bool IsEmpty( ) //判队列是否为空 { return (qsize==0)?true:false; } virtual void PushTail(type&)=0; //将元素插入队尾 virtual bool PopFront(type&)=0; //从对头提取元素 virtual void Clear( )=0; //清空队列 };

More Related