c#棧的習題2


—、單項選擇題1.棧和隊列具有相同的(    )。 A.抽象數據類型     B.邏輯結構     C.存儲結構     D.運算
2.棧是()。 A.順序存儲的線性結構     B.鏈式存儲的非線性結構 C.限制存取點的線性結構     D.限制存儲點的非線性結構
3.()不是棧的基本操作。 A.刪除棧頂元素     B.刪除棧底元素 C.判斷棧是否為空     D.將棧置為空棧
4.假定利用數組 a[n] 順序存儲一個棧,用top表示棧頂指針,top==-1表示桟空,並已知棧未滿,當元素x進棧時所執行的操作為( )。 A. a[--top]=x     B. a[top--]=x     C. a[++top]=x     D. a[top++]=x
5.設有一個空棧,棧頂指針為1000H,每個元素需要1個存儲單元,在執行Push、Push、 Pop、Push、Pop、Push、Pop、Push操作后,桟頂指針的值為( )。 A. 1002H    B. 1003H    C. 1004H    D. 1005H
6.和順序棧相比,鏈棧有一個比較明顯的優勢是(    )。 A.通常不會出現棧滿的情況     B.通常不會出現棧空的情況 C.插入操作更容易實現     D.刪除操作更容易實現
7.設鏈表不帶頭結點且所有操作均在表頭進行,則下列最不適合作為鏈棧的是(    )。 A.只有表頭結點指針,沒有表尾指針的雙向循環鏈表 B.只有表尾結點指針,沒有表頭指針的雙向循環鏈表 C.只有表頭結點指針,沒有表尾指針的單向循環鏈表 D.只有表尾結點指針,沒有表頭指針的單向循環鏈表
8.向一個棧頂指針為top的鏈棧中插入一個x結點,則執行(    )。 A. top->next=x      B. x->next=top->next; top->next=x C. x->next=top; top=x      D. x->next=top, top=top->next
9.鏈棧執行Pop操作,並將出棧的元素存在x中應該執行( )。 A. x=top; top=top->next      B.x=top->data C. top=top->next; x=top->data      D. x=top->data; top=top->next
10.經過以下棧的操作后,變量x的值為(    )。 InitStack(st); Push(st, a); Push(st, b); Pop(st, x); Top(st,x);
A. a    B. b    C. NULL    D. FALSE
11.    3個不同元素依次進棧,能得到( )種不同的出棧序列。 A. 4    B. 5    C. 6    D. 7
12.設a、b、c、d、e、f以所給的次序迸棧,若在進棧操作時,允許出棧操作,則下面得不到的序列為( )。 A. fedcba    B. bcafed    C. dcefba    D. cabdef
13.用S表示進棧操作,用X表示出棧操作,若元素的進棧順序是1234,為了得到1342的出棧順序,相應的S和X的操作序列為( )。
A. SXSXSSXX     B. SSSXXSXX     C. SXSSXXSX     D. SXSSXSXX
14.【2010年計算機聯考真題】 若元素a、b、c、d、e、f依次進棧,允許進棧、退棧操作交替進行,但不允許連續3次進行退棧工作,則不可能得到的出棧序列是( )。 A. dcebfa    B. cbdaef    C. bcaefd    D. afedcb
15.設找S和隊列Q的初始狀態為空,元素e1、e2、e3、e4、e5和e6依次通過棧S,一個元素出棧后即進隊列Q,若6個元素出棧的序列是e2、e4、e3、e6、e5、e1,則棧S的容量至少應該是( )。 A. 6    B. 4    C. 3    D. 2
16.【2009年計算機聯考真題】 設棧S和隊列Q的初始狀態均為空,元素abcdefg依次進入棧S。若每個元素出棧后立即進入隊列Q,且7個元素出隊的順序是bdefeag,則棧S的容量至少是( )。 A. 1    B. 2    C. 3    D. 4
17.若一個棧的輸入序列是1, 2,3, …, n,輸出序列的第一個元素是n,則第i個輸出元素是( )。 A.不確定    B. n-i    C. n-i-1    D. n-i+1
18.一個棧的輸入序列為1, 2, 3, …, n,輸出序列的第一個元素是i,則第j個輸出元素是( )。 A, i-j-1    B. i-j    C. j-i+1    D.不確定
19.某棧的輸入序列為a、b、c、d,下面的4個序列中,不可能是它的輸出序列的是()。 A. a,b,c,d    B. c,b,d,a    C. d,c,a,b    D. a,c,b,d
20.若一個棧的輸入序列是P1, P2, …, Pn,其輸出序列是1, 2, 3, …, n,若P3=1,則p1的值( )。 A.可能是2     B. 一定是2     C.不可能是2     D.不可能是3
21.若已知一個棧的入棧序列是1、2、3、4。其出棧序列為P1、P2、P3、P4,則P2、P4不可能是( )。 A. 2、4    B. 2、1    C. 4、3    D. 3、4
22.設桟的初始狀態為空,當字符序列"n 1 _"作為棧的輸入時,輸出長度為3,且可用做C語言標識符的序列有( )個。 A. 4    B. 5    C. 3    D. 6
23.【2011年計算機聯考真題】 元素a、b、c、d、e依次進入初始為空的棧中,若元素進棧后可停留、可出棧,直到所有元素都出棧,則在所有可能的出棧序列中,以元素d開頭的序列個數是()。 A. 3    B. 4    C. 5    D. 6
24.釆用共享棧的好處是(    )。 A.減少存取時間,降低發生上溢的可能 B.節省存儲空間,降低發生上溢的可能 C.減少存取時間,降低發生下溢的可能 D.節省存儲空間,降低發生下溢的可能
25.設有一個順序共享棧Share[0: n-1],其中第一個棧頂指針top1的初值為-1,第二個棧頂指針top2的初值為n,則判斷共享棧滿的條件是( )。 A. top2-top1==1     B. top1-top2==1     C. top1==top2     D.以上都不對

二、綜合應用題

1.有5個元素,其入棧次序為A、B、C、D、E,在各種可能的出棧次序中,第一個出棧元素為C且第二個出棧元素為D的出棧序列有哪幾個?
2.若元素的進棧序列為A、B、C、D、E,運用棧操作,能否得到出棧序列B、C、A、 E、D 和 D、B、A、C、E?為什么?
3.假設以I和O分別表示入棧和出棧操作。棧的初態和終態均為空,入棧和出棧的操作序列可表示為僅由I和O組成的序列,可以操作的序列稱為合法序列,否則稱為非法序列。
1) 下面所示的序列中哪些是合法的? a. IOIIOIOO     b. IOOIOIIO     c. IIIOIOIO     d. IIIOOIOO
2) 通過對1)的分析,寫出一個算法,判定所給的操作序列是否合法。若合法,返回 true,否則返回false(假定被判定的操作序列已存入一維數組中)。
4.設單鏈表的表頭指針為h,結點結構由data和next兩個域構成,其中data域為字符型。試設計算法判斷該鏈表的前n個字符是否中心對稱。例如xyx、xyyx都是中心對稱。
5.設有兩個棧s1、s2都釆用順序棧方式,並且共享一個存儲區[0, …, maxsize-1],為了盡量利用空間,減少溢出的可能,可釆用棧頂相向、迎面增長的存儲方式。試設計s1、s2 有關入棧和出棧的操作算法。

答案與解析

一、單項選擇題

1.    B 線性表、棧和隊列的邏輯結構都是相同的,都屬於線性結構,只是它們對數據的運算不同,從而表現出不同的特點。
2.    C 首先棧是一種線性表,所以B、D錯。按存儲結構的不同可分為順序棧和鏈棧,但不可以把棧局限在某種存儲結構上,所以A錯。棧和隊列都是限制存取點的線性結構。
3.    B 基本操作是指該結構最核心、最基本的運算,其他較復雜的操作可以通過基本操作實現。刪除棧底元素不屬於棧的基本運算,但它可以通過調用棧的基本運算求得。
4.    C 入棧指針top加1,初始時top為-1,則第1個元素入找后,top為0,即指向棧頂元素,故入棧時應先將指針top加1,再將元素入棧,只有C符合題意。
5.    A 每個元素需要1個存儲單元,所以每入棧一次top加1,出棧一次top減1。指針top的值依次為 1001H,1002H, 1001H, 1002H,1001H,1002H,1001H,1002H。
6.    A 順序棧釆用數組存儲,數組的大小是固定的,不能動態地分配大小。和順序棧相比,鏈棧的最大優勢在於它可以動態地分配存儲空間,所以答案為A。
7.    C 通常棧的插入和刪除在表頭進行。對於選項C,插入和刪除一個結點后,仍需將其變為循環單鏈表,因此需要找到其尾結點,時間復雜度為o(n)。
若不做題干中的限制,則棧頂可取表頭(帶頭結點的鏈表)或第二個結點(不帶頭結點的鏈表),找指針的位置取頭結點(帶頭結點的鏈表)或表頭(不帶頭結點的鏈表)。
8.    C 鏈棧釆用不帶頭結點的單鏈表表示時,進棧橾作在首部插入一個結點x(即x->next=top),插入完后需將top指向該插入的結點X。請思考當鏈棧存在頭結點時的情況。
9.    D 這里假設棧頂指針指向的是棧頂元素,所以選D;而A中首先將top指針賦給了 x,錯誤;B中沒有修改top指針的值;C為top指針指向棧頂元素的上一個元素時的答案。
10.    A 執行前3句后,棧st內的值為a,b,其中b為棧頂元素,執行第4句后,x的值為b,執行最后一句后x的值為a。
11.    B 對於n個不同元素進棧,出棧序列的個數為

上述的公式叫做卡特蘭(Catalan)數,可釆用數學歸納法證明,有興趣的讀者可以參考組合數學的教材(知道該公式即可)。考題中給出的n值不會很大,可以根據棧的特點,若Xi已經出棧,則Xi前面的尚未出棧的元素一定逆置有序地出棧,因此可以釆取例舉的方法。如a、b、c依次進棧的出棧序列有abc,acb, bac, bca, cba。
12.    D 根據棧“先進后出”的特點,並且在進棧操作的同時允許出棧操作,顯然,答案D中c 最先出棧,則此時棧內必定為a和b,但由於a先於b進棧,故要晚出棧。對於某個出棧的元素,在它之前進棧卻晚出棧的元素必定是按逆序出棧的,其余答案均是可能出現的情況。
此題也可以釆用將各序列逐個代入,以確定是否有對應的進出棧序列(類似下題)。
13.    D 釆用排除法,選項A、B、C得到的出棧序列分別為1243、3241、1324。由1234得到 1342的進出棧序列為:1進,1出,2進,3進,3出,4進,4出,2出,故選D。
14.    D 選項A可由a進,b進,c進,d進,d出,c出,e進,e出,b出,f進,f出,a出得到; 選項B可由a進,b進,c進,c出,b出,d進,d出,a出,e進,e出,f進,f出得到; 選項C可由a進,b進,b出,c進,c出,a出,d進,e進,e出,f進,f出,d出得到; 選項D可由a進,a出,b進,c進,d進,e進,f進,f出,e出,d出,c出,b出得到,但要求不允許連續3次退棧操作,故選D。
15.    C 本題將隊列和棧結合起來,由於隊列“先進先出”的特性,所以出隊的序列與進隊的序列是相同的,從而可以得到出棧的次序為e2、e4、e3、e6、e5、e1;再由棧“先進后出”的特性,進棧的次序為e1、e2、e3、e4、e5、e6,可見,排在某個元素之后出棧卻排在它之前進棧的元素個數,表示之前棧內的元素個數。因此,e4進棧后,e1和e3在棧中;而后e4 和e3出找;e6進找后,e5和e1也在找中。因此,找的最小容量為3。
16.    C 時刻注意棧的特點是先進后出,下表是出入棧的詳細過程。

序號 說明 棧內 棧外 序號 說明 棧內 棧外
1 a入棧 a   8 e入棧 ae bdc
2 b入棧 ab   9 f入棧 aef bdc
3 b出棧 a b 10 f出棧 ae bdcf
4 c入錢 ac b 11 e出棧 a bdcfe
5 d入棧 acd b 12 a出枝   bdcfea
6 d出棧 ac bd 13 g入棧 g bdcfea
7 c出棧 a bdc 14 g出棧   bdcfeag

棧內的最大深度為3,故棧S的容量至少是3。
另解:由於元素的出隊順序和入隊順序是一樣的,所以,元素的出棧順序也就是b、d、 c、f、e、a、g,所以,元素的入棧出棧順序為 Push(S, a),Push(S, b),Pop(S, b),Push(S, c),Push(S, d),Pop(S, d),Pop(S, c),Push(S, e)。Push(S, f),Pop(S, f),Pop(S,e), Pop(S,a),Push(S, g),Pop(S, g)。假設初始所需容量為0,每做一次Push操作進行一次加1操作,每做一次Pop進行一次減1操作,記錄容量的最大值為3,所以答案選C。
17.    D 第n個元素先出棧,說明前n-1個元素都已經按順序入棧,由“先進后出”的特點可知,此時的輸出序列一定是輸入序列的逆序,故答案選D。
18.    D 當第i個元素第一個出棧時,則i之前的元素可以依次排在i之后出棧,但剩余的元素可以在此時進棧並且也會排在i之前的元素出棧,所以,第j個出棧的元素是不確定的。
19.    C 對於A,可能的順序是a入,a出,b入,b出,c入,c出,d入,d出。 對於B,可能的順序是a入,b入,c入,c出,b出,d入,d出,a出。 對於D,可能的順序是a入,a 出,b入,c入,c出,b出,d入,d出。 C沒有對應的序列。
另解:若出棧序列的第一個元素為d,則出棧序列只能是dcba。該思想通常也適用了出棧序列的局部分析:如12345入棧,問出棧序列34152是否正確?如何分析?若第一個出棧元素是3,則此時12必停留在棧中,它們出棧的相對順序只能是21,故34152錯誤。
20.    C 入棧序列是P1,P2,…,Pn。由於P3=1,即P1、P2、P3連續入棧后,第一個出棧元素是 P3,說明P1、P2已經按序進棧,根據先進后出的特點可知,P2必定在P1之前出棧,而第二個出棧元素是2,而此時P1必定不是棧頂元素,因為P2尚未出棧。因此P1的值不可能是2。
21.    C 對於A,可能的順序是1入棧,1出棧,2入棧,2出棧,3入棧,3出棧,4入棧,4 出棧。 對於B,可能的順序是1入棧,2入棧,3入棧,3出找,2出找,4入棧,4出橈,1 出棧。 對於D,可能的順序是1入棧,1出棧,2入棧,3入棧,3出棧,2出桟,4入棧,4 出棧。 C則沒有對應的序列。
22.    C 標識符的第一個字符必須是大小寫英文字母或者下畫線,而不能是數字。按照上述規定"n 1 _"三個字符符合規定的標識符有n1_、n_1、_1n, _n1四種形式。第一種:n進棧再出棧, 1進棧再出棧,_進棧再出棧。第二種:n進棧再出棧,1進棧,_進棧,_出棧,1出棧。第三種:n進棧,1進棧_進棧,_出棧,1出棧,n出棧。而根據棧的操作特性,_n1這種情況不可能出現,故選C。
23. B 出棧順序必為d_c_b_a,e的順序不定,在任意一個"_"上都有可能。
另解:d首先出棧,則abc停留在棧中,此時錢的狀態如下圖所示。此時可以有如下4種操作: ①e進棧后出棧,則出棧序列為decba; ②c出棧,e進桟后出棧,出桟序列為dceba; ③cb出桟,e進棧后出棧,出棧序列為dcbea; ④cba出找,e進棧后出棧,出棧序列為dcbae。

第23題圖

24.    B 存取棧中的元素都只需要0(1)的時間,所以,減少存取時間無從談起。另外,棧的插入和刪除操作都是在棧頂進行的,只可能發生上溢(棧頂指針超出了最大范圍),不可能發生下溢(對於上溢、下溢,只需大概了解即可,不必深究),因此本題答案為B。
25.    A 這種情況就是前面我們所描述的,詳細內容請參見本節考點精析部分對共享棧的講解。另外,讀者可以思考若top1的初值為0,top2的初值為n-1時棧滿的條件。
注意:棧頂、隊頭與隊尾的指針的定義是不唯一的,讀者務必要仔細審題。

二、綜合應用題

1.解答: CD出棧后的狀態如下圖所示。
此時有如下3種操作: ①E進棧后出棧,則出棧序列為CDEBA; ②B 出棧,E進棧后出棧,出棧序列為CDBEA; ③B出棧,A出棧,E進棧后出棧,出棧序列為CDBAE。
所以,以CD開頭的出棧序列有:CDEBA、CDBEA、CDBAE三種。

第1題圖

2.解答: 能得到出棧序列BCAED。可由A進,B進,B出,C進,C出,A出,D進,E進,E出,D出得到。不能得到出棧序列DBACE。若出棧序列以D開頭,說明在D之前的入棧元素是A、B和C,三個元素中C是棧頂元素,B和A不可能早於C出棧,故不可能得到出棧序列DBACE。
3.解答: 1) A、D合法,而B、C不合法。在B中,先入棧1次,再連續出棧2次,錯誤。在 C中,入棧和出棧次數不一致,會導致最終的棧不空。A、D均為合法序列,請自行模擬。注意:在操作過程中,入棧次數一定大於或等於出棧次數;結束時,棧一定為空。
2) 設被判定的操作序列已存入一維數組A中。算法的基本設計思想:依次逐一掃描入棧出棧序列(即由"I"和"O"組成的字符串),每掃描至任一位置均需檢查出棧次數(即 “O”的個數)是否小於入棧次數("I"的個數),若大於則為非法序列。掃描結束后,再判斷入棧和出棧次數是否相等,若不相等則不合題意,為非法序列。

  1. int Judge(char A[]) {
  2. //判斷字符數組A中的輸入輸出序列是否是合法序列。如是,返回true,否則返回false
  3. i=0;
  4. j=k=0; //i為下標,j和k分別為字母I和O的個數
  5. while (A[i]!='\0') { //未到字符數組尾
  6. switch(A[i]){
  7. case 'I' ; j++; break; //入棧次數增 1
  8. case 'O' : k++;
  9. if (k>j ) { printf ("序列非法\n") ; exit (0) ; }
  10. }
  11. i++; //不論A[i]是“I”或“0”,指針i均后移
  12. } //while
  13. if (j!=k) {
  14. printf ("序列非法\n" );
  15. return false;
  16. }else{
  17. printf ("序列合法\n");
  18. return true;
  19. }
  20. }

另解:入棧后,棧內元素個數加1;出棧后,棧內元素個數減1,因此,可以將判定一組出入棧序列是否合法,轉化為一組+1、-1組成的序列,它的任意前綴子序列的累加和不小於0 (每次出棧或入棧操作后判斷),則合法;否則,非法。
4.解答: 算法思想:使用棧來判斷鏈表中的數據是否中心對稱。將鏈表的前一半元素依次進棧。在處理鏈表的后一半元素時,當訪問到鏈表的一個元素后,就從棧中彈出一個元素,兩個元素比較,若相等,則將鏈表中下一個元素與棧中再彈出的元素比較,直至鏈表到尾。這時若棧是空棧,則得出鏈表中心對稱的結論;否則,當鏈表中的一個元素與棧中彈出元素不等時,結論為鏈表非中心對稱,結束算法的執行。

int dc(LinkList L, int n){
    //h是帶頭結點的n個元素單鏈表,本算法判斷鏈表是否是中心對稱
    char s[n/2];int i=1;  //i記結點個數,s字符棧
    P=L->next;  //p是鏈表的工作指針,指向待處理的當前元素
    for{i=0;i<n/2;i++) {  //鏈表前一半元素進棧
        s[i]=p->data;
        p=p->next;
    }
    i--;  //恢復最后的i值
    if(n%2==1)  //若n是奇數,后移過中心結點
        p=p->next;

    while(p!=NULL && s[i] ==p->data) { //檢測是否中心對稱
        i--;  //i充當找頂指針
        p=p->next;
    }

    if (i==-1)    //桟為空找
        return 1;    //鏈表中心對稱
    else
        return 0;    //鏈表不中心對稱
}

算法先將“鏈表的前一半”元素(字符)進棧。當n為偶數時,前一半和后一半的個數相同;當n為奇數時,鏈表中心結點字符不必比較,移動鏈表指針到下一字符開始比較。比較過程中遇到不相等時,立即退出while循環,不再進行比較。
本題也可以先將單鏈表中的元素全部入棧,然后再次掃描單鏈表L並比較,直到比較到單鏈表L尾為止,但是算法需要兩次掃描單鏈表L,效率不及上述算法高。
5.解答:
兩個棧共享向量空間,將兩個棧的棧底設在向量兩端,初始時,s1棧頂指針為-1,s2 棧頂指針為maxsize。兩個棧頂指針相鄰時為棧滿。兩個棧頂相向、迎面增長,棧頂指針指向棧頂元素。

#define maxsize  // 兩個棧共享順序存儲空間所能達到的最多元素數
#define elemtp int  //假設元素類型為整型
typedef struct{
    elemtp stack[maxsize];  //棧空間
    int top [2];  //top為兩個棧頂指針
}stk;
stk s;  //s是如上定義的結構類型變量,為全局變量

本題的關鍵在於,兩個桟入棧和退棧時的棧頂指針的計算。s1棧是通常意義下的棧;而 s2棧入棧操作時,其棧頂指針左移(減1),退棧時,棧頂指針右移(加1)。
此外,對於所有棧的操作,都要注意“入棧判滿、出棧判空”的檢查。
1) 入棧操作

int push(int i, int x){
    //入棧操作。i為棧號,i=0表示左邊的s1棧,i=1表示右邊的s2棧,x是入棧元素
    //入棧成功返回1,否則返回0
    if(i<0 || i>1){
        printf ("棧號輸入不對");
        exit(0);
    }

    if(s.top[1]-s.top[0]==1){
        printf ("棧已滿\n");
        return 0;
    }

    switch(i){
        case 0: s.stack[++s.top[0]] = x; return 1; break;
        case 1: s.stack[--s.top[1]] = x; return 1;
    }
}

2) 退棧操作

elemtp pop(int i) {
    //退棧算法。i代表棧號,i=0時為s1棧,i=l時為s2棧
    //退棧成功返回退棧元素,否則返回-1
    if(i<0||i>1){
        printf ("棧號輸入錯誤\1n");
        exit(0);
    }

    switch(i) {
        case 0:
            if (s.top[0]==-1) {
                printf ("棧空\n");
                return -1;
            }else
                return s.stack[s.top[0]--];
        case 1:
            if(s.top[1]==maxsize){
                printf ("棧空\n");
                return -1;
            }else
                return s.stack[s.top[1]++];
    }//switch
}

2.1. 對於棧操作數據的原則是(B )。

A. 先進先出    B.后進先出      C.后進后出     D. 不分順序

1.2.一個棧的輸入序列為123…n,若輸出序列的第一個元素是n,輸出第i(1<=i<=n)個元素是( B )。

A.不確定       B.n-i+1       C. i     D. n-i      1.3. 若一個棧的輸入序列為1,2,3,…,n,輸出序列的第一個元素是i,則第j個輸出元素是(D )。

A.i-j-1       B.i-j     C.j-i+1       D. 不確定的

1.4. 若已知一個棧的入棧序列是1,2,3,…,n,其輸出序列為p1,p2,p3,…,pN,若pN是n,則pi是( D )。

A. i     B.n-i     C.n-i+1    D. 不確定

1.5. 有六個元素6,5,4,3,2,1 的順序進棧,問下列哪一個不是合法的出棧序列?( C )。

A. 5 4 3 6 1 2     B. 4 5 3 1 2 6     C. 3 4 6 5 2 1     D. 2 3 4 1 5 6

1.6. 設棧的輸入序列是1,2,3,4,則(D )不可能是其出棧序列。

A. 1,2,4,3,      B. 2,1,3,4,    C. 1,4,3,2, D. 4,3,1,2,      E. 3,2,1,4,

1.7. 一個棧的輸入序列為1 2 3 4 5,則下列序列中不可能是棧的輸出序列的是( B )。

A. 2 3 4 1 5      B. 5 4 1 3 2    C. 2 3 1 4 5      D. 1 5 4 3 2

1.8. 設一個棧的輸入序列是 1,2,3,4,5,則下列序列中,是棧的合法輸出序列的是( D )。

A. 5 1 2 3 4      B. 4 5 1 3 2     C. 4 3 1 2 5      D. 3 2 1 5 4

1.9. 某堆棧的輸入序列為a, b,c ,d,下面的四個序列中,不可能是它的輸出序列的是( D )。

A. a,c,b,d     B. b, c,d,a     C. c, d,b, a     D. d, c,a,b

1.10. 設abcdef以所給的次序進棧,若在進棧操作時,允許退棧操作,則下面得不到的序列為( D )。

A.fedcba    B. bcafed     C. dcefba    D. cabdef

1.11. 設有三個元素X,Y,Z順序進棧(進的過程中允許出棧),下列得不到的出棧排列是( C )。

A.XYZ       B. YZX       C. ZXY       D. ZYX

1.12. 用鏈接方式存儲的隊列,在進行刪除運算時(D )。

A. 僅修改頭指針      B. 僅修改尾指針       C. 頭、尾指針都要修改       D. 頭、尾指針可能都要修改

1.13. 用不帶頭結點的單鏈表存儲隊列時,其隊頭指針指向隊頭結點,其隊尾指針指向隊尾結點,則在進行刪除操作時( D )。

A.僅修改隊頭指針     B. 僅修改隊尾指針       C. 隊頭、隊尾指針都要修改   D. 隊頭,隊尾指針都可能要修改

1.14. 遞歸過程或函數調用時,處理參數及返回地址,要用一種稱為(C )的數據結構。

A.隊列      B.多維數組     C.棧       D. 線性表

 

二、判斷題

1. 消除遞歸不一定需要使用棧,此說法(√ )

2. 棧是實現過程和函數等子程序所必需的結構。(√ )

3. 兩個棧共用靜態存儲空間,對頭使用也存在空間溢出問題。(√ )

4.兩個棧共享一片連續內存空間時,為提高內存利用率,減少溢出機會,應把兩個棧的棧底分別設在這片內存空間的兩端。(√ )

5. 即使對不含相同元素的同一輸入序列進行兩組不同的合法的入棧和出棧組合操作,所得的輸出序列也一定相同。(× )

6. 棧與隊列是一種特殊操作的線性表。(√ )

7. 若輸入序列為1,2,3,4,5,6,則通過一個棧可以輸出序列3,2,5,6,4,1. (√ )

8. 棧和隊列都是限制存取點的線性結構。( √ )

9.若輸入序列為1,2,3,4,5,6,則通過一個棧可以輸出序列1,5,4,6,2,3。(× )

10. 任何一個遞歸過程都可以轉換成非遞歸過程。(√  )

11. 只有那種使用了局部變量的遞歸過程在轉換成非遞歸過程時才必須使用棧。(× )

12. 隊列是一種插入與刪除操作分別在表的兩端進行的線性表,是一種先進后出型結構。(× )

13. 通常使用隊列來處理函數或過程的調用。(× )

14. 隊列邏輯上是一個下端和上端既能增加又能減少的線性表。(√ )

15. 循環隊列通常用指針來實現隊列的頭尾相接。(× )

16. 循環隊列也存在空間溢出問題。(√ )

17. 隊列和棧都是運算受限的線性表,只允許在表的兩端進行運算。(× )

18. 棧和隊列都是線性表,只是在插入和刪除時受到了一些限制。(√ )

19. 棧和隊列的存儲方式,既可以是順序方式,又可以是鏈式方式。(√ )

 

三、填空 1.棧是操作受限(或限定僅在表尾進行插入和刪除操作)的線性表,其運算遵循后進先出的原則。

2.棧 是限定僅在表尾進行插入或刪除操作的線性表。

3. 一個棧的輸入序列是:1,2,3則不可能的棧輸出序列是3 1 2。

4.兩個棧共享空間時棧滿的條件兩棧頂指針值相減的絕對值為1(或兩棧頂指針相鄰)。。

5.在作進棧運算時應先判別棧是否滿;在作退棧運算時應先判別棧是否空;當棧中元素為n個,作進棧運算時發生上溢,則說明該棧的最大容量為n。為了增加內存空間的利用率和減少溢出的可能性,由兩個棧共享一片連續的空間時,應將兩棧的棧底 分別設在內存空間的兩端,這樣只有當兩棧頂指針相鄰(即值之差的絕對值為1)時才產生溢出。

6. 多個棧共存時,最好用鏈式存儲結構作為存儲結構。

7.用S表示入棧操作,X表示出棧操作,若元素入棧的順序為1234,為了得到1342出棧順序,相應的S和X的操作串為S×SS×S×× 。

8. 循環隊列的引入,目的是為了克服假溢出時大量移動數據元素。

9.隊列又稱作先進先出表。

10. 已知鏈隊列的頭尾指針分別是f和r,則將值x入隊的操作序列是s=(LinkedList)malloc(sizeof(LNode)); s->data=x;s->next=r->next;r->next=s;r=s;。

11.區分循環隊列的滿與空,只有兩種方法,它們是犧牲一個存儲單元和設標記。

 

四、應用題

1.1. 名詞解釋:棧。

答:棧是只准在一端進行插入和刪除操作的線性表,允許插入和刪除的一端叫棧頂,另一端叫棧底。最后插入的元素最先刪除,故棧也稱后進先出(LIFO)表。

1.2. 名詞解釋:隊列

答:隊列是允許在一端插入而在另一端刪除的線性表,允許插入的一端叫隊尾,允許刪除的一端叫隊頭。最先插入隊的元素最先離開(刪除),故隊列也常稱先進先出(FIFO)表。

1.3. 什么是循環隊列?

答:用常規意義下順序存儲結構的一維數組表示隊列,由於隊列的性質(隊尾插入和隊頭刪除),容易造成“假溢出”現象,即隊尾已到達一維數組的高下標,不能再插入,然而隊中元素個數小於隊列的長度(容量)。循環隊列是解決“假溢出”的一種方法。通常把一維數組看成首尾相接。在循環隊列下,通常采用“犧牲一個存儲單元”或“作標記”的方法解決“隊滿”和“隊空”的判定問題。

1.4. 假設以S和X分別表示入棧和出棧操作,則對初態和終態均為空的棧操作可由S和X組成的序列表示(如SXSX)。

(1)試指出判別給定序列是否合法的一般規則。

答:通常有兩條規則。第一是給定序列中S的個數和X的個數相等;第二是從給定序列的開始,到給定序列中的任一位置,S的個數要大於或等於X的個數。

 

(2)兩個不同合法序列(對同一輸入序列)能否得到相同的輸出元素序列?如能得到,請舉列說明。

答:可以得到相同的輸出元素序列。例如,輸入元素為A,B,C,則兩個輸入的合法序列ABC和BAC均可得到輸出元素序列ABC。對於合法序列ABC,我們使用本題約定的S×S×S×操作序列;對於合法序列BAC,我們使用SS××S×操作序列。

 

1.5. 有5 個元素,其入棧次序為:A,B,C,D,E,在各種可能的出棧次序中,以元素C,D最先出棧(即C第一個且D第二個出棧)的次序有哪幾個?

答:三個:CDEBA,CDBEA,CDBAE

1.6. 如果輸入序列為1 2 3 4 5 6,試問能否通過棧結構得到以下兩個序列:4 3 5 6 1 2和1 3 5 4 2 6;請說明為什么不能或如何才能得到。

答:輸入序列為123456,不能得出435612,其理由是,輸出序列最后兩元素是12,前面4個元素(4356)得到后,棧中元素剩12,且2在棧頂,不可能棧底元素1在棧頂元素2之前出棧。    得到135426的過程如下:1入棧並出棧,得到部分輸出序列1;然后2和3入棧,3出棧,部分輸出序列變為:13;接着4和5入棧,5,4和2依次出棧,部分輸出序列變為13542;最后6入棧並退棧,得最終結果135426。

1.7. 若元素的進棧序列為:A、B、C、D、E,運用棧操作,能否得到出棧序列B、C、A、E、D和D、B、A、C、E?為什么?

答: 能得到出棧序列B、C、A、E、D,不能得到出棧序列D、B、A、C、E。其理由為:若出棧序列以D開頭,說明在D之前的入棧元素是A、B和C,三個元素中C是棧頂元素,B和A不可能早於C出棧,故不可能得到D、B、A、C、E出棧序列。

1.8. 設輸入序列為a,b,c,d,試寫出借助一個棧可得到的兩個輸出序列和兩個不能得到的輸出序列。

答:借助棧結構,n個入棧元素可得到1/(n+1)((2n)!/(n!*n!))種出棧序列。本題4個元素,可有14種出棧序列,abcd和dcba就是其中兩種。但dabc和adbc是不可能得到的兩種。

1.9. 設輸入序列為2,3,4,5,6,利用一個棧能得到序列2,5,3,4,6嗎?棧可以用單鏈表實現嗎?

答:不能得到序列2,5,3,4,6。棧可以用單鏈表實現,這就是鏈棧。由於棧只在棧頂操作,所以鏈棧通常不設頭結點。

 

五、算法設計題

1.1. 設從鍵盤輸入一整數的序列:a1, a2, a3,…,an,試編寫算法實現:用棧結構存儲輸入的整數,當ai≠-1時,將ai進棧;當ai=-1時,輸出棧頂整數並出棧。算法應對異常情況(入棧滿等)給出相應的信息。

答:#define maxsize 棧空間容量
     void InOutS(int s[maxsize])
     //s是元素為整數的棧,本算法進行入棧和退棧操作。
        {int top=0; //top為棧頂指針,定義top=0時為棧空。
         for(i=1; i<=n; i++) //n個整數序列作處理。
        {scanf(“%d”,&x); //從鍵盤讀入整數序列。
         if(x!=-1) // 讀入的整數不等於-1時入棧。
        if(top==maxsize-1){printf(“棧滿\n”);exit(0);}else s[++top]=x; //x入棧。
        else //讀入的整數等於-1時退棧。
         {if(top==0){printf(“棧空\n”);exit(0);} else printf(“出棧元素是%d\n”,s[top--]);}}
      }//算法結束。 

1.2. 設表達式以字符形式已存入數組E[n]中,‘#’為表達式的結束符,試寫出判斷表達式中括號(‘(’和‘)’)是否配對的C語言描述算法:EXYX(E); (注:算法中可調用棧操作的基本算法。) 

答:[題目分析]判斷表達式中括號是否匹配,可通過棧,簡單說是左括號時進棧,右括號時退棧。退棧時,若棧頂元素是左括號,則新讀入的右括號與棧頂左括號就可消去。如此下去,輸入表達式結束時,棧為空則正確,否則括號不匹配。
     int EXYX(char E[],int n)
      //E[]是有n字符的字符數組,存放字符串表達式,以‘#’結束。本算法判斷表達式中圓括號是否匹配。
     {char s[30]; //s是一維數組,容量足夠大,用作存放括號的棧。
     int top=0; //top用作棧頂指針。
     s[top]= ‘#’; //‘#’先入棧,用於和表達式結束符號‘#’匹配。
     int i=0; //字符數組E的工作指針。
     while(E[i]!= ‘#’) //逐字符處理字符表達式的數組。
          switch(E[i])
      {case‘(’: s[++top]=‘(’; i++ ; break ;
      case‘)’: if(s[top]==‘(’{top--; i++; break;}
           else{printf(“括號不配對”);exit(0);}
           case‘#’: if(s[top]==‘#’){printf(“括號配對\n”);return (1);}
           else {printf(“ 括號不配對\n”);return (0);} //括號不配對
          default : i++; //讀入其它字符,不作處理。
          }
      }//算法結束。
     [算法討論]本題是用棧判斷括號匹配的特例:只檢查圓括號的配對。一般情況是檢查花括號(‘{’,‘}’)、方括號(‘[’,‘]’)和圓括號(‘(’,‘)’)的配對問題。編寫算法中如遇左括號(‘{’,‘[’,或‘(’)就壓入棧中,如遇右括號(‘}’,‘]’,或‘)’),則與棧頂元素比較,如是與其配對的括號(左花括號,左方括號或左圓括號),則彈出棧頂元素;否則,就結論括號不配對。在讀入表達式結束符‘#’時,棧中若應只剩‘#’,表示括號全部配對成功;否則表示括號不匹配。
     另外,由於本題只是檢查括號是否匹配,故對從表達式中讀入的不是括號的那些字符,一律未作處理。再有,假設棧容量足夠大,因此入棧時未判斷溢出。 

1.3. 從鍵盤上輸入一個逆波蘭表達式,用偽碼寫出其求值程序。規定:逆波蘭表達式的長度不超過一行,以$符作為輸入結束,操作數之間用空格分隔,操作符只可能有+、-、*、/四種運算。例如:234 34+2*$


答:[題目分析]逆波蘭表達式(即后綴表達式)求值規則如下:設立運算數棧OPND,對表達式從左到右掃描(讀入),當表達式中掃描到數時,壓入OPND棧。當掃描到運算符時,從OPND退出兩個數,進行相應運算,結果再壓入OPND棧。這個過程一直進行到讀出表達式結束符$,這時OPND棧中只有一個數,就是結果。
     float expr( )
      //從鍵盤輸入逆波蘭表達式,以‘$’表示輸入結束,本算法求逆波蘭式表達式的值。float OPND[30]; // OPND是操作數棧。
      init(OPND); //兩棧初始化。
     float num=0.0; //數字初始化。
     scanf (“%c”,&x);//x是字符型變量。
     while(x!=’$’)
      {switch
           {case0’<=x<=’9’:while((x>=’0’&&x<=’9’)||x==’.’) //拼數
               if(x!=’.’) //處理整數
     {num=num*10+(ord(x)-ord(‘0’)); scanf(“%c”,&x);}
                else //處理小數部分。
               {scale=10.0; scanf(“%c”,&x);
                while(x>=’0’&&x<=’9’)
                {num=num+(ord(x)-ord(‘0’)/scale;
                scale=scale*10; scanf(“%c”,&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
      scanf(“%c”,&x);//讀入表達式中下一個字符。
     }//結束while(x!=‘$’)
     printf(“后綴表達式的值為%f”,pop(OPND));
      }//算法結束。
     [算法討論]假設輸入的后綴表達式是正確的,未作錯誤檢查。算法中拼數部分是核心。若遇到大於等於‘0’且小於等於‘9’的字符,認為是數。這種字符的序號減去字符‘0’的序號得出數。對於整數,每讀入一個數字字符,前面得到的部分數要乘上10再加新讀入的數得到新的部分數。當讀到小數點,認為數的整數部分已完,要接着處理小數部分。小數部分的數要除以10(或10的冪數)變成十分位,百分位,千分位數等等,與前面部分數相加。在拼數過程中,若遇非數字字符,表示數已拼完,將數壓入棧中,並且將變量num恢復為0,准備下一個數。這時對新讀入的字符進入‘+’、‘-’、‘*’、‘/’及空格的判斷,因此在結束處理數字字符的case后,不能加入break語句。 
View Code

 以上練習題都是整理自網上的,再次說明,希望大家學習交流,不可用於其他用途


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM