數(shù)據(jù)結(jié)構(gòu)(C語言版) 第3章 棧與隊列
《數(shù)據(jù)結(jié)構(gòu)(C語言版) 第3章 棧與隊列》由會員分享,可在線閱讀,更多相關《數(shù)據(jù)結(jié)構(gòu)(C語言版) 第3章 棧與隊列(25頁珍藏版)》請在裝配圖網(wǎng)上搜索。
1、第3章 棧與隊列 棧與隊列:限定操作的線性表。 1 棧 1.1 邏輯結(jié)構(gòu) 1.1.1 定義 限定只能在表的一端進行插入、刪除的線性表。 棧頂top,棧底bottom。 后進先出LIFO表(Last In First Out) 1.1.2 基本操作 進棧Push/出棧Pop 取棧頂元素GetTop 判別??読sEmpty/棧滿isFull 1.1.3 應用領域 實例:“進制數(shù)轉(zhuǎn)換”、“表達式求值”、“函數(shù)調(diào)用關系”、“括號匹配問題”、“漢諾塔問題”、“迷宮問題”、“九連環(huán)”…… 許多問題的求解分為若干步驟,而當前步驟的解答,是建立在后繼步驟的
2、解答基礎上的。=》問題分解的步驟和求解的步驟次序恰好相反。
1.2 順序棧
/////////////////////////////////
// 項目路徑:1順序棧
/////////////////////////////////
1.2.1 類的定義
const int StackSize=10;
template
3、;
SeqStack(SeqStack
4、Stack
5、false;
}
// 判斷棧是否為滿
template
6、SeqStack
7、/ 項目路徑:1順序棧(2個)
/////////////////////////////////
1.4 鏈棧
/////////////////////////////////
// 項目路徑:2鏈棧
/////////////////////////////////
1.4.1 類的定義
template
8、 棧頂指針:鏈表頭指針
public:
LinkStack( );
~LinkStack( );
void Push(T x); // 進棧
T Pop( ); // 出棧
T GetTop( ); // 取棧頂元素(不刪除)
bool isEmpty( ); // 判斷鏈棧是否為空棧
};
// 棧滿:系統(tǒng)內(nèi)存不夠
1.4.2 基本操作
1.4.2.1 構(gòu)造/析構(gòu)
template
9、late
10、op = newp;
}
// 出棧
template
11、:
N
n div 8
n mod 8
1348
168
4
168
21
0
21
2
5
2
0
2
void Conversion(int n,int k)
{ LinkStack 12、 : 0
Equal( "(((a)(b))" ) : 1
Equal( "((a)(b)))" ) : -1
int Equal(char s[])
{ LinkStack 13、 return(1); // (多
return(0); // 完全匹配
}
2.3 迷宮算法(思考)
2.4 后綴表達式求值
中綴表達式
后綴表達式
A+B*C
ABC*+
B*(D-C)+A
BDC-*A+
2*(3-4)+5
234-*5+
算符在運算數(shù)之間
算符在運算數(shù)之后,沒有括號,算符沒有優(yōu)先級
按“算符優(yōu)先級”求值
按“順序計算法”求值
輔助數(shù)據(jù)結(jié)構(gòu):一個運算數(shù)棧OPND。
算法:自左向右掃描后綴表達式,直至遇到結(jié)束符為止。
遇算數(shù):進棧,
遇算符:退棧二數(shù),運算結(jié)果再進棧,
// 只能處理 14、1位數(shù)運算數(shù)
float PostExpression(char s[])
{ LinkStack 15、()); /* 棧中唯一值:表達式值 */
}
float Eval(float a, char op, float b)
{ switch(op)
{ case '+': return(a+b);
case '-': return(a-b);
case '/': return(a/b);
case '*': return(a*b);
}
}
2.5 中綴表達式轉(zhuǎn)換為后綴表達式
示例數(shù)據(jù):
Mid[]: "2*(3-4)+5#"
Post[]:"234-*5+"
輔助數(shù)據(jù)結(jié)構(gòu):一個運算符棧OPTR。
16、 算法:自左向右掃描Mid[],直至遇到結(jié)束符#。
遇算數(shù):加入Post[]。
遇算符op:取棧頂算符pre_op
若op>pre_op:op進棧;
若op 17、
c='*'
c='('
c='-' c='/'
c=')'
c=')'
C=')'
c='+'
c='+'
c='+'
C='#'
void MidToPost(char Mid[],char Post[])
{ LinkStack 18、 { Post[iPost++]=c; c=Mid[iMid++]; continue; }
char pre_op=OPTR.GetTop();
switch( Precede(pre_op,c) ) // 比較算符優(yōu)先級
{ case '<': // pre_op < c
OPTR.Push(c); c=Mid[iMid++]; break;
case '=':
OPTR.Pop(); c=Mid[iMid++]; break;
case '>': // pre_o 19、p > c
OPTR.Pop(); Post[iPost++]=pre_op;
}
}
Post[iPost]=0;
}
// 算符優(yōu)先級比較的代碼
分析:先乘除,后加減;從左到右;先括號內(nèi),再括號外。
后算符
前算符
+
-
×
/
(
)
#
+
>
>
<
<
<
>
>
-
>
>
<
<
<
>
>
×
>
>
>
>
<
>
>
/
>
>
>
>
<
>
>
(
<
<
<
<
<
=
)
>
>
>
>
>
20、>
#
<
<
<
<
<
=
char priority[7][7]=
// + - * / ( ) #
{{'>', '>', '<', '<', '<', '>', '>'}, // +
{'>', '>', '<', '<', '<', '>', '>'}, // -
{'>', '>', '>', '>', '<', '>', '>'}, // *
{'>', '>', '>', '>', '<', '>', '>'}, // /
{'<', '<', '<', '<', ' 21、<', '=', '0'}, // (
{'>', '>', '>', '>', '0', '>', '>'}, // )
{'<', '<', '<', '<', '<', '0', '='} // #
};
int OpID(char op)
{ switch (op)
{ case '+' : return(0);
case '-' : return(1);
case '*' : return(2);
case '/' : return(3);
case '(' : return(4);
22、 case ')' : return(5);
case '#' : return(6);
}
}
char Precede(char op1,char op2)
{ return(priority[OpID(op1)][OpID(op2)]); }
2.6 中綴表達式求值的算法
示例數(shù)據(jù):
s[]: 1+2*(3+4*(5+6))#
與2.5算法的相似處:
當前運算是否立即執(zhí)行?必須先和“上一個運算符”比較優(yōu)先級。
輔助數(shù)據(jù)結(jié)構(gòu):運算符棧OPTR,運算數(shù)棧OPND
算法:自左向右掃描s[],直至遇到結(jié)束符#。
遇算數(shù) 23、:OPND.Push(c-'0');
遇算符op:取棧頂算符pre_op
若op>pre_op:OPTR.Push(c);
若op 24、kStack 25、case '<': // pre_op < c
OPTR.Push(c); i++; break;
case '=':
OPTR.Pop(); i++; break;
case '>': // pre_op > c 執(zhí)行pre_op
OPTR.Pop();
float opd1=OPND.Pop();
float opd2=OPND.Pop();
OPND.Push( Eval(opd2,pre_op,opd1) );
26、 }
}
return(OPND.GetTop());
}
測試案例:"#", "3#","3+5#","3+5+2#"
"3*5+2#", "3+5*2#","(3+5)*2#",
"(3+5)*(2+1)#","((3+5)/2+1)*2#" …………
作業(yè)與上機
實現(xiàn)棧類和中綴表達式求值功能。
層次1:運算數(shù)可以實數(shù)、負數(shù)
層次2:表達式語法檢查、報錯誤位置
層次3:多個表達式依次求值(含變量)
層次4:超長運算數(shù)的表達式求值
附錄:九連環(huán)的玩法
void down_1(int n) 27、 { printf("%2ddown,",n); } //下第n個環(huán)
void down_12() { printf("12down,"); } //下1、2環(huán)
void up_1(int n) { printf("%2dup, ",n); } //上第n個環(huán)
void up_12() { printf("12up, "); } //上1、2環(huán)
void huan_down(int n) //下前n個環(huán)
{ if(n==1) { down_1(n); return; }
if(n==2) { down_12(); return; 28、}
huan_down(n-2); down_1(n);
huan_up(n-2); huan_down(n-1);
}
void huan_up(int n) //上前n個環(huán)
{ if(n==1) { up_1(n); return; }
if(n==2) { up_12(); return; }
huan_up(n-1); huan_down(n-2);
up_1(n); huan_up(n-2);
}
//打印下九連環(huán)的步驟
main(){ huan_down(9); }
3 隊列
3.1 邏輯結(jié)構(gòu)
29、 只能在一端(隊尾rear)插入,在另一端(隊頭front)刪除的線性表。
先進先出表FIFO(First In First Out)
基本操作:進隊列Enter/出隊列Leave
判別隊列空isEmpty/隊列滿isFull
應用領域:排隊模型。排隊問題無處不在,各種服務行業(yè)、甚至生產(chǎn)管理中都存在排隊問題。
3.2 鏈隊列
/////////////////////////////////
// 項目路徑:3鏈隊列
/////////////////////////////////
3.2.1 類的定義
template 30、ass T>
struct LinkNode
{ T data;
LinkNode 31、nt( ); // 取隊列的隊頭元素
bool isEmpty( ); // 判斷隊列是否為空
};
3.2.2 基本操作
3.2.2.1 構(gòu)造/析構(gòu)
template 32、T>::Enter(T e)
{ LinkNode 33、 T e=p->data; //暫存隊頭元素
m_Front=p->next; delete p;
if(m_Front==NULL) m_Rear=NULL;
return e;
}
//取隊頭元素
template 34、/////////////////////////////////
3.2.1 類的定義
const int QueueSize=6; // 隊列存儲空間的長度
template 35、 進隊列
T Leave( ); // 出隊列
T GetFront( ); // 取隊頭元素(不刪除)
bool isEmpty( ); // 判斷隊列是否為空
bool isFull( ); // 判斷隊列是否為滿
};
3.2.2 隊頭/尾指針的取值討論=》循環(huán)隊列
以往的常識:進隊列m_Rear++; 出隊列m_Front++
常識中隱藏了陷阱:假溢出!
循環(huán)隊列:
進隊列m_Rear =(m_Rear +1)% QueueSize;
出隊列m_Front=( 36、m_Front+1)% QueueSize;
約定:
m_Rear
下一個進隊列元素的位置
m_Front
隊列不空時,指向首元素;
隊列為空時,等于rear
隊列空時
m_Front==m_Rear
隊列滿時
(m_Rear+1) % QueueSize==m_Front
=》必須浪費一個結(jié)點空間
3.2.3 基本操作
3.2.3.1 構(gòu)造/析構(gòu)
template 37、e 38、_Front) throw "下溢";
T e = m_Data[m_Front];
m_Front = (m_Front+1) % QueueSize;
return e;
}
// 隊列長度
template 39、實例:離散事件的模擬
4.1 逐行打印二項展開式(a + b)n的系數(shù)(楊輝三角形)
void YANGVI(int n, vector 40、1+e2);
e1=e2;
}
Q.Enter(1);
}
for(i=0; !Q.isEmpty(); i++)
coefs.push_back( Q.Leave() );
}
4.2 最簡單的排隊問題
某加油站只有一臺加油機,平均為每輛車加油需要5分鐘,假定一個小時內(nèi),有20輛車隨機進入加油站加油,計算每輛車的平均等待時間。
// ServiceTime: 每輛車加油需要的時間
// TotalTime: 總的時間段
// n: 在TotalTime內(nèi),n輛車隨機進入加油站
// 返回平均等待時間
float 41、 OilStation(int n,int TotalTime,float ServiceTime)
{ // 生成模擬數(shù)據(jù)
vector 42、riveTimes[i]);
// 出隊列,仿佛享受加油站的服務
float BeginOilTime=0, WaitTime=0;
while( !Q.isEmpty() )
{ float ArriveTime=Q.Leave();
if(BeginOilTime > ArriveTime)
WaitTime+=BeginOilTime - ArriveTime; // 需要等待
else
BeginOilTime = ArriveTime; // 不需等待
BeginOil 43、Time += ServiceTime; // 加油機為下輛車加油的時刻
}
return WaitTime/n;
}
思考:加油站有二臺加油機的情形?有k臺加油機的情形?
4.3 稍微復雜一些的排隊問題
銀行營業(yè)所有n種業(yè)務,每類業(yè)務的服務時間是Ti,每種業(yè)務量是Ki/日。問每類業(yè)務應該設置幾個服務窗口?
4.4 優(yōu)先級隊列(Priority Queue)
優(yōu)先級:數(shù)據(jù)元素的某個值。
進隊列:按次序從隊尾進。
出隊列:取隊列中優(yōu)先權(quán)最高的元素。
5 棧、隊列的習題
5.1 進棧出棧的組合問題(初級)
①已知操作次序: 44、push(1); pop(); push(2); push(3); pop(); pop( ); push(4); pop( ); 請寫出出棧序列。
②設進棧次序固定為push(1); push(2); push(3); push(4); 請分析1、2、3、4的24種排列中,哪些序列可以通過出棧操作實現(xiàn),哪些不能實現(xiàn)?
1234
1243
1324
1342
1423 X
1432
2134
2143
2314
2341
2413 X
2431
3124 X
3142 X
3214
3241
3412 X
3421
4123
41 45、32 X
4213 X
4231 X
4312 X
4321 X
5.2 兩個棧組合一個隊列的問題
/////////////////////////////////
// 項目路徑:5兩個鏈棧組合一個隊列
/////////////////////////////////
a0,…ai進隊列
a0出隊列
ai+1,…an-1進隊列
a1,…ai出隊列
ai+1出隊列
template 46、:
LinkQueue( ){ }
~LinkQueue( ){ }
void Enter(T e); // 進隊列
T Leave( ); // 出隊列
};
template 47、 return( S2.Pop() );
while( !S1.isEmpty() )
S2.Push( S1.Pop() );
return( S2.Pop() );
}
5.3 進棧出棧的組合問題(高級)
已知進棧次序為1……n,要求窮舉出所有可能的出棧序列。
/////////////////////////////////
// 項目路徑:6棧的棧
/////////////////////////////////
5.3.1 數(shù)據(jù)結(jié)構(gòu)
小棧
SeqStack 48、eqStack 49、若s不空,出棧變化:s2=s,s2出棧,s2進大棧;
⑦轉(zhuǎn)②
5.3.4 算法結(jié)果分析
i個數(shù)
序列個數(shù)
Si
第1段
Ai,1
第2段
Ai,2
第3段
Ai,3
第4段
Ai,4
第5段
Ai,5
第6段
Ai,6
第7段
Ai,7
第8段
Ai,8
第9段
Ai,9
第10段
Ai,10
2
2
1
1
3
5
2
2
1
4
14
5
5
3
1
5
42
14
14
9
4
1
6
132
42
42
28
14
5
1
7
429
132
132
90
48
20
6
1
8
1430
429
429
297
165
75
27
7
1
9
4862
1430
1430
1001
572
275
110
35
8
1
10
16796
4862
4862
3432
2002
1001
429
154
44
9
1
3-25
- 溫馨提示:
1: 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
2: 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
3.本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
5. 裝配圖網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負責。
6. 下載文件中如有侵權(quán)或不適當內(nèi)容,請與我們聯(lián)系,我們立即糾正。
7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。