数据结构和算法单向链表一之单向链表的简单实现

  链表在我们java中也是一种基础的数据结构,可以理解成是一种和数组同级的数组结构,正如我们所知,在我们使用这集合ArrayList和LinkedList的时候,总会学习底层数组实现的ArrayList和双向链表实现的LinkedList的区别。在这里,我们将要讲说的是单向链表的简单实现,让我们体会一下链表在实现增删改查的时候是怎么样的一个操作,在和前边涉及到的数组的增删改查进行对比,得到我们学习的结论,数组的增删效率低于链表结构,查改效率高于链表结构!

  什么叫做单向链表,我们可以理解为一个一个节点链接起来的一条链子,从第一个开始有指向下一个的箭头,也就是说单向链表的每一个节点我们可以理解为是一个对象,里面包含了date内容属性,同时也包含了next下一个对象的属性。代码如下:

public class MyList {
    //定义一个头节点
    private Node head;
    //定义一个节点内部类
    class Node{
        int date;
        Node next;
        public Node(int date){
            this.date = date;
        }
    }
    /**
     * 获取链表的长度
     * @return
     */
    public int getSize(){
        //判断是否头结点为空
        if(head == null){
            return 0;
        }else {
            Node current = head;
            int size = 1;
            while((current = current.next)!=null){
                 size++;
            }
            return size;
        }
    }
    /**
     * 判断链表是否为空
     * @return
     */
    public boolean isEmpty(){
        if(head==null){
            return true;
        }else {
            return false;
        }
    }
    /**
     * 根据节点信息判断是否包含这个节点
     * @param date
     * @return
     */
    public boolean contains(int date){
        //判断头结点是否为空
        if(head==null){
            return false;
        }else {
            for(int i = 0;i < getSize();i++){
                if(head.date==date){
                    return true;
                }
                head = head.next;
            }
            return false;
        }
    }
    /**
     * 根据下角标获取对象的节点
     * @param index
     * @return
     */
    public Node getNode(int index){
        //对index的有效进行判断
        if(index < 0 || index >= getSize()){
            throw new IndexOutOfBoundsException();
        }else {
            int i = 0;
            Node current = head;
            while(i < index){
                current = current.next;
                i++;
            }
            return current;
        }
    }
    /**
     * 根据节点内容获取节点对象
     * @param date
     * @return
     */
    public Node getNodeByDate(int date){
        //判断链表是否为空
        if(getSize()==0){
            return null;
        }else {
            for (int i = 0; i < getSize(); i++) {
                if(getNode(i).date == date){
                    return getNode(i);
                }
            }
            return null;
        }
    }
    /**
     * 插入头结点
     * @param date
     */
    public void addFirstNode(int date){
        Node node = new Node(date);
        node.next = head;
        head = node;
    }
    /**
     * 在链表尾端插入节点
     * @param date
     */
    public void addLastNode(int date){
        //判断头结点是否为空
        if(head == null){
            addFirstNode(date);
        }else {
            //获取原尾端节点
            Node node = getNode(getSize()-1);
            //获取当前节点
            Node nowNode = new Node(date);
            //建立连接
            node.next = nowNode;
        }
    }
    /**
     * 在任意位置插入节点
     * @param index
     * @param date
     */
    public void addNode(int index,int date){
        //判断index的有效性
        if(index < 0 || index > getSize()){
            throw new IndexOutOfBoundsException();
        }else {
            if(index == 0){
                addFirstNode(date);
            }else if(index == getSize()){
                addLastNode(date);
            }else {
                //获取新的当前节点
                Node nowNode = new Node(date);
                //获取上一个节点
                Node node1 = getNode(index - 1);
                //获取旧的当前节点
                Node node2 = getNode(index);
                //断开原来节点的连接
                node1.next = nowNode;
                //建立与node2的连接
                nowNode.next = node2;
            }
        }
    }
    /**
     * 删除任意位置的节点
     * @param index
     */
    public void deleteNode(int index){
        //判断index的有效性质
        if(index < 0 || index >= getSize()){
            throw new IndexOutOfBoundsException();
        }else {
            //判断是否是头结点
            if(index == 0){
                head.next = null;
                head = head.next;
            }else {
                //获取删除节点的上一个节点
                Node node1 = getNode(index - 1);
                //获取当前删除节点
                Node nowNode = getNode(index);
                //建立上一个节点和下一个节点的连接
                node1.next = nowNode.next;
                //断开删除节点和下一个节点的连接
                nowNode = nowNode.next;
            }
        }
    }
    /**
     * 打印所有的节点信息
     */
    public void printAll(){
        Node current = head;
        while(current!=null){
            System.out.println(current.date);
            current = current.next;
        }
    }
    /**
     * 打印index以后的所有节点信息
     * @param index
     */
    public void printFromIndex(int index){
        //判断index的有效
        if(index < 0 || index >= getSize()){
            throw new IndexOutOfBoundsException();
        }else {
            //获取当前节点
            Node node = getNode(index);
            while(node!=null){
                System.out.println(node.date);
                node = node.next;
            }
        }
        
    }
    /**
     * 进行测试所有的方法
     * @param args
     */
    public static void main(String[] args) {
        MyList list = new MyList();
        list.addFirstNode(1);
        list.addLastNode(2);
        list.addFirstNode(3);
        list.addLastNode(4);
        list.addNode(3, 5);
        list.deleteNode(3);
        list.printAll();
        System.out.println(list.isEmpty());
        System.out.println(list.getSize());
        System.out.println(list.getNodeByDate(1));
        System.out.println(list.getNode(2));
        list.printFromIndex(2);
    }
}

    在上述代码中就是单向链表的简单实现,总的来说我们需要注意的是在输入数据时候,比如下标,我们需要对下标的合法性就行判断在进行操作,我们应该考虑到多种异常情况,然后也就比较简单了。明天我们将继续讲述关于单向链表的一些简单操作问题,如以下

  1、求单链表中节点的个数

  2、查找单链表中的倒数第k个结点

  3、查找单链表中的中间结点

  4、合并两个有序的单链表,合并之后的链表依然有序

  5、单链表的反转

  6、从尾到头打印单链表

  7、判断单链表是否有环

  8、取出有环链表中,环的长度

  9、单链表中,取出环的起始点

  10、判断两个单链表相交的第一个交点

  

原文地址:https://www.cnblogs.com/zslli/p/7990072.html