代码如下:
DuLinkList类:
import java.util.Scanner;
public class DuLinkList
{
public DuLNode head; //头结点
public DuLinkList()
{
//初始化:1)头结点,2)前驱,3)后继;
head=new DuLNode();
head.prior=head;
head.next=head;
}
//逆向创建循环链表,n为节点个数
public DuLinkList(int n) throws Exception
{
this();
Scanner sc = new Scanner(System.in);
for(int j=0;j<n;j++)
{
insert(0,sc.next()); //生成新节点插入到表头
}
}
//获取长度
public int length()
{
DuLNode p = head.next;
int length = 0;
while(!p.equals(head))
{
p = p.next;
++length;
}
return length;
}
//头插法创建链表P46算法2.9
public void creatList(int n) throws Exception
{
Scanner sc=new Scanner(System.in);
for(int j=0;j<n;j++)
{
insert(0, sc.next());
}
}
//获取数据元素与P41算法2.4相同,只不过在双向列表中从首节点向后查找是直到p与head相等(即回到了原先的结点)是就认为到达了尾结点
public Object get(int i)throws Exception
{
DuLNode p=head.next;
int j=0;
while (!p.equals(head)&&j<i)
{
p=p.next;
++j;
}
if(j>i)
{
throw new Exception("第"+i+"个元素不存在!");
}
return p.data;
}
//插入数据元素P54
public void insert(int i, Object x)throws Exception
{
DuLNode p=head.next;
int j=0;
while (!p.equals(head)&&j<i)
{
p=p.next;
++j;
}
if(i>=j+1)
throw new Exception("插入位置不合法!");
DuLNode s=new DuLNode(x);
p.prior.next=s;
s.prior=p.prior;
s.next=p;
p.prior=s;
System.out.println("插入成功!");
}
//删除数据元素
public void remove(int i)throws Exception
{
DuLNode p=head.next;
int j = 0;
//指针没走完双向链表的前提下,从第0个元素开始寻找删除的位
while (!p.equals(head)&&j<i)
{
p=p.next;
++j;
}
if(j!=i)
{
throw new Exception("删除节点不合法");
}
//断开两条链,建立两条新的链
p.prior.next=p.next; //p结点的上一个结点的后继next指向下一个结点的前驱prior
p.next.prior=p.prior; //p结点的下一个结点的前驱prior指向上一个结点的后继next
System.out.println("删除成功!");
}
//获得元素下标
public int indexOf(Object x) {
DuLNode p = head.next;
int j = 0;
//双向链表不为空并且数据元素与所输入的元素比较以后不相等
while (!p.equals(head) && !p.data.equals(x))
{
p = p.next; //指针后移
++j; //计数器加1
}
//在双向链表没有走完一次的情况下,就找到了位置j,走完了就说明,没有找到返回-1
if (!p.data.equals(x))
{
return -1;
}
else
{
return j;
}
}
//输出双向列表数据
public void display()
{
DuLNode node=head.next;
while(!node.equals(head))
{
System.out.print(node.data + " ");
node = node.next;
}
System.out.println();
}
//就地逆置
public void exList()
{
DuLNode p=head.next;
DuLNode q=p.next;
int n=length();
for(int i=0;i<=n;i++)
{
q = p.next; //交换p的前驱、后继中的地址信息
p.next = p.prior;
p.prior = q;
p=q; //p后移
}
display();
}
}
DuLNode类:
public class DuLNode
{
public Object data;
public DuLNode prior;
public DuLNode next;
public DuLNode()
{
this(null);
}
public DuLNode(Object data)
{
this.data=data;
this.prior=null;
this.next=null;
}
}
Test类:
import java.util.Scanner;
public class Test
{
public static void main(String[] args)throws Exception
{
Scanner sc=new Scanner(System.in);
DuLinkList list = new DuLinkList();
System.out.println("新建空链表成功");
for(int i=0;;i++)
{
System.out.println("1:插入结点及其信息\t2:删除结点\t3:查找数据元素\t4查找元素下标\t5:链表长度\t6:链表所有结点\t7:就地逆置\t8:初始化链表\t9:退出程序");
System.out.println("请输入要执行的操作编号!");
int choose=sc.nextInt();
switch(choose)
{
case 1:
System.out.println("请输入所插入的位置及节点信息:");
list.insert(sc.nextInt(), sc.next());
break;
case 2:
System.out.println("请输入所删除的结点的位置:");
list.remove(sc.nextInt());
break;
case 3:
System.out.println("请输入所查找的结点的位置:");
System.out.println("所查找的数据元素为:"+list.get(sc.nextInt()));
break;
case 4:
System.out.println("请输入所查找的数据元素:");
System.out.println("您所查找的元素第一次出现的位置为: "+list.indexOf(sc.next()));
break;
case 5:
System.out.println("该链表的长度为"+list.length());
break;
case 6:
System.out.println("链表的所有数据元素为:");
list.display();
break;
case 7:
System.out.println("链表的逆置结果为:");
list.exList();
break;
case 8:
System.out.println("请输入要创建链表的的结点个数:");
int n=sc.nextInt ();
System.out.println("请逆序输入链表的数据元素:");
list.creatList(n);
break;
case 9:
System.out.println("程序已终止");
System.exit(9);
break;
default :
System.out.println("输入有误");
break;
}
}
}
}
二、题目6:树的孩子兄弟表示法及相关操作:
使用孩子-兄弟表示法作为树的存储结构,求树中结点的个数、求树的深度、求结点的孩子个数、实现树的先根、后根和层次遍历。
代码如下:
CSTree类:
import java.util.LinkedList;
import java.util.Queue;
import java.util.Scanner;
public class CSTree
{
public CSTreeNode root;
public CSTree()
{
this.root=null;
}
public CSTree(CSTreeNode root)
{
this.root=root;
}
//由先根遍历序列建立一颗孩子兄弟树
private static int index=0; //记录T的索引值
public CSTree(String T)
{
char c=T.charAt(index++); //取出字符串索引为index的字符,且index加1即index ++;
if(c!='#')
{
//字符#表示无后继结点
root=new CSTreeNode(c); //建立树的根结点
root.firstchild=new CSTree(T).root; //建立树的左子树
root.nextsibling=new CSTree(T).root; //建立树的右子树
}
else
{
root=null;
}
}
private int i=0;
//树中结点个数
public int countNode(CSTreeNode T)
{
int count=0;
if(T!=null)
{
++count;
count+=countNode(T.firstchild); //左孩子的节点数加1
count+=countNode(T.nextsibling);
}
return count;
}
//树的深度
public int getDepth(CSTreeNode T)
{
if(T!=null)
{
int LDepth = getDepth(T.firstchild);
int rDepth = getDepth(T.nextsibling);
return 1+ (LDepth > rDepth ? LDepth : rDepth);
}
else
return 0;
}
//求结点的孩子个数
int a ;
public void countChildNode(String X,CSTreeNode T){
if(T!=null){
if(X.equals(T.data.toString()))
{
if(T.firstchild!=null)
{
T = T.firstchild;
for(a=1;a<countNode(T)&&T.nextsibling!=null;a++)
{
T = T.nextsibling;
}
}
System.out.println("孩子结点为"+a);
}
else
{
countChildNode(X,T.firstchild);
countChildNode(X,T.nextsibling);
}
}
}
//树的先根遍历
public void preRootTraverse(CSTreeNode T)
{
if(T!=null)
{
System.out.println(T.data);
preRootTraverse(T.firstchild);
preRootTraverse(T.nextsibling);
}
}
//树的后根遍历
public void postRootTraverse(CSTreeNode T)
{
if(T!=null)
{
postRootTraverse(T.firstchild);
System.out.println(T.data);
postRootTraverse(T.nextsibling);
}
}
//层次遍历
public void level(CSTreeNode T)
{
Queue L = new LinkedList();
L.offer(T); //入队
while(L.isEmpty()!=true)
{
CSTreeNode s = (CSTreeNode) L.poll();
System.out.println(s.data + " ");
if(s.firstchild!=null)
{
L.offer(s.firstchild);
}
if(s.nextsibling!=null)
{
L.offer(s.nextsibling);
}
}
}
public static void main(String[] args)
{
Scanner sc=new Scanner(System.in);
System.out.println("请输入结点:");
String T1 = sc.next();
// 输入样例:ABC##DE##F###
CSTree T=new CSTree(T1);
System.out.println("输出的节点数为"+T.countNode(T.root));
System.out.println("树的深度为:"+T.getDepth(T.root));
System.out.println("先根遍历结果是:");
T.preRootTraverse(T.root);
System.out.println("后根遍历结果是:");
T.postRootTraverse(T.root);
System.out.println("层次遍历结果是:");
T.level(T.root);
System.out.println("请输入要计算的孩子的结点:");
String t=sc.next();
T.countChildNode(t,T.root);
sc.close();
}
}
CSTreeNode类:
public class CSTreeNode
{
public Object data;
public CSTreeNode firstchild,nextsibling;
public CSTreeNode(){
this(null);
}
public CSTreeNode(Object data){
this(data,null,null);
}
public CSTreeNode(Object data,CSTreeNode firstchild,CSTreeNode nextsibling){
this.data=data;
this.firstchild=firstchild;
this.nextsibling=nextsibling;
}
}
三、题目九、已知港沟卫生职业技术学院校园各楼之间的距离,如何用最小的代价布置网线使各楼互连并通信?要求使用两种算法实现。
代码如下:
arcNode:
public class arcNode
{
int value;//权值
int adjVex;//该弧指向的前一顶点的位置
int nextVex;//该弧指向的后一顶点的位置
arcNode nextArc;//指向下一条弧
public int getValue()
{
return value;
}
public void setValue(int value)
{
this.value = value;
}
public int getAdjVex()
{
return adjVex;
}
public void setAdjVex(int adjVex)
{
this.adjVex = adjVex;
}
public int getNextVex()
{
return nextVex;
}
public void setNextVex(int nextVex)
{
this.nextVex = nextVex;
}
public arcNode()
{
this.adjVex = -1;
this.nextVex = -1;
this.value = -1;
this.nextArc = null;
}
public arcNode(int value)
{
this.adjVex = -1;
this.nextVex = -1;
this.value = value;
this.nextArc = null;
}
public arcNode(int u,int v,int value)
{
this.adjVex = u;
this.nextVex = v;
this.value = value;
this.nextArc = null;
}
}
Graph:
import java.util.Scanner;
public class Graph
{
int arcNum,vexNum; //边的数量、顶点的数量
VNode [] vexs; //顶点数组的定义(存储顶点)
arcNode [] arcs; //边数组的定义(存储边)
public int getArcNum()
{
return arcNum;
}
public int getVexNum()
{
return vexNum;
}
//创建带权值的图,无向图;
Graph()
{
Scanner sc = new Scanner(System.in);
System.out.println("请输入教学楼的数量:");
vexNum = sc.nextInt();
System.out.println("请输入连接各教学楼的道路的数量:");
arcNum = sc.nextInt();
vexs = new VNode[vexNum];//创建有n个值顶点数组
arcs=new arcNode[arcNum*2];//创建有n个值边数组
System.out.println("请输入各教学楼的名称:");
for(int i=0;i<vexNum;i++)
{
vexs[i] = new VNode(sc.next());
}
System.out.println("请输入各条路连接的教学楼名称及每条路的长度:");
//依次给顶点数组赋值(教学楼名称、路的长度)
for(int j=0;j<arcNum;j++)
{
int v=locateVex(sc.next());
int u=locateVex(sc.next());
int value = sc.nextInt();
addArc(u,v,value);
addArc(v,u,value);
arcs[j]=new arcNode(u,v,value);
arcs[j+arcNum]=new arcNode(v,u,value);
}
//对边数组按权值进行排序,由小到大
for(int i=0;i<arcs.length;i++)
{
for(int j=0;j<arcs.length-1;j++)
{
if(arcs[j].value>arcs[j+1].value)
{
arcNode temp=arcs[j];
arcs[j]=arcs[j+1];
arcs[j+1]=temp;
}
}
}
sc.close();
}
Graph(int vex,int arc,VNode[] vexs)
{
this.arcNum=arc;
this.vexNum=vex;
this.vexs=vexs;
}
//添加边结点
void addArc(int v,int u,int value)
{
arcNode arc = new arcNode(value);
arc.adjVex=v;
arc.nextVex=u;
arc.nextArc = vexs[v].firstArc;
vexs[v].firstArc = arc;
}
//根据输入的顶点名称查找顶点在邻接表中的位置,并返回位置号
int locateVex(Object vex)
{
for(int i=0;i<vexNum;i++)
{
if(vexs[i].data.equals(vex))
{
return i;
}
}
return -1;
}
public VNode[] getVex()
{
return vexs;
}
//查找第一个邻接点
int firstAdjVex(int v)
{
if(v<0&&v>=vexNum)
{
System.out.println("第"+v+"个结点不存在!");
}
VNode vex = vexs[v];
if(vex.firstArc!=null)
{
return vex.firstArc.adjVex;
}
else
return -1;
}
//查找下一个邻接点
int nextAdjVex(int v,int w)
{
if(v<0&&v>=vexNum)
{
System.out.println("第"+v+"个结点不存在!");
}
VNode vex = vexs[v];
arcNode arcvw = null;
for(arcNode arc=vex.firstArc;arc!=null;arc=arc.nextArc)
{
if(arc.adjVex==w)
{
arcvw = arc;
break;
}
}
if(arcvw!=null&&arcvw.nextArc!=null)
return arcvw.nextArc.adjVex;
else
return -1;
}
//获取第v个结点
public Object getVex(int v) throws Exception
{
if (v < 0 && v >= vexNum)
throw new Exception("第" + v + "个顶点不存在!");
return vexs[v].data;
}
//克鲁斯卡尔算法求最小生成树
void kruskal()
{
int k=0;
int sn1,sn2;
int[] vset = new int[vexNum];//定义一个辅助数组用来记录两个顶点间是否连通
for(int i=0;i<vexNum;i++)
{
vset[i] = i;
}
k = 1;
int j = 0;
while(k<vexNum)
{
//最小生成树边数为:vexNum-1'边的数减去1
sn1 = vset[arcs[j].adjVex];//用vest数组标记arcNode的前驱节点
sn2 = vset[arcs[j].nextVex];//用vest数组标记arcNode的后继节点
if(sn1!=sn2)
{
//如果sn1和sn2不相等 则不形成环,打印出这条边
System.out.println(vexs[arcs[j].adjVex].data+"<---->"+vexs[arcs[j].nextVex].data);
k++;
}
for(int i=0;i<vexNum;i++)
{
if(vset[i]==sn2)
{//判断是否能够形成环
vset[i]=sn1;//形成了就再找新的顶点
}
}
j++;
}
}
//获取以i,j为顶点的边
int getArcs(int i,int j)
{
for(int k=0;k<arcs.length;k++)
{
if(arcs[k].adjVex==i&&arcs[k].nextVex==j)
{
return arcs[k].value;
}
}
return Integer.MAX_VALUE;
}
// 内部类辅助记录从顶点U到V-U的代价最小的边
private class CloseEdge
{
Object adjVex;
int lowCost;
public CloseEdge(Object adjVex, int lowCost)
{
this.adjVex = adjVex;
this.lowCost = lowCost;
}
}
// 用Prime算法从第u个顶点出发构造网G的最小生成树T,返回由生成树边组成的二维数组
public Object[][] PRIM(Graph G, Object u) throws Exception
{
Object[][] tree = new Object[getVexNum() - 1][2];
int count = 0;
CloseEdge[] closeEdge = new CloseEdge[getVexNum()];//记录U-U-v的边的集合
int k = locateVex(u);
for (int j = 0; j < getVexNum(); j++)
{
// 辅助数组初始化
if (j != k)
{
closeEdge[j] = new CloseEdge(u, getArcs(k, j));
closeEdge[k] = new CloseEdge(u, 0);// 初始,U={u}
}
}
for (int i = 1; i < getVexNum(); i++)
{
// 选择其余G.vexnum - 1个顶点
k = getMinMum(closeEdge);// 求出T的下一个结点:第k个顶点
tree[count][0] = closeEdge[k].adjVex;// 生成树的边放入数组
tree[count][1] = vexs[k].data;
count++;
closeEdge[k].lowCost = 0;// 第k个顶点并入U集
for (int j = 0; j < getVexNum(); j++)
{
//新顶点并入U后重新选择最小边
if (getArcs(k, j) < closeEdge[j].lowCost)
{
closeEdge[j] = new CloseEdge(getVex(k), getArcs(k, j));
}
}
}
return tree;
}
//在closeEdge中选出lowCost最小且不为0的顶点
private int getMinMum(CloseEdge[] closeEdge)
{
int min = Integer.MAX_VALUE;
int v = -1;
for (int i = 0; i < closeEdge.length; i++)
{
if (closeEdge[i].lowCost != 0 && closeEdge[i].lowCost < min)
{
min = closeEdge[i].lowCost;
v = i;
}
return v;
}
return min;
}
}
TestGraph:
public class TestGraph
{
public static void main(String args[]) throws Exception
{
Graph a = new Graph();
System.out.println("kruskal算法求出的最小代价方案为:");
a.kruskal();
System.out.println("Prim算法求出的最小代价方案为:");
Object[][] tree = a.PRIM(a,a.getVex(0));
for(int i=0;i<tree.length;i++)
{
System.out.println(tree[i][1]+"<--->"+tree[i][0]);
}
}
}
VNode:
public class VNode
{
Object data;
arcNode firstArc;//指向第一条依附于该节点的弧
VNode()
{
this.data = null;
this.firstArc = null;
}
VNode(Object data)
{
this.data = data;
this.firstArc = null;
}
}
以上代码为初步未修改版本,仅供参考,欢迎各位批评指正。