链表中所有的数据都通过Node封装后实现了动态保存,并且取消了数组长度的限制。但是保存在链表中的数据也需要被外界获取,那么此时就可以利用数组的形式返回链表中的保存数据。考虑到此功能的通用性,所以返回的数组类型应该是Object,操作结构如图。
在进行链表数据获取时,应该根据当前链表所保存的集合长度开辟相应的数组,随后利用索引的方式从链表中取得相应的数据并将其保存在数组中。
(1)【ILink】在ILink接口中追加方法用于返回链表数据。
public Object[] toArray();
(2)【LinkImpl】在LinkImpl子类中定义两个成员属性,用于返回数组声明与数组索引控制。
private int foot; //数组操作脚标 private Object[] returnData; //返回数据保存
(3)【LinkImpl.Node】在Node类中追加新的方法,通过递归的形式将链表中的数据保存在数组中。
public void toArrayNode(){
//将当前节点的数据取出保存到returnData数组中,同时进行索引自增
LinkImpl.this.returnData[LinkImpl.this.foot++]=this.data;
if(this.next !=null){ //还有下一个数据
this.next.toArrayNode(); //递归调用
}
}
(4)【LinkImpl】覆写ILink接口中的toArray()方法。
@Override
public Object[] toArray(){
if(this.isEmpty()){ //空集合
throw new NullPointerException("集合内容为空");
}
this.foot=0; //脚标清零
this.returnData=new Object[this.count]; //根据已有长度开辟数组
this.root.toArrayNode(); //利用Node类进行递归数据获取
return this.returnData; //返回全部元素
}
(5)【测试类】编写测试程序调用toArray()方法。
public class Main{
public static void main(String args[]){
ILinklink=new LinkImpl(); //实例化链表对象
link.add("浩汉"); //链表中保存数据
link.add("浩渺");
link.add("JOE");
Object results[]=link.toArray(); //获取全部保存数据
for(Object obj:results){
String str=(String) obj; //确定为String类型,强制转型
System.out.println(str+"、") //输出对象
}
}
}
完整代码如下:
package cn.kuiba.util; interface ILink{ public void add(E e); public int size(); public boolean isEmpty(); public Object[] toArray(); } class LinkImpl implements ILink { private int foot; private Object[] retuenData; private int count; private class Node { private E data; private Node next; public Node(E data){ this.data=data; } public void addNode(Node newNode){ if (this.next == null){ this.next=newNode; }else { this.next.addNode(newNode); } } public void toArrayNode(){ LinkImpl.this.retuenData[LinkImpl.this.foot++]=this.data; if (this.next != null){ this.next.toArrayNode(); } } } private Node root; @Override public void add(E e){ if (e == null){ return; } Node newNode=new Node (e); if (this.root == null){ this.root=newNode; }else { this.root.addNode(newNode); } this.count++; } @Override public int size(){ return this.count; } @Override public Object[] toArray(){ if (this.isEmpty()){ throw new NullPointerException("集合内容为空"); } this.foot=0; this.retuenData=new Object[this.count]; this.root.toArrayNode(); return this.retuenData; } @Override public boolean isEmpty(){ return this.count==0; } } public class Main { public static void main(String args[]){ ILink link=new LinkImpl (); System.out.println("数据保存前链表元素个数:"+link.size()); link.add("浩汉"); link.add("浩渺"); link.add("JOE"); System.out.println("数据保存后链表元素个数:"+link.size()); Object results[]= link.toArray(); for (Object obj:results){ String str=(String) obj; System.out.println(str+"、"); } } } 程序执行结果: 数据保存前链表元素个数:0 数据保存后链表元素个数:3 浩汉、 浩渺、 JOE、
本程序通过链表中的toArray()方法可以将保存在链表中的数据全部取出,就可以利用foreach实现内容打印。
5.根据索引取得数据传统数组和链表都是基于顺序式的形式实现了数据的保存,所以链表也可以利用索引的形式通过递归获取指定数据,操作如图
(1)【ILink】在ILink接口中定义新的方法可以根据索引获取数据。
public E get(int index);
(2)【LinkImpl.Node】在Node类中追加索引获取数据的方法,此时可以利用LinkImpl类中的foot进行索引判断。
public E getNode(int index){
if(LinkImpl.this.foot++ == index){ //索引相同
return this.data; //返回当前数据
}else{ //继续向后获取数据
return this.next.getNode(index);
}
}
(3)【LinkImpl】在LinkImpl子类中覆写get()方法。
@Override
public E get(int index){
if(index >= this.count){ //索引不在指定范围内
throw new ArrayIndexOutOfBoundsException("不正确的数据索引");
}
this.foot=0; //重置索引的下标
return this.foot.getNode(index); //交由Node类查找
}
(4)【测试类】编写测试程序,调用get()方法。
public class Main{
public static void main(String args[]){
Ilinklink=new LinkImpl(); //实例化链表对象
link.add("浩汉"); //链表中保存数据
link.add("浩渺");
link.add("JOE");
System.out.println(link.get(1)); //获取第2个元素
System.out.println(link.get(3)); //错误的索引
}
}
package cn.kuiba.util; interface ILink{ public void add(E e); public int size(); public boolean isEmpty(); public Object[] toArray(); public E get(int index); } class LinkImpl implements ILink { private int foot; private Object[] returnData; private int count; private class Node { public E getNode(int index){ if (LinkImpl.this.foot++==index){ return this.data; }else { return this.next.getNode(index); } } private E data; private Node next; public Node(E data){ this.data=data; } public void addNode(Node newNode){ if (this.next == null){ this.next=newNode; }else { this.next.addNode(newNode); } } public void toArrayNode(){ LinkImpl.this.returnData[LinkImpl.this.foot++]=this.data; if (this.next != null){ this.next.toArrayNode(); } } } private Node root; @Override public void add(E e){ if (e == null){ return; } Node newNode=new Node (e); if (this.root == null){ this.root=newNode; }else { this.root.addNode(newNode); } this.count++; } @Override public int size(){ return this.count; } @Override public Object[] toArray(){ if (this.isEmpty()){ throw new NullPointerException("集合内容为空"); } this.foot=0; this.returnData=new Object[this.count]; this.root.toArrayNode(); return this.returnData; } @Override public boolean isEmpty(){ return this.count==0; } @Override public E get(int index){ if (index>=this.count){ throw new ArrayIndexOutOfBoundsException("不正确的数据索引"); } this.foot=0; return this.root.getNode(index); } } public class Main { public static void main(String args[]) { ILink link = new LinkImpl (); System.out.println("数据保存前链表元素个数:" + link.size()); link.add("浩汉"); link.add("浩渺"); link.add("JOE"); System.out.println("数据保存后链表元素个数:" + link.size()); System.out.println(link.get(1)); System.out.println(link.get(3)); } } //} 程序执行结果:数据保存前链表元素个数:0 数据保存后链表元素个数:3 浩渺 Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 不正确的数据索引 at cn.kuiba.util.LinkImpl.get(Main.java:76) at cn.kuiba.util.Main.main(Main.java:95)
本程序在get()方法中由于存在索引的检查机制,所以一旦使用了不正确的索引将会产生相应的异常提示。
6.修改链表结构链表中的数据由于存在foot这个成员变量就可以通过索引的形式来进行操作,利用索引可以实现内容的修改。
(1)【ILink】在ILink接口中追加数据修改方法。
public void set(int index,E data);
(2)【LinkImpl.Node】在Node类中增加一个索引数据修改的方法。
public void setNode(int index,E data){
if (LinkImpl.this.foot++==index){ //索引相同
this.data=data; //修改数据
}else {
this.next.setNode(index,data); //后续节点操作
}
}
(3)【LinkImpl】在LinkImpl子类中覆写set()方法。
@Override
public void set(int index ,E data){
if (index>=this.count){ //索引不在指定的范围内
throw new ArrayIndexOutOfBoundsException("不正确的数据索引");
}
this.foot=0; //重置索引的下标
this.root.setNode(index,data); //Node类修改数据
}
(4)【测试类】编写程序实现内容修改。
public class Main {
public static void main(String args[]) {
ILink link = new LinkImpl(); //实例化链表对象
link.add("浩汉"); //链表中保存数据
link.add("浩渺");
link.add("JOE");
link.set(1, "世界"); //修改内容
System.out.println(link.get(1)); //获取第2个元素
}
}
程序执行结果:
世界
本程序利用了set()方法修改了指定索引的内容,随后利用get()方法获取索引数据,实质上set()和get()两个方法的实现原理相同。



