zoukankan      html  css  js  c++  java
  • 【数据结构】数组

    什么是数组?

    数组对应的英文是array,是一个存储相同类型的变量所组成的一个有序集合,数组中每一个变量称为元素,每个元素都有一个对应的索引(索引从0开始)。
    数组的存储方式如下:
    数组.png
    数组还有另一个特点,就是在内存中是顺序存储的。
    内存是由一个个连续的内存单元所组成的,每一个内存单元都对应一个地址,在内存单元中,有些被占用了,有些是空闲的。
    数组中的每一个元素,都存储在内存单元中,并且这些内存单元之间紧密排列,既不能打乱存储顺序,也不能跳过某个内存单元进行存储。

    基于数组进行二次封装

    1、读取元素
    对于数组来说,读取元素是最简单的操作。由于数组在内存中顺序存储,所以只要给出一个数组的索引,就可以读取到索引对应的元素。

    2、修改元素
    更新数组中的某一个元素,也是一个非常简单的操作。直接利用数组的索引,就可以把新值赋值给索引对应的元素。

    3、插入元素
    在数组中插入元素分为三种情况:

    • 尾部插入

      这是最简单的情况,直接把插入的元素放在数组的尾部空闲的位置就可以了。

    • 中间插入

      稍微复杂一些,在数组中每一个元素都对应一个索引,所以首先先把插入位置的元素和后面的元素向后移动,再把插入的元素插入到对应的索引中。

    • 超范围插入

      假如现在有一个长度为10的数组,并且这个数组中已经填满了元素,如果这时还想添加一个元素,该怎么办?
      这里就涉及到了扩容机制了,在一开始数组的长度就已经确定了,那么如何扩容呢?
      我们可以创建一个新的数组,并且这个新数组的长度是原来的数组的长度的2倍,然后再把旧数组当中的元素插入到新数组当中,这样就实现了数组的扩容。

    4、删除元素
    删除元素和插入元素的过程正好相反,我们把要删除的元素后面的元素往前移动就可以了。注意:虽然这里不涉及扩容问题,但是如果当前的数组的元素的个数要比数组的长度小很多,是不是就浪费了内存?所以我们可以在这里加入缩容机制,防止浪费内存。

    整体代码如下:

    /**
     * 描述:基于数组二次封装成动态数组。
     * <p>
     * Create By ZhangBiao
     * 2020/5/8
     */
    public class Array<E> {
    
        private E[] data;
    
        private int size;
    
        /**
         * 构造函数,传入数组的容量capacity构造Array。
         *
         * @param capacity 容量大小
         */
        public Array(int capacity) {
            data = (E[]) new Object[capacity];
            size = 0;
        }
    
        /**
         * 无参数的构造函数,默认数组的容量capacity=10。
         */
        public Array() {
            this(10);
        }
    
        public Array(E[] arr) {
            this.data = (E[]) new Object[arr.length];
            for (int i = 0; i < arr.length; i++) {
                this.data[i] = arr[i];
            }
            this.size = this.data.length;
        }
    
        /**
         * 获取数组的容量。
         *
         * @return
         */
        public int getCapacity() {
            return data.length;
        }
    
        /**
         * 获取数组中的元素个数。
         *
         * @return
         */
        public int getSize() {
            return size;
        }
    
        /**
         * 返回数组是否为空。
         *
         * @return
         */
        public boolean isEmpty() {
            return size == 0;
        }
    
        /**
         * 向所有元素后添加一个新元素
         *
         * @param e
         */
        public void addLast(E e) {
            /*if (size == data.length) {
                throw new IllegalArgumentException("AddLast failed. Array is full.");
            }
            data[size] = e;
            size++;*/
            add(size, e);
        }
    
        public void addFirst(E e) {
            add(0, e);
        }
    
        /**
         * 在index索引的位置插入一个新元素e
         *
         * @param index
         * @param e
         */
        public void add(int index, E e) {
            if (index < 0 || index > size) {
                throw new IllegalArgumentException("Add failed. Require index >= 0 and index <= size.");
            }
            if (size == data.length) {
                resize(2 * data.length);
            }
            for (int i = size - 1; i >= index; i--) {
                data[i + 1] = data[i];
            }
            data[index] = e;
            size++;
        }
    
        /**
         * 扩容
         *
         * @param newCapacity
         */
        private void resize(int newCapacity) {
            E[] newData = (E[]) new Object[newCapacity];
            for (int i = 0; i < size; i++) {
                newData[i] = data[i];
            }
            data = newData;
        }
    
        /**
         * 获取index索引位置的元素。
         *
         * @param index
         * @return
         */
        public E get(int index) {
            if (index < 0 || index >= size) {
                throw new IllegalArgumentException("Get failed. Index is illgal.");
            }
            return data[index];
        }
    
        /**
         * 获取索引为0的元素。
         *
         * @return
         */
        public E getFirst() {
            return get(0);
        }
    
        /**
         * 获取索引为size-1的元素。
         *
         * @return
         */
        public E getLast() {
            return get(size - 1);
        }
    
        /**
         * 修改index索引位置的元素为e。
         *
         * @param index
         * @param e
         */
        public void set(int index, E e) {
            if (index < 0 || index >= size) {
                throw new IllegalArgumentException("Set failed. Index is illegal.");
            }
            data[index] = e;
        }
    
        /**
         * 查找数组中是否有元素e。
         *
         * @param e
         * @return
         */
        public boolean contains(E e) {
            for (int i = 0; i < size; i++) {
                if (data[i] == e) {
                    return true;
                }
            }
            return false;
        }
    
        /**
         * 查找数组中元素e所在的索引,如果不存在元素e,则返回-1。
         *
         * @param e
         * @return
         */
        public int find(E e) {
            for (int i = 0; i < size; i++) {
                if (data[i] == e) {
                    return i;
                }
            }
            return -1;
        }
    
        /**
         * 从数组中删除index位置的元素,返回删除的元素。
         *
         * @param index
         * @return
         */
        public E remove(int index) {
            if (index < 0 || index >= size) {
                throw new IllegalArgumentException("Remove failed. Index is illegal.");
            }
            E ret = data[index];
            for (int i = index + 1; i < size; i++) {
                data[i - 1] = data[i];
            }
            size--;
            if (size == data.length / 4 && data.length / 2 != 0) {
                resize(data.length / 2);
            }
            return ret;
        }
    
        /**
         * 从数组中删除第一个元素并返回删除的元素。
         *
         * @return
         */
        public E removeFirst() {
            return remove(0);
        }
    
        /**
         * 从数组中删除最后一个元素并返回删除的元素。
         *
         * @return
         */
        public E removeLast() {
            return remove(size - 1);
        }
    
        /**
         * 从数组中删除元素e。
         *
         * @param e
         */
        public void removeElement(E e) {
            int index = find(e);
            if (index != -1) {
                remove(index);
            }
        }
    
        public void swap(int i, int j) {
            if (i < 0 || i >= size || j < 0 || j >= size) {
                throw new IllegalArgumentException("Index is Illegal");
            }
            E temp = data[i];
            data[i] = data[j];
            data[j] = temp;
        }
    
        @Override
        public String toString() {
            StringBuilder res = new StringBuilder();
            res.append(String.format("Array: size = %d , capacity = %d
    ", 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();
        }
    
    }
    

    数组的优劣势

    1、优势
    数组拥有高效的随机访问能力,只要给出索引,就可以立即找到对应的元素。
    2、劣势
    数组的劣势体现在插入元素和删除元素,由于数组的存储方式,导致在插入和删除这两个操作中大量的元素需要被迫移动,从而影响效率。

  • 相关阅读:
    了解 NoSQL 的必读资料
    关于什么时候用assert(断言)的思考
    这次见到了一些大侠
    NetBeans 时事通讯(刊号 # 87 Jan 12, 2010)
    动态链接库dll,静态链接库lib, 导入库lib
    新女性十得 写得了代码,查得出异常
    记录系统乱谈
    新女性十得 写得了代码,查得出异常
    fullpage.js禁止滚动
    RunningMapReduceExampleTFIDF hadoopclusternet This document describes how to run the TFIDF MapReduce example against ascii books. This project is for those who wants to experiment hadoop as a skunkworks in a small cluster (110 nodes) Google Pro
  • 原文地址:https://www.cnblogs.com/zhangbiao97/p/12853124.html
Copyright © 2011-2022 走看看