顺序存储和链式存储的基本实现

顺序存储结构

数组:一组连续的数,以下标为索引,在内存中是连续的



import java.util.Arrays;

/**
 * 面向对象的数组
 * 扩展:集合的底层实现原理
 */
public class Demo {

    private int[] elements;

    public Demo() {
        elements = new int[0];
    }

    /**
     * 获取数组的长度
     *
     * @return
     */
    public int size() {
        return elements.length;
    }

    /**
     * 往数组中添加一个元素
     *
     * @param val
     */
    public void add(int val) {
        int[] newArray = new int[elements.length + 1];
        for (int i = 0; i < elements.length; i++) {
            newArray[i] = elements[i];
        }
        newArray[newArray.length - 1] = val;
        elements = newArray;
    }

    /**
     * 删除某个元素
     *
     * @param index 删除元素的下标,从0开始
     */
    public void remove(int index) {

        if (index < 0 || index > elements.length - 1) {
            throw new RuntimeException("数组下标越界");
        }

        int[] newArray = new int[elements.length - 1];

        for (int i = 0; i < newArray.length; i++) {
            if (i < index) {
                newArray[i] = elements[i];
            } else {
                newArray[i] = elements[i + 1];
            }
        }

        elements = newArray;

    }

    /**
     * 向指定位置插入一个元素
     *
     * @param val   插入的值
     * @param index 插入的位置 从0开始
     */
    public void insert(int val, int index) {

        if (index < 0 || index > elements.length - 1) {
            throw new RuntimeException("数组下标越界");
        }

        int[] newArray = new int[elements.length + 1];

        for (int i = 0; i < newArray.length; i++) {
            if (i < index) {
                newArray[i] = elements[i];
            } else if (i == index) {
                newArray[i] = val;
            } else {
                newArray[i] = elements[i - 1];
            }
        }

        elements = newArray;
    }

    /**
     * 打印数组
     */
    public void print() {
        System.out.println(Arrays.toString(elements));
    }


}

栈:一组连续的数,区分于数组的点在于其数据遵循先进后出的原则



public class Demo {

    private int[] elements;

    public Demo() {
        elements = new int[0];
    }

    /**
     * 压入一个数据
     *
     * @param val
     */
    public void push(int val) {

        int[] array = new int[elements.length + 1];

        for (int i = 0; i < elements.length; i++) {
            array[i] = elements[i];
        }

        array[array.length - 1] = val;
        elements = array;

    }

    /**
     * 取出栈顶元素
     */
    public int pop() {

        if (elements.length == 0) {
            throw new RuntimeException("stack is empty");
        }

        int[] array = new int[elements.length - 1];

        for (int i = 0; i < array.length; i++) {
            array[i] = elements[i];
        }

        int result = elements[elements.length - 1];

        elements = array;

        return result;

    }

    /**
     * 查看栈顶元素
     *
     * @return
     */
    public int peek() {

        if (elements.length == 0) {
            throw new RuntimeException("stack is empty");
        }
        return elements[elements.length - 1];
    }


}

队列:一组连续的数,其特点是先进先出

/**
 * 队列
 *
 * 其特点是先进先出
 */
public class Queue {

    private int[] elements;

    public Queue() {
        elements = new int[0];
    }


    /**
     * 入队
     *
     * @param val
     */
    public void add(int val) {

        int[] array = new int[elements.length + 1];

        for (int i = 0; i < elements.length; i++) {
            array[i] = elements[i];
        }

        array[array.length - 1] = val;
        elements = array;

    }

    /**
     * 出队
     *
     * @return
     */
    public int poll() {

        if (elements.length <= 0) {
            throw new RuntimeException("queue is empty");
        }

        int element = elements[0];

        int[] array = new int[elements.length - 1];

        for (int i = 0; i < array.length; i++) {
            array[i] = elements[i + 1];
        }

        elements = array;

        return element;

    }


}

链式存储结构

单链表:每一节点分成两部分,一部分存储本身的值另一部分存储下一个节点的地址

/**
 * 单链表
 * 链式存储结构,每一节点分成两部分,一部分存储本身的值另一部分存储下一个节点的地址
 * 扩展知识点:
 * 对于Java来说,所谓的地址其实就是对象本身,基本类型存储的是值,引用类型存储的都是地址
 * ,所以当前类的属性next是一个对象,但是我们说成存储的是下一个对象的地址
 */
public class Node {

    private int data;
    private Node next;//下一个对象的地址


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

    /**
     * 追加节点,
     */
    public Node append(Node next) {

        Node current = this;

        //如果当前节点有下一节点就一直循环,直到找到最后一个节点
        while (current.hasNext()) {
            current = current.next;
        }

        current.next = next;

        return current;
    }

    /**
     * 删除下一个节点,单链表只能删除下一个节点
     */
    public void removeNext() {
        //取出下下个节点
        Node node = next.next;
        //将下下个节点赋值给当前节点的下一个节点
        next = node;
    }

    /**
     * 插入一个节点,单链表只能往后插入一个新节点
     */
    public void insert(Node node){
        //下一节点作为当前节点的下一节点
        node.next = next;
        //要插入的节点作为当前节点的下一个节点
        this.next = node;
    }

    /**
     * 获取下一个节点
     */
    public Node next() {
        return next;
    }

    /**
     * 获取节点中的数据
     */
    public int getData() {
        return this.data;
    }

    /**
     * 判断当前节点是否是最后一个节点
     */
    public boolean hasNext() {
        return next != null;
    }

    /**
     * 打印所有节点
     *
     * @return
     */
    public void show() {

        Node current = this;

        while (current.hasNext()) {
            System.out.print(current.data + ",");
            current = current.next;
        }

        System.out.println(current.getData());

    }


}

循环单链表:和单链表唯一的区别就是最后一个节点指向第一个节点,所有数据形成一个闭环,不存在第一个节点和最后一个节点

/**
 * 循环链表
 * <p>
 * 和单链表唯一的区别就是最后一个节点指向第一个节点
 */
public class LoopNode {

    private int data;
    private LoopNode next = this;


    public LoopNode(int data) {
        this.data = data;
    }

    /**
     * 删除下一个节点
     */
    public void removeNext() {
        //取出下下个节点
        LoopNode node = next.next;
        //将下下个节点赋值给当前节点的下一个节点
        next = node;
    }

    /**
     * 插入一个节点
     */
    public void insert(LoopNode node) {
        //下一节点作为当前节点的下一节点
        node.next = next;
        //要插入的节点作为当前节点的下一个节点
        this.next = node;
    }

    /**
     * 获取下一个节点
     */
    public LoopNode next() {
        return next;
    }

    /**
     * 获取节点中的数据
     */
    public int getData() {
        return this.data;
    }


}

双链表:在单链表的基础上增加一部分用来存储上一个节点的地址

/**
 * 双向链表
 * 在单链表的基础上再增加一部分用来存储上一个节点的地址
 *
 * 当前类展示的是双向循环链表
 */
public class DoubleNode {

    private DoubleNode previous = this;
    private int data;
    private DoubleNode next = this;

    public DoubleNode(int data){
        this.data = data;
    }

    /**
     * 插入一个节点
     */
    public void insert(DoubleNode doubleNode){

        //当前节点的下一个节点的前一个节点为要插入的节点
        next.previous = doubleNode;
        //要插入的节点的下一个节点为当前节点的下一个节点
        doubleNode.next = next;
        //要插入节点的前一个节点为当前节点
        doubleNode.previous = this;
        //当前节点的下一个节点为要插入的节点
        this.next = doubleNode;

    }

    /**
     * 获取下一个节点
     */
    public DoubleNode next() {
        return next;
    }

    /**
     * 获取上一个节点
     */
    public DoubleNode previous(){
        return previous;
    }

    /**
     * 获取值
     */
    public int getData() {
        return data;
    }
}

综上就是数据存储的两种基本结构,顺序存储查询更快,链式存储增删更快。

发布了41 篇原创文章 · 获赞 26 · 访问量 3万+

猜你喜欢

转载自blog.csdn.net/weixin_40655220/article/details/104950464