13.链表(二)

4.返回链表数据

        链表中所有的数据都通过Node封装后实现了动态保存,并且取消了数组长度的限制。但是保存在链表中的数据也需要被外界获取,那么此时就可以利用数组的形式返回链表中的保存数据。考虑到此功能的通用性,所以返回的数组类型应该是Object,操作结构如图。

在进行链表数据获取时,应该根据当前链表所保存的集合长度开辟相应的数组,随后利用索引的方式从链表中取得相应的数据并将其保存在数组中。

(1)【ILink】在ILink接口中追加方法用于返回链表数据。

/**
 * 获取链表中的全部内容,该内容将以数组的形式返回
 * @return 如果链表有内容则返回与保存元素个数相当的数组,如果没有内容则返回null
 */
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[]){
        ILink<String>link=new LinkImpl<String>();    //实例化链表对象
        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<E>{
    public void add(E e);
    public int size();
    public boolean isEmpty();
    public Object[] toArray();
}
class LinkImpl<E> implements ILink<E>{
    private int foot;
    private Object[] retuenData;
    private int count;
    private class Node<E>{
        private E data;
        private Node<E> next;
        public Node(E data){
            this.data=data;
        }
        public void addNode(Node<E> 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<E> root;
    @Override
    public void add(E e){
        if (e == null){
            return;
        }
        Node<E> newNode=new Node<E>(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<String>link=new LinkImpl<String>();
        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接口中定义新的方法可以根据索引获取数据。

/**
 * 根据索引获取链表中的指定元素内容
 * @param index要获取元素的索引
 * @return 指定索引的位置的数据
 */
public E get(int index);

(2)【LinkImpl.Node】在Node类中追加索引获取数据的方法,此时可以利用LinkImpl类中的foot进行索引判断。

/**
 * 根据节点索引获取元素
 * @param index 要获取的索引编号,该索引编号一定是有效编号
 * @return 索引对应的数据
 */
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[]){
        Ilink<String>link=new LinkImpl<String>();    //实例化链表对象
        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<E>{
    public void add(E e);
    public int size();
    public boolean isEmpty();
    public Object[] toArray();
    public E get(int index);
}
class LinkImpl<E> implements ILink<E>{
    private int foot;
    private Object[] returnData;
    private int count;
    private class Node<E>{
        public E getNode(int index){
            if (LinkImpl.this.foot++==index){
                return this.data;
            }else {
                return this.next.getNode(index);
            }
        }
        private E data;
        private Node<E> next;
        public Node(E data){
            this.data=data;
        }
        public void addNode(Node<E> 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<E> root;
    @Override
    public void add(E e){
        if (e == null){
            return;
        }
        Node<E> newNode=new Node<E>(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<String> link = new LinkImpl<String>();
        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 + "、");*/
            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接口中追加数据修改方法。

/**
 * 修改指定索引中的数据内容
 * @param index要修改的数据索引
 * @param data要替换的新内容
 */
public void set(int index,E data);

(2)【LinkImpl.Node】在Node类中增加一个索引数据修改的方法。

/**
 * 修改指定索引中的数据内容
 * @param index要修改的数据索引
 * @param data要替换的新内容
 */
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<String> link = new LinkImpl<String>();        //实例化链表对象
        link.add("浩汉");                                   //链表中保存数据
        link.add("浩渺");
        link.add("JOE");
        link.set(1, "世界");                                //修改内容
        System.out.println(link.get(1));                    //获取第2个元素
    }
}



程序执行结果:
世界

        本程序利用了set()方法修改了指定索引的内容,随后利用get()方法获取索引数据,实质上set()和get()两个方法的实现原理相同。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值