IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 数据结构与算法 -> 邻接矩阵转邻接表并使用bfs遍历+BFS验证六度空间理论 -> 正文阅读

[数据结构与算法]邻接矩阵转邻接表并使用bfs遍历+BFS验证六度空间理论

邻接矩阵转邻接表并使用bfs遍历

邻接矩阵转邻接表

算法思路

邻接矩阵转邻接表:先用邻接矩阵存图,然后遍历每个点,每个点可以直接相连的点放入对应的邻接表中,邻接表用一个结构体表示,结构体存直接相连的点个数n与n个点的编号与其所对应的边的权值

算法复杂度分析

邻接矩阵存图时间复杂度为m,空间复杂度为n^ 2,转邻接表时因为要遍历每个点,所以时间复杂度为n^ 2,空间复杂度为nm。

邻接表进行BFS遍历

算法思路

BFS遍历:先任意挑一个点出发,第一次遍历和它直接相邻的点,接着遍历和它直接相邻的点的相邻点,依次遍历下去,直到该点可以遍历的所有点都被遍历,注意避免重复遍历,所以需要一个vis数组标记是否被访问过。现在我们的问题就是如何存储被访问过但没有被访问过直接相邻点的点,我们可以采用队列这一数据结构来完成这一操作。

队列的实现:我们可以使用数组直接模拟队列,分别定义一个头指针和尾指针i和j就行了,i代表队列头的下标,尾代表队列尾的下标,而且我们还可以使用循环队列来提高空间利用率。但是这种做法就受限于数组的大小,因此我们使用链式队列来表示队列,它的本质就是一个链表,头部表示队头,尾部表示队尾,分别用两个指针变量存储,这样入队和出队都是O(1)的复杂度,但是为了更方便的进行入队出队,我们头部用一个哑节点表示,他没有任何实际意义,它的next才是队头。

队列的函数实现:对于一个链式队列,我们不仅仅只是封装入队和出队操作,我们还需要进行对队列进行空间释放避免内存泄露,对队列判断是否为空避免出队时发生内存段错误,而判空这个操作可以用哑节点的next是否为空判断,也可以用当前队列中元素个数判断

算法复杂度分析

队列入队出队复杂度都是1,bfs会遍历n个点,所以bfs遍历复杂度为n

代码

#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#define maxn 10001
int graph[maxn][maxn]={0};//graph[i][j]=0表示i,j之间没有边
int vis[maxn] = { 0 };
struct edge{
	int num;
	int to[maxn];
	int w[maxn];
}v[maxn];
//链式队列
struct node {
	int val;
	struct node* next;
};
struct queue {
	struct node* head, * to;
	int size;
};
struct queue* creat_queue() {
	struct node* head = malloc(sizeof(struct node));
	head->val = -1;
	head->next = NULL;
	struct queue* q = malloc(sizeof(struct queue));
	q->head = q->to = head;
	q->size=0;
	return q;
}
void push(int val, struct queue* q) {
	struct node* p = malloc(sizeof(struct node));
	p->val = val;
	p->next = NULL;
	q->size++;
	q->to->next = p;
	q->to = q->to->next;
}
void pop(struct queue*q) {
	struct node* p = q->head->next;
	q->head->next = p->next;
	free(p);
	if (q->head->next == NULL)
		q->to = q->head;
	q->size--;
}
int is_Empty(struct queue* q) {
	return q->size == 0;
}
void clear(struct queue* q) {
	while (!is_Empty(q))
		pop(q);
	free(q->head);
	q->head=q->to=NULL;
	free(q);
	q = NULL;
}
int top(struct queue* q) {
	return q->head->next->val;
}
int main() {
	int n, m;
	printf("请输入节点数和边数:");
	scanf("%d%d", &n, &m);
	int u, v1,w;
	printf("请输入每条边对应的两个节点以及权值\n");
	for (int i = 0; i < m; i++)
		scanf("%d%d%d", &u, &v1, &w), graph[u][v1] = graph[v1][u] = w;
	//转邻接表
	for (int i = 1; i <= n; i++)
		v[i].num = 0, memset(v[i].to, 0, sizeof(v[i].to));
	for (int i = 1; i <= n; i++)
		for (int j = 1; j <= n; j++)
			if (graph[i][j])
				v[i].to[v[i].num] = j, v[i].w[v[i].num++] = graph[i][j];
	//BFS
	int bfs[maxn]={0},len=0;
	for (int i = 1; i <= n; i++) {
		if (!vis[i]) {
			vis[i] = 1;
			struct queue* q = creat_queue();
			push(i, q);
			while (!is_Empty(q)) {
				int val = top(q);
				for(int j=0;j<v[val].num;j++)
					if (!vis[v[val].to[j]]) {
						push(v[val].to[j], q);
						vis[v[val].to[j]] = 1;
					}
				bfs[len++] = top(q);
				pop(q);
			}
			clear(q);
		}
	}
	for (int i = 0; i < len; i++)
		printf("%d ", bfs[i]);
	putchar('\n');
	return 0;	
}

邻接表遍历验证六度空间理论

算法思路

因为需要判断距离是否超过6,所以我们队列中的数据不再只是点的编号,而应该是点的编号和到起始点的距离,因此我们需要再开一个结构体来存储数据。

BFS遍历的时候不再像前面一样遍历到底,而是发现距离超过6后就不再继续扩展,最后记录每个点可以扩展到的点个数,求占总点数的比例就行了

算法复杂度分析

时间复杂度取决于图的样式,最好情况下时间复杂度为n+m,因为要遍历n个点,每个点只能扩展到它本身,最坏情况下每个点都被遍历n次,复杂度为n^2+m,m是存图时的时间复杂度。空间复杂度为nm+n,nm是邻接表的空间复杂度,n是队列的空间复杂度。

代码

#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#define maxn 10001
int vis[maxn] = { 0 };
struct edge {
	int num;
	int to[maxn];
	int w[maxn];
}v[maxn];//邻接表
struct database {
	int step;
	int val;
};
//链式队列
struct node {
	struct database data;
	struct node* next;
};
struct queue {
	struct node* head, * to;
	int size;
};
struct queue* creat_queue() {
	struct node* head = malloc(sizeof(struct node));
	head->data.step=head->data.val = -1;
	head->next = NULL;
	struct queue* q = malloc(sizeof(struct queue));
	q->head = q->to = head;
	q->size = 0;
	return q;
}
void push(int val,int step, struct queue* q) {
	struct node* p = malloc(sizeof(struct node));
	p->data.val = val;
	p->data.step = step;
	p->next = NULL;
	q->size++;
	q->to->next = p;
	q->to = q->to->next;
}
void pop(struct queue* q) {
	struct node* p = q->head->next;
	q->head->next = p->next;
	free(p);
	if (q->head->next == NULL)
		q->to = q->head;
	q->size--;
}
int is_Empty(struct queue* q) {
	return q->size == 0;
}
void clear(struct queue* q) {
	while (!is_Empty(q))
		pop(q);
	free(q->head);
	q->head = q->to = NULL;
	free(q);
	q = NULL;
}
struct database top(struct queue* q) {
	return q->head->next->data;
}
int main() {
	int n, m;
	printf("请输入节点数和边数:");
	scanf("%d%d", &n, &m);
	int u, v1, w;
	printf("请输入每条边对应的两个节点以及权值\n");
	for (int i = 0; i < m; i++) {
		scanf("%d%d%d", &u, &v1, &w);
		v[u].to[v[u].num] = v1;
		v[v1].to[v[v1].num] = u;
		v[u].w[v[u].num++] = w;
		v[v1].w[v[v1].num++] = w;
	}
	int ans[maxn]={0};
	for (int i = 1; i <= n; i++) {
		int vis[maxn] = { 0 };
		vis[i] = 1;
		struct queue* q = creat_queue();
		push(i, 0, q);
		while (!is_Empty(q)) {
			int val = top(q).val, step = top(q).step;
			for (int j = 0; j < v[val].num; j++) {
				if (!vis[v[val].to[j]]&&step+v[val].w[j]<=6) {
					ans[i]++;
					push(v[val].to[j], step + v[val].w[j], q);
					vis[v[val].to[j]] = 1;
				}
			}
			pop(q);
		}
		clear(q);
	}
	for (int i = 1; i <= n; i++)
		printf("%d: %%%.2lf\n", i,1.0*(ans[i]+1)/n*100);
	return 0;
}
/*
10 18
1 2 4
1 3 3
2 3 5
2 5 3
2 4 5
3 4 5
3 10 3
5 4 4
4 10 4
5 6 3
9 10 3
4 6 4
4 7 4
4 8 4
4 9 4
6 7 3
7 8 3
8 9 3
*/
  数据结构与算法 最新文章
【力扣106】 从中序与后续遍历序列构造二叉
leetcode 322 零钱兑换
哈希的应用:海量数据处理
动态规划|最短Hamilton路径
华为机试_HJ41 称砝码【中等】【menset】【
【C与数据结构】——寒假提高每日练习Day1
基础算法——堆排序
2023王道数据结构线性表--单链表课后习题部
LeetCode 之 反转链表的一部分
【题解】lintcode必刷50题<有效的括号序列
上一篇文章      下一篇文章      查看所有文章
加:2022-12-25 11:33:24  更:2022-12-25 11:36:33 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年12日历 -2024/12/26 20:24:33-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码
数据统计