浙江中醫藥大學-《資料結構》-棧和佇列演算法設計
阿新 • • 發佈:2019-01-07
1、從鍵盤上輸入一個字尾表示式,試編寫演算法計算表示式的值。規定:逆波蘭表示式的長度不超過一行,以$符作為輸入結束,運算元之間用空格分隔,操作符只可能有+、-、*、/四種運算。例如:234 34+2*$。
思路:逆波蘭表示式(即字尾表示式)求值規則如下:設立運算數棧OPND,對錶達式從左到右掃描(讀入),當表示式中掃描到數時,壓入OPND棧。當掃描到運算子時,從OPND退出兩個數,進行相應運算,結果再壓入OPND棧。這個過程一直進行到讀出表示式結束符$,這時OPND棧中只有一個數,就是結果。
float expr( ) //從鍵盤輸入逆波蘭表示式,以‘$’表示輸入結束,本演算法求逆波蘭式表示式的值。 {float OPND[30]; // OPND是運算元棧。 init(OPND); //兩棧初始化。 float num=0.0; //數字初始化。 cin>>x;//x是字元型變數。 while(x!=’$’) {switch {case‘0’<=x<=’9’: while((x>=’0’&&x<=’9’)||x==’.’) //拼數 if(x!=’.’) //處理整數 {num=num*10+(ord(x)-ord(‘0’)); cin>>x;} else //處理小數部分。 {scale=10.0; cin>>x; while(x>=’0’&&x<=’9’) {num=num+(ord(x)-ord(‘0’)/scale; scale=scale*10; cin>>x; } }//else push(OPND,num); num=0.0;//數壓入棧,下個數初始化 case x=‘ ’:break; //遇空格,繼續讀下一個字元。 case x=‘+’:push(OPND,pop(OPND)+pop(OPND));break; case x=‘-’:x1=pop(OPND);x2=pop(OPND);push(OPND,x2-x1);break; case x=‘*’:push(OPND,pop(OPND)*pop(OPND));break; case x=‘/’:x1=pop(OPND);x2=pop(OPND);push(OPND,x2/x1);break; default: //其它符號不作處理。 }//結束switch cin>>x;//讀入表示式中下一個字元。 }//結束while(x!=‘$’) cout<<“字尾表示式的值為”<<pop(OPND); }//演算法結束。
2、已知f為單鏈表的表頭指標, 連結串列中儲存的都是整型資料,試寫出實現下列運算的遞迴演算法:
① 求連結串列中的最大整數;
② 求連結串列的結點個數;
③ 求所有整數的平均值。
3、假設以帶頭結點的迴圈連結串列表示佇列,並且只設一個指標指向隊尾元素站點(注意不設頭指標) ,試編寫相應的置空隊、判隊空 、入隊和出隊等演算法。① int GetMax(LinkList p) { if(!p->next) return p->data; else { int max=GetMax(p->next); return p->data>=max ? p->data:max; } } ② int GetLength(LinkList p) { if(!p->next) return 1; else { return GetLength(p->next)+1; } } ③ double GetAverage(LinkList p , int n) { if(!p->next) return p->data; else { double ave=GetAverage(p->next,n-1); return (ave*(n-1)+p->data)/n; } }
思路:置空隊就是建立一個頭節點,並把頭尾指標都指向頭節點,頭節點是不存放資料的;判隊空就是當頭指標等於尾指標時,隊空;入隊時,將新的節點插入到鏈佇列的尾部,同時將尾指標指向這個節點;出隊時,刪除的是隊頭節點,要注意佇列的長度大於1還是等於1的情況,這個時候要注意尾指標的修改,如果等於1,則要刪除尾指標指向的節點。
//先定義鏈隊結構: typedef struct queuenode {Datatype data; struct queuenode *next; }QueueNode; //以上是結點型別的定義 typedef struct {queuenode *rear; }LinkQueue; //只設一個指向隊尾元素的指標 (1) 置空隊 void InitQueue( LinkQueue *Q) { //置空隊:就是使頭結點成為隊尾元素 QueueNode *s; Q->rear = Q->rear->next;//將隊尾指標指向頭結點 while (Q->rear!=Q->rear->next)//當佇列非空,將隊中元素逐個出隊 {s=Q->rear->next; Q->rear->next=s->next; delete s; }//回收結點空間 } (2) 判隊空 int EmptyQueue( LinkQueue *Q) { //判隊空。當頭結點的next指標指向自己時為空隊 return Q->rear->next->next==Q->rear->next; } (3) 入隊 void EnQueue( LinkQueue *Q, Datatype x) { //入隊。也就是在尾結點處插入元素 QueueNode *p=new QueueNode;//申請新結點 p->data=x; p->next=Q->rear->next;//初始化新結點並鏈入 Q-rear->next=p; Q->rear=p;//將尾指標移至新結點 } (4) 出隊 Datatype DeQueue( LinkQueue *Q) {//出隊,把頭結點之後的元素摘下 Datatype t; QueueNode *p; if(EmptyQueue( Q )) Error("Queue underflow"); p=Q->rear->next->next; //p指向將要摘下的結點 x=p->data; //儲存結點中資料 if (p==Q->rear) {//當佇列中只有一個結點時,p結點出隊後,要將隊尾指標指向頭結點 Q->rear = Q->rear->next; Q->rear->next=p->next; } else Q->rear->next->next=p->next;//摘下結點p delete p;//釋放被刪結點 return x; }