1、数据结构

栈结构 

  • 栈的定义:

           栈结构是一种只能从一端存取数据并且遵循“后进先出(LIFO)”原则的线性存储结构。

  • 实现栈容器

package www.reptile.com;

import java.util.Arrays;
import java.util.EmptyStackException;

/**
 * TODO
 *
 * @author dang
 * @date 2022/1/25 16:59
 */
public class Stack<E> {

    /**
     * 初始化一个物理容器
     */
    private Object[] arr;

    /**
     * 初始化栈容器的大小
     */
    private int stackLength = 4;

    /**
     * 数组的长度
     */
    private int size;

    /**
     * 初始化指针
     */
    private int index = -1;


    /**
     * 判断栈容器是否为空
     *
     * @return
     */
    public boolean empty() {
        return this.size == 0;
    }

    /**
     * 获取栈顶元素
     *
     * @return
     */
    public E pop() {
        if (this.index == -1) {
            throw new EmptyStackException();
        }
        this.size--;
        return (E) this.arr[this.index--];

    }

    /**
     * 添加元素
     *
     * @param element
     * @return
     */
    public E push(E element) {
        //初始化数组或者以1.5倍进行扩容
        this.capacity();
        //向容器中添加元素
        this.arr[++this.index] = element;
        //记录容器大小
        this.size++;
        return element;
    }

    /**
     * 初始化数组或者以1.5倍进行扩容
     */
    private void capacity() {
        if (this.arr == null) {
            this.arr = new Object[this.stackLength];
        } else {
            if (this.size - (this.stackLength - 1) >= 0) {
                this.stackLength = this.stackLength + (this.stackLength >> 1);
                this.arr = Arrays.copyOf(this.arr, this.stackLength);
            }
        }
    }


    public static void main(String[] args) {
        Stack<String> stack = new Stack<String>();
        stack.push("a");
        stack.push("b");
        stack.push("c");
        stack.push("d");
        stack.push("e");
        System.out.println(stack.size);
        System.out.println(stack.pop());
        System.out.println(stack.pop());
        System.out.println(stack.pop());
        System.out.println(stack.empty());
    }

}

链表结构

定义:

  1. 链表结构是由许多节点构成,每个节点包含两个部门:
  •   数据部分:保存该节点的实际数据。
  •   地址部分:保存的是上一个或下一个节点的地址。

分类:

  • 单向链表结构
  • 双向链表结构
  • 双向循环链表结构

特点:

  • 节点在存储容器中的位置是任意的,不像数组这个数据结构是连续存储,即逻辑上相邻的数据元素在物理上不一定相邻。
  • 访问时只能通过头指针或者尾部指针进入链表,并通过每个节点的指针域向前或向后扫描其余节点,所以寻找第一个节点和最后一个节点所花费的时间不等,所以查询效率较为低下。
  • 优点:数据元素的个数可以自由扩充、插入、删除等操作不需要移动数据,只需要修改前后节点的指针地址即可,修改效率较高。
  • 缺点:必须采用顺序存储,即存取数据元素时,只能按照链表的顺序进行访问,访问节点效率低。

单向链表

定义:

单向链表是链表的一种,其特点是链表的链接方向是单向的,对链表的访问要通过从头开始顺序读取。

 示例:

package www.reptile.com;

/**
 * TODO
 *
 * @author DangWangYi
 * @date 2022/1/25 15:43
 */
public interface List<E> {

    /**
     * 获取元素的个数
     *
     * @return
     */
    int size();

    boolean isEmpty();

    /**
     * 添加元素
     *
     * @param element
     */
    void add(E element);

    /**
     * 根据元素位置获取元素
     *
     * @param index
     * @return
     */
    E get(int index);

    /**
     * 根据元素位置删除元素
     *
     * @param index
     * @return
     */
    E remove(int index);
}

package www.reptile.com;

/**
 * TODO 单向链表数据结构
 *
 * @author DangWangYi
 * @date 2022/1/25 15:50
 */
public class SingleLinkedList<E> implements List<E> {

    /**
     * 头节点
     */
    private Node<E> head;

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


    /**
     * 获取元素的个数
     *
     * @return
     */
    @Override
    public int size() {
        return this.size;
    }


    @Override
    public boolean isEmpty() {
        return this.size() == 0;
    }

    /**
     * 添加元素
     *
     * @param element
     */
    @Override
    public void add(E element) {
        //创建节点
        Node<E> node = new Node<E>(element, null);
        //找到尾结点
        Node tailNode = getTailNode();
        //节点挂接
        if (tailNode == null) {
            this.head = node;
        } else {
            tailNode.next = node;
        }
        //记录元素个数
        this.size++;
    }

    /**
     * 找到尾结点
     *
     * @return
     */
    private Node getTailNode() {
        //判断头节点是否存在
        if (this.head == null) {
            return null;
        }
        Node<E> node = this.head;
        while (true) {
            //当当前节点的下一个节点为空退出循环
            if (node.next == null) break;
            node = node.next;//当前节点的下一个节点
        }
        return node;
    }

    /**
     * 根据元素位置获取元素
     *
     * @param index
     * @return
     */
    @Override
    public E get(int index) {
        //校验指针的合法性
        this.checkIndex(index);
        //根据指针位置获取节点
        Node<E> node = getNode(index);
        //将该节点的元素返回
        return node.item;
    }

    /**
     * 根据指针获取节点
     *
     * @param index
     * @return
     */
    private Node<E> getNode(int index) {
        Node<E> node = this.head;
        for (int i = 0; i < index; i++) {
            node = node.next;
        }
        return node;
    }

    /**
     * 校验指针的合法性
     */
    private void checkIndex(int index) {
        if (index < 0 || index >= size) {
            throw new IndexOutOfBoundsException("Index: " + index + ", Size: " + this.size);
        }
    }

    /**
     * 根据元素位置删除元素
     *
     * @param index
     * @return
     */
    @Override
    public E remove(int index) {
        //校验指针的合法性
        this.checkIndex(index);
        //根据指针获取对应的节点
        Node<E> node = this.getNode(index);
        //获取该节点对象中的元素
        E item = node.item;
        //将该对象从单项列表中移除
        if (this.head == node) {
            this.head = node.next;
        } else {
            Node<E> temp = this.head;
            for (int i = 0; i < index - 1; i++) {
                temp = temp.next;
            }
            temp.next = node.next;
        }
        node.next = null;
        //记录元素个数
        this.size--;
        return item;
    }


    /**
     * 定义单项列表节点对象
     */
    class Node<E> {
        /**
         * 当前节点元素
         */
        private E item;

        /**
         * 当前节点的下一个节点
         */
        private Node<E> next;

        Node(E item, Node<E> next) {
            this.item = item;
            this.next = next;
        }
    }


    public static void main(String[] args) {
        List<Integer> list = new SingleLinkedList<Integer>();
        list.add(1);
        list.add(2);
        list.add(3);
        list.add(4);
        System.out.println(list.remove(0));
        System.out.println(list.size());
        for (int i = 0; i < list.size(); i++) {
            System.out.println(list.get(i));
        }
    }
}

双向链表

定义:

双向链表也叫双链表,是链表的一种,它的每个数据结点中都有两个指针,分别指向直接后继和直接前驱。所以,从双向链表中的任意一个结点开始,都可以很方便地访问它的前驱结点和后继结点。

 示例:

package www.reptile.com;

/**
 * TODO 双向链表数据结构
 *
 * @author DangWangYi
 * @date 2022/1/25 15:52
 */
public class DoubleLinkedList<E> implements List<E> {

    private Node<E> head; //记录头节点

    private Node<E> tail; //记录尾节点

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


    @Override
    public int size() {
        return this.size;
    }

    @Override
    public boolean isEmpty() {
        return this.size() == 0;
    }

    @Override
    public void add(E element) {
        this.linkLast(element);
    }

    /**
     * 将节点对象添加到双向列表的尾部
     */
    public void linkLast(E element) {
        //获取尾节点
        Node<E> tail = this.tail;
        //创建节点对象
        Node<E> node = new Node<E>(tail, element, null);
        //将新节点定义为尾部节点
        this.tail = node;
        if (tail == null) {
            this.head = node;
        } else {
            tail.nextNode = node;
        }
        this.size++;
    }

    @Override
    public E get(int index) {
        //校验指针的合法性
        this.checkIndex(index);
        //根据指针查找节点对象
        Node<E> node = getNode(index);
        return node.item;
    }

    /**
     * 根据指针查找节点对象
     *
     * @param index
     * @return
     */
    private Node<E> getNode(int index) {
        if (index < this.size >> 1) {
            Node<E> node = this.head;
            for (int i = 0; i < index; i++) {
                node = node.nextNode;
            }
            return node;
        } else {
            Node<E> node = this.tail;
            for (int i = this.size - 1; i > index; i--) {
                node = node.prevNode;
            }
            return node;
        }
    }

    /**
     * 校验指针的合法性
     *
     * @param index
     */
    private void checkIndex(int index) {
        if (index < 0 || index >= this.size) {
            throw new IndexOutOfBoundsException("Index: " + index + ",Size: " + this.size);
        }
    }

    @Override
    public E remove(int index) {
        //校验指针合法性
        this.checkIndex(index);
        //根据位置获取节点对象
        Node<E> node = this.getNode(index);
        //获取节点对象中的元素
        E item = node.item;
        //判断当前节点是否为头节点
        if (node.prevNode == null) {
            this.head = node.nextNode;
        } else {
            node.prevNode.nextNode = node.nextNode;
        }
        if (node.nextNode == null) {
            this.tail = node.prevNode;
        } else {
            node.nextNode.prevNode = node.prevNode;
        }
        node.prevNode = null;
        node.nextNode = null;
        node.item = null;
        this.size--;
        return item;
    }


    /**
     * 在链表的头部添加元素
     *
     * @param element
     */
    public void addLinkFirst(E element) {
        Node<E> head = this.head;
        Node<E> node = new Node<E>(null, element, head);
        this.head = node;
        if (head == null) {
            this.tail = node;
        } else {
            head.prevNode = node;
        }
        this.size++;
    }

    /**
     * 在链表的尾部添加元素
     *
     * @param element
     */
    public void addLinkLast(E element) {
        this.linkLast(element);
    }

    /**
     * 定义双向链表的节点的对象
     *
     * @param <E>
     */
    class Node<E> {
        /**
         * 记录前一个节点对象
         */
        private Node<E> prevNode;

        /**
         * 当前元素
         */
        private E item;

        /**
         * 记录后一个节点对象
         */
        private Node<E> nextNode;

        Node(Node<E> prevNode, E item, Node<E> nextNode) {
            this.prevNode = prevNode;
            this.item = item;
            this.nextNode = nextNode;
        }
    }

    public static void main(String[] args) {
        List<String> list = new DoubleLinkedList<String>();
        list.add("a");
        list.add("b");
        list.add("c");
        list.add("d");
        System.out.println(list.remove(2));
        System.out.println(list.size());
        ((DoubleLinkedList<String>) list).addLinkFirst("A");
        for (int i = 0; i < list.size(); i++) {
            System.out.println(list.get(i));
        }
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值