浙大版《資料結構(第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
X
在Data
中的位置,即陣列下標(注意:元素從下標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; /* 定義單鏈表型別 */
L1
和L2
是給定的帶頭結點的單鏈表,其結點儲存的資料是遞增有序的;函式Merge
要將L1
和L2
合併為一個非遞減的整數序列。應直接使用原序列中的結點,返回歸併後的帶頭結點的連結串列頭指標。
裁判測試程式樣例:
#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)=x−x2+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
元素可以通過>、==、<進行比較;minD
和maxD
分別為待刪除元素的值域的下、上界。函式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;
注意:Push
和Inject
應該在正常執行完操作後返回true,或者在出現非正常情況時返回false。當Front
和Rear
相等時佇列為空,Pop
和Eject
必須返回由裁判程式定義的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:如下圖
輸出樣例1:
Yes
輸入樣例2:如下圖
輸出樣例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
是傳入的被刪除的關鍵詞,i
是Key
所在的連結串列的編號;最後返回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:散列表如下圖
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;
}
/* 你的程式碼將被嵌在這裡 */
輸入樣例:給定圖如下
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;
}
/* 你的程式碼將被嵌在這裡 */
輸入樣例:給定圖如下
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;
}
}
}