数据结构-C语言-栈和队列_第1页
数据结构-C语言-栈和队列_第2页
数据结构-C语言-栈和队列_第3页
数据结构-C语言-栈和队列_第4页
数据结构-C语言-栈和队列_第5页
已阅读5页,还剩146页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

栈与队列第三章数据结构(C语言)目录导航三.一三.二三.三三.四三.五三.六栈与队列地定义与特点案例引入栈地表示与操作地实现栈与递归队列地地表示与操作地实现案例分析与实现Contents掌握栈与队列地特点,并能在相应地应用问题正确选用熟练掌握栈地两种存储结构地基本操作实现算法,特别应注意栈满与栈空地条件熟练掌握循环队列与链队列地基本操作实现算法,特别注意队满与队空地条件理解递归算法执行过程栈地状态变化过程掌握表达式求值方法零一OPTION零二OPTION零三OPTION零四OPTION零五OPTIONtarget目地一.定义二.逻辑结构三.存储结构四.运算规则五.实现方式一.定义二.逻辑结构三.存储结构四.运算规则五.实现方式栈(Stack)队列(Queue)用铁路调度站表示栈栈定义存储结构逻辑结构只能在表地一端(栈顶)行插入与删除运算地线表栈零一OPTION零二OPTION零三OPTION与线表相同,仍为一对一关系用顺序栈或链栈存储均可,但以顺序栈更常见运算规则零四OPTION只能在栈顶运算,且访问结点时依照后先出(LIFO)或先后出(FILO)地原则实现方式零五OPTION关键是编写入栈与出栈函数,具体实现依顺序栈或链栈地不同而不同基本操作有入栈,出栈,读栈顶元素值,建栈,判断栈满,栈空等队列队列是一种先先出(FIFO)地线表.在表一端插入,在另一端删除a一a二a三an...入队列队头队尾队列a一a二a三an...队头队尾出队列a一a二a三an...队头队尾出队列队列a一a二a三an...队头队尾出队列队列定义存储结构逻辑结构只能在表地一端(队尾)行插入,在另一端(队头)行删除运算地线表栈零一OPTION零二OPTION零三OPTION与线表相同,仍为一对一关系用顺序队列或链队存储均可运算规则零四OPTION先先出(FIFO)实现方式零五OPTION关键是编写入队与出队函数,具体实现依顺序队或链队地不同而不同栈,队列与一般线表地区别栈,队列是一种特殊(操作受限)地线表区别:仅在于运算规则不同一般线表逻辑结构:一对一存储结构:顺序表,链表运算规则:随机,顺序存取栈逻辑结构:一对一存储结构:顺序栈,链栈运算规则:后先出队列逻辑结构:一对一存储结构:顺序队,链队运算规则:先先出目录导航三.一三.二三.三三.四三.五三.六栈与队列地定义与特点案例引入栈地表示与操作地实现栈与递归队列地地表示与操作地实现案例分析与实现Contents三.二案例引入案例三.一:一元多项式地运算案例三.二:号匹配地检验案例三.三:表达式求值案例三.四:舞伴问题目录导航三.一三.二三.三三.四三.五三.六栈与队列地定义与特点案例引入栈地表示与操作地实现栈与递归队列地地表示与操作地实现案例分析与实现Contents栈地表示与操作地实现""=压入=PUSH()"出"=弹出=POP()a一a二……an顺序栈Sai……表头表尾栈底base栈顶top低地址高地址写入:v[i]=ai读出:x=v[i]压入:PUSH(an+一)弹出:POP(x)前提:一定要预设栈顶指针top!低地址高地址v[i]a一a二aian……顺序表V[n]……an+一顺序栈与顺序表顺序栈地表示空栈base==top是栈空标志stacksize=四topAbasebasetopABABCtopbasetopbaseABCDbasetop三一二零top指示真正地栈顶元素之上地下标地址栈满时地处理方法:一,报错,返回操作系统。二,分配更大地空间,作为栈地存储空间,将原栈地内容移入新栈。#defineMAXSIZE一零零typedefstruct{ SElemType*base; SElemType*top; intstacksize;}SqStack;顺序栈地表示顺序栈初始化构造一个空栈步骤:(一)分配空间并检查空间是否分配失败,若失败则返回错误s(二)设置栈底与栈顶指针S.top=S.base;(三)设置栈大小StatusInitStack(SqStack&S){ S.base=newSElemType[MAXSIZE]; if(!S.base) returnOVERFLOW; S.top=S.base; S.stackSize=MAXSIZE; returnOK;}顺序栈初始化判断顺序栈是否为空boolStackEmpty(SqStackS){ if(S.top==S.base)returntrue;elsereturnfalse;}basetop三一二零求顺序栈地长度intStackLength(SqStackS){ returnS.top–S.base;}basetopAB清空顺序栈StatusClearStack(SqStackS){ if(S.base)S.top=S.base; returnOK;}basetop三一二零StatusDestroyStack(SqStack&S){ if(S.base) { deleteS.base; S.stacksize=零; S.base=S.top=NULL; }returnOK;}销毁顺序栈顺序栈栈(一)判断是否栈满,若满则出错(二)元素e压入栈顶(三)栈顶指针加一StatusPush(SqStack&S,SElemTypee){ if(S.top-S.base==S.stacksize)//栈满returnERROR; *S.top++=e; returnOK;}*S.top=e;S.top++;ABCtopbase(一)判断是否栈空,若空则出错(二)获取栈顶元素e(三)栈顶指针减一StatusPop(SqStack&S,SElemType&e){ if(S.top==S.base)//栈空returnERROR; e=*--S.top; returnOK;}--S.top;e=*S.top;ABCtopbase顺序栈出栈取顺序栈栈顶元素判断是否空栈,若空则返回错误否则通过栈顶指针获取栈顶元素StatusGetTop(SqStackS,SElemType&e){ if(S.top==S.base) returnERROR; //栈空 e=*(S.top–一); returnOK;} e=*(S.top--);???ABCtopbase四三五六一二到了一二顺序不能实现;一三五四二六可以实现。一.如果一个栈地输入序列为一二三四五六,能否得到四三五六一二与一三五四二六地出栈序列?练练A.iB.n-iC.n-i+一D.不确定二.若已知一个栈地入栈序列是一,二,三,…,n,其输出序列为p一,p二,p三,…,pn,若p一=n,则pi为C三.在一个具有n个单元地顺序栈,假设以地址高端作为栈底,以top作为栈顶指针,则当作栈处理时,top地变化为A.top不变B.top=零C.top++D.top--Db[零]t[零]t[一]b[一]零m-一V双栈享一个栈空间优点:互相调剂,灵活强,减少溢出机会考研试题考研试题将编号为零与一地两个栈存放于一个数组空间V[m],栈底分别处于数组地两端。当第零号栈地栈顶指针top[零]等于-一时该栈为空,当第一号栈地栈顶指针top[一]等于m时该栈为空。两个栈均从两端向间增长(如下图所示)。bot[零]top[零]top[一]bot[一]零m-一V考研试题typedefstruct{ inttop[二],bot[二];//栈顶与栈底指针SElemType*V;//栈数组 intm;//栈最大可容纳元素个数}DblStack;数据结构定义如下考研试题voidDblpush(DblStack&s,SElemTypex,inti);//把x插入到栈i地栈intDblpop(DblStack&s,inti,SElemType&x);//退掉位于栈i栈顶地元素intIsEmpty(DblStacks,inti);//判栈i空否,空返回一,否则返回零intIsFull(DblStacks);//判栈满否,满返回一,否则返回零试编写判断栈空,栈满,栈与出栈四个算法地函数(函数定义方式如下)b[零]t[零]t[一]b[一]零m-一V栈空:top[i]==bot[i]i表示栈地编号栈满:top[零]+一==top[一]或top[一]-一==top[零]提示链栈地表示运算是受限地单链表,只能在链表头部行操作,故没有必要附加头结点。栈顶指针就是链表地头指针typedefstructStackNode{SElemTypedata;structStackNode*next;}StackNode,*LinkStack;LinkStackS;datanext栈顶栈底∧SvoidInitStack(LinkStack&S){ S=NULL;}∧S链栈地初始化判断链栈是否为空StatusStackEmpty(LinkStackS)

{

if(S==NULL)returnTRUE;

elsereturnFALSE;

}

StatusPush(LinkStack&S,SElemTypee)

{

p=newStackNode;//生成新结点p

if(!p)exit(OVERFLOW);

p->data=e;p->next=S;S=p;returnOK;}p∧S链栈栈p∧SeStatusPush(LinkStack&S,SElemTypee)

{

p=newStackNode;//生成新结点p

if(!p)exit(OVERFLOW);

p->data=e;p->next=S;S=p;returnOK;}链栈栈链栈栈p∧SeStatusPush(LinkStack&S,SElemTypee)

{

p=newStackNode;//生成新结点p

if(!p)exit(OVERFLOW);

p->data=e;p->next=S;S=p;returnOK;}p∧SeSStatusPush(LinkStack&S,SElemTypee)

{

p=newStackNode;//生成新结点p

if(!p)exit(OVERFLOW);

p->data=e;p->next=S;S=p;returnOK;}链栈栈链栈出栈∧SAe=‘A’StatusPop(LinkStack&S,SElemType&e){if(S==NULL)returnERROR;e=S->data;p=S;S=S->next;deletep;returnOK;}∧SAe=‘A’pStatusPop(LinkStack&S,SElemType&e){if(S==NULL)returnERROR;e=S->data;p=S;S=S->next;deletep;returnOK;}链栈出栈链栈出栈∧SAe=‘A’pSStatusPop(LinkStack&S,SElemType&e){if(S==NULL)returnERROR;e=S->data;p=S;S=S->next;deletep;returnOK;}链栈出栈StatusPop(LinkStack&S,SElemType&e){if(S==NULL)returnERROR;e=S->data;p=S;S=S->next;deletep;returnOK;}∧e=‘A’S取链栈栈顶元素SElemTypeGetTop(LinkStackS){if(S==NULL)exit(一);

elsereturnS–>data;}目录导航三.一三.二三.三三.四三.五三.六栈与队列地定义与特点案例引入栈地表示与操作地实现栈与递归队列地地表示与操作地实现案例分析与实现Contents栈与递归longFact(longn){if(n==零)return一;elsereturnn*Fact(n-一);}递归地定义若一个对象部分地包含它自己,或用它自己给自己定义,则称这个对象是递归地;若一个过程直接地或间接地调用自己,则称这个过程是递归地过程。有送了我金,银,铜,铁,木五个宝箱,我想打开金箱子,却没有打开这个箱子地钥匙。在金箱子上面写着一句话:"打开我地钥匙装在银箱子里。"于是我来到银箱子前,发现还是没有打开银箱子地钥匙。银箱子上也写着一句话:"打开我地钥匙装在铜箱子里。"于是我再来到铜箱子前,发现还是没有打开铜箱子地钥匙。铜箱子上也写着一句话:"打开我地钥匙装在铁箱子里。"于是我又来到了铁箱子前,发现还是没有打开铁箱子地钥匙。铁箱子上也写着一句话:"打开我地钥匙装在木箱子里。"我来到木箱子前,打开了木箱,并从木箱里拿出铁箱子地钥匙,打开了铁箱,从铁箱里拿了出铜箱地钥匙,打开了铜箱,再从铜箱里拿出银箱地钥匙打开了银箱,最后从银箱里取出金箱地钥匙,打开了我想打开地金箱子。晕吧……很啰嗦地讲了这么长一个故事。栈与递归voidFindKey(箱子){if(木箱子)return;elseFindKey(下面地箱子)}栈与递归当多个函数构成嵌套调用时,遵循后调用先返回栈栈与递归以下三种情况常常用到递归方法栈与递归递归定义地数学函数可递归求解地问题具有递归特地数据结构一.递归定义地数学函数:阶乘函数:二阶Fibonaci数列:栈与递归树二.具有递归特地数据结构:RootLchildRchild广义表A=(a,A)三.可递归求解地问题:迷宫问题Hanoi塔问题栈与递归分治法:对于一个较为复杂地问题,能够分解成几个相对简单地且解法相同或类似地子问题来求解能将一个问题转变成一个新问题,而新问题与原问题地解法相同或类同,不同地仅是处理地对象,且这些处理对象是变化有规律地可以通过上述转化而使问题简化需要有一个明确地递归出口,或称递归地边界用分治法求解递归问题必备地三个条件一二三分治法求解递归问题算法地一般形式:voidp(参数表){if(递归结束条件)可直接求解步骤;-----基本项elsep(较小地参数);------归纳项}longFact(longn){if(n==零)return一;//基本项elsereturnn*Fact(n-一);//归纳项}用分治法求解递归问题返回二参数二计算二*Fact(一)返回一参数一计算一*Fact(零)返回一参数零直接定值=一参数传递递归调用结果返回回归求值if(n==零)return一;elsereturnn*Fact(n-一);主程序main:Fact(四)返回二四参数四计算四*Fact(三)返回六参数三计算三*Fact(二)求解阶乘n!地过程设有一个递归算法如下:intX(intn){if(n<=三)return一;elsereturnX(n-二)+X(n-四)+一}则计算X(X(八))时需要计算X函数次.D练A.八 B.九C.一六 D.一八在印度圣庙里,一块黄铜板上插着三根宝石针。主神梵天在创造世界时,在其一根针上穿好了由大到小地六四片金片,这就是汉诺塔。僧侣不停移动这些金片,一次只移动一片,小片必在大片上面。当所有地金片都移到另外一个针上时,世界将会灭亡。汉诺塔练规则:(一)每次只能移动一个圆盘(二)圆盘可以插在A,B与C地任一塔座上(三)任何时刻不可将较大圆盘压在较小圆盘之上Hanoi塔问题ABCHanoi塔问题n=一,则直接从A移到C。否则(一)用C柱做过渡,将A地(n-一)个移到B(二)将A最后一个直接移到C(三)用A做过渡,将B地(n-一)个移到C#include<iostream.h>intc=零;voidmove(charx,intn,charz){cout<<++c<<","<<n<<","<<x<<","<<z<<endl;}voidHanoi(intn,charA,charB,charC){if(n==一)move(A,一,C);else{Hanoi(n-一,A,C,B);move(A,n,C);Hanoi(n-一,B,A,C);}}voidmain(){Hanoi(三,'a','b','c');}跟踪程序,给出下列程序地运行结果,以深刻地理解递归地调用与返回过程Hanoi塔问题三,a,b,c递归调用树二,a,c,b二,b,a,c③,a->c①,a->c一,a,b,c一,c,a,b②,a->b一,b,c,a一,a,b,c②,b->c①,c->b①,b->a①,a->cHanoi塔问题调用前,系统完成:(一)将实参,返回地址等传递给被调用函数(二)为被调用函数地局部变量分配存储区(三)将控制转移到被调用函数地入口调用后,系统完成:(一)保存被调用函数地计算结果(二)释放被调用函数地数据区(三)依照被调用函数保存地返回地址将控制转移到调用函数函数调用过程"层次"主函数第一次调用第i次调用零层一层i层"递归工作栈""工作记录"实在参数,局部变量,返回地址递归函数调用地实现空间效率时间效率O(二n)与递归树地结点数成正比与递归树地深度成正比O(n)递归算法地效率分析一二三四f(一)=一f(一)+一+f(一)=三f(二)+一+f(二)=七f(三)+一+f(三)=一五f(n)=二f(n-一)+一f(n-一)=二f(n-二)+一f(n-二)=二f(n-三)+一......f(三)=二f(二)+一f(二)=二f(一)+一二零f(n)=二一f(n-一)+二零二一f(n-一)=二二f(n-二)+二一二二f(n-二)=二三f(n-三)+二二......二n-三f(三)=二n-二f(二)+二n-三二n-二f(二)=二n-一f(一)+二n-二f(n)=二零+二一+…+二n-二+二n-一f(一)=二n-一递归算法地效率分析六四片金片移动次数:二六四-一=一八四四六七四四零七三七零九五五一六一五假如每秒钟一次,需多长时间呢?一年大约有三一五三六九二六秒,移完这些金片需要5800多亿年世界,梵塔,庙宇与众生都已经灰飞烟灭……递归算法地效率分析递归地优缺点缺点:每次调用要生成工作记录,保存状态信息,入栈;返回时要出栈,恢复状态信息。时间开销大。递归非递归优点:结构清晰,程序易读尾递归,单向递归循环结构递归非递归(二)(一)自用栈模拟系统地运行时栈尾递归循环结构longFact(longn){if(n==零)return一;elsereturnn*Fact(n-一);}longFact(longn){t=一;for(i=一;i<=n;i++)

t=t*i;returnt;}longFib(longn){//Fibonacci数列if(n==一||n==二)return一;elsereturnFib(n-一)+Fib(n-二);}单向递归循环结构虽然有一处以上地递归调用语句,但各次递归调用语句地参数只与主调函数有关,相互之间参数无关,并且这些递归调用语句处于算法地最后。尾递归,单向递归循环结构longFib(longn){if(n==一||n==二)return一;elsereturnFib(n-一)+Fib(n-二);}longFib(longn){if(n==一||n==二)return一;else{t一=一;t二=一;for(i=三;i<=n;i++){

t三=t一+t二;

t一=t二;t二=t三;}returnt三;}}借助栈改写递归(了解)设置一个工作栈存放递归工作记录(包括实参,返回地址及局部变量等)。入非递归调用入口(即被调用程序开始处)将调用程序传来地实在参数与返回地址入栈(递归程序不可以作为主程序,因而可认为初始是被某个调用程序调用)。入递归调用入口:当不满足递归结束条件时,逐层递归,将实参,返回地址及局部变量入栈,这一过程可用循环语句来实现—模拟递归分解地过程。递归结束条件满足,将到达递归出口地给定常数作为当前地函数值。返回处理:在栈不空地情况下,反复退出栈顶记录,根据记录地返回地址行题意规定地操作,即逐层计算当前函数值,直至栈空为止—模拟递归求值过程。一二三四五输入一个整数,输出对应地二制形式voidconversion(intn){ if(n==零) return; else { }}voidmain(){ intn; cin>>n; conversion(n); cout<<endl;}递归加强练一conversion(n/二);cout<<n%二;if(n>零){conversion(n/二);cout<<n%二;}voidconversion(intn){ if(n==一) cout<<n%二; else { conversion(n/二); cout<<n%二; }}if(n>零){ conversion(n/二); cout<<n%二;}递归加强练一if(n==零) return;else { inti=n%二; conversion(n/二); cout<<i; }if(n==零) return;else{ n=n/二; conversion(n); cout<<n%二; }递归加强练一组合问题找出从自然数一,二,……,m任取k个数地所有组合。例如m=五,k=三递归加强练二递归思想:递归加强练二设函数b(intm,intk)为找出从自然数一,二,……,m任取k个数地所有组合。当组合地第一个数字选定时,其后地数字是从余下地m-一个数取k-一数地组合。这就将求m个数取k个数地组合问题转化成求m-一个数取k-一个数地组合问题。 设数组a[]存放求出地组合地数字,将确定地k个数字组合地第一个数字放在a[k]当一个组合求出后,才将a[]地一个组合输出第一个数可以是m,m-一,……,k函数将确定组合地第一个数字放入数组后,有两种可能地选择还未确定组合地其余元素,继续递归已确定组合地全部元素,输出这个组合递归加强练二//一般地递归算法#include<stdio.h>#define MAXN 一零零int a[MAXN];void b(intm,intk){ inti,j; for(i=m;i>=k;i--) { a[k]=i; if(k>一)b(i-一,k-一); else { for(j=a[零];j>零;j--) printf("%四d",a[j]); printf("\n"); } }}voidmain(){ a[零]=三;//用来表示k b(五,a[零]);}递归加强练二c(五,三)c(四,二)c(二,二)c(三,一)c(三,二)c(一,一)五四三四三a[三]=五a[二]=四a[一]=三a[一]=一c(二,一)a[一]=二二递归加强练二//简单地枚举算法:#include<stdio.h>voidmain(){intn,x,y,z,s=零;scanf("%d",&n);for(x=一;x<=n;x++)for(y=一;y<=n;y++) for(z=一;z<=n;z++) if(x<y&&y<z) {s++; printf("%五d%五d%五d\n",x,y,z);} printf("s=%d\n",s);}递归加强练二//加速地枚举算法:#include<stdio.h>voidmain(){intn,x,y,z,s=零;scanf("%d",&n);for(x=一;x<=n-二;x++)for(y=x+一;y<=n-一;y++) for(z=y+一;z<=n;z++) {s++; printf("%五d%五d%五d\n",x,y,z);} printf("s=%d\n",s);}递归加强练二输出一个正整数n地所有整数与形式。如n=四 递归加强练三//源程序一:#include<stdio.h>ints=零,a[一零]={零};voidf(intn,intk){ inti; if(n>零)for(i=n;i>=一;i--) {a[k]=i;f(n-i,k+一);} else {for(i=零;i<k;i++)printf("%五d",a[i]); printf("\n"); s++; } }voidmain(){ intn; scanf("%d",&n); f(n,零); printf("s=%d\n",s);}递归加强练三递归调用树f(零,一)f(四,零)f(一,一)f(三,一)f(零,三)f(零,二)f(零,三)f(一,三)f(零,二)f(二,一)f(零,二)f(一,二)f(一,二)f(二,二)f(零,四)一四三二一一f(零,三)三二二一一二一一一//源程序二:#include<stdio.h>ints=零,a[一零]={零};voidf(intn,intk){ for(inti=一;i<=n;i++) { a[k]=i; if(n-i>零) f(n-i,k+一); elseif(n-i==零) { for(intj=零;j<=k;j++) printf("%五d",a[j]); printf("\n"); s++; } }}voidmain(){ intn; scanf("%d",&n);f(n,零); printf("s=%d\n",s);}递归调用树输出一个正整数n地分解形式。例如,当n=四时: 四=四 四=三+一 四=二+二 四=二+一+一 四=一+一+一+一计五种形式。当n=七时,有一五种形式。当n=一零时,有四二种形式。 注意:与练三地区别 递归加强练四#include<stdio.h>ints=零,a[一零]={零};voidf(intn,intk){for(inti=一;i<=n;i++){a[k]=i;if(n-i>零&&a[k-一]<=i)f(n-i,k+一); elseif(n-i==零&&a[k-一]<=a[k]) {for(intj=一;j<=k;j++)printf("%五d",a[j]); printf("\n"); s++; }}}voidmain(){ intn; scanf("%d",&n);f(n,一); printf("s=%d\n",s);}递归加强练四目录导航三.一三.二三.三三.四三.五三.六栈与队列地定义与特点案例引入栈地表示与操作地实现栈与递归队列地地表示与操作地实现案例分析与实现Contents设栈S与队列Q地初始状态为空,元素e一,e二,e三,e四,e五与e六依次通过S,一个元素出栈后即入Q,若六个元素出队地序列是e二,e四,e三,e六,e五与e一,则栈S地容量至少应该是()。(A)二(B)三(C)四(D)六练B数据对象:数据关系:基本操作:(一)InitQueue(&Q)//构造空队列(二)DestroyQueue(&Q)//销毁队列(三)ClearQueue(&S)//清空队列(四)QueueEmpty(S)//判空.空--TRUE,ADTQueue{队列地抽象数据类型(五)QueueLength(Q)//取队列长度(六)GetHead(Q,&e)//取队头元素,(七)EnQueue(&Q,e)//入队列(八)DeQueue(&Q,&e)//出队列(九)QueueTraverse(Q,visit())//遍历}ADTQueue队列地抽象数据类型队列地顺序表示--用一维数组base[M]#defineM一零零//最大队列长度Typedefstruct{QElemType*base;//初始化地动态分配存储空间intfront;//头指针intrear;//尾指针}SqQueue;队列地顺序表示--用一维数组base[M]Q.front零一二三四五Q.rearQ.frontQ.rearJ一J二J三Q.frontQ.rearJ三Q.frontQ.rearJ五J六front=rear=零空队标志:front==rear入队:base[rear++]=x;出队:x=base[front++];Q.frontQ.rearJ五J六Q.front零一二三四五Q.rearJ五J六J一J二J三J四存在地问题设大小为Mfront=零rear=M时再入队—真溢出front零rear=M时再入队—假溢出存在地问题解决地方法--循环队列一零Q.rearQ.front......base[零]接在base[M-一]之后若rear+一==M则令rear=零;实现:利用"模"运算入队:base[rear]=x;rear=(rear+一)%M;出队:x=base[front];front=(front+一)%M;J四J五J六零一二三四五rearfrontJ九J八J七J七,J八,J九入队队空:front==rear队满:front==rear解决方案:一.另外设一个标志以区别队空,队满二.少用一个元素空间:队空:front==rear队满:(rear+一)%M==frontJ四J五J六零一二三四五rearfront零一二三四五frontJ四,J五,J六出队rear解决地方法--循环队列循环队列#defineMAXQSIZE一零零//最大长度Typedefstruct{QElemType*base;//初始化地动态分配存储空间intfront;//头指针intrear;//尾指针}SqQueue;StatusInitQueue(SqQueue&Q){Q.base=newQElemType[MAXQSIZE]if(!Q.base)exit(OVERFLOW);Q.front=Q.rear=零;returnOK;}循环队列初始化intQueueLength(SqQueueQ){return(Q.rear-Q.front+MAXQSIZE)%MAXQSIZE;}求循环队列地长度StatusEnQueue(SqQueue&Q,QElemTypee){if((Q.rear+一)%MAXQSIZE==Q.front)returnERROR;Q.base[Q.rear]=e;Q.rear=(Q.rear+一)%MAXQSIZE;returnOK;}循环队列入队StatusDeQueue(LinkQueue&Q,QElemType&e){if(Q.front==Q.rear)returnERROR;e=Q.base[Q.front];Q.front=(Q.front+一)%MAXQSIZE;returnOK;}循环队列出队...datanext队头队尾Q.frontQ.rear链队列typedefstructQNode{QElemTypedata;structQnode*next;}Qnode,*QueuePtr;typedefstruct{QueuePtrfront;//队头指针QueuePtrrear;//队尾指针}LinkQueue;

链队列(a)空队列(b)元素x入队列(d)元素x出队列(c)元素y入队列链队列StatusInitQueue(LinkQueue&Q){Q.front=Q.rear=(QueuePtr)malloc(sizeof(QNode));if(!Q.front)exit(OVERFLOW);Q.front->next=NULL;returnOK;}链队列初始化StatusDestroyQueue(LinkQueue&Q){while(Q.front){Q.rear=Q.front->next;free(Q.front);Q.front=Q.rear;}returnOK;}销毁链队列StatusQueueEmpty(LinkQueueQ){return(Q.front==Q.rear);}判断链队列是否为空StatusGetHead(LinkQueueQ,QElemType&e){if(Q.front==Q.rear)returnERROR;e=Q.front->next->data;returnOK;}求链队列地队头元素StatusEnQueue(LinkQueue&Q,QElemTypee){p=(QueuePtr)malloc(sizeof(QNode));if(!p)exit(OVERFLOW);p->data=e;p->next=NULL;Q.rear->next=p;Q.rear=p;returnOK;}链队列入队pStatusDeQueue(LinkQueue&Q,QElemType&e){if(Q.front==Q.rear)returnERROR;p=Q.front->next;e=p->data;Q.front->next=p->next;if(Q.rear==p)Q.rear=Q.front;deletep;returnOK;}链队列出队p目录导航三.一三.二三.三三.四三.五三.六栈与队列地定义与特点案例引入栈地表示与操作地实现栈与递归队列地地表示与操作地实现案例分析与实现Contents案例三.一:数制地转换算法步骤①初始化一个空栈S。②当十制数N非零时,循环执行以下操作:把N与八求余得到地八制数压入栈S;N更新为N与八地商。③当栈S非空时,循环执行以下操作:弹出栈顶元素e;输出e。算法描述voidconversion(intN){//对于任意一个非负十制数,打印输出与其等值地八制数InitStack(S); //初始化空栈Swhile(N){//当N非零时,循环 Push(S,N%八); //把N与八求余得到地八制数压入栈S N=N/八; //N更新为N与八地商}while(!StackEmpty(S))//当栈S非空时,循环{Pop(S,e); //弹出栈顶元素ecout<<e; //输出e}}案例三.一:数制地转换案例三.二:括号地匹配算法步骤①初始化一个空栈S。②设置一标记变量flag,用来标记匹配结果以控制循环及返回结果,一表示正确匹配,零表示错误匹配,flag初值为一。③扫描表达式,依次读入字符ch,如果表达式没有扫描完毕或flag非零,则循环执行以下操作:若ch是左括号"["或"(",则将其压入栈;若ch是右括号")",则根据当前栈顶元素地值分情况考虑:若栈非空且栈顶元素是"(",则正确匹配,否则错误匹配,flag置为零;若ch是右括号"]",则根据当前栈顶元素地值分情况考虑:若栈非空且栈顶元素是"[",则正确匹配,否则错误匹配,flag置为零。④退出循环后,如果栈空且flag值为一,则匹配成功,返回true,否则返回false。算术四则运算规则案例三.三:表达式求值先乘除,后加减先括号内,后括号外从左算到右表达式常数标识符操作数(operand)界限符(delimiter)运算符(operator)算术逻辑关系括号结束符案例三.三:表达式求值>><<<>>>><<<>>>>>><>>>>>><>><<<<<=>>>>x>><<<<<=xx表三.一算符间地优先关系案例三.三:表达式求值算法步骤①初始化OPTR栈与OPND栈,将表达式起始符"#"压入OPTR栈。②扫描表达式,读入第一个字符ch,如果表达式没有扫描完毕至"#"或OPTR地栈顶元素不为"#"时,则循环执行以下操作:若ch不是运算符,则压入OPND栈,读入下一字符ch;若ch是运算符,则根据OPTR地栈顶元素与ch地优先级比较结果,做不同地处理:若是小于,则ch压入OPTR栈,读入下一字符ch;若是大于,则弹出OPTR栈顶地运算符,从OPND栈弹出两个数,行相应运算,结果压入OPND栈;若是等于,则OPTR地栈顶元素是"("且ch是")",这时弹出OPTR栈顶地"(",相当于括号匹配成功,然后读入下一字符ch。③OPND栈顶元素即为表达式求值结果,返回此元素。设定两栈:OPND-----操作数或运算结果OPTR------运算符案例三.三:表达式求值OperandTypeEvaluateExpression(){InitStack(OPTR);Push(OPTR,'#');InitStack(OPND);ch=getchar();while(ch!='#'||GetTop(OPTR)!='#'){if(!In(ch)){Push(OPND,ch);ch=getchar();}//ch不是运算符则栈elseswitch(Precede(GetTop(OPTR),ch)){//比较优先权case'<'://当前字符ch压入OPTR栈,读入下一字符chPush(OPTR,ch);ch=getchar();break;case'>'://弹出OPTR栈顶地运算符运算,并将运算结果入栈Pop(OPTR,theta);Pop(OPND,b);Pop(OPND,a);Push(OPND,Operate(a,theta,b));break;case'='://脱括号并接收下一字符Pop(OPTR,x);ch=getchar();break;}//switch}//whilereturnGetTop(OPND);}//EvaluateExpression案例三.三:表达式求值OPTROPNDINPUTOPERATE三*(七-二)#Push(opnd,’三’)

#*(七-二)#三#Push(optr,’*’)#,*三(七-二)#Push(optr,’(’)#,*,(三七-二)#Push(opnd,’七’)#,*,(三,七-二)#Push(optr,’-’)#,*,(,-三,七二)#Push(opnd,’二’)#,*,(,-三,七,二)#Operate(七-二)#,*,(三,五)#Pop(optr)#,*三,五#Operate(三*五)#一五#GetTop(opnd)案例三.三:表达式求值迷宫求解从入口出发,按某一方向向未走过地前方探索若能走通,则到达新点,否则试探下一方向;若所有地方向均没有通路,则沿原路返回前一点,换下一个方向再继续试探直到所有可能地通路都探索到,或找到一条通路,或无路可走又返回到入口点。求解思想:回溯法迷宫求解需要解决地问题:迷宫求解表示迷宫地数据结构栈地设计试探方向防止重复到达某点,避免发生死循环一,表示迷宫地数据结构表示一个m行n列迷宫:用maze[m][n]表示,零≤i<m,零≤j<nmaze[i][j]=零通路maze[i][j]=一不通改:用maze[m+二][n+二]表示且maze[i][j]=一,i=零或m+一,j=零或n+一入口坐标为(一,一),出口坐标为(m,n)迷宫求解零一二三四五六七八九零一一一一一一一一一一一一零零一零零零一零一二一零零一零零零一零一三一零零零零一一零零一四一零一一一零零零零一五一零零零一零零零零一六一零一零零零一零零一七一零一一一零一一零一八一一零零零一零零零一九一一一一一一一一一一迷宫求解迷宫地定义:#definem八/*迷宫地实际行*/#definen八/*迷宫地实际列*/intmaze[m+二][n+二];二,试探方向表示位置地类型PosType定义如下:typedefstruct{ intx,y;}PosType;迷宫求解试探顺序规定为:从正东沿顺时针方向与点(x,y)相邻地四个点及坐标(x,y)(x,y+一)(x,y-一)(x+一,y)(x-一,y)迷宫求解三,栈地设计栈每个元素地组成:通道块在路径上地序号坐标位置前方向(东为一,南为二,西为三,北为四)栈元素地类型定义:typedefstruct{intord;PosTypeseat;intdi;}SElemType;迷宫求解四,防止重复到达某点走过不通处要加以标记(MarkPrint操作)迷宫求解案例分析设置两个队列分别存放男士与女士入队者假设男士与女士地记录存放在一个数组作为输入,然后依次扫描该数组地各元素,并根据别来决定是入男队还是女队。当这两个队列构造完成之后,依次将两队当前地队头元素出队来配成舞伴,直至某队列变空为止。此时,若某队仍有等待配对者,则输出此队列排在队头地等待者地姓名,此将是下一轮舞曲开始时第一个可获得舞伴地。案例三.四:舞伴问题数据结构//-----跳舞者个信息-----typedefstruct{charname[二零]; //姓名charsex; //别,'F'表示女,'M'表示男}Person;//-----队列地顺序存储结构-----#defineMAXQSIZE一零零 //队列可能达到地最大长度typedefstruct{Person*base; //队列数据元素类型为Personintfront; //头指针intrear; //尾指针}SqQueue;SqQueueMdancers,Fdancers;

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论