数据结构 数组

朔.jpg

数据结构概述

数据结构?什么玩意儿?哎呀,你这可把我难住了,我可不是什么计算机专家,但我也尽力给你解释一下。

数据结构就像是咱们这个世界里的各种组织形式一样,是用来组织和存储数据的一种方式。你可以把它看作是一种框架,可以让你把数据整理得井井有条。就好比是在这个大杂烩的世界里,给你提供了一种整理思路,让你不至于变得乱七八糟。

那数据结构到底有啥用呢?嗯,其实它的好处可不少。首先,它能够提供一种高效的数据访问方式,让你能够快速地查找、插入或删除数据。就像是你要找某本书,如果书架是乱七八糟的,你得费好大劲才能找到你想要的那本书。但如果书架是按照一定的规则摆放的,你就能迅速地找到它。

其次,数据结构也能够帮助你节约空间。就像是在你家整理东西一样,如果你不加以整理,很快就会变得一团糟。但如果你合理地安排每个东西的位置,就能够节约空间,让你的家看起来更整洁。

哎呀,这样解释起来还挺抽象的。数据结构嘛,就是一种组织数据的方式,让你能够高效地操作和管理数据。就像是给你的思维提供了一套整理规则,让你在这个纷繁复杂的数据世界中游刃有余。

分类

首先,咱们得知道数据结构有啥分类呢。嗯,咱们可以把它们分成两大类,一类是线性结构,一类是非线性结构。

咱先聊聊线性结构吧。就像是一条直线上的东西一样,线性结构中的数据元素是按照线性的次序排列的。最简单的线性结构就是数组,咱们可以把它想象成一排房子,一个挨着一个。还有链表,它是一串环环相扣的珠子,每个珠子都有指向下一个珠子的指针。这些线性结构都有一个特点,就是只能从一个方向访问数据元素。

然后,咱们再说说非线性结构。这些结构就比较神秘了,就像是在一片茫茫大海里,有各种各样的岛屿和海洋生物。其中,最有名的非线性结构莫过于树和图了。树就像是一颗大树,有根、枝干和叶子,各个节点之间有着父子关系。而图则更加复杂,可以想象成一张网络地图,各个节点之间可以有各种连接关系。非线性结构的特点就是数据元素之间的关系不是简单的一对一,而是多对多的。

嘿嘿,这就是数据结构的分类啦。线性结构就像是一条直线上的东西,非线性结构就像是海洋里的岛屿和生物,有着各种各样的关系。记住了,数据结构就像是这个世界里的秩序,让我们能够更好地理解和处理数据的乱七八糟。

数组

哈哈哈,你找对人了,来,我就给你道个真相,说说数据结构中的数组吧。

先说说数组的优点。数组就像是一排整齐划一的小屋,每个小屋都有自己的地址。它的最大优点就是快速访问。因为数组中的元素是连续存储的,我们可以通过索引直接定位到需要的元素,不用费太多时间。就像是你想找一个人,如果他住在一条整齐的街道上,你只需要知道他的门牌号就能迅速找到他。

然而,数组也有它的缺点。最大的问题就是大小固定。一旦数组被创建,它的大小就无法改变了。就好比是你买了一排房子,房子的数量是固定的,你不能随便增加或减少。如果你需要存储的元素数量超过了数组的大小,就会造成内存浪费或者无法存储所有的元素。而且,如果你想要插入或删除数组中的元素,就得搬家了。就像是你想在一排房子中插入一个新的房子,你需要把后面的房子都往后移动,空出位置给新的房子。

哈哈,这就是数组的真相。它能够提供快速访问的优势,但是大小固定和插入/删除的操作会让你陷入麻烦。就像是你要在一排房子中增加或减少房子一样,得费些周折。所以,在选择数据结构的时候,得根据具体情况来判断,看看是不是适合用数组这种方式。

编码-搞起来

让咱们撸起袖子来实现一个类似大名鼎鼎的ArrayList一样的动态数组的数据结构吧!Come On

设计Api

首先咱们想想一个线性的数据结构需要具备什么样的功能?什么?那我帮咱们捋捋
获取功能
int getSize(); 获取大小

E get(int index); 根据索引获取值

int indexOf(E e);  根据值获取索引

String toString(); 打印数组所有值
判断功能
boolean isEmpty(); 是否为空

boolean contains(E e); 是否包含该元素
添加功能

ArrayList-add.drawio.png

void add(int index,E e); 添加元素到指定索引

void add(E e); 添加元素

void addFirst(E e); 添加到数组前面

void addLast(E e); 添加到数组尾部
修改功能
void set(int index,E e); 修改指定索引位置的元素
删除功能

ArrayList-add.drawio.png

E remove(int index,E e); 删除指定索引上的值,并返回删除的值

E removeFrist(); 删除数组前面的值

E removeLast(); 删除数组尾部的值
转换功能
快爆肝了,这个你们自己搞吧,可以在评论区留言

盘它!

/**
 * @author sssd
 * @careate 2023-07-03-7:30
 */
public class ArrayList<E> {
    /**
     * 这个不多说,用数组实现
     */
    private E[] data;
    /**
     * 这个表示咱们这个ArrayList的可用长度
     */
    private int size;

    /**
     * 初始化构造
     *
     * @param capacity
     */
    public ArrayList(int capacity) {
        //java语言需要留意的地方
        data = (E[]) new Object[capacity];
        //刚开始的时候长度为0
        size = 0;
    }

    /**
     * 初始化构造
     */
    public ArrayList() {
        //默认初始化数量为10
        this(10);
    }

    public int getSize() {
        return size;
    }

    public E get(int index) {
        if (index < 0 || index >= size) {
            throw new IllegalArgumentException("你丫看看index的值,传了个啥...");
        }
        return data[index];
    }

    public int indexOf(@NotNull E e) {
        for (int i = 0; i < size; i++) {
            if (e.equals(data[size])) {
                return i;
            }
        }
        return -1;
    }

    public void add(int index, E e) {
        if (size == data.length) {
            throw new IllegalArgumentException("你丫看看都越出了,还往里面塞...");
        }
        if (index < 0 || index > size) {
            throw new IllegalArgumentException("你丫看看index的值,传了个啥...");
        }
        for (int i = size - 1; i >= index; i--) {
            data[i + 1] = data[i];
        }
        data[index] = e;
        size++;
    }

    public void addFirst(E e) {
        add(0, e);
    }

    public void addLast(E e) {
        add(size, e);
    }


    public E remove(int index) {
        if (index < 0 || index >= size) {
            throw new IllegalArgumentException("你丫看看index的值,传了个啥...");
        }
        E e = data[index];
        for (int i = index + 1; i < size; i++) {
            data[i - 1] = data[i];
        }
        size--;
        return e;
    }

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

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


    public void set(int index, E e) {
        if (index < 0 || index >= size) {
            throw new IllegalArgumentException("你丫看看index的值,传了个啥...");
        }
        data[index] = e;
    }

    public boolean contains(E e) {
        for (int i = 0; i < size; i++) {
            if (e.equals(data[i])) {
                return true;
            }
        }
        return false;
    }


    @Override
    public String toString() {
        StringBuilder builder = new StringBuilder();
        builder.append("[");
        for (int i = 0; i < size; i++) {
            if (i == size - 1) {
                builder.append(data[i]);
            } else {
                builder.append(data[i] + ",");
            }
        }
        builder.append("]");
        return builder.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;
}
之前添加的代码
if (size == data.length) {
    throw new IllegalArgumentException("你丫看看都越出了,还往里面塞...");
}
扩容 之前容量的2倍,ArrayList源码中应该是1.5倍
if (size == data.length) {
    resize(2 * data.length);
}
之前删除的代码
E e = data[index];
for (int i = index + 1; i < size; i++) {
    data[i - 1] = data[i];
}
size--;
data[size] = null;
这块添加缩容的代码
缩容 缩小至原来的二分之一
if (size == data.length / 2) {
    resize(data.length / 2);
}

作者:傻傻三多

出处:https://www.sssd.top

版权:本作品采用「署名-非商业性使用-相同方式共享 4.0 国际」许可协议进行许可。


sssd
1 声望0 粉丝