忘记题目是啥了。。。。。
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("操作错误,请重新选择");
}
}
}
}