版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報或認(rèn)領(lǐng)
文檔簡介
一、教學(xué)內(nèi)容:
1、 棧和隊(duì)列的定義及特點(diǎn);
2、 棧的順序存儲表示和鏈接存儲表示;
3、 隊(duì)列的順序存儲表示和鏈接存儲表示;
4、 棧和隊(duì)列的應(yīng)用舉例。
第三章棧和隊(duì)列二、教學(xué)要求:
1、掌握棧和隊(duì)列的定義、特性,并能正確應(yīng)用它們解決實(shí)際問題;
2、熟練掌握棧的順序表示、鏈表表示以及相應(yīng)操作的實(shí)現(xiàn)。特別注意??蘸蜅M的條件;
3、熟練掌握隊(duì)列的順序表示、鏈表表示以及相應(yīng)操作的實(shí)現(xiàn)。特別是循環(huán)隊(duì)列中隊(duì)頭與隊(duì)尾指針的變化情況
棧和隊(duì)列是兩種特殊的線性表,是操作受限的線性表,稱限定性數(shù)據(jù)結(jié)構(gòu)。棧棧的應(yīng)用隊(duì)列隊(duì)列的應(yīng)用3.1棧(stack)一、棧的定義:限定僅在表尾進(jìn)行插入或刪除操作的線性表,表尾—棧頂,表頭—棧底,不含元素的空表稱空棧特點(diǎn):先進(jìn)后出(FILO)或后進(jìn)先出(LIFO)ana1a2……...棧底棧頂...出棧進(jìn)棧棧s=(a1,a2,……,an)棧的特點(diǎn)根據(jù)棧的定義可知,最先放入棧中元素在棧底,最后放入的元素在棧頂,而刪除元素剛好相反,最后放入的元素最先刪除,最先放入的元素最后刪除。也就是說,棧是一種后進(jìn)先出(LastInFirstOut)的線性表,簡稱為LIFO表。
stack棧的基本操作1.初始化棧:INISTACK(&S)將棧S置為一個空棧(不含任何元素)。2.進(jìn)棧:PUSH(&S,X)將元素X插入到棧S中,也稱為“入?!?、“插入”、“壓入”。3.出棧:POP(&S)
刪除棧S中的棧頂元素,也稱為”退?!?、“刪除”、“彈出”。4.取棧頂元素:GETTOP(S,&e)取棧S中棧頂元素。5.判??眨篠tackEmpty(S)判斷棧S是否為空,若為空,返回值為true,否則返回值為false。例1:對于一個棧,給出輸入項(xiàng)A、B、C,如果輸入項(xiàng)序列由ABC組成,試給出所有可能的輸出序列。A進(jìn)A出B進(jìn)B出C進(jìn)C出ABCA進(jìn)A出B進(jìn)C進(jìn)C出B出ACBA進(jìn)B進(jìn)B出A出C進(jìn)C出BACA進(jìn)B進(jìn)B出C進(jìn)C出A出BCAA進(jìn)B進(jìn)C進(jìn)C出B出A出CBA不可能產(chǎn)生輸出序列CAB例2:一個棧的輸入序列是12345,若在入棧的過程中允許出棧,則棧的輸出序列43512可能實(shí)現(xiàn)嗎?12345的輸出呢?43512不可能實(shí)現(xiàn),主要是其中的12順序不能實(shí)現(xiàn);
12345的輸出可以實(shí)現(xiàn),只需壓入一個立即彈出一個即可。435612中到了12順序不能實(shí)現(xiàn);
135426可以實(shí)現(xiàn)。例3:如果一個棧的輸入序列為123456,能否得到435612和135426的出棧序列?答:答:例4:計(jì)算機(jī)系2005年考研題(程序設(shè)計(jì)基礎(chǔ))設(shè)依次進(jìn)入一個棧的元素序列為c,a,b,d,則可得到出棧的元素序列是:
A)a,b,c,dB)c,d,a,bC)b,c,d,aD)a,c,d,bA、D可以(B、C不行)。答:二、順序棧由于棧是運(yùn)算受限的線性表,因此線性表的存儲結(jié)構(gòu)對棧也適應(yīng)。棧的順序存儲結(jié)構(gòu)簡稱為順序棧,它是運(yùn)算受限的線性表。因此,可用數(shù)組來實(shí)現(xiàn)順序棧。因?yàn)闂5孜恢檬枪潭ú蛔兊?,所以可以將棧底位置設(shè)置在數(shù)組的兩端的任何一個端點(diǎn);棧頂位置是隨著進(jìn)棧和退棧操作而變化的,故需用一個整型變量top來指示當(dāng)前棧頂?shù)奈恢茫ǔ7Qtop為棧頂指針。因此,順序棧的類型定義只需將順序表的類型定義中的長度屬性改為top即可。順序棧的類型定義如下(靜態(tài))
#defineStackSize100typedefstruct{ElemTypedata[StackSize];inttop;}SeqStack;//-----棧的順序存儲表示
-----(動態(tài))
#defineSTACK_INIT_SIZE100;
#defineSTACKINCREMENT10;
typedefstruct{
SElemType
*base;
SElemType
*top;
intstacksize;
}
SqStack;top=0123450??諚m斨羔榯op,指向?qū)嶋H棧頂后的空位置,初值為0top123450進(jìn)棧Atop出棧棧滿BCDEF設(shè)數(shù)組維數(shù)為Mtop=0,??眨藭r出棧,則下溢(underflow)top=M,棧滿,此時入棧,則上溢(overflow)toptoptoptoptop123450ABCDEFtoptoptoptoptoptop??諚m攖op的值為下一個將要進(jìn)棧的元素下標(biāo)。
設(shè)S是SeqStack類型的指針變量。若棧底位置在向量的低端,即s–>data[0]是棧底元素,那么棧頂指針s–>top是正向增加的,即進(jìn)棧時需將s–>top加1,退棧時需將s–>top減1。因此,s–>top=0表示空棧,s–>top=stacksize表示棧滿。當(dāng)棧滿時再做進(jìn)棧運(yùn)算必定產(chǎn)生空間溢出,簡稱“上溢”;當(dāng)棧空時再做退棧運(yùn)算也將產(chǎn)生溢出,簡稱“下溢”。上溢是一種出錯狀態(tài),應(yīng)該設(shè)法避免之;下溢則可能是正?,F(xiàn)象,因?yàn)闂T诔绦蛑惺褂脮r,其初態(tài)或終態(tài)都是空棧,所以下溢常常用來作為程序控制轉(zhuǎn)移的條件。1、置空棧
voidinitstack(seqstack*s){s–>top=0;}2、判斷???/p>
intstackempty(seqstack*s){return(s–>top==0);}3、判斷棧滿
intstackfull(seqstack*s){return(s–>top==stacksize);}4、進(jìn)棧
voidpush(seqstack*s,ElemTypex){if(stackfull(s))error(“stackoverflow”);s–>data[s–>top++]=x;}5、退棧
voidpop(seqstack*s,ElemType*x){if(stackempty(s))error(“stackunderflow”);s–>top--;*x=s–>data[top];}
6、取棧頂元素ElemTypestacktop(seqstack*s){if(stackempty(s)error(“stackisempty”);returns–>data[s–>top-1];}
3.1.3鏈棧
棧的鏈?zhǔn)酱鎯Y(jié)構(gòu)稱為鏈棧,它的運(yùn)算是受限的單鏈表,插入和刪除操作僅限制在表頭位置上進(jìn)行。由于只能在鏈表頭部進(jìn)行操作,故鏈表可以沒有必要像單鏈表那樣附加頭結(jié)點(diǎn)。棧頂指針就是鏈表的頭指針。鏈棧的類型說明如下:
棧的鏈接存儲結(jié)構(gòu)鏈棧的結(jié)點(diǎn)定義typedefstructnode{ElemTypedata;structnode*next;}LinkStack;
棧的鏈接表示—鏈?zhǔn)綏f準(zhǔn)綏o棧滿問題,空間可擴(kuò)充插入與刪除僅在棧頂處執(zhí)行鏈?zhǔn)綏5臈m斣阪滎^適合于多棧操作在鏈棧中,棧的基本運(yùn)算算法如下:(1)初始化棧initStack(&L)
建立一個空棧L。實(shí)際上是創(chuàng)建鏈棧的頭結(jié)點(diǎn),并將其next域置為NULL。對應(yīng)算法如下:voidInitStack(ListStack*&L){ L=(ListStack*)malloc(sizeof(ListStack)); L->next=NULL;}
(2)銷毀棧ClearStack(&L)
釋放棧L占用的全部存儲空間。對應(yīng)算法如下:voidClearStack(ListStack*&L){ ListStack*p=L->next; while(p!=NULL) { free(L); L=p; p=p->next; }}
(3)求棧的長度StackLength(L)
從第一個數(shù)據(jù)結(jié)點(diǎn)開始掃描單鏈表,用i記錄訪問的數(shù)據(jù)結(jié)點(diǎn)個數(shù),最后返回i值。對應(yīng)算法如下:intStackLength(ListStack*L){ inti=0; ListStack*p; p=L->next; while(p!=NULL) {i++;p=p->next;} return(i);}
(4)判斷棧是否為空StackEmpty(L)
棧L為空的條件是L->next==NULL,即單鏈表中沒有數(shù)據(jù)結(jié)點(diǎn)。對應(yīng)算法如下:intStackEmpty(ListStack*L){ return(L->next==NULL);}
(5)進(jìn)棧Push(&L,e)
將新數(shù)據(jù)結(jié)點(diǎn)插入到頭結(jié)點(diǎn)之后。對應(yīng)算法如下:voidPush(ListStack*&L,ElemTypee){ ListStack*p; p=(ListStack*)malloc(sizeof(ListStack)); p->data=e; p->next=L->next; /*插入*p結(jié)點(diǎn)作為第一個數(shù)據(jù)結(jié)點(diǎn)*/ L->next=p;}
(6)出棧Pop(&L,&e)
在棧不為空的條件下,將頭結(jié)點(diǎn)后繼數(shù)據(jù)結(jié)點(diǎn)的數(shù)據(jù)域賦給e,然后將其刪除。對應(yīng)算法如下:intPop(ListStack*&L,ElemType&e){ ListStack*p; if(L->next==NULL)return0;/*??盏那闆r*/ p=L->next; /*p指向第一個數(shù)據(jù)結(jié)點(diǎn)*/ e=p->data; L->next=p->next; free(p); return1;}
(7)取棧頂元素GetTop(L)
在棧不為空的條件下,將頭結(jié)點(diǎn)后繼數(shù)據(jù)結(jié)點(diǎn)的數(shù)據(jù)域賦給e。對應(yīng)算法如下:
intGetTop(ListStack*L,ElemType&e){ if(L->next==NULL)return0; /*??盏那闆r*/ e=L->next->data; return1;}
(8)顯示棧中元素DispStack(L)
從第一個數(shù)據(jù)結(jié)點(diǎn)開始掃描單鏈表,并輸出當(dāng)前訪問結(jié)點(diǎn)的數(shù)據(jù)域值。對應(yīng)算法如下:voidDispStack(ListStack*L){ ListStack*p=L->next; while(p!=NULL) { printf("%c",p->data); p=p->next; } printf("\n");}3.2棧的應(yīng)用舉例
由于棧結(jié)構(gòu)具有的后進(jìn)先出的固有特性,致使棧成為程序設(shè)計(jì)中常用的工具。以下是幾個棧應(yīng)用的例子。一、棧的應(yīng)用舉例-----數(shù)制轉(zhuǎn)換十進(jìn)制N和其它進(jìn)制數(shù)的轉(zhuǎn)換是計(jì)算機(jī)實(shí)現(xiàn)計(jì)算的基本問題,其解決方法很多,其中一個簡單算法基于下列原理:N=(ndivd)*d+nmodd(其中:div為整除運(yùn)算,mod為求余運(yùn)算)
例如(1348)10=(2504)8,其運(yùn)算過程如下:
nndiv8nmod8134816841682102125202
voidconversion(){initstack(s);scanf(“%d”,&n);while(n){push(s,n%8);n=n/8;}while(!Stackempty(s)){pop(s,e);printf(“%d”,e);}}二、括號匹配的檢驗(yàn)假設(shè)在表達(dá)式中([]())或[([][])]等為正確的格式,[(])或([())或(()])均為不正確的格式。則檢驗(yàn)括號是否匹配的方法可用“期待的急迫程度”這個概念來描述。分析可能出現(xiàn)的不匹配的情況:到來的右括弧并非是所“期待”的;例如:考慮下列括號序列:
[([][])]12345678到來的是“不速之客”;直到結(jié)束,也沒有到來所“期待”的括弧。算法的設(shè)計(jì)思想:1)凡出現(xiàn)左括弧,則進(jìn)棧;2)凡出現(xiàn)右括弧,首先檢查棧是否空若???,則表明該“右括弧”多余,否則和棧頂元素比較,若相匹配,則“左括弧出?!?/p>
,否則表明不匹配。3)表達(dá)式檢驗(yàn)結(jié)束時,若??眨瑒t表明表達(dá)式中匹配正確,否則表明“左括弧”有余。Statusmatching(string&exp){
intstate=1;
while(i<=Length(exp)&&state){
switchofexp[i]{
case
”(”
:{Push(S,exp[i]);i++;break;}
case”)”:{
if(NOTStackEmpty(S)&&GetTop(S)=“(“{Pop(S,e);i++;}
else{state=0;}
break;}……}
if(StackEmpty(S)&&state)returnOK;…...三、行編輯程序問題如何實(shí)現(xiàn)?“每接受一個字符即存入存儲器”?
并不恰當(dāng)!
設(shè)立一個輸入緩沖區(qū),用以接受用戶輸入的一行字符,然后逐行存入用戶數(shù)據(jù)區(qū),并假設(shè)“#”為退格符,“@”為退行符。
在用戶輸入一行的過程中,允許用戶輸入出差錯,并在發(fā)現(xiàn)有誤時可以及時更正。合理的作法是:假設(shè)從終端接受了這樣兩行字符:
whli##ilr#e(s#*s)
outcha@putchar(*s=#++);則實(shí)際有效的是下列兩行:
while(*s)
putchar(*s++);
while(ch!=EOF&&ch!='\n'){
switch(ch){
case'#':Pop(S,c);break;
case'@':ClearStack(S);break;//重置S為空棧
default
:Push(S,ch);break;
}ch=getchar();//從終端接收下一個字符
}ClearStack(S);//重置S為空棧if(ch!=EOF)ch=getchar();while(ch!=EOF){//EOF為全文結(jié)束符將從棧底到棧頂?shù)淖址麄魉椭琳{(diào)用過程的數(shù)據(jù)區(qū);(這是棧應(yīng)用的典型例子)
這里,表達(dá)式求值的算法是“算符優(yōu)先法”。例如:3*(7–2)(1)要正確求值,首先了解算術(shù)四則運(yùn)算的規(guī)則:
a.
從左算到右
b.先乘除,后加減
c.先括號內(nèi),后括號外由此,此表達(dá)式的計(jì)算順序?yàn)椋?/p>
3*(7–2)=3*5=15四、棧的應(yīng)用舉例--表達(dá)式計(jì)算(2)根據(jù)上述三條運(yùn)算規(guī)則,在運(yùn)算的每一步中,對任意相繼出現(xiàn)的算符
1和
2
,都要比較優(yōu)先權(quán)關(guān)系。算符優(yōu)先法所依據(jù)的算符間的優(yōu)先關(guān)系見教材P53表3.1
(是提供給計(jì)算機(jī)用的表?。5膽?yīng)用(表達(dá)式求值)(3)算法思想:設(shè)定兩棧:操作符棧OPTR,操作數(shù)棧OPND棧初始化:設(shè)操作數(shù)棧OPND為空;操作符棧OPTR的棧底元素為表達(dá)式起始符‘#’;依次讀入字符:是操作數(shù)則入OPND棧,是操作符則要判斷:
if操作符<棧頂元素,則退棧、計(jì)算,結(jié)果壓入OPND棧;
操作符=棧頂元素且不為‘#’,脫括號(彈出左括號);
操作符>棧頂元素,壓入OPTR棧。OPTROPNDINPUTOPERATE3*(7-2)#Push(opnd,’3’)
#*(7-2)#3#Push(optr,’*’)#,*3(7-2)#Push(optr,’(’)#,*,(37-2)#Push(opnd,’7’)#,*,(3,7-2)#Push(optr,’-’)#,*,(,-3,72)#Push(opnd,’2’)#,*,(,-3,7,2)#Operate(7-2)#,*,(3,5)#Pop(optr)#,*3,5#Operate(3*5)#15#GetTop(opnd)StatusEvaluateExpression(OperandType&result){InitStack(OPND);InitStack(OPTR);Push(OPTR,’#’);c=getchar();while((c!=‘#’)&&(GetTop(OPTR)!=‘#’)){if(!In(c,OP){Push(OPND,c);c=getchar();}elseswitch(compare(c,GetTop(OPTR))){case‘>’:Push(OPTR,c);c=getchar();break;case‘=’:Pop(OPTR);c=getchar();break;
case‘<’:op=Pop(OPTR);b=Pop();a=Pop();//退棧
result=Operate(a,op,b);Push(OPND,result);c=getchar();break;}//switch}//whileresult=GetTop(OPND);}//EvaluateExpression此函數(shù)在哪里?五、實(shí)現(xiàn)遞歸將所有的實(shí)在參數(shù)、返回地址等信息傳遞給被調(diào)用函數(shù)保存;為被調(diào)用函數(shù)的局部變量分配存儲區(qū);將控制轉(zhuǎn)移到被調(diào)用函數(shù)的入口。
當(dāng)在一個函數(shù)的運(yùn)行期間調(diào)用另一個函數(shù)時,在運(yùn)行該被調(diào)用函數(shù)之前,
需先完成三項(xiàng)任務(wù):保存被調(diào)函數(shù)的計(jì)算結(jié)果;釋放被調(diào)函數(shù)的數(shù)據(jù)區(qū);依照被調(diào)函數(shù)保存的返回地址將控制轉(zhuǎn)移到調(diào)用函數(shù)。從被調(diào)用函數(shù)返回調(diào)用函數(shù)之前,應(yīng)該完成下列三項(xiàng)任務(wù):多個函數(shù)嵌套調(diào)用的規(guī)則是:此時的內(nèi)存管理實(shí)行“棧式管理”后調(diào)用先返回!例如:voidmain(){voida(){voidb(){……
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 2025-2030年中國齒科材料行業(yè)發(fā)展現(xiàn)狀規(guī)劃研究報告
- 2025-2030年中國馬齒莧市場運(yùn)行狀況及投資前景趨勢分析報告
- 2025-2030年中國鐘表行業(yè)前景趨勢展望及投資潛力分析報告
- 2025-2030年中國金屬家具制造行業(yè)運(yùn)行狀況及發(fā)展趨勢預(yù)測報告
- 2025年度深水井鉆井設(shè)備租賃與承包合同3篇
- 2025年度互聯(lián)網(wǎng)金融服務(wù)平臺軟件開發(fā)與維護(hù)合同3篇
- 2024版建筑工程預(yù)算審核委托合同書版
- 2025年度建筑設(shè)備維護(hù)與改造合同2篇
- 2025年戰(zhàn)略聯(lián)盟與經(jīng)營權(quán)共享合同3篇
- GB/T 2992-1998通用耐火磚形狀尺寸
- 英語名著閱讀老人與海教學(xué)課件(the-old-man-and-the-sea-)
- 學(xué)校食品安全知識培訓(xùn)課件
- 全國醫(yī)學(xué)博士英語統(tǒng)一考試詞匯表(10000詞全) - 打印版
- 最新《會計(jì)職業(yè)道德》課件
- DB64∕T 1776-2021 水土保持生態(tài)監(jiān)測站點(diǎn)建設(shè)與監(jiān)測技術(shù)規(guī)范
- ?中醫(yī)院醫(yī)院等級復(fù)評實(shí)施方案
- 數(shù)學(xué)-九宮數(shù)獨(dú)100題(附答案)
- 理正深基坑之鋼板樁受力計(jì)算
- 學(xué)校年級組管理經(jīng)驗(yàn)
- 10KV高壓環(huán)網(wǎng)柜(交接)試驗(yàn)
評論
0/150
提交評論