日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

3.2栈的应用举例

發布時間:2025/3/15 编程问答 12 豆豆
生活随笔 收集整理的這篇文章主要介紹了 3.2栈的应用举例 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

數制轉換

十進制數N和其他d進制數的轉換是計算機實現計算的基本問題,其解決方法很多,簡單算法基于下列原理:

N=(N div d)*d+N mod d(其中:div為整除運算,mod為求余運算)

例如(1348)10=(2504)8

計算過程如下圖:


(這算法很簡單,在此不做解釋)


我們發現到,對于任意一個非負整數,它的計算是從低位開始,然后才是高位。所以可以用棧先進后出的規則,下面是代碼:

算法3.1

void conversion (int Num) { // 對于輸入的任意一個非負十進制整數,打印輸出與其等值的八進制數ElemType e; SqStack S;InitStack(S); // 構造空棧while (Num) {Push(S, Num % 8);Num = Num/8;}while (!StackEmpty(S)) {Pop(S,e);printf ("%d", e);}printf("\n"); } // conversion 現在來分析下:

1.這里面Num是輸入的任意一個非負十進制整數。

2.這里push就是入棧,Pop就是出棧,每次把num除以8的余數入棧,入棧后再把Num除以8,這和上面的算法一樣。

3.StackEmpty()顧名思義,就是是不是空棧,他的返回值應該是0和非0(c語言沒有bool類型)。

4.隨后用先進后出的思想,就可以實現輸出了。




行編輯程序

當用戶輸入錯誤用“#”表示退格,用“@”表示行無效。

如下圖所示:


下面編寫一個程序:如果他既不是退格符也不是換行符,則將該字符壓入棧頂;如果是一個退格符,則從棧頂刪去一個字符;如果它是一個退行符,則將字符棧清空為空棧。

算法如下:

void LineEdit() { //利用字符棧S,從終端接收一行并傳送至調用過程的數據區。char ch,*temp;SqStack S;InitStack(S); //構造空棧Sprintf("請輸入一行(#:退格;@:清行):\n");ch = getchar(); //從終端接收第一個字符while (ch != EOF) { //EOF為全文結束符while (ch != EOF && ch != '\n') {switch (ch) {case '#': Pop(S, ch); break; // 僅當棧非空時退棧case '@': ClearStack(S); break; // 重置S為空棧default : Push(S, ch); break; // 有效字符進棧,未考慮棧滿情形}ch = getchar(); // 從終端接收下一個字符} temp=S.base;while(temp!=S.top) {printf("%c",*temp); ++temp;} // 將從棧底到棧頂的棧內字符傳送至調用過程的數據區;ClearStack(S); // 重置S為空棧printf("\n");if (ch != EOF) {printf("請輸入一行(#:退格;@:清行):\n");ch = getchar();}}DestroyStack(S); }
下面來分析下:

1.這里有個EOF,注釋為全文結束符,這是一個宏,在此程序里面,我們不必要高清這個宏具體指什么,只需要知道,有那么一個東西即可。

2.getchar這個函數只能接受一個字符,比如,當你從鍵盤上輸入hjuijij這幾個字母后,只有h被接受,如下圖所示:


3.這個DestroyStack就是銷毀棧,C/C++的特點就是要及時銷毀不用內存。

4.這個程序的思路就是從鍵盤輸入字符,判斷是什么字符,如果是‘#’則棧頂元素出棧,如果是‘@’則清空棧,如果是其他字符,則入棧。



迷宮求解

為了保證在任何位置上都能沿原路退回,顯然需要用一個后進先出的結構來保存從入口到當前位置的路徑。

下面說明一個迷宮:


可以寫出如下算法:


下面說明下這個棧的元素類型的結構體:

typedef struct{int ord; //通道塊在路徑上的“序號”PosType seat; //通道塊在迷宮中的“坐標位置”int di; //從此通道塊走向下一通道塊的“方向” }SElemType;
算法3.2:迷宮maze中存在從入口start到出口end的通道,則求的一條存放在棧中。

下面是代碼:

Status MazePath(MazeType &maze, PosType start, PosType end) { // 若迷宮maze中從入口 start到出口 end的通道,則求得一條存放在棧中// (從棧底到棧頂),并返回TRUE;否則返回FALSEStack S;PosType curpos;int curstep;SElemType e;InitStack(S);curpos = start; // 設定"當前位置"為"入口位置"curstep = 1; // 探索第一步do {if (Pass(curpos)) { // 當前位置可通過,即是未曾走到過的通道塊FootPrint(curpos); // 留下足跡e.di =1;e.ord = curstep;e.seat= curpos;Push(S,e); // 加入路徑if (curpos == end) return (TRUE); // 到達終點(出口)curpos = NextPos(curpos, 1); // 下一位置是當前位置的東鄰curstep++; // 探索下一步} else { // 當前位置不能通過if (!StackEmpty(S)) {Pop(S,e);while (e.di==4 && !StackEmpty(S)) {MarkPrint(e.seat); Pop(S,e); // 留下不能通過的標記,并退回一步} // whileif (e.di<4) {e.di++;Push(S, e); // 換下一個方向探索curpos = NextPos(e.seat, e.di); // 當前位置設為新方向的相鄰塊} // if} // if} // else} while (!StackEmpty(S) );return FALSE; } // MazePath 下面來分析下代碼:

這個程序的思路如下,PosType e,這個是定義了一個坐標類型,變量名為e,并且初始化了棧S,在程序開始(未循環時)把坐標設置為迷宮開始的位置。并且用了一個int型的curstep來說明當前的步驟(開始時設置為1)。在do循環中,可以看到一個叫Pass的函數,傳遞了一個參數,為當前位置。

如果可以通過則留下足跡,并且給e進行賦值(e為上面那個結構體SElemType)。這里我們看到了一個if(curpos==end)這個,然后我們到倒數第7行看到cusps=NextPos(e.seat,e.di)這個if就是根據他來的。當if(curpos==end)不滿足時,curpos后移,并且cursetp++。

如果不可以通過時,則要先看這個S棧是不是空,不為空這出棧,隨后判斷e.ei==4(這個,其實是標記,上下左右的標記,當此位置上下左右都被標記后就是4)。

差不多就這樣了,大家熟悉下思路就可以了。官方也沒有提供全代碼,也不好具體分析。



表達式求值

這里只介紹算符優先(編譯原理也有相關介紹):

如對下面的算術表達式求值:

4+2*3-10/5

這個表達式的計算順序為:4+2*3-10/5=4+6-10/5=10-10/5=10-2=8

算符優先法就是根據這個運算優先關系的規定來實現對表達式的編譯或解釋執行的。

我們知道算符只有三種關系:

1.低于2.等于3.高于

下面定義了算符之間的這種優先關系。


#是表達式結束符。


為了實現算符優先算法,可以使用兩個工作棧。一個叫OPTR,用以寄存器運算,一個叫OPND用以寄存操作數或運算結果。思路如下:

1.首先置操作數棧為空棧,表達式起始符“#”為運算符棧底元素;

2.依次讀入表達式中每個字符,若是操作數則進OPND棧,若是運算符則和OPTR棧的棧頂元素比較優先級后做相應操作,直至整個表達式求值完畢(即OPTR棧的棧頂元素和當前讀入的字符均為“#”)

先看一個例子,再來看代碼,例子如下:


下面是代碼:

這代碼我修改了下,與書上有些地方不同(個人覺得書上的不太好)

OperandType EvaluateExpression() {//算術表達式求值的算符優先算法。設OPTR和OPND分別為運算符和運算數棧,//OP為運算符集合StackChar OPTR; // 運算符棧,字符元素StackFloat OPND; // 運算數棧,實數元素float a,b;char theta,c;InitStack(OPTR);Push(OPTR,'#');InitStack(OPND);c=Nextchar();while(c!='#'||GetTop(OPTR)!='#') //OP為運算符集合{if(!In(c,OP)){Push(OPND,c); //操作數靜OPNDc=Nextchar();}else{switch(Precede(GetTop(OPTR),c)){case '<': //棧頂元素優先權低Push(OPTR,c);c=Nextchar();break;case '=': //脫括號并接受下一字符Pop(OPTR,c);c=Nextchar();break;case '>': //退棧并將運算結果入棧Pop(OPTR,theta);Pop(OPND,b);Pop(OPND,a);Push(OPND,Operate(a,theta,b));break; }}}return GetTop(OPND); } // EvaluateExpression
下面是分析:

這里兩個棧,OPTR和OPND,OPTR存運算符,OPND存數和結果。這里用Nextchar來獲取表達式的字符,這里有個In函數,其中里面有個OP,就是判斷獲得的這個字符,是不是運算符。這里還有個Operate,這里的Operate不是C++里面的Operate,這個大家就把他理解成一個運算的函數,他可以把數a和運算符theta和數b進行處理,最后得出結果

思路每次讀取字符,當發現是運算符時放入OPTR,當是數時放入OPND,還要判斷優先級,當棧頂優先級低,則入棧,當相等時(只有棧頂為左括號,待入棧為右括號時才會相等)當棧頂優先級大的時后著出棧,運算。



總結

以上是生活随笔為你收集整理的3.2栈的应用举例的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。