数据结构课程设计实验八

忘记题目是啥了。。。。。
IGraph.java

package CourseDesign.topic8;

public interface IGraph {
    //建图
    void createGraph();
    //获取顶点数
    int getVexNum();
    //获取课程名
    Object getVex(int v)throws Exception;
    //定位结点
    int locateVex(Object vex);
    //返回v的第一个邻接点,若v没有邻接点,则返回-1
    int firstAdjVex(int v)throws Exception;
    //返回v相对于w的下一个邻接点,若w是v的最后一个邻接点,则返回-1
    int nextAdjVex(int v,int w)throws Exception;
}

VNode.java
package CourseDesign.topic8;


public class VNode {
    public Object data;//顶点信息
    public ArcNode firstArc;//指向第一条依附于该顶点的弧
    public VNode(Object data){
        this(data,null);
    }
    public VNode(Object data, ArcNode firstArc){
        this.data=data;
        this.firstArc=firstArc;
    }

    public Object getData() {
        return data;
    }

    public void setData(Object data) {
        this.data = data;
    }

    public ArcNode getFirstArc() {
        return firstArc;
    }

    public void setFirstArc(ArcNode firstArc) {
        this.firstArc = firstArc;
    }
}

ArcNode.java
package CourseDesign.topic8;

public class ArcNode {
    public int adjVex;//该弧所指向的顶点的位置
    public int value;//边的权值
    public ArcNode nextArc;//指向的下一条弧;
    public ArcNode() {
        this(-1,0,null);
    }
    public ArcNode(int adjVex){

        this(adjVex,0,null);
    }
    public ArcNode(int adjVex,int value){
        this(adjVex,value,null);
    }
    public ArcNode(int adjVex, int value, ArcNode nextArc){
        this.adjVex=adjVex;
        this.value=value;
        this.nextArc=nextArc;
    }
}

ALGraph.java

package CourseDesign.topic8;


import java.util.ArrayList;
import java.util.Scanner;
import java.util.Stack;

public class ALGraph implements IGraph {
    private int vexNum,arcNum;          //图的当前顶点数和边数
    private VNode[]vexs;         //顶点
    private static boolean[]visited;
    private Stack S=new Stack();       //栈
    private ArrayList list=new ArrayList();    //动态数组
    public ALGraph(){

        this(0,0,null);
    }
    public ALGraph( int vexNum, int arcNum, VNode[]vexs){
        this.vexNum=vexNum;
        this.arcNum=arcNum;
        this.vexs=vexs;
    }
    public void createGraph(){
        createDG();    //有向图
    }
    private void createDG(){     //构造有向图
        Scanner scanner=new Scanner(System.in);
        System.out.println("请分别输入课程数和课程间的相互关系数:"); //课程名称相当于结点,相互关系相当于边
        vexNum=scanner.nextInt();   //结点数量
        arcNum=scanner.nextInt();   //边的数量
        vexs=new VNode[vexNum];     //结点集合
        System.out.println("请分别输入每个课程:");
        for (int v=0;v<vexNum;v++)
            vexs[v]=new VNode(scanner.next());    //将所有课程名放到一个数组里
        System.out.println("请输入课程间两两间的先后关系:");
        for (int k=0;k<arcNum;k++){
            int v=locateVex(scanner.next());    //弧尾
            int u=locateVex(scanner.next());    //弧头
            addArc(v,u,1);
        }
    }

    //在位置为v,u的顶点之间,添加一条弧,其权值为value
    public void addArc(int v,int u,int value){
        ArcNode arc=new ArcNode(u,value);
        arc.nextArc=vexs[v].firstArc;
        vexs[v].firstArc=arc;
    }

    //获取结点数
    @Override
    public int getVexNum() {
        return vexNum;
    }

    //给定顶点的值vex,返回其在图中的位置,若图中不包含此顶点,则返回-1
    public int locateVex(Object vex) {
        for (int v=0;v<vexNum;v++) {
            if (vexs[v].data.equals(vex))
                return v;
        }
        return -1;
    }
    //获取顶点数组
    public VNode[] getVexs() {
        return vexs;
    }

    //返回v表示结点的值
    @Override
    public Object getVex(int v) throws Exception {
        if (v<0||v>=vexNum)
            throw new Exception("第"+v+"个课程不存在");
        return vexs[v].getData();
    }

    //返回v的第一个邻接点,若v没有邻接点,则返回-1
    @Override
    public int firstAdjVex(int v) throws Exception {
        if (v<0||v>=vexNum)
            throw new Exception("第"+v+"个课程不存在");
        VNode vex=vexs[v];
        if(vex.firstArc!=null)
            return vex.firstArc.adjVex;
        else
            return -1;
    }

    //返回v相对于w的下一个邻接点,若w是v的最后一个邻接点,则返回-1
    @Override
    public int nextAdjVex(int v, int w) throws Exception {
        if (v<0||v>=vexNum)
            throw new Exception("第"+v+"个课程不存在");
        VNode vex = vexs[v];

        ArcNode arcNode=null;
        for (ArcNode arcNode1=vex.firstArc;arcNode1!=null;arcNode1=arcNode1.nextArc)
            if (arcNode1.adjVex ==w){
                arcNode=arcNode1;
                break;
            }
        if (arcNode!=null&&arcNode.nextArc!=null)
            return arcNode.nextArc.adjVex;
        else
            return -1;
    }

    //求各顶点入度
    public  int[]findInDegree(ALGraph G){
        int[]indegree=new int[G.getVexNum()];
        for (int i=0;i<G.getVexNum();i++)
            for (ArcNode arcNode=G.getVexs()[i].firstArc;arcNode!=null;arcNode=arcNode.nextArc)
                ++indegree[arcNode.adjVex];        //入度增1
        return indegree;
    }

    //综合
    public void synthesis(ALGraph G)throws Exception{
        Scanner scanner=new Scanner(System.in);
        boolean flag=Cycle(G);  //判断是否有环
        if (flag){
            System.out.println("请输入学期数:");
            float m=scanner.nextFloat();     //学期数
            System.out.println("[非递归的拓扑排序]");
            topologicalSort1(G);  //非递归拓扑排序
            ClassScheduling(G,m, list);  //排课方法
            System.out.println();
            list.clear();  //清空动态数组里非递归的内容
            System.out.println("[递归的拓扑排序]");
            topologicalSort2(G);  //递归拓扑排序
            ClassScheduling(G,m, list);  //排课方法
        }else {
            System.out.println("该图有环,不能运行拓扑排序!");
        }
        list.clear();         //及时清空动态数组
    }


    //结合实际,对于比如像八门课程分三学期学,本着课程能早学就早学的原则,后面留出多的时间让学生实习
    // 对于动态数组采用上取整的方法,八门课程分三学期学,分成3,3,2
    //排课
    private void ClassScheduling(ALGraph G, float term, ArrayList list){
        int a=0,count1=0,count2=0,count3=0;    //a为第几学期, count1:第几学期的课程下标,
                                                // count2:读取动态数组中元素时所用的下标,
                                                // count3:计最后一学期的课程需要的课程数,方便读出
        boolean flag=false;                     //判断是否为最后一学期(只是不能完全均衡分配的时候,例如3,3,2)
        //terms二维数组[学期][该学期的课程数](不能完全均衡分配的最后一学期的课程数不能被占满)
        Object terms[][]=new Object[(int) term][(int)Math.ceil(list.size()/term)];
        for (int i=0;i<(int)term;i++) {
            int n=list.size() - count2;           //可供分配的课程数
            for (int j = 0; j< (int) Math.ceil(list.size() / term); j++) {
                if (n>0) {
                    if ( n< (int) Math.ceil(list.size() / term)) {      //不能完全均衡分配的最后一学期,需要单独处理
                        for (int m = 0; m < n; m++) {
                            terms[a][m] = list.get(count2++);
                            count3++;
                        }
                        flag=true;
                        break;
                    }else
                        terms[a][count1++] = list.get(count2++);
                }
            }
            a++;
            if (n == 0) {                  //对于比如像四门课程分成三学期来学,采用上取整方法,第三学期将会没有课程
                                            // 在实际,四门课程分成三学期来学这样的做法,极其罕见
                                             //这里只是应对这样的个例,还是本着能早学就早学的原则
                System.out.println("第"+a+"学期没有课程!");
            }else {
                System.out.println("第" + a + "学期");
                //不能完全均衡分配的,这种的最后一学期的输出格式与可以均衡分配的不一样(只是最后一学期不一样)
                //需要分开处理
                if (flag) {
                    for (int j = 0; j < count3; j++)
                        System.out.print(terms[a - 1][j].toString() + " ");
                } else {
                    for (int j = 0; j < (int) Math.ceil(G.getVexNum() / term); j++)
                        System.out.print(terms[a - 1][j].toString() + " ");
                }
                System.out.println();
                count1 = 0;
            }
        }
    }

    //判断是否有环(有环返回false,无环返回true)
    public boolean Cycle(ALGraph G)throws Exception{
        int count=0;
        for (int i=0;i<G.getVexNum();i++){
            for (int v=G.firstAdjVex(i);v>=0;v=G.nextAdjVex(i,v)) {     //对于该顶点的每一条边都看是否有环
                for (int w = G.firstAdjVex(v); w >= 0; w = G.firstAdjVex(w)) {
                    count++;
                                                        //如果有环,count将无限增加,
                                                        // 把count限定在一个最大数,就能防止count无限增大
                    if (count > (G.getVexNum() * G.getVexNum() - 1)) {
                        return false;
                    }
                }
                count = 0;
            }
        }
        return true;
    }

    //非递归的拓扑排序
    private void topologicalSort1(ALGraph G)throws Exception{
        int []indegree=G.findInDegree(G);          //求各顶点入度
        for (int i=0;i<G.getVexNum();i++)
            if (indegree[i]==0)                    //入度为0者进栈
                S.push(i);
            while (!S.isEmpty()){
                int i=(Integer)S.pop();
                list.add(getVex(i));               //把下标所对应的顶点添加到动态数组里
                for (ArcNode arcNode=G.getVexs()[i].firstArc;arcNode!=null;arcNode=arcNode.nextArc){
                    int k=arcNode.adjVex;        //对i号顶点的每个邻接点的入度减1
                    if (--indegree[k]==0)        //若入度减为0,则入栈
                        S.push(k);
                }
            }
    }

    //递归的拓扑排序
    private void topologicalSort2(ALGraph G)throws Exception{
        visited=new boolean[G.getVexNum()];
        for (int i=0;i<visited.length;i++)
            visited[i]=false;
        for (int i=0;i<G.getVexNum();i++)
            if (!visited[i])
                dfs(G,i);
            while (!S.isEmpty()) {
                list.add(S.pop());    //当栈不为空,栈顶元素出栈,并添加到动态数组里
            }
    }
    private void dfs(ALGraph G,int v)throws Exception{
        visited[v]=true;
        for (int w = G.firstAdjVex(v); w >= 0; w =G.nextAdjVex(v, w)){
            if (!visited[w])   //对v的尚未访问的邻接顶点w递归调用dfs
                dfs(G,w);
        }
        S.push(getVex(v));     //下标所对应的顶点入栈
    }
}
 

TestALGraph.java

package CourseDesign.topic8;


import java.util.Scanner;

public class TestALGraph {
    public static void main(String[] args) throws Exception{
        Scanner scanner=new Scanner(System.in);
        ALGraph alGraph = new ALGraph();
        boolean flag=true;
        System.out.println("1、执行程序");
        System.out.println("2、退出程序");
        while (flag) {
            System.out.println("请输入您的选择:");
            switch (scanner.next()) {
                case "1":
                    alGraph.createGraph();
                    alGraph.synthesis(alGraph);
                    break;
                case "2":
                    System.out.println("已退出");
                    flag = false;
                    break;
                default:
                    System.out.println("操作错误,请重新选择");
            }
        }

    }
}
 

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

@8055@

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值