03.图的深度和广度优先遍历(递归和非递归都有,邻接表和邻接矩阵)
图论是一个很重要的工具,这节主要是图的创建和遍历的Java代码,不讲理论,只撸代码,理论网上很多,具体一步步该怎么走,其他的贴子也都给全了,但是都是c语言,我们用Java实现和模拟图论。
内容有点多,给个目录:
目录:
1. 图结点的创建
2. 图的创建
**2.1 图的结构和初始化**
**2.2 邻接矩阵**
**2.3 邻接表**
3. 邻接表的两种遍历
**3.1 深度优先遍历(邻接表)**
**3.1.1 递归算法(邻接表)**
**3.1.2 非递归算法(邻接表)**
**3.2 广度优先遍历(邻接表)**
4. 邻接矩阵的两种遍历
**4.1 深度优先遍历(邻接矩阵)**
**4.1.1 递归算法(邻接矩阵)**
**4.1.2 非递归算法(邻接矩阵)**
**4.2 广度优先搜索(邻接矩阵)**
5. 项目完整代码
1. 图结点的创建
public class Node {
public int name;
public Node next;
public Boolean flag;
public Node() {
// TODO Auto-generated constructor stub
this.name = 0;
this.next = null;
this.flag = false;
}
public Node(int name) {
this.name = name;
this.next = null;
this.flag = false;
}
}
2. 图的创建
2.1 图的结构和初始化
import java.util.Scanner;
public class Graph {
public Node[] nodes;
public int[][] A;
public int Sidenum;
public Seqqueue queue;
public Seqstack stack;
Scanner scanner;
public Graph(int Nodenum, int Sidenum) {
this.nodes = new Node[Nodenum];
for (int i = 0; i < Nodenum; i++) {
this.nodes[i] = new Node(i);
}
this.A = new int[Nodenum][Nodenum];
this.Sidenum = Sidenum;
for (int i = 0; i < Nodenum; i++) {
for (int j = 0; j < Nodenum; j++) {
this.A[i][j] = 0;
}
}
scanner = new Scanner(System.in);
this.queue = new Seqqueue();
this.queue.initQueue(20);
this.stack = new Seqstack();
this.stack.InitStack(20);
}
}
2.2 邻接矩阵
// 邻接矩阵创建(有向图)
void creat1() {
int a, b;
for (int i = 0; i < this.Sidenum; i++) {
a = scanner.nextInt();
b = scanner.nextInt();
this.A[a][b] = 1;
}
System.out.println("图创建成功");
}
// 邻接矩阵创建(无向图)
void creat2() {
int a, b;
for (int i = 0; i < this.Sidenum; i++) {
a = scanner.nextInt();
b = scanner.nextInt();
this.A[a][b] = 1;
this.A[b][a] = 1;
}
System.out.println("图创建成功");
}
// 遍历输出邻接矩阵
void traver1() {
for (int i = 0; i < nodes.length; i++) {
for (int j = 0; j < nodes.length; j++) {
System.out.print(this.A[i][j] + " ");
}
System.out.println("");
}
}
2.3 邻接表
// 邻接表创建
void creat3() {
int a, b;
for (int i = 0; i < this.Sidenum; i++) {
a = scanner.nextInt();
b = scanner.nextInt();
Node node = this.nodes[a];
// 防止把同一条边加入多次
while (node.next != null && node.next.name != b) {
node = node.next;
}
if (node.next == null) {
Node n = new Node(b);
n.next = nodes[a].next;
nodes[a].next = n;
}
}
System.out.println("图创建成功");
}
// 遍历输出邻接表
void traver2() {
Node node;
for (int i = 0; i < nodes.length; i++) {
node = nodes[i];
System.out.print(node.name + ":");
while (node.next != null) {
System.out.print(node.next.name + " ");
node = node.next;
}
System.out.println("");
}
}
3. 邻接表的两种遍历
flag属性用来标记结点有没有被访问过,所以需要初始化。
// 初始化访问标记
void initFlag() {
// 初始化
for (int i = 0; i < this.nodes.length; i++) {
this.nodes[i].flag = false;
}
}
3.1 深度优先遍历(邻接表)
3.1.1 递归算法(邻接表)
// 深度优先遍历(从head结点开始) 递归算法 邻接表
void DFS1(Node head) {
Node pNode;
if (!this.nodes[head.name].flag) {
System.out.print(head.name + " ");
this.nodes[head.name].flag = true;
}
pNode = this.nodes[head.name].next;
while (pNode != null) {
if (!this.nodes[pNode.name].flag) {
DFS1(pNode);
} else {
pNode = pNode.next;
}
}
}
3.1.2 非递归算法(邻接表)
用到的栈,定义在文章最后完整项目代码中有,这块只是引用。
// 深度优先遍历(从head结点开始) 非递归算法 邻接表
void DFS2(Node head) {
// 初始化访问标记
initFlag();
// 初始化栈
this.stack.InitStack(20);
Node pNode, wNode;
this.stack.push(head);
System.out.print(head.name + " ");
this.nodes[head.name].flag = true;
while (!this.stack.IsEmpty()) {
pNode = this.stack.pop();
wNode = pNode.next;
while (wNode != null) {
if (!this.nodes[wNode.name].flag) {
this.stack.push(wNode);
this.nodes[wNode.name].flag = true;
System.out.print(wNode.name + " ");
wNode = this.nodes[wNode.name].next;
} else {
wNode = wNode.next;
}
}
}
}
3.2 广度优先遍历(邻接表)
因为广度优先遍历需要用到队列,所以不能递归,递归只能是用到栈时才能。
用到的队列,定义在文章最后完整项目代码中有,这块只是引用。
void BFS1(Node head) {
// 初始化访问标记
initFlag();
// 初始化队列
this.queue.initQueue(20);
Node pNode;
this.queue.enterQueue(head);
this.nodes[head.name].flag = true;
while (!this.queue.isEmpty()) {
pNode = this.queue.deleteQueue();
pNode = this.nodes[pNode.name];
System.out.print(pNode.name + " ");
while (pNode != null) {
pNode = pNode.next;
if (pNode != null && !this.nodes[pNode.name].flag) {
this.queue.enterQueue(pNode);
this.nodes[pNode.name].flag = true;
}
}
}
}
4. 邻接矩阵的两种遍历
4.1 深度优先遍历(邻接矩阵)
4.1.1 递归算法(邻接矩阵)
// 深度优先遍历(从0号结点开始) 递归算法 邻接矩阵
void DFSM(int i) {
int j = 0;
System.out.print(this.nodes[i].name + " ");
this.nodes[i].flag = true;
for (j = 0; j < this.Sidenum; j++) {
if (this.A[i][j] == 1 && !this.nodes[j].flag) {
DFSM(j);
}
}
}
void DFS3() {
for (int i = 0; i < this.Sidenum; i++) {
if (!this.nodes[i].flag) {
DFSM(i);
}
}
}
4.1.2 非递归算法(邻接矩阵)
用到的栈,定义在文章最后完整项目代码中有,这块只是引用。
// 深度优先遍历(从0号结点开始) 非递归算法 邻接矩阵
void DFS4(Node head) {
// 初始化访问标记
initFlag();
int i = 0;
// 初始化栈
this.stack.InitStack(20);
Node pNode, wNode = null;
this.stack.push(head);
System.out.print(head.name + " ");
this.nodes[head.name].flag = true;
while (!this.stack.IsEmpty()) {
pNode = this.stack.getTop();
for (i = 0; i < this.Sidenum; i++) {
if (this.A[pNode.name][i] == 1 && !this.nodes[i].flag) {
System.out.print(this.nodes[i].name + " ");
this.nodes[i].flag = true;
this.stack.push(this.nodes[i]);
break;
}
}
if (i == this.Sidenum) {
this.stack.pop();
}
}
}
4.2 广度优先搜索(邻接矩阵)
因为广度优先遍历需要用到队列,所以不能递归,递归只能是用到栈时才能。
用到的队列,定义在文章最后完整项目代码中有,这块只是引用。
// 广度优先遍历(从0号结点开始) 非递归算法 邻接矩阵
void BFS2(int k) {
// 初始化被访问标记
initFlag();
// 初始化队列
this.queue.initQueue(20);
Node node;
System.out.print(this.nodes[k].name + " ");
this.nodes[k].flag = true;
this.queue.enterQueue(this.nodes[k]);
while (!this.queue.isEmpty()) {
node = this.queue.deleteQueue();
for (int i = 0; i < this.Sidenum; i++) {
if (this.A[node.name][i] == 1 && !this.nodes[i].flag) {
System.out.print(this.nodes[i].name + " ");
this.nodes[i].flag = true;
this.queue.enterQueue(this.nodes[i]);
}
}
}
}
5. 项目完整代码
项目的代码比较多,主要有下面几个类,防止查找麻烦,目录如下:
目录:
- class Node 结点定义
- class Seqqueue 队列定义
- class Seqstack 栈的定义
- class Graph 图的定义及操作
- class Client 测试类
内容:
- //class Node 结点定义
package com.company.project.graph;
public class Node {
public int name;
public Node next;
public Boolean flag;
public Node() {
// TODO Auto-generated constructor stub
this.name = 0;
this.next = null;
this.flag = false;
}
public Node(int name) {
this.name = name;
this.next = null;
this.flag = false;
}
}
\2. //class Seqqueue 队列定义
package com.company.project.graph;
public class Seqqueue {
public Node[] queue;
public int QUEUE_SIZE;
public int front;
public int rear;
//初始化队列
public void initQueue(int size) {
this.QUEUE_SIZE = size;
this.queue = new Node[size];
this.front = 0;
this.rear = 0;
}
//判断队列是否为空
public boolean isEmpty() {
if(this.front == this.rear ) {
return true;
}
else {
return false;
}
}
//判断队列是否为满
public boolean isFull() {
if((this.front % this.QUEUE_SIZE) == ((this.rear+1) % this.QUEUE_SIZE)) {
return true;
}
else {
return false;
}
}
//入队
public void enterQueue(Node node) {
if(isFull()) {
System.out.println("队列已经满了,入队失败");
return;
}
this.queue[this.rear] = node;
this.rear ++;
this.rear = this.rear % this.QUEUE_SIZE;
}
//出队
public Node deleteQueue() {
if(isEmpty()){
System.out.println("队列为空,出队失败");
return null;
}
this.front = this.front % this.QUEUE_SIZE;
Node node = this.queue[this.front];
this.front++;
return node;
}
}
\3. //class Seqstack 栈的定义
package com.company.project.graph;
public class Seqstack {
// 节点数组(模拟顺序栈)
public Node[] nodes;
// 栈顶下标
public int top;
public Seqstack() {
// TODO Auto-generated constructor stub
this.top = -1;
}
// 初始化栈
public void InitStack(int size) {
this.nodes = new Node[size];
this.top = -1;
}
// 判断栈空
public boolean IsEmpty() {
if (this.top == -1) {
return true;
}
return false;
}
// 判断栈满
public boolean IsFull() {
if (this.top == this.nodes.length - 1) {
return true;
}
return false;
}
// 入栈
public void push(Node node) {
if (IsFull()) {
System.out.println("栈已经满了,入栈失败");
return;
}
this.top++;
this.nodes[this.top] = node;
}
// 出栈
public Node pop() {
if (IsEmpty()) {
System.out.println("栈已经空了,出栈失败");
return null;
}
Node node = this.nodes[this.top];
this.top--;
return node;
}
// 清空栈
public void ClearStack() {
// 如果不为空,就一直出栈
while (!IsEmpty()) {
Node node = pop();
}
}
// 拿到栈顶元素
public Node getTop() {
if (IsEmpty()) {
System.out.println("栈中没有元素");
return null;
}
return this.nodes[this.top];
}
}
\4. //class Graph 图的定义及操作
package com.company.project.graph;
import java.util.Scanner;
public class Graph {
public Node[] nodes;
public int[][] A;
public int Sidenum;
public Seqqueue queue;
public Seqstack stack;
Scanner scanner;
public Graph(int Nodenum, int Sidenum) {
this.nodes = new Node[Nodenum];
for (int i = 0; i < Nodenum; i++) {
this.nodes[i] = new Node(i);
}
this.A = new int[Nodenum][Nodenum];
this.Sidenum = Sidenum;
for (int i = 0; i < Nodenum; i++) {
for (int j = 0; j < Nodenum; j++) {
this.A[i][j] = 0;
}
}
scanner = new Scanner(System.in);
this.queue = new Seqqueue();
this.queue.initQueue(20);
this.stack = new Seqstack();
this.stack.InitStack(20);
}
// 邻接矩阵创建(有向图)
void creat1() {
int a, b;
for (int i = 0; i < this.Sidenum; i++) {
a = scanner.nextInt();
b = scanner.nextInt();
this.A[a][b] = 1;
}
System.out.println("图创建成功");
}
// 邻接矩阵创建(无向图)
void creat2() {
int a, b;
for (int i = 0; i < this.Sidenum; i++) {
a = scanner.nextInt();
b = scanner.nextInt();
this.A[a][b] = 1;
this.A[b][a] = 1;
}
System.out.println("图创建成功");
}
// 邻接表创建
void creat3() {
int a, b;
for (int i = 0; i < this.Sidenum; i++) {
a = scanner.nextInt();
b = scanner.nextInt();
Node node = this.nodes[a];
// 防止把同一条边加入多次
while (node.next != null && node.next.name != b) {
node = node.next;
}
if (node.next == null) {
Node n = new Node(b);
n.next = nodes[a].next;
nodes[a].next = n;
}
}
System.out.println("图创建成功");
}
// 遍历输出邻接矩阵
void traver1() {
for (int i = 0; i < nodes.length; i++) {
for (int j = 0; j < nodes.length; j++) {
System.out.print(this.A[i][j] + " ");
}
System.out.println("");
}
}
// 遍历输出邻接表
void traver2() {
Node node;
for (int i = 0; i < nodes.length; i++) {
node = nodes[i];
System.out.print(node.name + ":");
while (node.next != null) {
System.out.print(node.next.name + " ");
node = node.next;
}
System.out.println("");
}
}
//邻接表的两种遍历(递归和非递归)
// 初始化访问标记
void initFlag() {
// 初始化
for (int i = 0; i < this.nodes.length; i++) {
this.nodes[i].flag = false;
}
}
// 深度优先遍历(从head结点开始) 递归算法 邻接表
void DFS1(Node head) {
Node pNode;
if (!this.nodes[head.name].flag) {
System.out.print(head.name + " ");
this.nodes[head.name].flag = true;
}
pNode = this.nodes[head.name].next;
while (pNode != null) {
if (!this.nodes[pNode.name].flag) {
DFS1(pNode);
} else {
pNode = pNode.next;
}
}
}
// 深度优先遍历(从head结点开始) 非递归算法 邻接表
void DFS2(Node head) {
// 初始化访问标记
initFlag();
// 初始化栈
this.stack.InitStack(20);
Node pNode, wNode;
this.stack.push(head);
System.out.print(head.name + " ");
this.nodes[head.name].flag = true;
while (!this.stack.IsEmpty()) {
pNode = this.stack.pop();
wNode = pNode.next;
while (wNode != null) {
if (!this.nodes[wNode.name].flag) {
this.stack.push(wNode);
this.nodes[wNode.name].flag = true;
System.out.print(wNode.name + " ");
wNode = this.nodes[wNode.name].next;
} else {
wNode = wNode.next;
}
}
}
}
// 广度优先遍历(从head结点开始)(非递归) 邻接表
// 因为广度优先遍历需要用到队列,所以不能递归,递归只能是用到栈时才能
void BFS1(Node head) {
// 初始化访问标记
initFlag();
// 初始化队列
this.queue.initQueue(20);
Node pNode;
this.queue.enterQueue(head);
this.nodes[head.name].flag = true;
while (!this.queue.isEmpty()) {
pNode = this.queue.deleteQueue();
pNode = this.nodes[pNode.name];
System.out.print(pNode.name + " ");
while (pNode != null) {
pNode = pNode.next;
if (pNode != null && !this.nodes[pNode.name].flag) {
this.queue.enterQueue(pNode);
this.nodes[pNode.name].flag = true;
}
}
}
}
//邻接矩阵的两种遍历(递归和非递归)邻接矩阵
// 深度优先遍历(从0号结点开始) 递归算法 邻接矩阵
void DFSM(int i) {
int j = 0;
System.out.print(this.nodes[i].name + " ");
this.nodes[i].flag = true;
for (j = 0; j < this.Sidenum; j++) {
if (this.A[i][j] == 1 && !this.nodes[j].flag) {
DFSM(j);
}
}
}
void DFS3() {
for (int i = 0; i < this.Sidenum; i++) {
if (!this.nodes[i].flag) {
DFSM(i);
}
}
}
// 深度优先遍历(从0号结点开始) 非递归算法 邻接矩阵
void DFS4(Node head) {
// 初始化访问标记
initFlag();
int i = 0;
// 初始化栈
this.stack.InitStack(20);
Node pNode, wNode = null;
this.stack.push(head);
System.out.print(head.name + " ");
this.nodes[head.name].flag = true;
while (!this.stack.IsEmpty()) {
pNode = this.stack.getTop();
for (i = 0; i < this.Sidenum; i++) {
if (this.A[pNode.name][i] == 1 && !this.nodes[i].flag) {
System.out.print(this.nodes[i].name + " ");
this.nodes[i].flag = true;
this.stack.push(this.nodes[i]);
break;
}
}
if (i == this.Sidenum) {
this.stack.pop();
}
}
}
// 广度优先遍历(从0号结点开始) 非递归算法 邻接矩阵
void BFS2(int k) {
// 初始化被访问标记
initFlag();
// 初始化队列
this.queue.initQueue(20);
Node node;
System.out.print(this.nodes[k].name + " ");
this.nodes[k].flag = true;
this.queue.enterQueue(this.nodes[k]);
while (!this.queue.isEmpty()) {
node = this.queue.deleteQueue();
for (int i = 0; i < this.Sidenum; i++) {
if (this.A[node.name][i] == 1 && !this.nodes[i].flag) {
System.out.print(this.nodes[i].name + " ");
this.nodes[i].flag = true;
this.queue.enterQueue(this.nodes[i]);
}
}
}
}
}
\5. //class Client 测试类(里面有邻接表和邻接矩阵 的全部操作测试,需要那个,把剩余的注释就行)
package com.company.project.graph;
import java.util.Scanner;
public class Client {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
System.out.println("输入顶点数:");
int Nodenum = scanner.nextInt();
System.out.println("输入边数:");
int Sidenum = scanner.nextInt();
Graph graph = new Graph(Nodenum, Sidenum);
// 邻接矩阵创建
// 邻接矩阵创建
System.out.println("输入边的两个顶点:");
graph.creat1();
graph.traver1();
// 邻接表创建
// 邻接表创建
System.out.println("输入边的两个顶点:");
graph.creat3();
System.out.println("邻接表:");
graph.traver2();
//邻接表的搜索
// 深度优先搜索
System.out.println("深度优先搜索(递归)");
graph.initFlag();
graph.DFS1(graph.nodes[0]);
System.out.println("");
// 深度优先搜索
System.out.println("深度优先搜索(非递归)");
graph.DFS2(graph.nodes[0]);
System.out.println("");
// 广度优先遍历
System.out.println("广度优先搜索(非递归)");
graph.BFS1(graph.nodes[0]);
//邻接矩阵的搜索
// 深度优先搜索
System.out.println("深度优先搜索(递归)");
graph.initFlag();
graph.DFS3();
System.out.println("");
// 深度优先搜索
System.out.println("深度优先搜索(非递归)");
graph.initFlag();
graph.DFS4(graph.nodes[0]);
System.out.println("");
// 广度优先搜索
System.out.println("广度优先搜索(非递归)");
graph.initFlag();
graph.BFS2(0);
System.out.println("");
}
}
网友评论