大佬源码c#
大佬源码c
图
https://www.jianshu.com/p/bce71b2bdbc8
图的深度广度优先遍历
https://www.cnblogs.com/nr-zhang/p/11236369.html
树也算图
C# 通用树形数据结构
二叉树的前序、中序、后序遍历,本质上也可以认为是深度优先遍历。
二叉树的层序遍历,本质上也可以认为是广度优先遍历。
图的数据结构主要分两种,邻接矩阵(二维数组)和邻接链表。
对于插入来说,邻接链表更加方便。但是对于确定两顶点连接关系来说,邻接矩阵更方便。
邻接链表的结构说明:
c#图的邻接链表
添加顶点:直接添加
添加边:是从一个顶点,添加一条边到另一个顶点,因此需要设置起始顶点的firstEdge/secondEdge...,然后设置该边edge的endVex。
图的深度优先遍历,分为连通图的遍历,以及非连通图的遍历。
区别在于,连通图,只需要从第一个点开始遍历即可:第一个点,找到它的第一个边,然后获得边的终点,如果该终点未被访问过,递归遍历该点...递归结束后,找到它的第二个边...
非连通图:对每个点都要检索一遍;或者对每个非连通的子图其中一个点开始都搜索一遍。
连通图:所有点都能通过连线及中间连线访问到
连通分量:若无向图不是连通图,但图中存储某个子图复合连通图的性质,则该子图为连通分量。(说白了,就是大图里,分为多个小连通图,有几个小连通图,就有几个连通分量)
生成树
对连通图进行遍历,过程中所经过的边和顶点的组合可看作是一棵普通树,通常称为生成树。
生成树必须满足两个条件:1.包含连通图中所有顶点;2.任意两顶点之间有且仅有一条通路;即生成树中边数量=顶点数量-1
Kruskal最小生成树
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
public class AGraph
{
List m_Vertexes; //图的顶点集合
//public List Vertexes { get => m_Vertexes; }
public AGraph() : this(10) { }
public AGraph(int capacity)
{
m_Vertexes = new List(capacity);
}
// 添加一组顶点
public void AddVertex(params TValue[] items)
{
foreach (var x in items)
{
if (x != null)
{
AddVertex(x);
}
}
}
// 添加一个顶点
public void AddVertex(TValue item)
{
if (Contains(item))
{
Debug.LogError("插入了重复节点!");
return;
}
m_Vertexes.Add(new VertexNode(item));
}
// 添加无向边
public void AddEdge(TValue from, TValue to, float weight = 0)
{
VertexNode fromVer = Find(from);//找到起始节点
if (fromVer == null)
{
Debug.LogError("头节点并不存在!");
return;
}
VertexNode toVer = Find(to);//找到结束节点
if (toVer == null)
{
Debug.LogError("尾节点并不存在!");
return;
}
AddEdge(fromVer, toVer, weight);
}
// 添加单向边
public void AddDirectionEdge(TValue from, TValue to, float weight = 0)
{
VertexNode fromVer = Find(from);//找到起始节点
if (fromVer == null)
{
Debug.LogError("头节点并不存在!");
return;
}
VertexNode toVer = Find(to);//找到结束节点
if (toVer == null)
{
Debug.LogError("尾节点并不存在!");
return;
}
//无向边两个节点都需记录的边的信息
AddDirectedEdge(fromVer, toVer, weight);
}
///
/// 连线中所有的顶点
/// randomWeight:是否给每条边一个随机值,否则都给1
///
public void LineAllVertexes(float randomWeight0 = 0, float randomWeight1 = 0)
{
for (int i = 0; i < m_Vertexes.Count; i++)
{
for (int j = 0; j < m_Vertexes.Count; j++)
{
if (i != j)
{
// 判断是否已经连过线,如果连过那么不要连了。(不判断也没问题,因为内部有判定,不会重复添加)
if (GetEdge(m_Vertexes[i], m_Vertexes[j]) == null)
{
AddEdge(m_Vertexes[i], m_Vertexes[j], Random.Range(randomWeight0, randomWeight1));
}
}
}
}
}
// 根据顶点添加边(内部调用)
private void AddEdge(VertexNode fromVer, VertexNode toVer, float weight = 0)
{
//无向边两个节点都需记录的边的信息
AddDirectedEdge(fromVer, toVer, weight);
AddDirectedEdge(toVer, fromVer, weight);
}
private void AddDirectedEdge(VertexNode fromVer, VertexNode toVer, float weight = 0)
{
if (fromVer.firstEdge == null)//无邻接点的时候
{
fromVer.firstEdge = new EdgeNode(toVer, weight);
}
else
{
EdgeNode tmp, edgeNode = fromVer.firstEdge;
do
{
//检查是否添加了重复边
if (edgeNode.endvex.data.Equals(toVer.data))
{
Debug.LogError("添加了重复的边!");
return;
}
tmp = edgeNode;
edgeNode = edgeNode.next;
} while (edgeNode != null);
tmp.next = new EdgeNode(toVer, weight);//添加到链表末尾。
}
}
// 获取一条边,如果获取失败则返回null
private EdgeNode GetEdge(VertexNode fromVer, VertexNode toVer)
{
EdgeNode edgeNode = fromVer.firstEdge;
while (edgeNode != null)
{
if (edgeNode.endvex.data.Equals(toVer.data))
{
//找到了这条边
return edgeNode;
}
else
{
//没找到,继续往下找
edgeNode = edgeNode.next;
}
}
return null;
}
public bool Contains(TValue item)//查图中是否包含某项
{
foreach (VertexNode v in m_Vertexes)
{
if (v.data.Equals(item))
{
return true;
}
}
return false;
}
private VertexNode Find(TValue item)//查找指定项并返回
{
foreach (VertexNode v in m_Vertexes)
{
if (v.data.Equals(item))
{
return v;
}
}
return null;
}
private int GetIndex(TValue item) //查找指定项,返回index
{
for(int i = 0;i < m_Vertexes.Count;i ++)
{
if(m_Vertexes[i].data.Equals(item))
{
return i;
}
}
return -1;
}
public void Draw()
{
}
//public override string ToString()//仅用于测试
//{
// //打印每个顶点和它的邻接点
// string s = string.Empty;
// foreach (VertexNode v in items)
// {
// s += v.data.ToString() + ":";
// if (v.firstEdge != null)
// {
// EdgeNode tmp = v.firstEdge;
// while (tmp != null)
// {
// s += tmp.endvex.data.ToString() + "_" + tmp.weight + " ";
// tmp = tmp.next;
// }
// }
// s += "\r\n";
// }
// return s;
//}
//深度优先搜索
public void DFSTraverse()
{
InitVisited();//将visited标志全部置为false
DFS(m_Vertexes[0]);//从第一个顶点开始遍历
}
//广度优先搜索遍历
public void BFSTraverse()
{
InitVisited();//
BFS(m_Vertexes[0]);//从第一个顶点开始遍历
}
//非连通图深度优先遍历
public void DFSTraverse2()
{
InitVisited();
foreach (VertexNode v in m_Vertexes)
{
if (!v.visited)
{
DFS(v);
}
}
}
//非连通图广度优先遍历
public void BFSTraverse2()
{
InitVisited();
foreach (VertexNode v in m_Vertexes)
{
if (!v.visited)
{
BFS(v);
}
}
}
//初始化visited标志
private void InitVisited()
{
foreach (VertexNode v in m_Vertexes)
{
v.visited = false;//全部设为false
}
}
//深度优先遍历
private void DFS(VertexNode v)
{
v.visited = true;//将访问标志设为true
Debug.Log(v.data + " ");//访问
EdgeNode node = v.firstEdge;
while (node != null)//访问此顶点的所有邻节点
{
//如果邻节点未被访问,则递归访问它的边
if (!node.endvex.visited)
{
DFS(node.endvex);//递归
}
node = node.next;//访问下一个节点
}
}
//广度优先遍历
private void BFS(VertexNode v)//使用队列进行广度优先搜索
{
//创建一个队列
Queue queue = new Queue();
Debug.Log(v.data + " ");
v.visited = true;
queue.Enqueue(v);
while (queue.Count > 0)
{
VertexNode w = queue.Dequeue();
EdgeNode node = w.firstEdge;
while (node != null)
{
if (!node.endvex.visited)
{
Debug.Log(node.endvex.data + " ");//访问
node.endvex.visited = true;//设置访问标志
queue.Enqueue(node.endvex);//进队
}
node = node.next;//访问下一个邻节点
}
}
}
///
/// 边节点:连着终点,并且拥有“起点”连接的下一个边的指针
///
public class EdgeNode
{
public VertexNode endvex; //边连着的“终点”
public EdgeNode next; //下一条边
public float weight; //边权重
public EdgeNode(VertexNode endVex, float edgeWeight = 0)
{
endvex = endVex;
weight = edgeWeight;
}
}
///
/// 顶点:作为起点,连着一个边
///
public class VertexNode
{
public TValue data; //数据
public EdgeNode firstEdge; //第一条相邻边
public bool visited; //访问标志,用于遍历
public VertexNode(TValue value)
{
data = value;
}
}
//-------------------------------------------------
List m_SpanVertexes; //最小生成树的顶点集合
List m_SpanEdges;
public List spanEdges { get => m_SpanEdges; }
public void Kruskal()
{
// 创建生成树节点列表
CopyNodes();
// 获得根据权重排序好的边列表
var edges = GetSortedEdges();
int treeEdgeCount = 0; //树连边个数
int[] vends = new int[m_SpanVertexes.Count]; // 用于保存"已有最小生成树"中每个顶点在该最小树中的终点。
m_SpanEdges = new List();
// 遍历所有的边
for (int i = 0;i < edges.Length;i ++)
{
//m_SpanEdges.Add(edges[i]);
//var vex1 = edges[i].begin.parentNode; //获得起点_父节点
//var vex2 = edges[i].end.parentNode; //获得终点_父节点
var p1 = GetIndex(edges[i].begin.data);
var p2 = GetIndex(edges[i].end.data);
var m = get_end(vends, p1); // 获取p1在"已有的最小生成树"中的终点
var n = get_end(vends, p2); // 获取p2在"已有的最小生成树"中的终点
// 如果m!=n,意味着"边i"与"已经添加到最小生成树中的顶点"没有形成环路
if (m != n)
{
vends[m] = n; // 设置m在"已有的最小生成树"中的终点为n
m_SpanEdges.Add(edges[i]);
treeEdgeCount++;
if (treeEdgeCount == (m_SpanVertexes.Count - 1)) break; //边的数量达到最大值
}
}
Debug.LogError(treeEdgeCount);
}
int get_end(int[] vends, int i)
{
while (vends[i] != 0)
i = vends[i];
return i;
}
private void CopyNodes()
{
m_SpanVertexes = new List(m_Vertexes.Count);
for (int i = 0; i < m_Vertexes.Count; i++)
{
var vertex = new SpanTreeVertexNode();
vertex.data = m_Vertexes[i].data;
vertex.parentNode = null;
m_SpanVertexes.Add(vertex);
}
}
// 遍历所有顶点,获得无向边,然后排序无向边。
private SpanTreeEdgeNode[] GetSortedEdges()
{
InitVisited();
List result = new List();
for (int i = 0; i < m_Vertexes.Count; i++)
{
m_Vertexes[i].visited = true;
EdgeNode edge = m_Vertexes[i].firstEdge; //获得每个顶点的第一条边
while(edge != null)
{
// 遍历所有的边,如果终点还没访问过,那么创建生成树的边结构,加入列表
if(edge.endvex.visited == false)
{
var spanTreeEdge = new SpanTreeEdgeNode();
spanTreeEdge.begin = m_SpanVertexes[i];
spanTreeEdge.end = m_SpanVertexes[GetIndex(edge.endvex.data)];
spanTreeEdge.weight = edge.weight;
//{ begin = m_SpanVertexes[i], end = m_SpanVertexes[GetIndex(edge.endvex.data)], weight = edge.weight };
result.Add(spanTreeEdge);
}
edge = edge.next;
}
}
return result.OrderBy(x => x.weight).ToArray();
}
public class SpanTreeEdgeNode
{
public SpanTreeVertexNode begin;
public SpanTreeVertexNode end;
public float weight;
}
public class SpanTreeVertexNode
{
public TValue data;
public SpanTreeVertexNode parentNode;
}
}
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PrimGenerater : MonoBehaviour
{
AGraph roomGraph;
private void Start()
{
roomGraph = new AGraph();
Room normal1 = new Room(RoomType.Normal);
Room normal2 = new Room(RoomType.Normal);
Room normal3 = new Room(RoomType.Normal);
Room normal4 = new Room(RoomType.Normal);
Room normal5 = new Room(RoomType.Normal);
Room normal6 = new Room(RoomType.Normal);
roomGraph.AddVertex(normal1, normal2, normal3, normal4, normal5, normal6);
roomGraph.LineAllVertexes(0, 10);
roomGraph.Kruskal();
}
private void Update()
{
foreach (var x in roomGraph.spanEdges)
{
//Debug.Log(x.begin.data.ToString() + " " + x.end.data.ToString() + " " + x.weight);
Debug.DrawLine(x.begin.data.roomObject.transform.position, x.end.data.roomObject.transform.position, Color.red);
}
}
}
public enum RoomType
{
Entrance, //入口
Boss, //boss房
Normal, //普通房间
Treasure, //宝箱房间
Secret, //密室
Sacrifice, //献祭房
Gamble, //赌博房
Teleport, //传送房
Chanllenge, //挑战房
Puzzle, //解谜房
Shop, //商店房
X, //原初房
}
public class Room
{
private RoomType m_RoomType;
public RoomType RoomTp { get => m_RoomType; }
private int m_RoomID;
public static int roomIndex;
public Vector3 roomSize; //房间的大小
public GameObject roomObject; //房间物体
public Room(RoomType roomType, float roomX = 1, float roomY = 1, float roomZ = 1)
{
m_RoomType = roomType;
roomIndex++;
m_RoomID = roomIndex;
roomSize = new Vector3(roomX, roomY, roomZ);
roomObject = GameObject.CreatePrimitive(PrimitiveType.Cube);
roomObject.transform.parent = GameObject.Find("PrimGenerater").transform;
roomObject.transform.localScale = roomSize;
roomObject.name = ToString();
}
public override string ToString()
{
return m_RoomType.ToString() + m_RoomID;
}
}
图的最小环:Floyd
https://blog.csdn.net/Harington/article/details/81982299