1. 程式人生 > 其它 >pta資料結構樹和圖實驗題

pta資料結構樹和圖實驗題

技術標籤:資料結構pta

先序輸出葉結點(15分)

本題要求按照先序遍歷的順序輸出給定二叉樹的葉結點。

函式介面定義:

void PreorderPrintLeaves( BinTree BT );

其中BinTree結構定義如下:

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

函式PreorderPrintLeaves應按照先序遍歷的順序輸出給定二叉樹BT的葉結點,格式為一個空格跟著一個字元。

裁判測試程式樣例:

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

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

BinTree CreatBinTree(); /* 實現細節忽略 */
void PreorderPrintLeaves( BinTree BT );

int main()
{
    BinTree BT = CreatBinTree();
    printf("Leaf nodes are:");
    PreorderPrintLeaves(BT);
    printf("\n");

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

輸出樣例(對於圖中給出的樹):

Leaf nodes are: D E H I

void PreorderPrintLeaves( BinTree BT )
{
	if(BT == NULL)return;//如果根節點為空,什麼都不執行
	if(BT->Left == NULL && BT->Right == NULL)//如果一個節點既沒有左孩子,又沒有右孩子,說明是葉子節點 
	{
		printf(" %c", BT->Data);//題目要求:空格+字元 
	 } 
	 PreorderPrintLeaves(BT->Left);//訪問左孩子 
	 PreorderPrintLeaves(BT->Right); //訪問右孩子 
}

鄰接矩陣儲存圖的深度優先遍歷(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 < Graph->Nv; i++)
	{
		if(Graph->G[V][i] == 1 && !Visited[i])
		{
			DFS(Graph, i, Visit);
		}
	}
} 

鄰接表儲存圖的廣度優先遍歷(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 que[1000];
	int f = 0, r = 0;
	que[r++] = S;
	Visit(S);
	Visited[S] = true;
	while(f != r)
	{
		PtrToAdjVNode tmp = Graph->G[que[f++]].FirstEdge;
		while(tmp)
		{
			Vertex pos = tmp->AdjV;
			if(!Visited[pos])
			{
				Visited[pos] = true;
				Visit(pos);
				que[r++] = pos;
			}
			tmp = tmp->Next;
		 } 
	}
}

二叉樹的遍歷(25分)

本題要求給定二叉樹的4種遍歷。

函式介面定義:

void InorderTraversal( BinTree BT );
void PreorderTraversal( BinTree BT );
void PostorderTraversal( BinTree BT );
void LevelorderTraversal( BinTree BT );

其中BinTree結構定義如下:

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

要求4個函式分別按照訪問順序打印出結點的內容,格式為一個空格跟著一個字元。

裁判測試程式樣例:

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

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

BinTree CreatBinTree(); /* 實現細節忽略 */
void InorderTraversal( BinTree BT );
void PreorderTraversal( BinTree BT );
void PostorderTraversal( BinTree BT );
void LevelorderTraversal( BinTree BT );

int main()
{
    BinTree BT = CreatBinTree();
    printf("Inorder:");    InorderTraversal(BT);    printf("\n");
    printf("Preorder:");   PreorderTraversal(BT);   printf("\n");
    printf("Postorder:");  PostorderTraversal(BT);  printf("\n");
    printf("Levelorder:"); LevelorderTraversal(BT); printf("\n");
    return 0;
}
/* 你的程式碼將被嵌在這裡 */

輸出樣例(對於圖中給出的樹):

Inorder: D B E F A G H C I
Preorder: A B D F E C G H I
Postorder: D E F B H G I C A
Levelorder: A B C D F G I E H
void InorderTraversal( BinTree BT )
{
	if(BT)
	{
		InorderTraversal(BT->Left);
		printf(" %c", BT->Data);
		InorderTraversal(BT->Right);
	}
}
void PreorderTraversal( BinTree BT )
{
	if(BT)
	{
		printf(" %c", BT->Data);
		PreorderTraversal(BT->Left);
		PreorderTraversal(BT->Right); 
	}
}
void PostorderTraversal( BinTree BT )
{
	if(BT)
	{
		PostorderTraversal(BT->Left);
		PostorderTraversal(BT->Right);
		printf(" %c", BT->Data);
	}
}
void LevelorderTraversal( BinTree BT )
{
	BinTree que[1000];
	int f = 0, r = 0;
	if(BT)que[r++] = BT;
	while(f != r)
	{
		BinTree q = que[f++];
		printf(" %c", q->Data);
		if(q->Left)que[r++] = q->Left;
		if(q->Right)que[r++] = q->Right;
	}
}

樹的遍歷(25分)

給定一棵二叉樹的後序遍歷和中序遍歷,請你輸出其層序遍歷的序列。這裡假設鍵值都是互不相等的正整數。

輸入格式:

輸入第一行給出一個正整數N(≤30),是二叉樹中結點的個數。第二行給出其後序遍歷序列。第三行給出其中序遍歷序列。數字間以空格分隔。

輸出格式:

在一行中輸出該樹的層序遍歷的序列。數字間以1個空格分隔,行首尾不得有多餘空格。

輸入樣例:

7
2 3 1 5 7 6 4
1 2 3 4 5 6 7

輸出樣例:

4 1 6 3 5 7 2

#include<iostream>
using namespace std;
struct Node
{
	int data;
	Node* left;
	Node* right;
}*root;
int t;
int post[55], in[55];//輸入的陣列
void create(Node*& root, int l, int r)
{
	int flag = -1;
	for(int i = l; i <= r; i++)
	{
		if(post[t] == in[i])//說明找到了根節點
		{
			flag = i;
			break;
		} 
	}
	if(flag == -1)return;//沒有找到根節點,什麼也不執行
	root = new Node;
	root->data = in[flag];
	root->left = root->right = NULL;
	t--;//t儲存的是後序的下標, 故--
	create(root->right, flag + 1, r);//已知中序和後序,先建立右子樹,再建立左子樹
	//已知前序和中序,先建立左子樹,再建立右子樹 
	create(root->left, l, flag - 1); 
 } 
void level(Node* root)
{
	Node* que[1000];
	int f = 0, r = 0;
	if(root)que[r++] = root;
	while(f != r)
	{
		Node* q = que[f++];
		if(f > 1)cout<<" ";//控制輸出空格 
		cout<<q->data;
		if(q->left)que[r++] = q->left;
		if(q->right)que[r++] = q->right;
	}
}
int main()
{
	root = NULL;
	int n;
	cin>>n;
    t = n - 1;
	for(int i = 0; i < n; i++)cin>>post[i];
	for(int i = 0; i < n; i++)cin>>in[i];
	create(root, 0, n -1);
	level(root);
	return 0;
}

還原二叉樹(25分)

給定一棵二叉樹的先序遍歷序列和中序遍歷序列,要求計算該二叉樹的高度。

輸入格式:

輸入首先給出正整數N(≤50),為樹中結點總數。下面兩行先後給出先序和中序遍歷序列,均是長度為N的不包含重複英文字母(區別大小寫)的字串。

輸出格式:

輸出為一個整數,即該二叉樹的高度。

輸入樣例:

9
ABDFGHIEC
FDHGIBEAC

輸出樣例:

5

#include<iostream>
using namespace std;
struct Node
{
	int data;
	Node* left;
	Node* right;
}*root;
int t = 0;
char pre[55], in[55];//輸入的陣列
void create(Node*& root, int l, int r)
{
	int flag = -1;
	for(int i = l; i <= r; i++)
	{
		if(pre[t] == in[i])//說明找到了根節點
		{
			flag = i;
			break;
		} 
	}
	if(flag == -1)return;//沒有找到根節點,什麼也不執行
	root = new Node;
	root->data = in[flag];
	root->left = root->right = NULL;
	t++;//t儲存的是前序的下標, 故++ 
	create(root->left, l, flag - 1);
	create(root->right, flag + 1, r);
	//已知前序和中序,先建立左子樹,再建立右子樹 
	 
 } 
int height(Node* root)
{
	if(root == NULL)return 0;
	int m = height(root->left);
	int n = height(root->right);
	return m > n ? m + 1 : n + 1;
}
int main()
{
	
	root = NULL;
	int n;
	cin>>n;
	cin>>pre>>in;
	create(root, 0, n -1);
    cout<<height(root)<<endl;
	return 0;
}

根據後序和中序遍歷輸出先序遍歷(25分)

本題要求根據給定的一棵二叉樹的後序遍歷和中序遍歷結果,輸出該樹的先序遍歷結果。

輸入格式:

第一行給出正整數N(≤30),是樹中結點的個數。隨後兩行,每行給出N個整數,分別對應後序遍歷和中序遍歷結果,數字間以空格分隔。題目保證輸入正確對應一棵二叉樹。

輸出格式:

在一行中輸出Preorder:以及該樹的先序遍歷結果。數字間有1個空格,行末不得有多餘空格。

輸入樣例:

7
2 3 1 5 7 6 4
1 2 3 4 5 6 7

輸出樣例:

Preorder: 4 1 3 2 6 5 7
#include<iostream>
using namespace std;
struct Node
{
	int data;
	Node* left;
	Node* right;
}*root;
int t;
int post[55], in[55];//輸入的陣列
void create(Node*& root, int l, int r)
{
	int flag = -1;
	for(int i = l; i <= r; i++)
	{
		if(post[t] == in[i])//說明找到了根節點
		{
			flag = i;
			break;
		} 
	}
	if(flag == -1)return;//沒有找到根節點,什麼也不執行
	root = new Node;
	root->data = in[flag];
	root->left = root->right = NULL;
	t--;
	create(root->right, flag + 1, r);
	create(root->left, l, flag - 1);	 
 } 
void Preorder(Node* root)
{
	if(root)
	{
		printf(" %d", root->data);
		Preorder(root->left);
		Preorder(root->right);
	}
}
int main()
{
	root = NULL;
	int n;
	cin>>n;
	t = n - 1;
	for(int i = 0; i < n; i++)cin>>post[i];
	for(int i = 0; i < n; i++)cin>>in[i];
	create(root, 0, n -1);
    cout<<"Preorder:";
    Preorder(root);
	return 0;
}

二叉搜尋樹的結構(30分)

二叉搜尋樹或者是一棵空樹,或者是具有下列性質的二叉樹: 若它的左子樹不空,則左子樹上所有結點的值均小於它的根結點的值;若它的右子樹不空,則右子樹上所有結點的值均大於它的根結點的值;它的左、右子樹也分別為二叉搜尋樹。(摘自百度百科)

給定一系列互不相等的整數,將它們順次插入一棵初始為空的二叉搜尋樹,然後對結果樹的結構進行描述。你需要能判斷給定的描述是否正確。例如將{ 2 4 1 3 0 }插入後,得到一棵二叉搜尋樹,則陳述句如“2是樹的根”、“1和4是兄弟結點”、“3和0在同一層上”(指自頂向下的深度相同)、“2是4的雙親結點”、“3是4的左孩子”都是正確的;而“4是2的左孩子”、“1和3是兄弟結點”都是不正確的。

輸入格式:

輸入在第一行給出一個正整數N(≤100),隨後一行給出N個互不相同的整數,數字間以空格分隔,要求將之順次插入一棵初始為空的二叉搜尋樹。之後給出一個正整數M(≤100),隨後M行,每行給出一句待判斷的陳述句。陳述句有以下6種:

  • A is the root,即"A是樹的根";
  • A and B are siblings,即"AB是兄弟結點";
  • A is the parent of B,即"AB的雙親結點";
  • A is the left child of B,即"AB的左孩子";
  • A is the right child of B,即"AB的右孩子";
  • A and B are on the same level,即"AB在同一層上"。

題目保證所有給定的整數都在整型範圍內。

輸出格式:

對每句陳述,如果正確則輸出Yes,否則輸出No,每句佔一行。

輸入樣例:

5
2 4 1 3 0
8
2 is the root
1 and 4 are siblings
3 and 0 are on the same level
2 is the parent of 4
3 is the left child of 4
1 is the right child of 2
4 and 0 are on the same level
100 is the right child of 3

輸出樣例:

Yes
Yes
Yes
Yes
Yes
No
No
No
#include <bits/stdc++.h>
using namespace std;
struct BTNode
{
	int data;	
	BTNode* left;
	BTNode* right;
	BTNode(int x):data(x),left(NULL),right(NULL){};
}*root;
int m,n,t,level[50000];      //全域性變數
void CreateBSTree(BTNode*& root,int x)
{
	if(root == NULL)root = new BTNode(x);
	else if(root->data > x)CreateBSTree(root->left,x);
	else CreateBSTree(root->right,x);
}
void levelorder(BTNode* root)
{
	int front = 0,rear = 0;
	n = 1;
	BTNode* que[100000] = {};
	if(root)que[rear++] = root;
	while(front != rear && n <= 50000)
	{
		BTNode* p = que[front++];
		if(p){
			level[n++] = p->data;
			que[rear++] = p->left;
			que[rear++] = p->right;
		}
		else{
			n++;
            rear += 2;
		}
	}
}
int height(BTNode* root,int x) //這裡可以加上一句if(root == NULL)return 0;但我可以保證x一定存在於樹中,所以不必判斷
{
	if(root->data > x)return 1 + height(root->left,x);
	else if(root->data < x)return 1 + height(root->right,x);
	return 1;
}
void GetNum(char* str,int& a,int& b)
{
	int i = 0;   //這裡去掉對a的負數判斷後依然可以ac,所以去掉了a的符號判斷
	while(str[i] != ' ')a = (a * 10 + str[i++] - '0');
	bool flag = 0;
	for(;str[i];i++){
		if(str[i] >= '0' && str[i] <= '9')b = (b * 10 + str[i] - '0');
		if(str[i] == '-')flag = 1;
	}
	if(flag)b = -b;
}
int find(int x)
{
	for(int i = 1;i <= n;i++)	
		if(level[i] == x)return i;
	return -INT_MAX;
}
int main()
{
	char str[100];
	for(int i = 0;i < 50000;i++)level[i] = -INT_MAX;
	cin >> n;
	for(int i = 0;i < n;i++)
	{
		cin >> t;	
		CreateBSTree(root,t);
	}
	levelorder(root);
	cin >> m;
	getchar();
	for(int i = 0;i < m;i++)
	{
		int a = 0,b = 0;
		cin.getline(str,100);
		GetNum(str,a,b);
		int fa = find(a),  fb = find(b);
		if(strstr(str,"root")){
			if(level[1] == a)cout << "Yes" << endl;
			else cout << "No" << endl;
		}
		else if(strstr(str,"siblings")){
			if(fa != -INT_MAX && fb != -INT_MAX && fa != fb && (fa / 2 == fb / 2))cout << "Yes" << endl;
			else cout << "No" << endl;
		}
		else if(strstr(str,"parent")){
			if(fa != -INT_MAX && fb != -INT_MAX && (fb / 2 == fa))cout << "Yes" << endl;
			else cout << "No" << endl;
		}
		else if(strstr(str,"left")){
			if(fa != -INT_MAX && fb != -INT_MAX && (fb * 2 == fa))cout << "Yes" << endl;
			else cout << "No" << endl;
		}
		else if(strstr(str,"right")){
			if(fa != -INT_MAX && fb != -INT_MAX && (fb * 2 + 1 == fa))cout << "Yes" << endl;
			else cout << "No" << endl;
		}
		else if(strstr(str,"same")){
			if(fa != -INT_MAX && fb != -INT_MAX && (height(root,a) == height(root,b)))cout << "Yes" << endl;
			else cout << "No" << endl;
		}
	}
	return 0;
}