算法与数据结构实战实验——图型数据结构及其应用(使用java)

实验目的——通过实验达到:
⑴ 理解和掌握图的基本概念、基本逻辑结构;
⑵ 理解和掌握图的邻接矩阵存储结构、邻接链表存储结构;
⑶ 理解和掌握图的DFS、BFS遍历操作的思想及其实现;
⑷ 加深对堆栈、队列的概念及其典型操作思想的理解;
⑸ 掌握典型图操作算法的算法分析。

题目:图的建立、遍历及其应用

设图结点的元素类型为char,建立一个不少于8个顶点的带权无向图G,实现以下图的各种基本操作的程序:
① 用邻接矩阵作为储结构存储图G并输出该邻接矩阵;
② 用邻接链表作为储结构存储图G并输出该邻接链表;
③ 按DFS算法输出图G中顶点的遍历序列;
④ 按BFS算法输出图G中顶点的遍历序列;
⑤ 按Prime算法从某个指定的顶点出发输出图G的最小生成树;
⑥ 主函数通过函数调用实现以上各项操作。

⑴ 所定义的数据结构:

邻接矩阵:

	/*
	邻接矩阵:
	*/
	static final int MAXV=100;//最大顶点数
	int[][] edges = new int[MGraph.MAXV][MGraph.MAXV];//邻接矩阵
	int vNum=0;//顶点数
	int eNum=0;//边数
	char[] vexs=new char[MAXV];//顶点数组
	
	boolean visited[]=new boolean[MAXV];//记录是否被访问过
	Queue<Integer> q=new LinkedList<Integer>();//队列,辅助搜索

邻接表:

/*
邻接表:
*/
//图的顶点类型
class Vex {
	char value; //顶点值
	Node next=null;//链域
	Vex(char v) {
		value=v;
	}
	Vex(char v,Node n){
		this.value=v;
		this.next=n;
	}
}

//作为某个点的邻接点的顶点信息
class Node{
	int i;  //顶点序号
	int w;  //权值
	Node next=null; //指向下一个顶点
	Node(int i,int w){
		this.i=i;
		this.w=w;
	}
}

//存储边的两个顶点及边的权值
class Edge{
	char u;  //起始顶点
	char v;  //终点顶点
	int w;  //权值
	Edge(char u,char v,int w) {
		this.u=u;
		this.v=v;
		this.w=w;
	}
}

⑵ 主要操作算法思想或算法步骤:

邻接矩阵:

package edu.dgut.experiment.three;

import java.util.LinkedList;
import java.util.Queue;

/**
 * 设图结点的元素类型为char,建立一个不少于8个顶点的带权无向图G,实现以下图的各种基本操作的程序:
① 用邻接矩阵作为储结构存储图G并输出该邻接矩阵;
③ 按DFS算法输出图G中顶点的遍历序列;
④ 按BFS算法输出图G中顶点的遍历序列;
⑤ 按Prime算法从某个指定的顶点出发输出图G的最小生成树;
⑥ 主函数通过函数调用实现以上各项操作。

 * @author 未花时采
 *
 */
public class MGraph {
	static final int MAXV=100;//最大顶点数
	int[][] edges = new int[MGraph.MAXV][MGraph.MAXV];//邻接矩阵
	int vNum=0;//顶点数
	int eNum=0;//边数
	char[] vexs=new char[MAXV];//顶点数组
	
	boolean visited[]=new boolean[MAXV];//记录是否被访问过
	Queue<Integer> q=new LinkedList<Integer>();//队列,辅助搜索
	
	
	/**
	 * 
	 * @param vexs 顶点数组
	 * @param edge 边
	 * @param n	边二维数组中的一维长度
	 */
	MGraph(char vexs[],int edge[][],int n) {
		//初始化顶点
		this.vNum=vexs.length;
		for(int i=0;i<vexs.length;i++) {
			this.vexs[i]=vexs[i];
		}
		//初始化边
		for(int i = 0; i < n; i++) {
			for(int j = 0; j < n; j++){
				edges[i][j] = edge[i][j];
				if(edges[i][j] != 0)//权值不为0,代表边存在
					eNum++;
			}
		}
		eNum/=2;//无向图
	}
	
	
	/**
	 * 输出邻接矩阵
	 * @param g
	 */
	public void display() {
		System.out.println("邻接矩阵:");
		for(int i = 0; i < this.vNum; i++)
		{
			for(int j = 0; j < this.vNum; j++)
				System.out.print(this.edges[i][j] + " ");
			System.out.println();
		}
	}
	
	
	/**
	 * 广度优先搜索
	 */
	public void bfs(){
		System.out.println("广度优先搜索:");
		for(int i=0;i<vNum;i++){
			visited[i]=false;
		}
		q.clear();
		for(int i=0;i<vNum;i++){
			if(!visited[i])
				bfs(i);
		}
	}
	private void bfs(int vn){
		q.add(vn);
		while(!q.isEmpty()){
			for(int i=0;i<vNum;i++){
				if(visited[i]||edges[q.peek()][i]==0)
					continue;
				q.add(i);
				System.out.print(vexs[i]+"  ");
				visited[i]=true;
			}
			q.remove();
		}
		System.out.println();
	}

	
	/**
	 * 深度优先搜索
	 */
	public void dfs(){
		System.out.println("深度优先搜索:");
		for(int i=0;i<vNum;i++){
			visited[i]=false;
		}
		for(int i=0;i<vNum;i++){
			if(!visited[i])
				dfs(i);
		}
	}
	private void dfs(int vn){
		if(!visited[vn]) {
			System.out.print(vexs[vn]+"  ");
			visited[vn]=true;
		}
		for(int i=0;i<vNum;i++){
			if(visited[i]||edges[vn][i]==0)
				continue;
			dfs(i);
		}
	}

	
	/**
	 * 最小生成树
	 */
	public void prime() {
		System.out.println("\n最小生成树:");
		int f[]=new int[MAXV];//父节点下标集合
		prime(f,edges,vNum,vexs);
	}
	
	private void prime(int f[],int e[][], int n,char vexs[]) {
        int INF=100000;//最大值
        int w[] = new int[n];//存放当前遍历过的结点的权值集合
        int k = 0;
        int m;//当前最小权值
        //初始化:第一个结点与其它结点的边的权值放入集合
        for(int j = 0; j < n; j++) {
        	w[j] = (e[0][j] == 0 ? INF : e[0][j]);
            //第一个结点没有父结点,初始化为0
            f[j] = 0;
        }
        
        System.out.println("父节点--权值--孩子");
        
        //从第二个结点开始遍历
        for(int i = 0; i < n; i++) {
        	//遍历与当前结点相连接的各个结点的权值并找出具有最小权值的结点
            m = INF;
            for(int j = 0; j < n; j++) {
                if(w[j] <= m && w[j] != 0&&w[j] != INF) {
                    m = w[j];
                    k = j;
                }   
            }
            
            //输出过程
            if(k!=0) {//第一个为根节点
            	//System.out.println("父节点--权值--孩子");
            	System.out.println(vexs[f[k]]+"--"+w[k]+"--"+vexs[k]);
            }
            
            //已输出的置为0
            w[k] = 0;
            
            //更新父结点及权值集合,将k结点与其它结点连接的最小权值放进d[j]中
            for(int j = 0; j < n; j++) {
                if(w[j] > e[k][j]&&w[j] != 0&&e[k][j]!=0) {
                    w[j] = e[k][j];
                    f[j] = k;
                }
            }
        }
    }

	
	/**
	 * 测试主函数
	 * @param args
	 */
	public static void main(String[] args) {
		//10个顶点
		int n=10;  //A B C D E F G H I J
		int[][] e ={{0,3,1,4,0,6,0,0,0,0},//A
					{3,0,0,0,0,0,0,0,0,4},//B
					{1,0,0,5,0,0,0,0,0,0},//C
					{4,0,5,0,3,0,0,0,0,0},//D
					{0,0,0,3,0,0,0,7,4,0},//E
					{6,0,0,0,0,0,5,2,0,0},//F
					{0,0,0,0,0,5,0,0,0,0},//G
					{0,0,0,0,7,2,0,0,0,0},//H
					{0,0,0,0,4,0,0,0,0,0},//I
					{0,4,0,0,0,0,0,0,0,0}};//J
		char[] v= {'A','B','C','D','E','F','G','H','I','J'};//顶点
		
		//创建图
		MGraph g = new MGraph(v, e, n);
		//输出邻接矩阵
		g.display();
		//广度优先搜索
		g.bfs();
		//深度优先搜索
		g.dfs();
		//最小生成树
		g.prime();
	}
}

邻接表:

package edu.dgut.experiment.three;

import java.util.LinkedList;
import java.util.Queue;

/**
 * 设图结点的元素类型为char,建立一个不少于8个顶点的带权无向图G,实现以下图的各种基本操作的程序:
② 用邻接链表作为储结构存储图G并输出该邻接链表;
③ 按DFS算法输出图G中顶点的遍历序列;
④ 按BFS算法输出图G中顶点的遍历序列;
⑤ 按Prime算法从某个指定的顶点出发输出图G的最小生成树;
⑥ 主函数通过函数调用实现以上各项操作。

 * @author 未花时采
 *
 */

//图的顶点类型
class Vex {
	char value; //顶点值
	Node next=null;//链域
	Vex(char v) {
		value=v;
	}
	Vex(char v,Node n){
		this.value=v;
		this.next=n;
	}
}

//作为某个点的邻接点的顶点信息
class Node{
	int i;  //顶点序号
	int w;  //权值
	Node next=null; //指向下一个顶点
	Node(int i,int w){
		this.i=i;
		this.w=w;
	}
}

//存储边的两个顶点及边的权值
class Edge{
	char u;  //起始顶点
	char v;  //终点顶点
	int w;  //权值
	Edge(char u,char v,int w) {
		this.u=u;
		this.v=v;
		this.w=w;
	}
}

public class ALGraph {
	Vex vexs[];
	int vNum;//顶点数
	int eNum;//边数
	
	/**
	 * 
	 * @param v
	 * @param e
	 */
	ALGraph(Vex[] v,Edge[] e){
		vexs=v;
		vNum=vexs.length;
		eNum=e.length;
		for(int i=0;i<e.length;i++) {
			for(int j=0;j<vexs.length;j++) {
				if(vexs[j].value==e[i].u) {
					Node node = new Node(search(e[i].v),e[i].w);
					addNode(j, node);
				}
				if(vexs[j].value==e[i].v) {
					Node node = new Node(search(e[i].u),e[i].w);
					addNode(j, node);
				}
			}
		}
	}
	
	
	/**
	 * 从vexs中搜索字符,返回下标
	 * @param c  待搜索的字符
	 * @return
	 */
	public int search(char c) {
		for (int i=0; i<vexs.length;i++) {
			if(vexs[i].value==c) 
				return i;
		}
		return -1;
	}
	
	/**
	 * 插入边
	 * @param i vexs下标
	 * @param node 待插入节点
	 */
	public void addNode(int i,Node node) {
		if(vexs[i].next==null)
			vexs[i].next=node;
		else{
			Node p=vexs[i].next;
			while(p.next!=null) {
				p=p.next;
			}
			p.next=node;
		}
	}
	
	/**
	 * 输出邻接表
	 */
	public void display() {
		System.out.println("邻接表:");
		int count=0;//下标
		for (Vex vex : vexs) {
			System.out.print(count+" "+vex.value+":");
			count++;
			
			Node p=vex.next;
			while(p!=null) {
				System.out.print("---"+p.w+"---"+vexs[p.i].value+"  ");
				p=p.next;
			}
			System.out.println();
		}
	}
	

	/**
	 * 广度优先搜索
	 */
	private void bfs(){
		Queue q = new LinkedList<Integer>();//队列
		boolean visited[]=new boolean[vNum];//默认未被访问
		System.out.println("广度优先搜索:");
		//首顶点入队
		q.add(0);
		Node p=vexs[0].next;
		
		while(!q.isEmpty()) {
			while(p!=null) {
				if(visited[p.i]) {
					p=p.next;
					continue;
				}
				q.add(p.i);
				System.out.print(vexs[p.i].value+"  ");
				visited[p.i]=true;
				p=p.next;
			}
			p=vexs[(int) q.poll()].next;
		}
		System.out.println();//换行
	}
	
	/**
	 * 深度优先搜索
	 */
	public void dfs() {
		boolean visited[]=new boolean[vNum];//默认未被访问
		System.out.println("深度优先搜索:");
		dfs(visited,0);
	}
	private void dfs(boolean visited[],int vn) {
		//访问当前
		visited[vn]=true;
		System.out.print(vexs[vn].value+"  ");
		//继续深入访问
		if(vexs[vn].next!=null) {
			Node p=vexs[vn].next;
			while (p!=null) {
				if(!visited[p.i]) {
					dfs(visited,p.i);//递归调用
				}
				p=p.next;
			}
		}		
	}
	
	
	/**
	 * 最小生成树
	 * @param c 从c开始搜索
	 */
	public void prime(char c) {
		Queue q = new LinkedList<Integer>();//队列
		boolean visited[]=new boolean[vNum];//默认未被访问(该点的广度搜索一层)
		int w[]=new int[vNum];//当前可到达的各边的最小权值集合
		//辅助
		Node p;
		int k = 0;
        int m;//当前最小权值
        
        //初始化
    	for(int i=0;i<vNum;i++) {
        	w[i]=-1;
    	}

        System.out.println("\n最小生成树:(--边的权值--连着的顶点)");
        System.out.print("出发顶点"+c+":");
        //遍历
        q.add(search(c));
        while(!q.isEmpty()) {
        	int tmp=(int)q.poll();
        	p=vexs[tmp].next;
        	
			while(p!=null) {
				if(visited[p.i]) {
					p=p.next;
					continue;
				}
				if(!q.contains(p.i)) {
					q.add(p.i);
				}
	            //更新父结点及权值集合,将k结点与其它结点连接的最小权值放进d[j]中
                if((w[p.i] >= p.w&&w[p.i] != 0)||w[p.i]==-1) {
                    w[p.i] = p.w;
                    //System.out.print("#"+vexs[p.i].value+"#");
                }
                p=p.next;
			}
			visited[tmp]=true;
			//查找当前最小权值边
			m=Integer.MAX_VALUE;
			for(int i=0;i<vNum;i++) {
				if(w[i]<m&&w[i]!=0&&w[i]!=-1) {
					m=w[i];
					k=i;
				}
			}
			if(w[k]!=0) {//是否被输出过
				System.out.print("--"+w[k]+"--"+vexs[k].value+"   ");
			}
            w[k] = 0;//已输出的置为0
		}  
	}


	public static void main(String[] args) {
		//准备数据
		Vex vexs[]={new Vex('A'),new Vex('B'),
					new Vex('C'),new Vex('D'),
					new Vex('E'),new Vex('F'),
					new Vex('G'),new Vex('H'),
					new Vex('I'),new Vex('J')};
		Edge edges[]= {	new Edge('A', 'B', 3),new Edge('A', 'C', 1),
						new Edge('A', 'D', 4),new Edge('A', 'F', 6),
						new Edge('C', 'D', 5),new Edge('B', 'J', 4),
						new Edge('D', 'E', 3),new Edge('E', 'I', 4),
						new Edge('E', 'H', 7),new Edge('F', 'H', 2),new Edge('F', 'G', 5),};
		//创建邻接链表
		ALGraph g = new ALGraph(vexs, edges);
		//输出邻接表
		g.display();
		//广度优先搜索
		g.bfs();
		//深度优先搜索
		g.dfs();
		//prime,从B出发
		g.prime('B');
	}
}
  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值