首页 > 编程语言 > 详细

数据结构学习笔记(一)数组

时间:2019-01-13 19:56:47      阅读:160      评论:0      收藏:0      [点我收藏+]

基本概念

所谓数组,是有序的元素序列。也就是把数据码成一排存放的一种结构。

最大的优点

快速查询,根据索引可以快速查找相应的元素

二次封装自己的数组

一个数组应该具备的功能(并不固定,还可以扩充一些功能)

  • 获取数组的初始容量
  • 获取数组中元素的个数
  • 判断数组是否为空
  • 添加元素
    • 在数组首部添加元素
    • 在数组尾部添加元素
    • 在数组指定位置添加元素
  • 删除元素
    • 删除数组首部元素
    • 删除数组尾部元素
    • 删除数组指定位置元素
    • 删除数组中某一个元素
  • 修改元素
  • 查找元素
    • 判断元素是否存在
    • 查找元素对应的索引
/**
 * 动态数组--泛型使其支持任意类型的数据
 * @param <E>
 */
public class Array<E> {
    private E[] data;
    private int size;//数组中元素的个数

    //构造函数--创建一个指定容量的数组
    public Array(int capacity) {
        data = (E[]) new Object[capacity];
        size = 0;
    }

    //无参构造--默认创建一个容量为10的数组
    public Array() {
        this(10);
    }

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

    //获取数组的容量
    public int getCapacity() {
        return data.length;
    }

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

    //在数组尾部添加元素
    public void addLast(E e) {
        add(size, e);
    }

    //在数组首部添加元素
    public void addFirst(E e) {
        add(0, e);
    }

    //在指定位置添加元素
    public void add(int index, E e) {
        if (size == data.length)
            resize(2 * data.length);    //扩容2倍大小--思路就是把原来数组中的数据放到一个新的数组中
        if (index < 0 || index > size)
            throw new IllegalArgumentException("add fail, Required index >=0 && index <=size");
        for (int i = size - 1; i >= index; i--)
            data[i + 1] = data[i];

        data[index] = e;
        size++;
    }

    //查询数组某个位置的元素
    public E get(int index) {
        if (index < 0 || index > size)
            throw new IllegalArgumentException("get fail, index is illegal");
        return data[index];
    }

    //设置数组某个位置的元素
    public void set(int index, E e) {
        if (index < 0 || index >= size)
            throw new IllegalArgumentException("set fail, index is illegal");
        data[index] = e;
    }

    //查询数组中是否存在元素e
    public boolean contains(E e) {
        for (int i = 0; i < size; i++) {
            if (data[i] == e)
                return true;
        }
        return false;
    }

    //查询数组中是否存在元素e 存在则返回第一个索引
    public int find(E e) {
        for (int i = 0; i < size; i++) {
            if (data[i].equals(e))
                return i;
        }
        return -1;
    }

    //查询数组中是否存在元素e 存在则返回全部索引
    public int findAll(E e) {
        return -1;
    }

    //删除数组中index位置的元素并返回
    public E remove(int index) {
        if (index < 0 || index >= size)
            throw new IllegalArgumentException("remove fail, index is illegal");
        E ret = data[index];
        for (int i = index + 1; i < size; i++)
            data[i - 1] = data[i];
        size--;

        data[size] = null;//使用泛型后 数组中size位置存放的是类对象的引用 手动释放空间

        if (size == data.length / 4 && data.length / 2 !=0)    //防止复杂度震荡--以及数组长度为1的情况--在数组满的情况添加元素后又删除元素
            resize(data.length / 2);  //缩容

        return ret;
    }

    //删除数组中第一个元素
    public E removeFirst() {
        return remove(0);
    }

    //删除数组中最后一个元素
    public E removeLast() {
        return remove(size - 1);
    }

    //数组中如果存在一个元素,则进行删除一个
    public void removeElement(E e) {
        int index = find(e);
        if (index != -1)
            remove(index);
    }

    //数组中如果存在元素,则进行全部删除
    public void removeAllElement(E e) {
        int index;
        do {
            index = find(e);
            if (index != -1)
                remove(index);
        } while (index != -1);

    }

    //重写toString方法
    @Override
    public String toString() {
        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;
    }
}

复杂度分析

什么是时间复杂度这里看另外一篇文章https://blog.csdn.net/qq_41523096/article/details/82142747

  • 添加元素---O(n)-------复杂度分析一般考虑最坏的情况
    • 在数组首部添加元素---addFirst(e)---O(n)---因为向数组头添加元素 需要把每个元素向后挪
    • 在数组尾部添加元素---addLast(e)---O(1)  
    • 在数组指定位置添加元素--add(index,e)---O(n/2)=O(n)---平均的情况下添加元素每次需要挪n/2个元素
    • 扩容resize()---O(n)--最坏情况
  • 删除元素---O(n)
    • 删除数组首部元素---removeFirst()---O(n)
    • 删除数组尾部元素----removeLast(e)---O(1)  
    • 删除数组指定位置元素------remove(index,e)---O(n/2)=O(n)
    • 缩容resize()---O(n)--最坏情况
  • 修改元素---set(index,e)---已知索引是O(1)---未知索引是O(n)--因为需要遍历数组中每一个元素
  • 查找元素---已知索引是O(1)---未知索引是O(n)--因为需要遍历数组中每一个元素
    • 根据索引查找元素---get(index)--O(1)
    • 判断元素是否存在---contains(e)---O(n)---因为需要遍历数组中每一个元素
    • 查找元素对应的索引---find(e)---O(n)
  • 容量动态变化resize()--不应该考虑最坏情况,这是不合理的,因为不可能每次都触发这个方法--均摊复杂度

假设数组容量是8,使用addLast()方法需要9次操作才触发一次resize(转移8个元素到新数组),一共17次操作,相当于平均每次addLast,进行2次操作,所以均摊计算它的复杂度是O(1);

同理removeLast也是O(1); 同时考虑这两个方法,特殊情况当添加一个元素触发了扩容,然后有删除这个元素触发缩容,造成复杂度震荡.解决方法Lazy 也就是缩容的时候不用那么急

 

数据结构学习笔记(一)数组

原文:https://www.cnblogs.com/phperpxy/p/10263698.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!