初识数据结构

本文详细介绍了如何实现动态数组Array,包括构造函数、添加、删除等操作,并探讨了栈和队列的接口设计及循环队列的高效实现。此外,还展示了链表LinkedList的构造及其基本操作。这些数据结构在Java中的实现有助于理解数据结构的底层原理。
摘要由CSDN通过智能技术生成

数组Array:

        自己实现数组,依托的还是jdk底层的静态数组E[] data,数组的实际元素个数用size变量维护;

import java.util.ArrayList;
import java.util.Arrays;

public class Array<E> {

//    private int[] data;  // 现在只能承载int型数据
    private E[] data;     // 现在可以承载引用数据类型数据
    private int size;    // 用来描述我的数组中到底有多少个有效的数据

    // 构造函数,传入数组的容量capacity构造Array
    public Array(int capacity){
        data = (E[])new Object[capacity];
        size = 0;
    }
    // 无参构造,默认数组的容量capacity=10
    public Array(){
        this(10);
    }

    //获得数组中元素个数
    public int getSize(){
        return size;
    }

    //获得数组整体容量
    public int getCapacity(){
        return data.length;
    }

    //返回数组是否为空
    public boolean isEmpty(){
        return size == 0;
    }

    // 尾插 O(1)
    public void addLast(E e){
//        if (size == data.length){
//            throw new IllegalArgumentException("数组已满");
//        }
//        // data[size++] = e;
//        data[size] = e;
//        size++;
        add(size,e);
    }


    //头插 O(n)
    public void addFirst(E e){
        add(0,e);
    }

    // 向指定位置添加元素 O(n/2)=>O(n);忽略常数项
    public void add(int index, E e){
       // 对index合法性判断
       if (index < 0 || index > size){
           throw new IllegalArgumentException("index >= 0 and index <= size");
       }
        // 数组容量是否足够
        if (size == data.length){
//            throw new IllegalArgumentException("数组已满");
            resize(2*data.length);
        }
       for (int i = size - 1; i >= index;i--){
           data[i+1] = data[i];
       }
       data[index] = e;
       size++;
    }

    // 获取index索引位置的元素O(1)
    E get(int index){
        if (index < 0 || index >= size){
            throw new IllegalArgumentException("get failed index is illegal");
        }
        return data[index];
    }

    // 修改操作 O(1)
    void set(int index, E e){
        if (index < 0 || index >= size){
            throw new IllegalArgumentException("get failed index is illegal");
        }
        data[index] = e;
    }

    // 查找数组中是否包含元素e
    // O(n)
    public boolean contains(E e){
        for (int i = 0;i<size;i++){
            if (data[i].equals(e)){
                return true;
            }
        }
        return false;
    }

    // 查找数组中元素e所在的索引,如果不存在元素e,则返回-1
    // O(n)
    public int find(E e){
        for (int i = 0;i<size;i++){
            if (data[i].equals(e)){
                return i;
            }
        }
        return -1;
    }

    //从数组中删除index位置的元素,返回删除的元素
    public E remove(int index){
        if (index < 0 || index >= size){
            throw new IllegalArgumentException("get failed index is illegal");
        }
        E ret = data[index];
        for (int i =index +1;i<size;i++)
            data[i-1] = data[i];
        size--;
        data[size] = null;  // 被垃圾回收掉 loitering objects
        if (size == data.length / 4 && data.length / 2 != 0){
            resize(data.length / 2);
        }
        return ret;
    }
    //从数组中删除第一个位置的元素,返回删除的元素
    public E removeFirst(){
        return remove(0);
    }

    //从数组中删除最后位置的元素,返回删除的元素
    public E removeLast(){
        return remove(size-1);
    }

    // 从数组中删除元素e
    public void removeElement(E e){
        int index = find(e);
        if(index != -1)
            remove(index);
    }

    @Override
    public String toString() {
//        return "Array{" +
//                "data=" + Arrays.toString(data) +
//                ", size=" + size +
//                '}';
        StringBuilder res = new StringBuilder();
        res.append(String.format("Array: size = %d , capacity = %d\n",size,data.length));
        res.append('[');
        for (int i = 0; i<size;i++){
            res.append(data[i]);
            if (i != size -1){
                res.append(", ");
            }
        }
        res.append(']');
        return res.toString();
    }

    private void resize(int newCapacity){
        E[] newData = (E[])new Object[newCapacity];
        for (int i = 0;i<size;i++)
            newData[i] = data[i];
        data = newData;
    }
}

栈Stack:

        先进后出FILSO,所有的操作时间复杂度都是O(1)

public interface Stack<E> {

    /**
     * 获得栈中元素个数
     */
    int getSize();

    /**
     * 判断栈是否为空
     */
    boolean isEmpty();

    /**
     *压栈操作,添加元素
     */
    void push(E e);

    /**
     * 弹栈操作,取出元素
     */
    E pop();

    /**
     * 看一下栈顶的元素
     */
    E peek();
}

队列Queue:

        队列和栈所定义的接口方法一致,玩法不一致的地方就是队列是先进先出FIFO,如果使用上面自定义的Array动态数组做队列实现,出队的操作是O(n)的复杂度,所以设计一个循环队列,队首元素出队之后,不需要移动元素,这时候队列的所有操作的时间复杂度也是O(1)。

public interface Queue<E> {

    /**
     * 得到队列的大小
      */
    int getSize();

    /**
     * 判断队列是否为空
      */
    boolean isEmpty();

    /**
     *添加元素 
      */
    void enqueue(E e);

    /**
     * 取出元素
      */
    E dequeue();

    /**
     * 得到队列第一个元素
      */
    E getFront();
}

循环队列的实现:

public class LoopQueue<E> implements Queue<E> {

    private E[] data;
    private int front,tail;
    private int size;

    public LoopQueue(int capacity){
//        E[] data = (E[])new Object[capacity+1];  如果这么写,该变量仅仅存在这个方法内,不会被赋为全局变量
         data = (E[])new Object[capacity+1];
        front = 0;
        tail = 0;
        size = 0;
    }

    public LoopQueue(){
        this(10);
    }

    public int getCapacity(){
        return data.length - 1;
    }

    @Override
    public int getSize() {
        return size;
    }

    @Override
    public boolean isEmpty() {
        return front == tail;
    }

    @Override
    public void enqueue(E e) {
        if ((tail + 1) % data.length == front){
            resize(getCapacity() * 2);
        }
        data[tail] = e;
        tail = (tail + 1) % data.length;
        size++;
    }

    private void resize(int newCapacity){
        E[] newData = (E[])new Object[newCapacity +1];
        for (int i = 0;i<size;i++){
            newData[i] = data[(i+front)%data.length];
        }
        data = newData;
        front = 0;
        tail = size;
    }

    @Override
    public E dequeue() {
        if (isEmpty()){
            throw new IllegalArgumentException("队列中没有元素可供删除");
        }
        E ret = data[front];
        data[front] = null;
        front = (front +1) % data.length;
        size--;
        if (size == getCapacity() / 4 && getCapacity() / 2 != 0)
            resize(getCapacity() / 2);
        return null;
    }

    @Override
    public E getFront() {
        if (isEmpty()){
            throw new IllegalArgumentException("队列中没有元素可供删除");
        }
        return data[front];
    }

    @Override
    public String toString(){
        StringBuilder res = new StringBuilder();
        res.append(String.format("Queue: size = %d, capacity = %d\n",size,getCapacity()));
        res.append("front [");
        for (int i = front;i != tail ;i=(i+1) % data.length){
            res.append(data[i]);
            if ((i + 1) % data.length != tail)
                res.append(", ");
        }
        res.append("] tail");
        return res.toString();
    }

    public static void main(String[] args) {
        LoopQueue<Integer> queue = new LoopQueue<>();
        for (int i = 0;i<10;i++){
            queue.enqueue(i);
            System.out.println(queue);

            if (i % 3 == 2){
                queue.dequeue();
            }
        }
    }
}

力扣上的list 

public class ListNode {
      int val;
      ListNode next;

      ListNode() {}
      ListNode(int val) { this.val = val; }
      ListNode(int val, ListNode next) { this.val = val; this.next = next; }

      // 数组转链表(链表的构造函数)
      public ListNode(int[] arr){
          if (arr == null || arr.length == 0){
              throw new IllegalArgumentException("arr cannot be empty");
          }
          this.val = arr[0];
          ListNode cur = this;
          for (int i = 1;i<arr.length;i++){
              cur.next = new ListNode(arr[i]);
              cur = cur.next;
          }
      }

      @Override
      public String toString(){
          StringBuilder res = new StringBuilder();
        ListNode cur = this;
        while(cur != null){
            res.append(cur.val + "->");
            cur = cur.next;
        }
          res.append("NULL");
          return res.toString();
      }
  }

链表LinkedList:

        底层就是维护了一个内部类Node,Node有2个成员变量,一个存放数据的节点E e,还有个就是下一个节点的引用Node next(新new对象的引用,实际上就是这个对象在栈中的地址【指针】)

public class LinkedList<E> {

//    java.util.LinkedList
    private class Node{
        public E e;             // 元素
        public Node next;       // 指针 就是下一个元素的引用

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

        public Node(E e){
            this(e,null);
        }

        public Node(){
            this(null,null);
        }

        @Override
        public String toString(){
            return e.toString();
        }
    }

//    private Node head;
    private Node dummyHead;     // 虚拟头结点
    private int size;

    public LinkedList(){
        dummyHead = new Node(null,null);
        size = 0;
    }

    //链表中元素个数
    public int getSize(){
        return size;
    }

    // 返回链表是否为空
    public boolean isEmpty(){
        return size == 0;
    }

    //
//    public void add(int index,E e){
//        if(index < 0 || index > size)
//            throw new IllegalArgumentException("索引越界");
//        if (index == 0)
//            addFirst(e);
//        else {
//            Node prev = head;
//            for (int i = 0;i<index;i++)
//                prev = prev.next;
//
//            prev.next = new Node(e, prev.next);
//            size++;
//        }
//    }

    public void add(int index,E e){
        if(index < 0 || index > size)
            throw new IllegalArgumentException("索引越界");
        Node prev = dummyHead;
        for (int i = 0;i<index;i++)
            prev = prev.next;

        prev.next = new Node(e, prev.next);
        size++;
    }

    // 头添加
    public void addFirst(E e){
//        Node node = new Node(e);
//        node.next = head;
//        head = node;

//        head = new Node(e, head);
//        size++;
        add(0,e);
    }

    // 尾添加
    public void addLast(E e){
        add(size,e);
    }

    // 获得
    public E get(int index){
        if(index < 0 || index > size)
            throw new IllegalArgumentException("索引越界");
        Node cur = dummyHead.next;
        for (int i = 0;i<index;i++)
            cur = cur.next;
        return cur.e;
    }

    public E getFirst(){
        return get(0);
    }

    public E getLast(){
        return get(size - 1);
    }

    public void set(int index, E e){
        if(index < 0 || index > size)
            throw new IllegalArgumentException("索引越界");

        Node cur = dummyHead.next;
        for (int i=0;i<index;i++)
            cur = cur.next;
        cur.e = e;
    }

    // 是否包含
    public boolean contains(E e){
        Node cur = dummyHead.next;
        while(cur != null){
            if (cur.e.equals(e))
                return true;
            cur = cur.next;
        }
        return false;
    }

    // 删除元素
    public E remove(int index){
        if(index < 0 || index >= size)
            throw new IllegalArgumentException("索引越界");
        Node prev = this.dummyHead;
        for (int i=0;i<index;i++)
            prev = prev.next;
        Node retNode = prev.next;
        prev.next = retNode.next;
        retNode.next = null;
        size--;
        return retNode.e;
    }

    public E removeFirst(){
        return remove(0);
    }

    public E removeLast(){
        return remove(size - 1);
    }

    @Override
    public String toString(){
        StringBuilder res = new StringBuilder();
//        Node cur = dummyHead.next;
//        while(cur != null){
//            res.append(cur + "->");
//            cur = cur.next;
//        }
        for (Node cur = dummyHead.next;cur != null;cur = cur.next)
            res.append(cur + "->");
        res.append("NULL");
        return res.toString();
    }

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值