1、栈和队列数据结构学习(C+)之栈和队列栈和队列是操作受限的线性表,似乎每本讲数据结构的数都是这么说的。有些书按照这个思路给出了定义和实现;但是很遗憾,本文没有这样做,所以,有些书中的做法是重复建设,这或许可以用不是一个人写的这样的理由来开脱。顺序表示的栈和队列,必须预先分配空间,并且空间大小受限,使用起来限制比较多。而且,由于限定存取位置,顺序表示的随机存取的优点就没有了,所以,链式结构应该是首选。栈的定义和实现 #ifndef Stack_H#define Stack_H#include List.htemplate class Stack : List/栈类定义public:void Pu
2、sh(Type value)Insert(value);Type Pop()Type p = *GetNext();RemoveAfter();return p;Type GetTop()return *GetNext();List :MakeEmpty;List :IsEmpty;#endif 队列的定义和实现 #ifndef Queue_H#define Queue_H#include List.htemplate class Queue : List/队列定义public:void EnQueue(const Type &value)LastInsert(value);Type DeQu
3、eue()Type p = *GetNext();RemoveAfter();IsEmpty();return p;Type GetFront()return *GetNext();List :MakeEmpty;List :IsEmpty;#endif 测试程序 #ifndef StackTest_H#define StackTest_H#include Stack.hvoid StackTest_int()cout endl 整型栈测试 endl;cout endl 构造一个空栈 endl;Stack a;cout 将120入栈,然后再出栈 endl;for (int i = 1; i =
4、 20; i+) a.Push(i);while (!a.IsEmpty() cout a.Pop() ;cout endl;#endif#ifndef QueueTest_H#define QueueTest_H#include Queue.hvoid QueueTest_int()cout endl 整型队列测试 endl;cout endl 构造一个空队列 endl;Queue a;cout 将120入队,然后再出队 endl;for (int i = 1; i = 20; i+) a.EnQueue(i);while (!a.IsEmpty() cout a.DeQueue() ;co
5、ut endl;#endif 没什么好说的,你可以清楚的看到,在单链表的基础上,栈和队列的实现是如此的简单。 更多内容请看数据结构 数据结构教程 数据结构相关文章专题,或 栈应用栈的应用很广泛,栈的最大的用途是解决回溯问题,这也包含了消解递归;而当你用栈解决回溯问题成了习惯的时候,你就很少想到用递归了,比如迷宫求解。另外,人的习惯也是先入为主的,比如树的遍历,从学的那天开始,就是递归算法,虽然书上也教了用栈实现的方法,但应用的时候,你首先想到的还是递归;当然了,假如语言本身不支持递归(如BASIC),那栈就是唯一的选择了似乎现在的高级语言都是支持递归的。如下是表达式类的定义和实现,表达式可以是
6、中缀表示也可以是后缀表示,用头节点数据域里的type区分,这里有一点说明的是,由于单链表的赋值函数,我原来写的时候没有复制头节点的内容,所以,要是在两个表达式之间赋值,头节点里存的信息就丢了。你可以改写单链表的赋值函数来解决这个隐患,或者你根本不不在两个表达式之间赋值也行。 #ifndef EXPression_H#define Expression_H#include List.h#include Stack.h#define INFIX 0#define POSTFIX 1#define OPND 4#define OPTR 8template class ExpNodepublic:in
7、t type;union Type opnd; char optr;ExpNode() : type(INFIX), optr(=) ExpNode(Type opnd) : type(OPND), opnd(opnd) ExpNode(char optr) : type(OPTR), optr(optr) ;template class Expression : ListExpNode public:void Input()MakeEmpty(); Get()-type =INFIX;cout endl 输入表达式,以结束输入 opnd;if (opnd != 0)ExpNode newop
8、nd(opnd);LastInsert(newopnd);cin optr;ExpNode newoptr(optr);LastInsert(newoptr);void Print()First();cout endl;for (ExpNode *p = Next(); p != NULL; p = Next() )switch (p-type)case OPND:cout opnd; break;case OPTR:cout optr; break;default: break;cout ;cout type = POSTFIX) return *this;Stack s; s.Push(=
9、);Expression temp;ExpNode *p = Next();while (p != NULL)switch (p-type)case OPND:temp.LastInsert(*p); p = Next(); break;case OPTR:while (isp(s.GetTop() icp(p-optr) )ExpNode newoptr(s.Pop();temp.LastInsert(newoptr);if (isp(s.GetTop() = icp(p-optr) )s.Pop(); p =Next(); break;s.Push(p-optr); p = Next();
10、 break;default: break;*this = temp;pGetFirst()-data.type = POSTFIX;return *this;Type Calculate()Expression temp = *this;if (pGetFirst()-data.type != POSTFIX) temp.Postfix();Stack s; Type left, right;for (ExpNode *p = temp.Next(); p != NULL; p = temp.Next()switch (p-type)case OPND:s.Push(p-opnd); bre
11、ak;case OPTR:right = s.Pop(); left = s.Pop();switch (p-optr)case +: s.Push(left + right); break;case -: s.Push(left - right); break;case *: s.Push(left * right); break;case /: if (right != 0) s.Push(left/right); else return 0; break;/ case %: if (right != 0) s.Push(left%right); else return 0; break;
12、/ case : s.Push(Power(left, right); break;default: break;default: break;return s.Pop();private:int isp(char optr)switch (optr)case =: return 0;case (: return 1;case : return 7;case *: return 5;case /: return 5;case %: return 5;case +: return 3;case -: return 3;case ): return 8;default: return 0;int
13、icp(char optr)switch (optr)case =: return 0;case (: return 8;case : return 6;case *: return 4;case /: return 4;case %: return 4;case +: return 2;case -: return 2;case ): return 1;default: return 0;#endif 几点说明1、表达式用单链表储存,你可以看到这个链表中既有操作数又有操作符,假如你看过我的如何在一个链表中链入不同类型的对象,这里的方法也是对那篇文章的补充。2、输入表达式时,会将原来的内容清空
14、,并且必须按照中缀表示输入。假如你细看一下中缀表达式,你就会发现,除了括号,表达式的结构是“操作数”、“操作符”、“操作数”、“操作符()”,为了统一这个规律,同时也为了使输入函数简单一点,规定括号必须这样输入“0(”、“)0”;这样一来,“0”就不能作为操作数出现在表达式中了。因为我没有在输入函数中增加容错的语句,所以一旦输错了,那程序就“死”了。3、表达式求值的过程是,先变成后缀表示,然后用后缀表示求值。因为原书讲解的是这两个算法,并且用这两个算法就能完成中缀表达式的求值,所以我就没写中缀表达式的直接求值算法。具体算法说明参见原书,我就不废话了。4、Calculate()注释掉的两行,“”
15、是因为只对整型表达式合法,“”的Power()函数没有完成。5、isp(),icp()的返回值,原书说的不细,我来多说两句。(表达式开始和结束标志)的栈内栈外优先级都是最低。(栈外最高,栈内次最低。)栈外次最低,不进栈。栈内次最高,栈外比栈内低。栈内比栈外低,栈外比栈内低。栈内比栈外低,栈外比栈内低。这样,综合起来,就有9个优先级,于是就得出了书上的那个表。 更多内容请看数据结构 数据结构教程 数据结构相关文章专题,或 队列应用我看的两本教科书(数据结构(C语言版)还有这本黄皮书)都是以这个讲解队列应用的,而且都是银行营业模拟(太没新意了)。细比较,这两本书模拟的银行营业的方式还是不同的。 1
16、997版的数据结构(C语言版)的银行还是老式的营业模式(究竟是1997年的事了),现在的很多地方还是这种营业模式几个窗口同时排队。这种方式其实不太合理,经常会出现先来的还没有后来的先办理业务(经常前面一个人磨磨蹭蹭,别的队越来越短,让你恨不得把前面那人干掉)。1999版的这本黄皮书的银行改成了一种挂牌的营业方式,每个来到的顾客发一个号码,假如哪个柜台空闲了,就叫号码最靠前的顾客来办理业务;假如同时几个柜台空闲,就按照一种法则来决定这几个柜台叫号的顺序(最简单的是按柜台号码顺序)。这样,就能保证顾客按照先来后到的顺序接受服务因为大家排在一个队里。这样的营业模式我在北京的西直门工商银行见过,应该说
17、这是比较合理的一种营业模式。不过,在本文中最重要的是,这样的营业模式比较好模拟(一个队列总比N个队列好操作)。原书的这部分太难看了,我看的晕晕的,我也不知道按照原书的方法能不能做出来,因为我没看懂(旁白:靠,你小子这样还来现眼)。我按照实际情况模拟,实现如下: #ifndef Simulation_H#define Simulation_H#include #include #include class Tellerpublic:int totalCustomerCount;int totalServiceTime;int finishServiceTime;Teller() :totalCu
18、stomerCount(0), totalServiceTime(0),finishServiceTime(0) ;/#define PRINTPROCESSclass Simulationpublic:Simulation()cout endl 输入模拟参数 endl;cout tellerNum;cout simuTime;cout arrivalLow;cout arrivalHigh;cout serviceLow;cout serviceHigh;arrivalRange = arrivalHigh - arrivalLow + 1;serviceRange = serviceHig
19、h - serviceLow + 1;srand(unsigned)time(NULL);Simulation(int tellerNum, int simuTime, int arrivalLow, int arrivalHigh, int serviceLow, int serviceHigh): tellerNum(tellerNum), simuTime(simuTime), arrivalLow(arrivalLow), arrivalHigh(arrivalHigh),serviceLow(serviceLow), serviceHigh(serviceHigh),arrivalR
20、ange(arrivalHigh - arrivalLow + 1), serviceRange(serviceHigh - serviceLow + 1) srand(unsigned)time(NULL); void Initialize()curTime = nextTime = 0;customerNum = customerTime = 0;for (int i = 1; i = tellerNum; i+)tellersi.totalCustomerCount = 0;tellersi.totalServiceTime = 0;tellersi.finishServiceTime
21、= 0;customer.MakeEmpty();void Run()Initialize();NextArrived();#ifdef PRINTPROCESScout endl;cout tellerID;for (int k = 1; k = tellerNum; k+) cout TELLER k;cout endl;#endiffor (curTime = 0; curTime = nextTime)CustomerArrived();NextArrived();#ifdef PRINTPROCESScout Time: curTime ;#endiffor (int i = 1;
22、i = tellerNum; i+)if (tellersi.finishServiceTime curTime) tellersi.finishServiceTime = curTime;if (tellersi.finishServiceTime = curTime & !customer.IsEmpty()int t = NextService();#ifdef PRINTPROCESScout customerNum + 1 ( customer.GetFront() , t );#endifCustomerDeparture();tellersi.totalCustomerCount
23、+;tellersi.totalServiceTime += t;tellersi.finishServiceTime += t;#ifdef PRINTPROCESSelse cout ;#endif#ifdef PRINTPROCESScout endl;#endifPrintResult();void PtintSimuPara()cout endl 模拟参数 endl;cout 柜台数量: tellerNum 营业时间: simuTime endl;cout 两个顾客来到的最小间隔时间: arrivalLow endl;cout 两个顾客来到的最大间隔时间: arrivalHigh endl;cout 柜台服务最短时间: serviceLow endl;cout 柜台服务最长时间: serviceHigh endl;void PrintResult()int tSN = 0;long tST = 0;cout endl;cout 模拟结果;cout endl tellerID ServiceNum ServiceTime AverageTime
copyright@ 2008-2022 冰豆网网站版权所有
经营许可证编号:鄂ICP备2022015515号-1