1. 程式人生 > 其它 >浙大版《資料結構(第2版)》題目集(函式題)

浙大版《資料結構(第2版)》題目集(函式題)

技術標籤:C語言練習

習題1.8 二分查詢 (20分)

本題要求實現二分查詢演算法。

函式介面定義:

Position BinarySearch( List L, ElementType X );

其中List結構定義如下:

typedef int Position;
typedef struct LNode *List;
struct LNode {
    ElementType Data[MAXSIZE];
    Position Last; /* 儲存線性表中最後一個元素的位置 */
};

L是使用者傳入的一個線性表,其中ElementType元素可以通過>、==、<進行比較,並且題目保證傳入的資料是遞增有序的。函式BinarySearch

要查詢XData中的位置,即陣列下標(注意:元素從下標1開始儲存)。找到則返回下標,否則返回一個特殊的失敗標記NotFound

裁判測試程式樣例:

#include <stdio.h>
#include <stdlib.h>

#define MAXSIZE 10
#define NotFound 0
typedef int ElementType;

typedef int Position;
typedef struct LNode *List;
struct LNode {
    ElementType Data[MAXSIZE];
    Position Last; /* 儲存線性表中最後一個元素的位置 */
};

List ReadInput(); /* 裁判實現,細節不表。元素從下標1開始儲存 */
Position BinarySearch( List L, ElementType X );

int main()
{
    List L;
    ElementType X;
    Position P;

    L = ReadInput();
    scanf("%d", &X);
    P = BinarySearch( L, X );
    printf("%d\n", P);

    return 0;
}

/* 你的程式碼將被嵌在這裡 */

輸入樣例1:

5
12 31 55 89 101
31

輸出樣例1:

2

輸入樣例2:

3
26 78 233
31

輸出樣例2:

0

鳴謝寧波大學 Eyre-lemon-郎俊傑 同學修正原題!

Position BinarySearch( List L, ElementType X )
{
    int right = L->Last,left = 1;
    int mid = (right+left)/2;
    while(left<=right)
    {
        int mid = (right+left)/2;
        if(X==L->
Data[mid]) { return mid; } else if(X>L->Data[mid]) { left = mid+1; } else { right = mid-1; } } return NotFound; }

習題1.9 有序陣列的插入 (20分)

本題要求將任一給定元素插入從大到小排好序的陣列中合適的位置,以保持結果依然有序。

函式介面定義:

bool Insert( List L, ElementType X );

其中List結構定義如下:

typedef int Position;
typedef struct LNode *List;
struct LNode {
    ElementType Data[MAXSIZE];
    Position Last; /* 儲存線性表中最後一個元素的位置 */
};

L是使用者傳入的一個線性表,其中ElementType元素可以通過>、==、<進行比較,並且題目保證傳入的資料是遞減有序的。函式Insert要將X插入Data[]中合適的位置,以保持結果依然有序(注意:元素從下標0開始儲存)。但如果X已經在Data[]中了,就不要插入,返回失敗的標記false;如果插入成功,則返回true。另外,因為Data[]中最多隻能存MAXSIZE個元素,所以如果插入新元素之前已經滿了,也不要插入,而是返回失敗的標記false

裁判測試程式樣例:

#include <stdio.h>
#include <stdlib.h>

#define MAXSIZE 10
typedef enum {false, true} bool;
typedef int ElementType;

typedef int Position;
typedef struct LNode *List;
struct LNode {
    ElementType Data[MAXSIZE];
    Position Last; /* 儲存線性表中最後一個元素的位置 */
};

List ReadInput(); /* 裁判實現,細節不表。元素從下標0開始儲存 */
void PrintList( List L ); /* 裁判實現,細節不表 */
bool Insert( List L, ElementType X );

int main()
{
    List L;
    ElementType X;

    L = ReadInput();
    scanf("%d", &X);
    if ( Insert( L, X ) == false )
        printf("Insertion failed.\n");
    PrintList( L );

    return 0;
}

/* 你的程式碼將被嵌在這裡 */

輸入樣例1:

5
35 12 8 7 3
10

輸出樣例1:

35 12 10 8 7 3
Last = 5

輸入樣例2:

6
35 12 10 8 7 3
8

輸出樣例2:

Insertion failed.
35 12 10 8 7 3
Last = 5
bool Insert( List L, ElementType X )
{
    if(L->Last==MAXSIZE-1)
    {
        return false;
    }
    for(int i=0;i<=L->Last;i++)
    {
        if(X==L->Data[i])
        {
            return false;
        }
        else if(X>L->Data[i])
        {
            for(int j=L->Last;j>=i;j--)
            {
                L->Data[j+1]=L->Data[j];
            }
            L->Data[i]=X;
            L->Last=L->Last+1;
            break;
        }
        else if(i==L->Last&&L->Data[i]>X)
        {
            L->Data[L->Last+1]=X;
            L->Last=L->Last+1;
            break;
        }
    }
    return true;
}

習題2.4 遞增的整數序列連結串列的插入 (15分)

本題要求實現一個函式,在遞增的整數序列連結串列(帶頭結點)中插入一個新整數,並保持該序列的有序性。

函式介面定義:

List Insert( List L, ElementType X );

其中List結構定義如下:

typedef struct Node *PtrToNode;
struct Node {
    ElementType Data; /* 儲存結點資料 */
    PtrToNode   Next; /* 指向下一個結點的指標 */
};
typedef PtrToNode List; /* 定義單鏈表型別 */

L是給定的帶頭結點的單鏈表,其結點儲存的資料是遞增有序的;函式Insert要將X插入L,並保持該序列的有序性,返回插入後的連結串列頭指標。

裁判測試程式樣例:

#include <stdio.h>
#include <stdlib.h>

typedef int ElementType;
typedef struct Node *PtrToNode;
struct Node {
    ElementType Data;
    PtrToNode   Next;
};
typedef PtrToNode List;

List Read(); /* 細節在此不表 */
void Print( List L ); /* 細節在此不表 */

List Insert( List L, ElementType X );

int main()
{
    List L;
    ElementType X;
    L = Read();
    scanf("%d", &X);
    L = Insert(L, X);
    Print(L);
    return 0;
}

/* 你的程式碼將被嵌在這裡 */

輸入樣例:

5
1 2 4 5 6
3

輸出樣例:

1 2 3 4 5 6 
List Insert( List L, ElementType X )
{
    List head = L;
    PtrToNode p;
    p=(PtrToNode)malloc(sizeof(struct Node));
    p->Data = X;
    p->Next = NULL;
    if(L->Next==NULL)
    {
        L->Next=p;
        return head;
    }
    while(L->Next->Data<X)
    {
        L=L->Next;
        if(L->Next==NULL)
        {
            L->Next=p;
            return head;
        }
    }
    p->Next=L->Next;
    L->Next=p;
    return head;
}

習題2.5 兩個有序連結串列序列的合併 (15分)

本題要求實現一個函式,將兩個連結串列表示的遞增整數序列合併為一個非遞減的整數序列。

函式介面定義:

List Merge( List L1, List L2 );

其中List結構定義如下:

typedef struct Node *PtrToNode;
struct Node {
    ElementType Data; /* 儲存結點資料 */
    PtrToNode   Next; /* 指向下一個結點的指標 */
};
typedef PtrToNode List; /* 定義單鏈表型別 */

L1L2是給定的帶頭結點的單鏈表,其結點儲存的資料是遞增有序的;函式Merge要將L1L2合併為一個非遞減的整數序列。應直接使用原序列中的結點,返回歸併後的帶頭結點的連結串列頭指標。

裁判測試程式樣例:

#include <stdio.h>
#include <stdlib.h>

typedef int ElementType;
typedef struct Node *PtrToNode;
struct Node {
    ElementType Data;
    PtrToNode   Next;
};
typedef PtrToNode List;

List Read(); /* 細節在此不表 */
void Print( List L ); /* 細節在此不表;空連結串列將輸出NULL */

List Merge( List L1, List L2 );

int main()
{
    List L1, L2, L;
    L1 = Read();
    L2 = Read();
    L = Merge(L1, L2);
    Print(L);
    Print(L1);
    Print(L2);
    return 0;
}

/* 你的程式碼將被嵌在這裡 */

輸入樣例:

3
1 3 5
5
2 4 6 8 10

輸出樣例:

1 2 3 4 5 6 8 10 
NULL
NULL
List Merge( List L1, List L2 )
{
    List L,tmp,a,b;
    L = (List)malloc(sizeof(struct Node));
    a = L1->Next;
    b = L2->Next;
    tmp = L;
    while(a || b)
    {
        if(a == NULL)
        {
            tmp->Next=b;
            b=NULL;
        }
        else if(b == NULL)
        {
            tmp->Next=a;
            a=NULL;
        }
        else
        {
            if(a->Data>b->Data)
            {
                tmp->Next=b;
                b=b->Next;
                tmp=tmp->Next;
            }
            else
            {
                tmp->Next=a;
                a=a->Next;
                tmp=tmp->Next;
            }
        }
    }
    L1->Next=NULL;
    L2->Next=NULL;
    return L;
}

習題2.6 遞迴求簡單交錯冪級數的部分和 (15分)

本題要求實現一個函式,計算下列簡單交錯冪級數的部分和:

f(x,n)=xx2+x3−x4+⋯+(−1)n−1x**n

函式介面定義:

double fn( double x, int n );

其中題目保證傳入的n是正整數,並且輸入輸出都在雙精度範圍內。函式fn應返回上述級數的部分和。建議嘗試用遞迴實現。

裁判測試程式樣例:

#include <stdio.h>

double fn( double x, int n );

int main()
{
    double x;
    int n;

    scanf("%lf %d", &x, &n);
    printf("%.2f\n", fn(x,n));

    return 0;
}

/* 你的程式碼將被嵌在這裡 */

輸入樣例:

0.5 12

輸出樣例:

0.33
double fn( double x, int n )
{
    if(n==1)
        return x;
    else
        return x-fn(x,n-1)*x;
}

習題2.7 彈球距離 (15分)

設有一個球從高度為h米的地方落下,碰到地面後又彈到高度為原來p倍的位置,然後又落下,再彈起,再落下…。請編寫函式求初始高度為h的球下落後到基本停下來(高度小於給定閾值TOL)時在空中所經過的路程總和。

函式介面定義:

double dist( double h, double p );

其中h是球的初始高度,p是球彈起高度與彈起前落下高度的比值;函式dist要返回球下落後到基本停下來時在空中所經過的路程總和。注意:當彈起的高度小於裁判程式定義的常數TOL時,彈起的距離不計算在內。

裁判測試程式樣例:

#include <stdio.h>
#define TOL 1E-2

double dist( double h, double p );

int main()
{
    double h, p, d;
    scanf("%lf %lf", &h, &p);
    d = dist(h, p);
    printf("%.6f\n", d);
    return 0;
}

/* 你的程式碼將被嵌在這裡 */

輸入樣例:

1.0 0.4

輸出樣例:

2.319680
double dist( double h, double p )
{
    if(p*h<TOL)
        return h;
    else
        return h+p*h+dist(p*h,p);
}

習題3.3 線性表元素的區間刪除 (20分)

給定一個順序儲存的線性表,請設計一個函式刪除所有值大於min而且小於max的元素。刪除後表中剩餘元素保持順序儲存,並且相對位置不能改變。

函式介面定義:

List Delete( List L, ElementType minD, ElementType maxD );

其中List結構定義如下:

typedef int Position;
typedef struct LNode *List;
struct LNode {
    ElementType Data[MAXSIZE];
    Position Last; /* 儲存線性表中最後一個元素的位置 */
};

L是使用者傳入的一個線性表,其中ElementType元素可以通過>、==、<進行比較;minDmaxD分別為待刪除元素的值域的下、上界。函式Delete應將Data[]中所有值大於minD而且小於maxD的元素刪除,同時保證表中剩餘元素保持順序儲存,並且相對位置不變,最後返回刪除後的表。

裁判測試程式樣例:

#include <stdio.h>

#define MAXSIZE 20
typedef int ElementType;

typedef int Position;
typedef struct LNode *List;
struct LNode {
    ElementType Data[MAXSIZE];
    Position Last; /* 儲存線性表中最後一個元素的位置 */
};

List ReadInput(); /* 裁判實現,細節不表。元素從下標0開始儲存 */
void PrintList( List L ); /* 裁判實現,細節不表 */
List Delete( List L, ElementType minD, ElementType maxD );

int main()
{
    List L;
    ElementType minD, maxD;
    int i;

    L = ReadInput();
    scanf("%d %d", &minD, &maxD);
    L = Delete( L, minD, maxD );
    PrintList( L );

    return 0;
}

/* 你的程式碼將被嵌在這裡 */

輸入樣例:

10
4 -8 2 12 1 5 9 3 3 10
0 4

輸出樣例:

4 -8 12 5 9 10 
List Delete( List L, ElementType minD, ElementType maxD )
{
    Position n = L->Last;
    int j=0;
    for(int i=0;i<=n;i++)
    {
        if(L->Data[i]<=minD||L->Data[i]>=maxD)
        {
            L->Data[j] = L->Data[i];
            j++;
        }
    }
    L->Last = j-1;
    return L;
}

習題3.5 求連結串列的倒數第m個元素 (20分)

請設計時間和空間上都儘可能高效的演算法,在不改變連結串列的前提下,求鏈式儲存的線性表的倒數第m(>0)個元素。

函式介面定義:

ElementType Find( List L, int m );

其中List結構定義如下:

typedef struct Node *PtrToNode;
struct Node {
    ElementType Data; /* 儲存結點資料 */
    PtrToNode   Next; /* 指向下一個結點的指標 */
};
typedef PtrToNode List; /* 定義單鏈表型別 */

L是給定的帶頭結點的單鏈表;函式Find要將L的倒數第m個元素返回,並不改變原連結串列。如果這樣的元素不存在,則返回一個錯誤標誌ERROR

裁判測試程式樣例:

#include <stdio.h>
#include <stdlib.h>

#define ERROR -1

typedef int ElementType;
typedef struct Node *PtrToNode;
struct Node {
    ElementType Data;
    PtrToNode   Next;
};
typedef PtrToNode List;

List Read(); /* 細節在此不表 */
void Print( List L ); /* 細節在此不表 */

ElementType Find( List L, int m );

int main()
{
    List L;
    int m;
    L = Read();
    scanf("%d", &m);
    printf("%d\n", Find(L,m));
    Print(L);
    return 0;
}

/* 你的程式碼將被嵌在這裡 */

輸入樣例:

5
1 2 4 5 6
3

輸出樣例:

4
1 2 4 5 6 
ElementType Find( List L, int m )
{
    List p;
    int a=0;
    p=L->Next;
    while(p!=NULL)
    {
        a++;
        p=p->Next;
    }
    if(a<m)
        return ERROR;
    else
    {
        int i=0;
        p=L->Next;
        while((i+m)<a)
        {
            p=p->Next;
            i++;
        }
        return p->Data;
    }
}

習題3.12 另類迴圈佇列 (20分)

如果用一個迴圈陣列表示佇列,並且只設佇列頭指標Front,不設尾指標Rear,而是另設Count記錄佇列中元素個數。請編寫演算法實現佇列的入隊和出隊操作。

函式介面定義:

bool AddQ( Queue Q, ElementType X );
ElementType DeleteQ( Queue Q );

其中Queue結構定義如下:

typedef int Position;
typedef struct QNode *PtrToQNode;
struct QNode {
    ElementType *Data;  /* 儲存元素的陣列   */
    Position Front;     /* 佇列的頭指標     */
    int Count;          /* 佇列中元素個數   */
    int MaxSize;        /* 佇列最大容量     */
};
typedef PtrToQNode Queue; 

注意:如果佇列已滿,AddQ函式必須輸出“Queue Full”並且返回false;如果佇列是空的,則DeleteQ函式必須輸出“Queue Empty”,並且返回ERROR。

裁判測試程式樣例:

#include <stdio.h>
#include <stdlib.h>

#define ERROR -1
typedef int ElementType;
typedef enum { addq, delq, end } Operation;
typedef enum { false, true } bool;
typedef int Position;
typedef struct QNode *PtrToQNode;
struct QNode {
    ElementType *Data;  /* 儲存元素的陣列   */
    Position Front;     /* 佇列的頭、尾指標 */
    int Count;          /* 佇列中元素個數   */
    int MaxSize;        /* 佇列最大容量     */
};
typedef PtrToQNode Queue; 

Queue CreateQueue( int MaxSize )
{
    Queue Q = (Queue)malloc(sizeof(struct QNode));
    Q->Data = (ElementType *)malloc(MaxSize * sizeof(ElementType));
    Q->Front = 0;
    Q->Count = 0;
    Q->MaxSize = MaxSize;
    return Q;
}

bool AddQ( Queue Q, ElementType X );
ElementType DeleteQ( Queue Q );

Operation GetOp();  /* 裁判實現,細節不表 */

int main()
{
    ElementType X;
    Queue Q;
    int N, done = 0;

    scanf("%d", &N);
    Q = CreateQueue(N);
    while ( !done ) {
        switch( GetOp() ) {
        case addq: 
            scanf("%d", &X);
            AddQ(Q, X);
            break;
        case delq:
            X = DeleteQ(Q);
            if ( X!=ERROR ) printf("%d is out\n", X);
            break;
        case end:
            while (Q->Count) printf("%d ", DeleteQ(Q));
            done = 1;
            break;
        }
    }
    return 0;
}

/* 你的程式碼將被嵌在這裡 */

輸入樣例:

4
Del
Add 5
Add 4
Add 3
Del
Del
Add 2
Add 1
Add 0
Add 10
End

輸出樣例:

Queue Empty
5 is out
4 is out
Queue Full
3 2 1 0 
bool AddQ( Queue Q, ElementType X )
{
    if(Q->Count>=Q->MaxSize)
    {
        printf("Queue Full\n");
        return false;
    }
    else
    {
        Q->Count++;
        Q->Data[(Q->Front+Q->Count)%Q->MaxSize]=X;
        return true;
    }
}

ElementType DeleteQ( Queue Q )
{
    if(Q->Count==0)
    {
        printf("Queue Empty\n");
        return ERROR;
    }
    else
    {
        Q->Front=(Q->Front+1)%Q->MaxSize;
        Q->Count--;
        return Q->Data[Q->Front];
    }
}

習題3.13 雙端佇列 (25分)

雙端佇列(deque,即double-ended queue的縮寫)是一種具有佇列和棧性質的資料結構,即可以(也只能)線上性表的兩端進行插入和刪除。若以順序儲存方式實現雙端佇列,請編寫例程實現下列操作:

  • Push(X,D):將元素X插入到雙端佇列D的頭;
  • Pop(D):刪除雙端佇列D的頭元素,並返回;
  • Inject(X,D):將元素X插入到雙端佇列D的尾部;
  • Eject(D):刪除雙端佇列D的尾部元素,並返回。

函式介面定義:

bool Push( ElementType X, Deque D );
ElementType Pop( Deque D );
bool Inject( ElementType X, Deque D );
ElementType Eject( Deque D );

其中Deque結構定義如下:

typedef int Position;
typedef struct QNode *PtrToQNode;
struct QNode {
    ElementType *Data;      /* 儲存元素的陣列   */
    Position Front, Rear;   /* 佇列的頭、尾指標 */
    int MaxSize;            /* 佇列最大容量     */
};
typedef PtrToQNode Deque; 

注意:PushInject應該在正常執行完操作後返回true,或者在出現非正常情況時返回false。當FrontRear相等時佇列為空,PopEject必須返回由裁判程式定義的ERROR

裁判測試程式樣例:

#include <stdio.h>
#include <stdlib.h>

#define ERROR -1
typedef int ElementType;
typedef enum { push, pop, inject, eject, end } Operation;
typedef enum { false, true } bool;
typedef int Position;
typedef struct QNode *PtrToQNode;
struct QNode {
    ElementType *Data;      /* 儲存元素的陣列   */
    Position Front, Rear;   /* 佇列的頭、尾指標 */
    int MaxSize;            /* 佇列最大容量     */
};
typedef PtrToQNode Deque; 

Deque CreateDeque( int MaxSize )
{   /* 注意:為區分空佇列和滿佇列,需要多開闢一個空間 */
    Deque D = (Deque)malloc(sizeof(struct QNode));
    MaxSize++;
    D->Data = (ElementType *)malloc(MaxSize * sizeof(ElementType));
    D->Front = D->Rear = 0;
    D->MaxSize = MaxSize;
    return D;
}

bool Push( ElementType X, Deque D );
ElementType Pop( Deque D );
bool Inject( ElementType X, Deque D );
ElementType Eject( Deque D );

Operation GetOp();          /* 裁判實現,細節不表 */
void PrintDeque( Deque D ); /* 裁判實現,細節不表 */

int main()
{
    ElementType X;
    Deque D;
    int N, done = 0;

    scanf("%d", &N);
    D = CreateDeque(N);
    while (!done) {
        switch(GetOp()) {
        case push: 
            scanf("%d", &X);
            if (!Push(X, D)) printf("Deque is Full!\n");
            break;
        case pop:
            X = Pop(D);
            if ( X==ERROR ) printf("Deque is Empty!\n");
            else printf("%d is out\n", X);
            break;
        case inject: 
            scanf("%d", &X);
            if (!Inject(X, D)) printf("Deque is Full!\n");
            break;
        case eject:
            X = Eject(D);
            if ( X==ERROR ) printf("Deque is Empty!\n");
            else printf("%d is out\n", X);
            break;
        case end:
            PrintDeque(D);
            done = 1;
            break;
        }
    }
    return 0;
}

/* 你的程式碼將被嵌在這裡 */

輸入樣例:

3
Pop
Inject 1
Pop
Eject
Push 2
Push 3
Eject
Inject 4
Inject 5
Inject 6
Push 7
Pop
End

輸出樣例:

Deque is Empty!
1 is out
Deque is Empty!
2 is out
Deque is Full!
Deque is Full!
3 is out
Inside Deque: 4 5
bool Push( ElementType X, Deque D )
{
    if((D->Rear+1)%D->MaxSize==D->Front)
    {
        return false;
    }
    else
    {
        D->Front=(D->Front-1+D->MaxSize)%D->MaxSize;
        D->Data[D->Front]=X;
        return true;
    }
}

ElementType Pop( Deque D )
{
    ElementType a;
    if(D->Front==D->Rear)
    {
        return ERROR;
    }
    else
    {
        a=D->Data[D->Front];
        D->Front=(D->Front+1)%D->MaxSize;
        return a;
    }
}

bool Inject( ElementType X, Deque D )
{
    if((D->Rear+1)%D->MaxSize==D->Front)
    {
        return false;
    }
    else
    {
        D->Data[D->Rear]=X;
        D->Rear=(D->Rear+1)%D->MaxSize;
        return true;
    }
}

ElementType Eject( Deque D )
{
    if(D->Front==D->Rear)
    {
        return ERROR;
    }
    else
    {
        D->Rear=(D->Rear-1+D->MaxSize)%D->MaxSize;
        return D->Data[D->Rear];
    }
}

習題3.14 另類堆疊 (15分)

在棧的順序儲存實現中,另有一種方法是將Top定義為棧頂的上一個位置。請編寫程式實現這種定義下堆疊的入棧、出棧操作。如何判斷堆疊為空或者滿?

函式介面定義:

bool Push( Stack S, ElementType X );
ElementType Pop( Stack S );

其中Stack結構定義如下:

typedef int Position;
typedef struct SNode *PtrToSNode;
struct SNode {
    ElementType *Data;  /* 儲存元素的陣列 */
    Position Top;       /* 棧頂指標       */
    int MaxSize;        /* 堆疊最大容量   */
};
typedef PtrToSNode Stack;

注意:如果堆疊已滿,Push函式必須輸出“Stack Full”並且返回false;如果佇列是空的,則Pop函式必須輸出“Stack Empty”,並且返回ERROR。

裁判測試程式樣例:

#include <stdio.h>
#include <stdlib.h>

#define ERROR -1
typedef int ElementType;
typedef enum { push, pop, end } Operation;
typedef enum { false, true } bool;
typedef int Position;
typedef struct SNode *PtrToSNode;
struct SNode {
    ElementType *Data;  /* 儲存元素的陣列 */
    Position Top;       /* 棧頂指標       */
    int MaxSize;        /* 堆疊最大容量   */
};
typedef PtrToSNode Stack;

Stack CreateStack( int MaxSize )
{
    Stack S = (Stack)malloc(sizeof(struct SNode));
    S->Data = (ElementType *)malloc(MaxSize * sizeof(ElementType));
    S->Top = 0;
    S->MaxSize = MaxSize;
    return S;
}

bool Push( Stack S, ElementType X );
ElementType Pop( Stack S );

Operation GetOp();          /* 裁判實現,細節不表 */
void PrintStack( Stack S ); /* 裁判實現,細節不表 */

int main()
{
    ElementType X;
    Stack S;
    int N, done = 0;

    scanf("%d", &N);
    S = CreateStack(N);
    while ( !done ) {
        switch( GetOp() ) {
        case push: 
            scanf("%d", &X);
            Push(S, X);
            break;
        case pop:
            X = Pop(S);
            if ( X!=ERROR ) printf("%d is out\n", X);
            break;
        case end:
            PrintStack(S);
            done = 1;
            break;
        }
    }
    return 0;
}

/* 你的程式碼將被嵌在這裡 */

輸入樣例:

4
Pop
Push 5
Push 4
Push 3
Pop
Pop
Push 2
Push 1
Push 0
Push 10
End

輸出樣例:

Stack Empty
3 is out
4 is out
Stack Full
0 1 2 5 
bool Push( Stack S, ElementType X )
{
    if(S->Top==S->MaxSize)
    {
        printf("Stack Full\n");
        return false;
    }
    else
    {
        S->Top++;
        S->Data[S->Top-1]=X;
    }
}

ElementType Pop( Stack S )
{
    if(S->Top==0)
    {
        printf("Stack Empty\n");
        return ERROR;
    }
    else
    {
        S->Top--;
        return S->Data[S->Top];
    }
}

習題4.3 是否二叉搜尋樹 (25分)

本題要求實現函式,判斷給定二叉樹是否二叉搜尋樹。

函式介面定義:

bool IsBST ( BinTree T );

其中BinTree結構定義如下:

typedef struct TNode *Position;
typedef Position BinTree;
struct TNode{
    ElementType Data;
    BinTree Left;
    BinTree Right;
};

函式IsBST須判斷給定的T是否二叉搜尋樹,即滿足如下定義的二叉樹:

定義:一個二叉搜尋樹是一棵二叉樹,它可以為空。如果不為空,它將滿足以下性質:

  • 非空左子樹的所有鍵值小於其根結點的鍵值。
  • 非空右子樹的所有鍵值大於其根結點的鍵值。
  • 左、右子樹都是二叉搜尋樹。

如果T是二叉搜尋樹,則函式返回true,否則返回false。

裁判測試程式樣例:

#include <stdio.h>
#include <stdlib.h>

typedef enum { false, true } bool;
typedef int ElementType;
typedef struct TNode *Position;
typedef Position BinTree;
struct TNode{
    ElementType Data;
    BinTree Left;
    BinTree Right;
};

BinTree BuildTree(); /* 由裁判實現,細節不表 */
bool IsBST ( BinTree T );

int main()
{
    BinTree T;

    T = BuildTree();
    if ( IsBST(T) ) printf("Yes\n");
    else printf("No\n");

    return 0;
}
/* 你的程式碼將被嵌在這裡 */

輸入樣例1:如下圖

img

輸出樣例1:

Yes

輸入樣例2:如下圖

img

輸出樣例2:

No
bool IsBST ( BinTree T )
{
    if(T==NULL)
    {
        return true;
    }
    if(T->Left&&!IsBST(T->Left))
    {
        return false;
    }
    BinTree p = T->Left;
    if(p)
    {
        while(p->Right)
        {
            p= p->Right;
        }
        if(T->Data<p->Data)
        {
            return false;
        }
    }
    if(T->Right)
    {
        return IsBST(T->Right);
    }
    else
    {
        return true;
    }
}

習題5.10 線性探測法的查詢函式 (20分)

試實現線性探測法的查詢函式。

函式介面定義:

Position Find( HashTable H, ElementType Key );

其中HashTable是開放地址散列表,定義如下:

#define MAXTABLESIZE 100000  /* 允許開闢的最大散列表長度 */
typedef int ElementType;     /* 關鍵詞型別用整型 */
typedef int Index;           /* 雜湊地址型別 */
typedef Index Position;      /* 資料所在位置與雜湊地址是同一型別 */
/* 雜湊單元狀態型別,分別對應:有合法元素、空單元、有已刪除元素 */
typedef enum { Legitimate, Empty, Deleted } EntryType;

typedef struct HashEntry Cell; /* 散列表單元型別 */
struct HashEntry{
    ElementType Data; /* 存放元素 */
    EntryType Info;   /* 單元狀態 */
};

typedef struct TblNode *HashTable; /* 散列表型別 */
struct TblNode {   /* 散列表結點定義 */
    int TableSize; /* 表的最大長度 */
    Cell *Cells;   /* 存放雜湊單元資料的陣列 */
};

函式Find應根據裁判定義的雜湊函式Hash( Key, H->TableSize )從散列表H中查到Key的位置並返回。如果Key不存在,則返回線性探測法找到的第一個空單元的位置;若沒有空單元,則返回ERROR

裁判測試程式樣例:

#include <stdio.h>

#define MAXTABLESIZE 100000  /* 允許開闢的最大散列表長度 */
typedef int ElementType;     /* 關鍵詞型別用整型 */
typedef int Index;           /* 雜湊地址型別 */
typedef Index Position;      /* 資料所在位置與雜湊地址是同一型別 */
/* 雜湊單元狀態型別,分別對應:有合法元素、空單元、有已刪除元素 */
typedef enum { Legitimate, Empty, Deleted } EntryType;

typedef struct HashEntry Cell; /* 散列表單元型別 */
struct HashEntry{
    ElementType Data; /* 存放元素 */
    EntryType Info;   /* 單元狀態 */
};

typedef struct TblNode *HashTable; /* 散列表型別 */
struct TblNode {   /* 散列表結點定義 */
    int TableSize; /* 表的最大長度 */
    Cell *Cells;   /* 存放雜湊單元資料的陣列 */
};

HashTable BuildTable(); /* 裁判實現,細節不表 */
Position Hash( ElementType Key, int TableSize )
{
    return (Key % TableSize);
}

#define ERROR -1
Position Find( HashTable H, ElementType Key );

int main()
{
    HashTable H;
    ElementType Key;
    Position P;

    H = BuildTable(); 
    scanf("%d", &Key);
    P = Find(H, Key);
    if (P==ERROR)
        printf("ERROR: %d is not found and the table is full.\n", Key);
    else if (H->Cells[P].Info == Legitimate)
        printf("%d is at position %d.\n", Key, P);
    else
        printf("%d is not found.  Position %d is returned.\n", Key, P);

    return 0;
}

/* 你的程式碼將被嵌在這裡 */

輸入樣例1:(注:-1表示該位置為空。下同。)

11
11 88 21 -1 -1 5 16 7 6 38 10
38

輸出樣例1:

38 is at position 9.

輸入樣例2:

11
11 88 21 -1 -1 5 16 7 6 38 10
41

輸出樣例2:

41 is not found.  Position 3 is returned.

輸入樣例3:

11
11 88 21 3 14 5 16 7 6 38 10
41

輸出樣例3:

ERROR: 41 is not found and the table is full.
Position Find( HashTable H, ElementType Key )
{
    Position p,p0;
    int a=0;
    p=p0=Hash(Key,H->TableSize);
    while(H->Cells[p].Info!=Empty&&H->Cells[p].Data!=Key)
    {
        a++;
        if(a==MAXTABLESIZE)
        {
            return ERROR;
        }
        p=(p0+a)%H->TableSize;
    }
    return p;
}

習題5.11 分離連結法的刪除操作函式 (20分)

試實現分離連結法的刪除操作函式。

函式介面定義:

bool Delete( HashTable H, ElementType Key );

其中HashTable是分離連結散列表,定義如下:

typedef struct LNode *PtrToLNode;
struct LNode {
    ElementType Data;
    PtrToLNode Next;
};
typedef PtrToLNode Position;
typedef PtrToLNode List;

typedef struct TblNode *HashTable; /* 散列表型別 */
struct TblNode {   /* 散列表結點定義 */
    int TableSize; /* 表的最大長度 */
    List Heads;    /* 指向連結串列頭結點的陣列 */
};

函式Delete應根據裁判定義的雜湊函式Hash( Key, H->TableSize )從散列表H中查到Key的位置並刪除之,然後輸出一行文字:Key is deleted from list Heads[i],其中Key是傳入的被刪除的關鍵詞,iKey所在的連結串列的編號;最後返回true。如果Key不存在,則返回false。

裁判測試程式樣例:

#include <stdio.h>
#include <string.h>

#define KEYLENGTH 15                   /* 關鍵詞字串的最大長度 */
typedef char ElementType[KEYLENGTH+1]; /* 關鍵詞型別用字串 */
typedef int Index;                     /* 雜湊地址型別 */
typedef enum {false, true} bool;

typedef struct LNode *PtrToLNode;
struct LNode {
    ElementType Data;
    PtrToLNode Next;
};
typedef PtrToLNode Position;
typedef PtrToLNode List;

typedef struct TblNode *HashTable; /* 散列表型別 */
struct TblNode {   /* 散列表結點定義 */
    int TableSize; /* 表的最大長度 */
    List Heads;    /* 指向連結串列頭結點的陣列 */
};

Index Hash( ElementType Key, int TableSize )
{
    return (Key[0]-'a')%TableSize;
}

HashTable BuildTable(); /* 裁判實現,細節不表 */
bool Delete( HashTable H, ElementType Key );

int main()
{
    HashTable H;
    ElementType Key;

    H = BuildTable(); 
    scanf("%s", Key);
    if (Delete(H, Key) == false)
        printf("ERROR: %s is not found\n", Key);
    if (Delete(H, Key) == true)
        printf("Are you kidding me?\n");
    return 0;
}

/* 你的程式碼將被嵌在這裡 */

輸入樣例1:散列表如下圖

img

able

輸出樣例1:

able is deleted from list Heads[0]

輸入樣例2:散列表如樣例1圖

date

輸出樣例2:

ERROR: date is not found
bool Delete( HashTable H, ElementType Key )
{
    int a=Hash(Key,H->TableSize);
    List L=H->Heads+a;
    while(L->Next&&strcmp(L->Next->Data,Key))
    {
        L=L->Next;
    }
    if(L->Next==NULL)
    {
        return false;
    }
    else
    {
        PtrToLNode p=L->Next;
        L->Next=L->Next->Next;
        free(p);
        printf("%s is deleted from list Heads[%d]\n",Key,a);
        return true;
    }
}

練習6.1 鄰接矩陣儲存圖的深度優先遍歷 (20 分)

試實現鄰接矩陣儲存圖的深度優先遍歷。

函式介面定義:

void DFS( MGraph Graph, Vertex V, void (*Visit)(Vertex) );

其中MGraph是鄰接矩陣儲存的圖,定義如下:

typedef struct GNode *PtrToGNode;
struct GNode{
    int Nv;  /* 頂點數 */
    int Ne;  /* 邊數   */
    WeightType G[MaxVertexNum][MaxVertexNum]; /* 鄰接矩陣 */
};
typedef PtrToGNode MGraph; /* 以鄰接矩陣儲存的圖型別 */

函式DFS應從第V個頂點出發遞迴地深度優先遍歷圖Graph,遍歷時用裁判定義的函式Visit訪問每個頂點。當訪問鄰接點時,要求按序號遞增的順序。題目保證V是圖中的合法頂點。

裁判測試程式樣例:

#include <stdio.h>

typedef enum {false, true} bool;
#define MaxVertexNum 10  /* 最大頂點數設為10 */
#define INFINITY 65535   /* ∞設為雙位元組無符號整數的最大值65535*/
typedef int Vertex;      /* 用頂點下標表示頂點,為整型 */
typedef int WeightType;  /* 邊的權值設為整型 */

typedef struct GNode *PtrToGNode;
struct GNode{
    int Nv;  /* 頂點數 */
    int Ne;  /* 邊數   */
    WeightType G[MaxVertexNum][MaxVertexNum]; /* 鄰接矩陣 */
};
typedef PtrToGNode MGraph; /* 以鄰接矩陣儲存的圖型別 */
bool Visited[MaxVertexNum]; /* 頂點的訪問標記 */

MGraph CreateGraph(); /* 建立圖並且將Visited初始化為false;裁判實現,細節不表 */

void Visit( Vertex V )
{
    printf(" %d", V);
}

void DFS( MGraph Graph, Vertex V, void (*Visit)(Vertex) );


int main()
{
    MGraph G;
    Vertex V;

    G = CreateGraph();
    scanf("%d", &V);
    printf("DFS from %d:", V);
    DFS(G, V, Visit);

    return 0;
}

/* 你的程式碼將被嵌在這裡 */

輸入樣例:給定圖如下

img

5

輸出樣例:

DFS from 5: 5 1 3 0 2 4 6
void DFS( MGraph Graph, Vertex V, void (*Visit)(Vertex) )
{
    Visited[V]=true;
    Visit(V);
    for(int i=0;i<MaxVertexNum;i++)
    {
        if(Graph->G[V][i]==1&&Visited[i]==false)
        {
            DFS(Graph,i,Visit);
        }
    }
    return 0;
}

練習6.2 鄰接表儲存圖的廣度優先遍歷 (20 分)

試實現鄰接表儲存圖的廣度優先遍歷。

函式介面定義:

void BFS ( LGraph Graph, Vertex S, void (*Visit)(Vertex) );

其中LGraph是鄰接表儲存的圖,定義如下:

/* 鄰接點的定義 */
typedef struct AdjVNode *PtrToAdjVNode; 
struct AdjVNode{
    Vertex AdjV;        /* 鄰接點下標 */
    PtrToAdjVNode Next; /* 指向下一個鄰接點的指標 */
};

/* 頂點表頭結點的定義 */
typedef struct Vnode{
    PtrToAdjVNode FirstEdge; /* 邊表頭指標 */
} AdjList[MaxVertexNum];     /* AdjList是鄰接表型別 */

/* 圖結點的定義 */
typedef struct GNode *PtrToGNode;
struct GNode{  
    int Nv;     /* 頂點數 */
    int Ne;     /* 邊數   */
    AdjList G;  /* 鄰接表 */
};
typedef PtrToGNode LGraph; /* 以鄰接表方式儲存的圖型別 */

函式BFS應從第S個頂點出發對鄰接表儲存的圖Graph進行廣度優先搜尋,遍歷時用裁判定義的函式Visit訪問每個頂點。當訪問鄰接點時,要求按鄰接表順序訪問。題目保證S是圖中的合法頂點。

裁判測試程式樣例:

#include <stdio.h>

typedef enum {false, true} bool;
#define MaxVertexNum 10   /* 最大頂點數設為10 */
typedef int Vertex;       /* 用頂點下標表示頂點,為整型 */

/* 鄰接點的定義 */
typedef struct AdjVNode *PtrToAdjVNode; 
struct AdjVNode{
    Vertex AdjV;        /* 鄰接點下標 */
    PtrToAdjVNode Next; /* 指向下一個鄰接點的指標 */
};

/* 頂點表頭結點的定義 */
typedef struct Vnode{
    PtrToAdjVNode FirstEdge; /* 邊表頭指標 */
} AdjList[MaxVertexNum];     /* AdjList是鄰接表型別 */

/* 圖結點的定義 */
typedef struct GNode *PtrToGNode;
struct GNode{  
    int Nv;     /* 頂點數 */
    int Ne;     /* 邊數   */
    AdjList G;  /* 鄰接表 */
};
typedef PtrToGNode LGraph; /* 以鄰接表方式儲存的圖型別 */

bool Visited[MaxVertexNum]; /* 頂點的訪問標記 */

LGraph CreateGraph(); /* 建立圖並且將Visited初始化為false;裁判實現,細節不表 */

void Visit( Vertex V )
{
    printf(" %d", V);
}

void BFS ( LGraph Graph, Vertex S, void (*Visit)(Vertex) );

int main()
{
    LGraph G;
    Vertex S;

    G = CreateGraph();
    scanf("%d", &S);
    printf("BFS from %d:", S);
    BFS(G, S, Visit);

    return 0;
}

/* 你的程式碼將被嵌在這裡 */

輸入樣例:給定圖如下

img

2

輸出樣例:

BFS from 2: 2 0 3 5 4 1 6
void BFS ( LGraph Graph, Vertex S, void (*Visit)(Vertex) )
{
    int p[MaxVertexNum],head=0,tail=0;
    p[tail++]=S;
    Visited[S]=true;
    while(head<tail)
    {
        int temp =p[head++];
        Visit(temp);
        Visited[temp]=true;
        PtrToAdjVNode a=(Graph->G[temp]).FirstEdge;
        while(a)
        {
            int b=a->AdjV;
            if(Visited[b]==false)
            {
                Visited[b]=true;
                p[tail++]=b;
            }
            a=a->Next;
        }
    }
}