数据结构 -- 链式存储

1.特点

    通过指针连接起来的结点存储数据元素;

2. 节点结构由数据域和指针域组成

   

3.分类

  3.1 单链表

    

   说明,头部指向第一个元素的地址,第一个元素指针域指向第二个元素,依次指向,最后一个元素指针域为空,没有指向其它元素,这样的节点通过指针域构成起来的链表称为单链表

3.2 循环链表

  最后一个元素的指针域指向头部构成一个元素链表

 3.3 双链表

    

   有两个指针域,记住前一个元素的地址和后一个元素的地址,可以从双向遍历元素,相比于单链表遍历方式增加灵活性,但是占用多一个指针域空间

4.单链表插入和删除示意图

 4.1 在单链表中插入结点

   插入新元素c,把a元素的指针域指向c元素,把c元素的指针指向b元素

 4.2 单链表中删除元素

  

   删除b元素,a元素指向b元素的指针改成指向c元素

5.Java语言实现链式

 5.1 说明:定义一个静态内部类Node,称为结点,结点与结点相连在一起构成链式数据结构,每个结点有两个数据域,一个指向数据,另一个指向另外一个结点

5.2 在包中定义一个静态内部类

/**
 * 定义一个嵌套类,嵌套类与内部类的区别在于嵌套类是静态,内部类不是静态
 * @param <E>
 */
private static class Node<E> {
    /**
     * 指向对象一个引用,结点的数据部分
     */
    E data;
    /**
     * 指向下一个结点引用
     */
    Node next;
    public Node(E data, Node next) {
        this.data = data;
        this.next = next;
    }
}

5.3 外部类添加方法

/**
 * 添加元素方法
 * @param e
 * @return
 */
public boolean add(E e){
    //创建一个新结点,数据域保持数据对象
    Node<E> newNode = new Node<>(e);
    //记下前面一个结点地址
    newNode.next = first;
    //把当前结点赋给头结点
    first = newNode;
    size ++;
    return true;
}

 测试效果如下:

  

 封装的数据格式如下:  

6.简单代码示意

public class CustomLinkedList<E> {

    /**
     * 头引用,指向第一个元素
     */
    private Node first;

    /**
     * 记录元素的个数
     */
    private int size;


    /**
     * 添加元素方法
     * @param e
     * @return
     */
    public boolean add(E e){
        //创建一个新结点,数据域保持数据对象
        Node<E> newNode = new Node<>(e);
        //记下前面一个结点地址
        newNode.next = first;
        //把当前结点赋给头结点
        first = newNode;
        size ++;
        return true;
    }

    public Object[] toArray(){
        Object[] result = new Object[size];
        int i = 0;
        for(Node<E> e = first;e != null; e = e.next){
            result[i++] = e.data;
        }
        return result;
    }

    /**
     * 判断结点链中数据域是否等于给定的值
     * @param e
     * @return
     */
    public boolean contains(E e){
        if(e == null){
            return false;
        }
        boolean found = false;
        Node<E> currentNode = first;
        while(!found && currentNode != null){
            if(e.equals(currentNode.data)){
                found = true;
            }else {
             currentNode = currentNode.next;
            }
        }
        return found;
    }

    /**
     * 基本思路是删除一个结点,并将头引入指向第二结点
     * @return
     */
    public E remove(){
        E result = null;
        if(first != null){
            //读取头结点数据域
            result = (E)first.data;
            //将头结点指向第二个结点
            first = first.next;
            size --;
        }
        return result;
    }

    /**
     * 1.用链中的第一个结点数据域替换要移除值所在的结点
     * 2.从链中删除第一个结点
     * @param e
     * @return
     */
    public boolean remove(E e){
        boolean result = false;
        Node<E> currentElementNode = getReferenceNode(e);
        if( currentElementNode != null){
            //当前结点数据域保持第一个结点数据域
            currentElementNode.data = (E)first.data;
            //移除第一个结点
            first = first.next;
            size --;
            result = true;
        }
        return result;
    }

    /**
     * 清空链表
     */
    public void clear(){
        while (!isEmpty()){
            remove();
        }
    }

    /**
     * 判断是否为空
     * @return
     */
    public boolean isEmpty(){
        return size == 0;
    }

    /**
     * 根据给定的元素,获取该元素在链中的结点引用
     * @param e
     * @return
     */
    private Node<E> getReferenceNode(E e){
        boolean found = false;
        Node<E> currentNode = first;
        while (!found && currentNode != null){
            if(e.equals(currentNode.data)){
                found = true;
            }else {
                currentNode = currentNode.next;
            }
        }
        return currentNode;
    }


    /**
     * 定义一个嵌套类,嵌套类与内部类的区别在于嵌套类是静态,内部类不是静态
     * @param <E>
     */
    private static class Node<E> {
        /**
         * 指向对象一个引用,结点的数据部分
         */
        E data;
        /**
         * 指向下一个结点引用
         */
        Node next;

        public Node(E data) {
            this.data = data;
        }

        public Node(E data, Node next) {
            this.data = data;
            this.next = next;
        }
    }
}

猜你喜欢

转载自blog.csdn.net/weixin_40333020/article/details/88363361