链表java实现

java中实现链表

1.引出,给出一个创建节点的标准,完成节点的创建
interface ILinked<T t>{

public void add(T t);

}
2.创建步骤

通过实现类来完成节点的添加操作。因为在添加的过程中,操作的是节点,所以需要在实现类中定义一个内部类来将节点的信息进行封装

class ILinkedImpl<T> implements ILinked<T>{

		class Node{

				private T data;

				private T data;

				private Node next;

				private Node(T data){

							this.data=data;
			}
	}
  @override
  public void add(T t){
    
  }
}

定义完内部类Node后,因为链表中需要有根结点,所以需要定义个根结点,然后判断根结点是不是为空,如果为空,则将创建的节点,设置为根结点,如果根结点不为空,则需要添加节点,但是添加节点的信息,需要在Node内部类中进行操作。

class ILinkedImpl<T> implements ILinked<T> {
    //ILinked实现方法只负责添加数据,以及根节点的设置

    class Node<T> {
       private T data;
      private  Node next;

        private Node(T data) {
            this.data = data;
        }
    }

    Node root;
    @Override
    public void add(T t) {
        if (t == null) {
            return;
        }
        Node node=new Node(t);
        if (this.root==null)//现在没有根结点
        {
            this.root=node;//第一个节点为根结点
        }
        else
           //需要在内部类Node中进行操作

    }
}

编写内部类Node的添加节点操作

package LinkedClass;

interface ILinked<T> {
    public void add(T t);
}

class ILinkedImpl<T> implements ILinked<T> {
    //ILinked实现方法只负责添加数据,以及根节点的设置

    class Node<T> {
       private T data;
      private  Node next;

        private Node(T data) {
            this.data = data;
        }

        public void addNode(Node NewNode) {
            if (this.next== null) {//当前节点的下一个为空,保存当前节点
                this.next=NewNode;//添加节点
            }
            else
                 this.next.addNode(NewNode);//如果非空,则在下一个为空的节点中进行添加
        }

    }

    Node root;
    @Override
    public void add(T t) {
        if (t == null) {
            return;
        }
        Node node=new Node(t);
        if (this.root==null)//现在没有根结点
        {
            this.root=node;//第一个节点为根结点
        }
        else
            this.root.addNode(node);//创建节点
    }
}

3.整体测试类
package LinkedClass;

interface ILinked<T> {
    public void add(T t);
}

class ILinkedImpl<T> implements ILinked<T> {
    //ILinked实现方法只负责添加数据,以及根节点的设置

    class Node<T> {
       private T data;
      private  Node next;

        private Node(T data) {
            this.data = data;
        }

        public void addNode(Node NewNode) {
            if (this.next== null) {//当前节点的下一个为空,保存当前节点
                this.next=NewNode;
            }//即为根结点
            else
                 this.next.addNode(NewNode);
        }

    }

    Node root;
    @Override
    public void add(T t) {
        if (t == null) {
            return;
        }
        Node node=new Node(t);
        if (this.root==null)//现在没有根结点
        {
            this.root=node;//第一个节点为根结点
        }
        else
            this.root.addNode(node);

    }
}

public class LinkedDS {
    public static void main(String[] args) {

        ILinked<String> linked=new ILinkedImpl<>();
        linked.add("Hello");
        linked.add("World");

    }
}
4.对创建对象的个数统计

如果想要计算创建对象的统计的话,需要在ILinked接口中增加一个count方法,并且在实现类中能够将其复写,因此在创建成功一个对象则可num++,并将num返回即可,下面代码展示了计数对象个数的代码

package LinkedClass;

interface ILinked<T> {
    public void add(T t);
    public int count();
}

class ILinkedImpl<T> implements ILinked<T> {
    //ILinked实现方法只负责添加数据,以及根节点的设置
    private int num;
    class Node<T> {
       private T data;
      private  Node next;


        private Node(T data) {
            this.data = data;
        }

        public void addNode(Node NewNode) {
            if (this.next== null) {//当前节点的下一个为空,保存当前节点
                this.next=NewNode;
            }//即为根结点
            else
                 this.next.addNode(NewNode);
        }

    }

    Node root;
    @Override
    public void add(T t) {
        if (t == null) {
            return;
        }
        Node node=new Node(t);
        if (this.root==null)//现在没有根结点
        {
            this.root=node;//第一个节点为根结点
        }
        else
            this.root.addNode(node);
        this.num++;
    }

    @Override
    public int count() {
        return num;
    }
}

public class LinkedDS {
    public static void main(String[] args) {

        ILinked<String> linked=new ILinkedImpl<>();
        System.out.println("创建之前节点的个数"+linked.count());
        linked.add("Hello");
        linked.add("World");
        System.out.println("创建之后节点的个数"+linked.count());

    }
}
5.判断集合中元素是否为空

判断的时候可以根据根节点是否为空,以及计数是否为空,因此在ILinked接口中需要增加一个方法来判断,具体代码如下

package LinkedClass;

interface ILinked<T> {
    public void add(T t);//增加节点
    public int count();//获取数据个数
    public boolean isEmpty();//判断是否为空
}

class ILinkedImpl<T> implements ILinked<T> {
    //ILinked实现方法只负责添加数据,以及根节点的设置
    private int num;
    class Node<T> {
       private T data;
      private  Node next;


        private Node(T data) {
            this.data = data;
        }

        public void addNode(Node NewNode) {
            if (this.next== null) {//当前节点的下一个为空,保存当前节点
                this.next=NewNode;
            }//即为根结点
            else
                 this.next.addNode(NewNode);
        }

    }

    Node root;
    @Override
    public void add(T t) {
        if (t == null) {
            return;
        }
        Node node=new Node(t);
        if (this.root==null)//现在没有根结点
        {
            this.root=node;//第一个节点为根结点
        }
        else
            this.root.addNode(node);
        this.num++;
    }

    @Override
    public int count() {
        return num;
    }

    @Override
    public boolean isEmpty() {
        if (this.root==null||this.count()==0)
            return true;
        else return false;
    }
}

public class LinkedDS {
    public static void main(String[] args) {

        ILinked<String> linked=new ILinkedImpl<>();
        System.out.println("创建之前节点的个数"+linked.count()+"集合是否为空"+ linked.isEmpty());

        linked.add("Hello");
        linked.add("World");
            System.out.println("创建之前节点的个数"+linked.count()+"集合是否为空"+ linked.isEmpty());



    }
}
6.对链表中的数据进行结果集的返回

在进行结果集返回的时候需要创建一个对象数组来进行返回值的接受,创建的对象数组接受的内部类中的对象,因此可以定义在接口的实现类中。在创建数组的时候,我们应该需要创建一个角标来存储,一次需要定义个foot角标。

  • 在接口中定义结果集返回的结果。

    public Object[] returnAll();
    
  • 在实现类中定义结果集返回数组,以及定义角标

     private Object allNodes[];//返回节点中所有对象
        private int foot = 0;
    	
    
  • 实现类中复写接口中返回结果集方法

    @Override
    public Object[] returnAll() {
        if (this.isEmpty()) {//如果为空,返回null
            return null;
        }
        this.foot = 0;//角标清零
    
        //如果非空,则初始化结果集对象数组空间
        this.allNodes = new Object[this.num];//根据已有的长度开辟数组
        this.root.returnAll();
        return this.allNodes;
        //创建方法进行返回
    
    }
    

在上述返回结果集的时候,首先需要判断对象数组中的数据是否为空,如果为空则返回null。如果非空,则先初始化数组对象的空间大小,进而调用根结点来完成结果集的返回。

  • Node子类中实现结果集的返回

    public void returnAll() {
        ILinkedImpl.this.allNodes[ILinkedImpl.this.foot++] = this.data;
        if (this.next != null) {
            this.next.returnAll();
        }
    
    }
    

在返回结果集的时候,需要将当前对象的数据赋值给当前的数组对象,并能够动态的进行赋值,因此调用实现类中的allNodes对象数组属性来完成赋值,在进行调用后需要用当前节点的后继节点是否为空作为递归的结束条件,在方法中使用递归的方法依次遍历链表中的内容。然后在接口实现类中调用根结点完成结果集的返回

  • 下面给出结果集返回的测试代码
package LinkedClass;

interface ILinked<T> {
    public void add(T t);//增加节点

    public int count();//获取数据个数

    public boolean isEmpty();//判断是否为空

    public Object[] returnAll();
}

class ILinkedImpl<T> implements ILinked<T> {
    //ILinked实现方法只负责添加数据,以及根节点的设置

    class Node<T> {
        private T data;
        private Node next;

        private Node(T data) {
            this.data = data;
        }

        public void addNode(Node NewNode) {
            if (this.next == null) {//当前节点的下一个为空,保存当前节点
                this.next = NewNode;
            }//即为根结点
            else
                this.next.addNode(NewNode);
        }
//第一次调用为root节点
        //第二次调用为root.next
        //第三次调用为root.next.next
        public void returnAll() {
            ILinkedImpl.this.allNodes[ILinkedImpl.this.foot++] = this.data;
            if (this.next != null) {
                this.next.returnAll();
            }

        }

    }

    private int num;//节点对象数组长度
    private Node root;//根结点
    private Object allNodes[];//返回节点中所有对象
    private int foot = 0;

    @Override
    public void add(T t) {
        if (t == null) {
            return;
        }
        Node node = new Node(t);
        if (this.root == null)//现在没有根结点
        {
            this.root = node;//第一个节点为根结点
        } else
            this.root.addNode(node);
        this.num++;
    }

    @Override
    public int count() {
        return num;
    }

    @Override
    public boolean isEmpty() {
        if (this.root == null || this.count() == 0)
            return true;
        return false;
    }

    @Override
    public Object[] returnAll() {
        if (this.isEmpty()) {//如果为空,返回null
            return null;
        }
        this.foot = 0;//角标清零

        //如果非空,则初始化结果集对象数组空间
        this.allNodes = new Object[this.num];//根据已有的长度开辟数组
        this.root.returnAll();
        return this.allNodes;
        //创建方法进行返回

    }
}

public class LinkedDS {
    public static void main(String[] args) {

        ILinked<String> linked = new ILinkedImpl<>();
        System.out.println("创建之前节点的个数" + linked.count() + "集合是否为空" + linked.isEmpty());

        linked.add("Hello");
        linked.add("World");
        System.out.println("创建之前节点的个数" + linked.count() + "集合是否为空" + linked.isEmpty());
        Object result[] = linked.returnAll();
        for (Object o : result) {
            System.out.println(o);
        }



    }
}
7.按照id查找某个元素
  • 在接口中增加方法

    public T getNodeById(Integer id);//按照id返回对象
    
  • 接口实现类中复写接口中的方法

    @Override
    public T getNodeById(Integer id) {
        //判断是否为空
        if (this.num==0||id>=this.num)
            return null;
        this.foot=0;//角标清零
        return (T) this.root.getById(id);
    
    }
    

实现的过程需要判断链表是否为空以及查询的id是否超出范围,然后清零角标,在实现类的内部类中增加获取的方法

  • 内部类中实现按照id查找数组对象

    public T getById(Integer id){
        if (id==ILinkedImpl.this.foot++)//如果下标超过长度则则返回空
            return this.data;
        else
           return (T) this.next.getById(id);
    
    }
    

在传入的时候,同样采用递归的方式进行获取,因为链表在获取的时候,只能够通过foot角标挨个进行获取,因此在开始的时候需要判断id与当前对象的角标关系,并且每次角标需要++,如果id!=角标,需要采用递归方式,再进行查找

  • 测试代码

    package LinkedClass;
    
    interface ILinked<T> {
        public void add(T t);//增加节点
    
        public int count();//获取数据个数
    
        public boolean isEmpty();//判断是否为空
    
        public Object[] returnAll();//获取所有结果集
    
        public T getNodeById(Integer id);//按照id返回对象
    }
    
    class ILinkedImpl<T> implements ILinked<T> {
        //ILinked实现方法只负责添加数据,以及根节点的设置
    
        class Node<T> {
            private T data;
            private Node next;
    
            private Node(T data) {
                this.data = data;
            }
    
            public void addNode(Node NewNode) {
                if (this.next == null) {//当前节点的下一个为空,保存当前节点
                    this.next = NewNode;
                }//即为根结点
                else
                    this.next.addNode(NewNode);
            }
    //第一次调用为root节点
            //第二次调用为root.next
            //第三次调用为root.next.next
            public void returnAll() {
                ILinkedImpl.this.allNodes[ILinkedImpl.this.foot++] = this.data;
                if (this.next != null) {
                    this.next.returnAll();
                }
    
            }
            public T getById(Integer id){
                if (id==ILinkedImpl.this.foot++)//如果下标超过长度则则返回空
                    return this.data;
                else
                   return (T) this.next.getById(id);
    
            }
    
        }
    
        private int num;//节点对象数组长度
        private Node root;//根结点
        private Object allNodes[];//返回节点中所有对象
        private int foot = 0;
    
        @Override
        public void add(T t) {
            if (t == null) {
                return;
            }
            Node node = new Node(t);
            if (this.root == null)//现在没有根结点
            {
                this.root = node;//第一个节点为根结点
            } else
                this.root.addNode(node);
            this.num++;
        }
    
    
        @Override
        public int count() {
            return num;
        }
    
        @Override
        public boolean isEmpty() {
            if (this.root == null || this.count() == 0)
                return true;
            return false;
        }
    
        @Override
        public Object[] returnAll() {
            if (this.isEmpty()) {//如果为空,返回null
                return null;
            }
            this.foot = 0;//角标清零
    
            //如果非空,则初始化结果集对象数组空间
            this.allNodes = new Object[this.num];//根据已有的长度开辟数组
            this.root.returnAll();
            return this.allNodes;
            //创建方法进行返回
    
        }
    
        @Override
        public T getNodeById(Integer id) {
            //判断是否为空
            if (this.num==0||id>=this.num)
                return null;
            this.foot=0;//角标清零
            return (T) this.root.getById(id);
    
        }
    }
    
    public class LinkedDS {
        public static void main(String[] args) {
    
            ILinked<String> linked = new ILinkedImpl<>();
            System.out.println("创建之前节点的个数" + linked.count() + "集合是否为空" + linked.isEmpty());
    
            linked.add("Hello");
            linked.add("World");
            System.out.println("创建之前节点的个数" + linked.count() + "集合是否为空" + linked.isEmpty());
            Object result[] = linked.returnAll();
            for (Object o : result) {
                System.out.println(o);
            }
            System.out.println(linked.getNodeById(2));
    
    
        }
    }
    

上述代码中通过id进行查找的时间复杂度为O(n),因为需要通过角标进行遍历,然而数组进行查找的时候时间复杂度为O(1)

8.根据ID来更改所属Id的数据信息
  • 接口中定义规范
public void modifyById(Integer index,T data);
  • 接口实现类内部类完成modifyNode操作

    public void modifyNode(Integer index,T data){
        if (index==ILinkedImpl.this.foot++){
            this.data=data;
        }
        else
            this.next.modifyNode(index,data);
    }
    
  • 在接口实现类中复写方法并且调用内部类的操作

    @Override
    public void modifyById(Integer index, T data) {
        if (index>=this.num){
            return;
        }
        this.foot=0;//角标清零
        this.root.modifyNode(index,data);
    }
    

上述操作与查找操作基本类似,不在赘述

9.判断链表中是否存在某个元素
  • 在接口中定义方法public boolean contains(T data)

  • 在接口实现类中实现该方法

    public boolean contains(T data)
    
    {//判断传入的数据是否为空
    
    	if(data==null)
    
    	return false;
    
    	else{
    
    	//如果非空,在内部类中实现内容的递归查询
    	return	this.root.containsNode(data);
    
    }
    
    }
    
  • 在实现类中的内部类中实现遍历

    public boolean containsNode(T data){
    
    if(this.data.equals(data))
    
    	return true;
    
    else
    
    return this.next.containsNode(data);
    
    }
    
    10.链表中删除某个元素

    在删除的操作时,分为两种情况进行删除

    • 如果删除的是根节点
    • 如果删除的为非根结点

    步骤如下:

    • 在接口中定义删除的接口

      public void remove(T data);

    • 在实现类中实现接口

      public void remove(T data)
      
      {
      
      //判断元素是否存在
      
      if (this.contains(data))
      
      {
      
      //判断删除的是否为根结点
      
      		if(this.root.data.equals(data))
      
      				this.root=this.root.next;
      
      		else{
      				//如果为非根结点,在内部类中完成删除操作,需要传入删除节点的上一个节点
            this.root.removeNode(this.root,data);
      			
      
      }
      
      }
      
      }
      
      • 内部类中的实现
      public void removeNode(Node previous,T data){
      
      if(this.data.equals(data)){
      
      previous.next=this.next;
      
      }
      
      else
      
      {if(this.next!=null)
      
      this.next.removeNode(this,data);
      
      }}
      
      11.删除链表中所有元素

      删除所有元素的操作即设置根结点为空,并且链表中的元素个数为0

      • 接口中定义方法public void removeAll();

      • 接口实现类中定义复写方法

        public void removeAll(){
        
        this.root=null;
        
        this.num=0;
        
        }
        
12.链表操作的整体代码
package LinkedClass;

interface ILinked<T> {
    public void add(T t);//增加节点

    public int count();//获取数据个数

    public boolean isEmpty();//判断是否为空

    public Object[] returnAll();//获取所有结果集

    public T getNodeById(Integer id);//按照id返回对象

    public void modifyById(Integer index, T data);

    public boolean contains(T t);

    public void remove(T t);

    public void removeAll();
}


class ILinkedImpl<T> implements ILinked<T> {
    //ILinked实现方法只负责添加数据,以及根节点的设置

    class Node<T> {
        private T data;
        private Node next;

        private Node(T data) {
            this.data = data;
        }

        public void addNode(Node NewNode) {
            if (this.next == null) {//当前节点的下一个为空,保存当前节点
                this.next = NewNode;
            }//即为根结点
            else
                this.next.addNode(NewNode);
        }

        //第一次调用为root节点
        //第二次调用为root.next
        //第三次调用为root.next.next
        public void returnAll() {
            ILinkedImpl.this.allNodes[ILinkedImpl.this.foot++] = this.data;
            if (this.next != null) {
                this.next.returnAll();
            }

        }

        public T getById(Integer id) {
            if (id == ILinkedImpl.this.foot++)//如果下标超过长度则则返回空
                return this.data;
            else
                return (T) this.next.getById(id);

        }

        public void modifyNode(Integer index, T data) {
            if (index == ILinkedImpl.this.foot++) {
                this.data = data;
            } else
                this.next.modifyNode(index, data);
        }

        public boolean containsNode(T t) {
            if (this.data.equals(t))
                return true;
            else
                return this.next.containsNode(t);
        }

        public void removeNode(Node Prior, T t) {
            if (this.data.equals(t)) {
                Prior.next = this.next;//当前节点的上一个指向当前节点的下一个节点

            } else {
                if (this.next != null)
                    this.next.removeNode(this, t);//向后继续删除
            }
        }
    }

    private int num;//节点对象数组长度
    private Node root;//根结点
    private Object allNodes[];//返回节点中所有对象
    private int foot = 0;

    @Override
    public void add(T t) {
        if (t == null) {
            return;
        }
        Node node = new Node(t);
        if (this.root == null)//现在没有根结点
        {
            this.root = node;//第一个节点为根结点
        } else
            this.root.addNode(node);
        this.num++;
    }


    @Override
    public int count() {
        return num;
    }

    @Override
    public boolean isEmpty() {
        if (this.root == null || this.count() == 0)
            return true;
        return false;
    }

    @Override
    public Object[] returnAll() {
        if (this.isEmpty()) {//如果为空,返回null
            return null;
        }
        this.foot = 0;//角标清零

        //如果非空,则初始化结果集对象数组空间
        this.allNodes = new Object[this.num];//根据已有的长度开辟数组
        this.root.returnAll();
        return this.allNodes;
        //创建方法进行返回

    }

    @Override
    public T getNodeById(Integer id) {
        //判断是否为空
        if (this.num == 0 || id >= this.num)
            return null;
        this.foot = 0;//角标清零
        return (T) this.root.getById(id);

    }

    @Override
    public void modifyById(Integer index, T data) {
        if (index >= this.num) {
            return;
        }
        this.foot = 0;//角标清零
        this.root.modifyNode(index, data);
    }

    @Override
    public boolean contains(T t) {
        if (t == null)
            return false;
        return this.root.containsNode(t);
    }

    @Override
    public void remove(T t) {
        if (this.contains(t))//判断删除的是否为根结点
        {
            if (this.root.data.equals(t))
                this.root = this.root.next;
            else {
                this.root.removeNode(this.root, t);
            }

        }
        this.num--;//成功删除后将链表的长度减一
    }

    @Override
    public void removeAll() {
        this.root = null;
        this.num = 0;
    }

}

public class LinkedDS {
    public static void main(String[] args) {

        ILinked<String> linked = new ILinkedImpl<>();
        System.out.println("创建之前节点的个数" + linked.count() + "集合是否为空" + linked.isEmpty());

        linked.add("Hello");
        linked.add("World");
        linked.remove("World");
//        linked.removeAll();
        System.out.println("创建之前节点的个数" + linked.count() + "集合是否为空" + linked.isEmpty());
        Object result[] = linked.returnAll();

        if (result != null) {
            for (Object o : result) {
                System.out.println(o);
            }
        }


    }
}

你可能感兴趣的:(java,链表,开发语言)