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

Posted GoNewLife

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了数据结构和算法--链表一之单向链表的简单实现相关的知识,希望对你有一定的参考价值。

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

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

public class MyList {
    // 定义一个头结点
    private Node head;
    // 链表的长度
    private int size;

    // 构造一个节点内部类
    class Node {
        // 节点的存放数据
        int date;
        // 节点的next域
        Node next;

        public Node(int date) {
            this.date = date;
        }
    }

    /**
     * 获取链表的长度
     * 
     * @return
     */
    public int getSize() {
        return size;
    }

    /**
     * 根据下标获取对应位置的节点
     * 
     * @param index
     * @return
     */
    public Node getNodeByIndex(int index) {
        // 判断index的有效性
        if (index < 0 || index > getSize() - 1) {
            return null;
        } else {
            // 对链表是否为空进行判断
            if (isEmpty()) {
                return null;
            } else {
                Node cur = head;
                for (int i = 0; i < index - 1; i++) {
                    cur = head.next;
                    head = cur;
                }
                return cur;
            }
        }
    }

    /**
     * 根据节点内容判断节点是否存在
     * 
     * @param date
     * @return
     */
    public boolean contains(int date) {
        for (int i = 0; i < getSize(); i++) {
            if (getNodeByIndex(i).date == date) {
                return true;
            }
        }
        return false;
    }

    /**
     * 根据节点内容获取节点位置 有返回index,没有返回-1
     * 
     * @param date
     * @return
     */
    public int getNodeByDate(int date) {
        // 判断节点是否存在
        boolean b = contains(date);
        if (b) {
            for (int i = 0; i < getSize(); i++) {
                if (getNodeByDate(date) == date) {
                    return i;
                }
            }
        }
        return -1;
    }

    /**
     * 判断链表是否为空
     * 
     * @return
     */
    public boolean isEmpty() {
        if (getSize() > 0) {
            return false;
        } else {
            return true;
        }
    }

    /**
     * 在链表前端插入一个节点
     * 
     * @param date
     */
    public void addFirstNode(int date) {
        // 通过链表是否为空判断是否有头节点
        if (isEmpty()) {
            head = new Node(date);
        } else {
            Node node = new Node(date);
            node.next = head;
        }
    }

    /**
     * 在链表的末端加入一个节点
     * 
     * @param date
     */
    public void addLastNode(int date) {
        // 获取链表末端的节点
        Node node = getNodeByIndex(getSize() - 1);
        // 得到需要插入的节点
        Node nowNode = new Node(date);
        // 将上一个节点的next指向当前节点
        node.next = nowNode;
    }

    /**
     * 在index位置插入节点
     * 
     * @param index
     * @param date
     */
    public void addNodeByIndex(int index, int date) {
        // 对index进行有效性判断
        if (index > getSize() || index < 0) {
            return;
        }
        if (index == 0) {
            addFirstNode(date);
        } else if (index == getSize()) {
            addLastNode(date);
        } else {
            // 获取上一个节点
            Node node1 = getNodeByIndex(index - 1);
            // 获取当前插入的节点
            Node nowNode = new Node(date);
            // 获取下一个节点
            Node node2 = getNodeByIndex(index + 1);
            // 与上下节点建立链接
            node1.next = nowNode;
            nowNode.next = node2;
        }
    }

    /**
     * 根据index删除对应位置的节点
     * 
     * @param index
     */
    public void deleteNode(int index) {
        // 找到index位置的节点,判断该节点是否为空
        if (getNodeByIndex(index) != null) {
            // 如果是头节点
            if (index == 0) {
                head.next = head;
            } else if (index == getSize() - 1) {
                // 获取上一个节点,并将它的next指向空
                getNodeByIndex(getSize() - 2).next = null;
            } else {
                // 获取上一个节点
                Node node1 = getNodeByIndex(index - 1);
                // 获取下一个节点
                Node node2 = getNodeByIndex(index + 1);
                // 获取当前节点
                Node nowNode = getNodeByIndex(index);
                // 断开当前节点和上下节点的链接
                nowNode.next = null;
                node1.next = node2;
            }
        }
    }

    /**
     * 对index位置的Node进行修改
     * 
     * @param index
     * @param date
     */
    public void updateNode(int index, int date) {
        // 判断该节点是否存在
        if (getNodeByIndex(index) != null) {
            // 获取对应位置的Node
            Node nowNode = getNodeByIndex(index);
            // 对它的date进行修改
            nowNode.date = date;
        }
    }

}

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

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

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

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

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

  5、单链表的反转

  6、从尾到头打印单链表

  7、判断单链表是否有环

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

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

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

 

 

  

以上是关于数据结构和算法--链表一之单向链表的简单实现的主要内容,如果未能解决你的问题,请参考以下文章

Day557.单向环形链表 -数据结构和算法Java

JavaScript数据结构与算法 单向链表

数据结构与算法什么是链表?并用代码手动实现一个单向链表

双向链表的实现(双向链表与单向链表的简单区别联系和实现)

双向链表的实现(双向链表与单向链表的简单区别联系和实现)

数据结构与算法学习-单向链表的实现