HIT-哈工大数据结构-作业4(C++)

1.分别实现有向图的邻接矩阵和邻接表存储结构的建立算法,分析和比较各建立算法的时间复杂度以及存储结构的空间占用情况。

逆邻接矩阵:

//邻接矩阵
typedef struct {
	char vertex[V_Number];//顶点表
	int edge[V_Number][V_Number];//边表
	int n;//顶点数
	int e;//边数
}MTGraph;
void CreatMTGragh(MTGraph* G)//构建有向图的逆邻接矩阵表
{
	cout << "输入顶点数和边数" << endl;
	cin >> G->n>> G->e;
	cout << "输入顶点信息" << endl;
	for (int i = 0; i < G->n; i++)
		cin >> G->vertex[i];
	for (int i = 0; i < G->n; ++i)
		for (int j = 0; j < G->n; ++j)
			G->edge[i][j] = 0;//初始化
	cout << "读入e条边建立邻接矩阵,分别输入tail、head、weight" << endl;
	for (int k = 0; k < G->e; k++) {
		int i, j, w;
		cin >> i >> j >> w;//输入边(i,j)上的权值
		G->edge[i][j] = w;
	}
}

邻接矩阵建立算法的时间复杂度为O(n2+n+e) 空间复杂度为O(n+n2)

逆邻接表:

//逆邻接表
typedef struct node {//边表
	int adjvex;//邻接点域
	int cost;//边上的权值
	struct node* next;//下一边链接指针
}EdgeNode;
typedef struct {//顶点表节点
	char vertex;//顶点数据域
	EdgeNode* firstedge;//边链表头指针
}VertexNode;
typedef struct {//图的邻接表
	VertexNode vexlist[V_Number];
	int n;
	int e;
}AdjGraph;

void CreateGraph(AdjGraph* G) {//建立有向图逆邻接表
	cout << "输入顶点数和边数" << endl;
	cin >> G->n >> G->e;
	cout << "输入顶点信息" << endl;
	for (int i = 0; i < G->n; ++i) {
		cin >> G->vexlist[i].vertex;
		G->vexlist[i].firstedge = NULL;//边表置为空表
	}
	int tail, head, weight;
	EdgeNode* temp;
	cout << "读入e条边建立邻接矩阵,分别输入tail、head、weight" << endl;
	for (int i = 0; i < G->e; ++i) {//逆邻接矩阵表
		cin >> tail >> head >> weight;
		EdgeNode *p= new EdgeNode;//头插法
		p->adjvex = head;
		p->cost = weight;
		p->next = G->vexlist[tail].firstedge;
		G->vexlist[tail].firstedge = p;
	}
}

邻接表建立算法的时间复杂度为O(n+e) 空间复杂度为O(n+e)

2.实现有向图的邻接矩阵和邻接表两种存储结构的相互转换算法。

示例有向图

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-t9czIL9I-1677332191110)(未命名.assets/图片2.png)]

邻接矩阵转换为邻接表:

测试代码

int main() {
	MTGraph* G = new MTGraph;
	AdjGraph* A = new AdjGraph;
	int in[V_Number] = { 0 };
	int out[V_Number] = { 0 };
	CreatMTGragh(G);
	cout << "邻接矩阵:" << endl;
	printm(G);
	cout << "转换后" << endl;
	A = TransToAdj(G);
	printa(A);

}

结果

图片3

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-u2W9oUPs-1677332191110)(未命名.assets/图片6.png)]

3.在上述两种存储结构上,分别实现有向图的深度优先搜索(递归 和非递归)和广度优先搜索算法。并以适当的方式存储和展示相应的搜索结果, 包括:深度优先或广度优先生成森林(或生成树)、深度优先或广度优先序列 和深度优先或广度优先编号。并分析搜索算法的时间复杂度和空间复杂度。

使用的栈类:

#define maxlength  10000


class MyStack {
public:
	MyStack();
	void MakeNull();//将栈置空
	void Push(int x);//进栈
	int Pop();//出栈
	bool Empty();//判断栈是否为空
	int Top();

public:
	int stk[maxlength];//用于存放横坐标、纵坐标
	int top;//用于记录栈顶
};

使用的队列类:

#define Max  1000


class Queue {//尾进头出
public:
    Queue();//无参构造初始化队列
    bool Empty();
    void EnQueue(int x);
    int DeQueue();

public:
    int front;
    int rear;
    int d[Max];
};
int dfn[V_Number];//顶点的先深编号
bool visited[V_Number];//访问标记数组
void visitm(MTGraph* G, int i) {//按下标访问逆邻接矩阵的顶点表
	cout << G->vertex[i] << " ";
}
void visita(AdjGraph* G, int i) {//按下标访问邻接表的顶点表
	cout << G->vexlist[i].vertex << " ";
}

//邻接矩阵的递归深度优先搜索
void DFSMR1(MTGraph* G, int i, int& count) {//从一个顶点出发的一次深度优先遍历算法
	visitm(G, i);
	visited[i] = true;//标记为访问过
	dfn[i] = count++;//对i顶点进行编号
	for (int j = 0; j < G->n; ++j) {
		if (G->edge[i][j] && (!visited[j])) {//找到下一个未被访问的邻接点
			DFSMR1(G, j, count);
		}
	}
}
void DFSMre(MTGraph* G) {//主算法
	int count = 1;
	for (int i = 0; i < G->n; ++i) {
		visited[i] = false;//标记数组初始化
	}
	for (int i = 0; i < G->n; ++i) {
		if (!visited[i])
			DFSMR1(G, i, count);//从顶点i出发的一次搜索
	}
}

//邻接表的递归深度优先搜索
void DFSAR1(AdjGraph* G, int i, int& count) {//从一个顶点出发的一次深度优先遍历算法
	EdgeNode* p;
	visita(G, i);
	visited[i] = true;
	dfn[i] = count++;//对i顶点进行编号
	p = G->vexlist[i].firstedge;
	while (p) {//有相邻边
		if (!visited[p->adjvex])//未访问过
			DFSAR1(G, p->adjvex, count);//访问该相邻点
		p = p->next;
	}
}
void DFSAre(AdjGraph* G) {//主算法
	int count = 1;
	for (int i = 0; i < G->n; ++i) {
		visited[i] = false;//标记数组初始化
	}
	for (int i = 0; i < G->n; ++i) {
		if (!visited[i])
			DFSAR1(G, i, count);//从顶点i出发的一次搜索
	}
}
//邻接矩阵的非递归深度优先搜索
void DFSM1(MTGraph* G, int i, int& count) {//从一个顶点出发的一次深度优先遍历算法
	MyStack S;
	S.Push(i);//进栈
	visitm(G, i);
	visited[i] = true;//标记为访问过
	dfn[i] = count++;//对i顶点进行编号
	for (int j = 0;;) {
		if (j == G->n) {
			if (S.Empty())
				break;//栈空退出
			i=S.Pop();
			j = 0;
		}
		if (G->edge[i][j] && !visited[j]) {
			visited[j] = true;
			visitm(G, j);
			dfn[j] = count++;
			S.Push(j);
			i = j;//从j开始
			j = -1;
		}
		++j;
	}
}
void DFSM(MTGraph* G) {//主算法
	int count = 1;
	for (int i = 0; i < G->n; ++i) {
		visited[i] = false;//标记数组初始化
	}
	for (int i = 0; i < G->n; ++i) {
		if (!visited[i])
			DFSM1(G, i, count);//依次访问顶点
	}
}
//邻接表的非递归深度优先搜索
void DFSA1(AdjGraph* G, int i, int& count) {//从一个顶点出发的一次深度优先遍历算法
	MyStack S;
	S.Push(i);
	visita(G, i);
	visited[i] = true;
	dfn[i] = count++;//对i顶点进行编号
	while (1) {
		EdgeNode* p = G->vexlist[i].firstedge;
		while (p) {
			if (!visited[p->adjvex]) {
				S.Push(p->adjvex);
				visita(G, p->adjvex);
				visited[p->adjvex] = true;
				dfn[p->adjvex] = count++;
				if (G->vexlist[p->adjvex].firstedge)//下一个顶点
					p = G->vexlist[p->adjvex].firstedge;
				else
					p = p->next;
			}
			else
				p = p->next;
		}
		if (S.Empty())
			break;
		i=S.Pop();
	}
}
void DFSA(AdjGraph* G) {//主算法
	int count = 1;
	for (int i = 0; i < G->n; ++i) {
		visited[i] = false;
	}
	for (int i = 0; i < G->n; ++i) {
		if (!visited[i])
			DFSA1(G, i, count);
	}
}


int bfn[V_Number];//顶点的先深编号
//邻接矩阵的广度优先遍历
void BFSM1(MTGraph* G, int i, int& count) {//从一个顶点出发的一次广度优先遍历算法
	Queue Q;//初始化队列
	visited[i] = true;
	visitm(G, i);
	bfn[i] = count++;
	Q.EnQueue(i);//顶点入队
	while (!Q.Empty()) {//队空搜索结束
		int i;
		i = Q.DeQueue();
		for (int j = 0; j < G->n; j++) {
			if (G->edge[i][j] && !visited[j]) {
				visitm(G, j);//访问j
				visited[j] = true;
				bfn[j] = count++;
				Q.EnQueue(j);
			}
		}
	}
}
void BFSM(MTGraph* G) {//主算法
	int count = 1;
	for (int i = 0; i < G->n; ++i) {
		visited[i] = false;//标记数组初始化
	}
	for (int i = 0; i < G->n; ++i) {
		if (!visited[i]) {
			BFSM1(G, i, count);
		}
	}

}
//邻接表的广度优先遍历
void BFSA1(AdjGraph* G, int i, int& count) {//从一个顶点出发的一次广度优先遍历算法
	EdgeNode* p;
	Queue Q;
	visita(G, i);
	visited[i] = true;
	bfn[i] = count++;
	Q.EnQueue(i);
	while (!Q.Empty()) {
		int i;
		i = Q.DeQueue();
		p = G->vexlist[i].firstedge;
		while (p) {
			if (!visited[p->adjvex]) {
				visita(G, p->adjvex);
				visited[p->adjvex] = true;
				bfn[p->adjvex] = count++;
				Q.EnQueue(p->adjvex);
			}
			p = p->next;
		}
	}

}
void BFSA(AdjGraph* G) {//主算法
	int count = 1;
	for (int i = 0; i < G->n; ++i) {
		visited[i] = false;//初始化标记数组
	}
	for (int i = 0; i < G->n; ++i) {
		if (!visited[i]) {
			BFSA1(G, i, count);
		}
	}
}

邻接矩阵的深度优先搜索时间复杂度为O(n2

表的深度优先搜索时间复杂度为O(n+e)

4.对于有向图,采用“邻接表”存储结构,设计和实现计算每个顶点入度、 出度和度的算法,并分析其时间复杂度。

void DU(AdjGraph* A, int in[], int out[]) {
	EdgeNode* p;
	for (int i = 0; i < A->n; ++i) {
		p = A->vexlist[i].firstedge;
		while (p) {
			in[i]++;
			out[p->adjvex]++;
			p = p->next;
		}
	}
}

时间复杂度为O(n+e)

5.以适当的方式输入图的顶点和边,并显示相应的结果。要求顶点不少于 10 个,边不少于 13 条。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-As94WU2W-1677332191111)(未命名.assets/图片2.png)]

完成实验目标345

测试代码:

int main() {
	MTGraph* G = new MTGraph;
	AdjGraph* A = new AdjGraph;
	int in[V_Number] = { 0 };
	int out[V_Number] = { 0 };
	CreatMTGragh(G);
	cout << "邻接矩阵:" << endl;
	printm(G);
	cout << "转换后" << endl;
	A = TransToAdj(G);
	printa(A);
	cout << "广度优先遍历序列:" << endl;
	BFSM(G);
	cout << endl;
	cout << "广度优先编号:" << endl;
	for (int i = 0; i < G->n; ++i) {
		cout << bfn[i] << " ";
	}
	cout << endl;
	cout << "深度优先搜索序列为:" << endl;
	DFSMre(G);
	cout << endl;
	cout << "深度优先编号为:" << endl;
	for (int i = 0; i < G->n; ++i) {
		cout << dfn[i] << " ";
	}
	cout << endl;
	DU(A, in, out);
	cout << "各顶点入度为:" << endl;
	for (int i = 0; i < A->n; ++i) {
		cout << in[i] << " ";
	}
	cout << endl;
	cout << "各顶点出度为:" << endl;
	for (int i = 0; i < A->n; ++i) {
		cout << out[i] << " ";
	}
	cout << endl;
	cout << "各顶点度为:" << endl;
	for (int i = 0; i < A->n; ++i) {
		cout << in[i] + out[i] << " ";
	}
	cout << endl;

}

结果:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-R92Od3Z1-1677332191111)(未命名.assets/图片7.png)]

<< " ";
}
cout << endl;
DU(A, in, out);
cout << “各顶点入度为:” << endl;
for (int i = 0; i < A->n; ++i) {
cout << in[i] << " ";
}
cout << endl;
cout << “各顶点出度为:” << endl;
for (int i = 0; i < A->n; ++i) {
cout << out[i] << " ";
}
cout << endl;
cout << “各顶点度为:” << endl;
for (int i = 0; i < A->n; ++i) {
cout << in[i] + out[i] << " ";
}
cout << endl;

}


结果:

[外链图片转存中...(img-R92Od3Z1-1677332191111)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-KizxPlAR-1677332191111)(未命名.assets/图片8.png)]
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值