链表的定义与使用

1、链表的设计思想:

2、链表及操作链表的方法:(使用泛型是为了避免转型的异常)

package com.demo;
// 设置泛型避免安全隐患;接口定义标准
interface ILink<E> {
    public void add(E e); //增加数据
    public int size() ; //获取数据的个数
    public boolean isEmpty() ; //空集合判断
    public Object[] toArray() ; //将集合元素以数组的形式返回
    public E get(int index) ; //获取指定索引数据
    public void set(int index, E data) ;  //修改指定索引的数据
    public boolean contains(E data) ; //判断数据是否存在
    public void remove(E data) ; //数据删除
    public void clean() ; //清空链表
}
// 实现接口
class LinkImpl<E> implements ILink<E> {
    
    //私有内部类-保存节点的数据关系
    private class Node {
        private E data ; //保存的数据
        private Node next ; 
        public Node(E data) { //有数据才有意义
            this.data = data ;
        }
        //保存新的Node数据
        public void addNode(Node newNode) {
            if(this.next == null) { //第一次调用该方法,this.next即为根节点的下一个节点
                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();
            }
        }
        //根据索引查找数据
        public E getNode(int index) {
            if(LinkImpl.this.foot++  == index) {
                return this.data ;
            }else {
                return this.next.getNode(index) ;
            }
        }
        //根据索引修改数据
        public void setNode(int index, E data) {
            if(LinkImpl.this.foot++  == index) {
                this.data = data ;
            }else {
                this.next.setNode(index, data) ;
            }
        }
        //判断数据是否存在
        public boolean containNode(E data) {
            //此处注意,由于整个链表没有null数据的存在,所以程序在判断的时候直接使用每一个节点数据发出equals()方法即可,但是如果链表中有空数据时,必须由待判断的数据data发出,因为在调用此方法之前,已经为data做了空值判断。
            //if(this.data.equals(data)) {
            if(data.equals(this.data)) {
                return true ;
            }else {
                if(this.next == null) { //找不到
                    return false ;
                }else {
                    return this.next.containNode(data) ; //向后继续比较
                }
            }
        }
        //删除非根节点
        public void removeNode(Node previous, E data) {
            if(this.data.equals(data)) {
                previous.next = this.next ; //空出当前节点
            }else {
                if(this.next != null) { //有后续节点
                    this.next.removeNode(this, data); //向后继续删除
                }
            }
        }
    }
    
    // Link类中定义的结构
    private Node root ; //保存根元素
    private int count ; //保存数据的个数
    private int foot ; //操作数组的脚标
    private Object[] returnData ; //返回的数据保存数组
    public void add(E e) {
        if(e == null) {
            return ; //方法调用直接结束
        }
        // 数据本身不具有关联特性;要想实现关联处理必须将数据包装在Node类中
        Node newNode = new Node(e) ; //创建一个新的节点
        if(this.root == null) { //当前没有根节点
            this.root = newNode ; //第一个节点作为根节点
        }else {
            // this.root.next = newNode ; 不能这样写,否则root的next永远在被替换
            //将新节点保存在合适的位
            this.root.addNode(newNode);
        }
        this.count ++ ; //数据增加成功数据个数加一
    }
    //返回链表中数据个数的方法
    public int size() {
        return this.count;
    }
    //空集合判断的方法
    public boolean isEmpty() {
        return this.root == null ;
    }
    //将集合元素以数组的形式返回
    public Object[] toArray() {
        if(this.isEmpty()) {
            return null;
        }
        this.foot = 0 ; //脚标清零
        this.returnData = new Object[this.count] ; //根据已有长度开辟数组
        //在Node类中根据递归获取数据
        this.root.toArrayNode() ;
        return this.returnData ;
    }
    //获取指定索引数据-这一特点和数组相似,但是数组获取一个数据的时间复杂度为1,而链表获取数据的时间复杂度为n
    public E get(int index) {
        if(index >= this.count) {
            return null;
        }
        this.foot = 0 ; //重置索引的下标
        return this.root.getNode(index) ;
    }
    //修改指定索引的数据
    public void set(int index, E data) {
        if(index >= this.count) {
            return ; //方法结束
        }
        this.foot = 0 ; //重置索引的下标
        this.root.setNode(index, data); //修改数据,具体方法在Node类中
    }
    //判断数据是否存在
    public boolean contains(E data) {
        if(data == null) {
            return false ; //没有数据
        }
        return this.root.containNode(data) ; //交个Node类判断
    }
    //数据删除-需要数据比较的支持(两种情况:删除的根节点(与LinkImpl有关)-让root指向root的next节点、删除的不是根节点(由node类负责))
    public void remove(E data) {
        if(this.contains(data)) { //判断数据是否存在
            if(this.root.data.equals(data)) { //根节点为要删除的节点
                this.root = this.root.next ;
            }else {
                this.root.next.removeNode(this.root, data);
            }
            this.count-- ;
        }
    }
    //清空链表
    public void clean() {
        this.root = null ; //后续的所有节点都没了
        this.count = 0 ; //个数清零
    }
}
public class LinkDemo {
    public static void main(String[] args) {
        ILink<String> all = new LinkImpl<String>() ;
        all.add("Hello");
        all.add("一只瓶子a");
        all.set(0,"Hi");
        System.out.println("【数据集合的长度】" + all.size());
        Object result [] = all.toArray() ;
        if(result != null) {
            for(Object obj : result) {
                System.out.println("【遍历数据】:" + obj);
            }
        }
        System.out.println("【根据索引获取数据】:" + all.get(1));
        System.out.println("【判断数据是否存在】:" + all.contains("一只瓶子a"));
    }
}

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值