Array数组-数据结构

Array数组

  1. 概念

数组简单来说就是将所有的数据排成一排放在系统分配的内存块上,通过使用特定元素的索引作为数组的下标,可以在常数范围内访问数组元素的结构。

 

  1. 数组的优
    1. 优点
      • 简单且易用;
      • 访问元素快;
    2. 缺点
      • 大小固定:数组的大小是静态的(在使用前必须制定数组的大小);
      • 分配一个连续空间块:数组初始分配空间时,有时候无法分配能存储整个数组的内存空间(当数组规模太大时);
      • 基于位置的插入操作实现复杂:如果要在数组中的给定位置插入元素,那么可能就会需要移动存储在数组中的其他元素,这样才能腾出指定的位置来放插入的新元素;而如果在数组的开始位置插入元素,那么这样的移动操作开销就会很大。
  2. 数据结构分析
    1. 创建自定义数组

public class Array<E>{    

private E[] data;    

private int size;    

/* 一些成员方法 */

}

说明:泛型封装数组、成员变量data用来存储数据、成员变量size有效个数,在构造函数里设置size从0开始。

    1. 构造函数

// 构造函数,传入数组的容量capacity构造Array

public Array(int capacity) {

data = (E[]) new Object[capacity];

size = 0;

}


// 无参数的构造函数,默认数组的容量capacity=10

public Array() {

this(10);

}

说明:capacity是数组的容量,

    1. 成员方法

// 获取数组的容量

public int getCapacity() {

return data.length;

}

// 获取数组中的元素个数

public int getSize() {

return size;

}

// 返回数组是否为空

public boolean isEmpty() {

return size == 0;

}

// 在index索引的位置插入一个新元素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++;

}

// 向所有元素后添加一个新元素

public void addLast(E e) {

add(size, e);

}

// 在所有元素前添加一个新元素

public void addFirst(E e) {

add(0, e);

}

// 获取index索引位置的元素

public E get(int index) {

if (index < 0 || index >= size)

throw new IllegalArgumentException("Get failed. Index is illegal.");

return data[index];}

// 修改index索引位置的元素为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

public boolean contains(E e) {

for (int i = 0; i < size; i++) {

if (data[i].equals(e))

return true;

} return false;

}

// 查找数组中元素e所在的索引,如果不存在元素e,则返回-1

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("Remove 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 != memory leak

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);

}

@Overridepublic 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();}

// 将数组空间的容量变成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;

}

声明:

  • 向数组末添加元素

 

 

  • 向数组指定位置添加元素

 

  • 数组指定位置删除元素:

 

  1. 时间复杂度分析
    1. 添加操作

分析得出addLast()方法是与n无关的,属于O(1)复杂度;addFirst()和add()方法涉及到需要移动数组元素,所以都是O(n)复杂度,综合起来添加操作的复杂度就是O(n)。

    1. 删除操作

分析得出removeLast()方法是与n无关的,所以为O(1)复杂度;而removeFirst()和remove()方法都涉及到挪动数组元素,所以都是O(n)复杂度,包括resize()方法;综合起来删除操作的复杂度就是O(n)。

    1. 修改操作

修改操作知道了修改元素索引,时间复杂度就是O(1)的。

    1. 查询操作

在查询操作中,如果我们已知索引,那么复杂度为O(1);如果未知索引,我们需要遍历整个数组,那么复杂度为O(n)级别。

  1. 总结

增加:O(n);

删除:O(n);

修改:已知索引 O(1);未知索引 O(n);

查询:已知索引 O(1);未知索引 O(n);

  1. Leecode题目
    1. 买卖股票的最佳时机
      • 题目:

给定一个数组 prices ,它的第 i 个元素 prices[i] 表示一支给定股票第 i 天的价格。

你只能选择 某一天 买入这只股票,并选择在 未来的某一个不同的日子 卖出该股票。设计一个算法来计算你所能获取的最大利润。返回你可以从这笔交易中获取的最大利润。如果你不能获取任何利润,返回 0 。

      • 例子:

 

      • 解题:

  public int maxProfit(int[] prices) {

         int minValue = Integer.MAX_VALUE;

         int maxProfit = 0;

         for(int i=0;i<prices.length;i++){

             if(prices[i] < minValue){

                 minValue = prices[i];

             }

             if(prices[i] - minValue > maxProfit){

                 maxProfit = prices[i] - minValue;

              }

              }

         return maxProfit;

             }

    1. 买卖股票的最佳时机∥
      • 题目:

给定一个数组,它的第 i 个元素是一支给定股票第 i 天的价格。

设计一个算法来计算你所能获取的最大利润。你可以尽可能地完成更多的交易(多次买卖一支股票)。

注意:你不能同时参与多笔交易(你必须在再次购买前出售掉之前的股票)。

      • 例子:

 

      • 解题:贪心算法

  public int maxProfit(int[] prices) {

         int ans = 0;

         int n =prices.length;

         for(int i = 1;i<n;i++){

             ans += Math.max(0,prices[i] - prices[i-1]);

         }

         return ans;

            }

    1. 删除排序数组中的重复项
      • 题目:

给定一个排序数组,你需要在原地删除重复出现的元素,使得每个元素只出现一次,返回移除后数组的新长度。

不要使用额外的数组空间,你必须在 原地 修改输入数组 并在使用 O(1) 额外空间的条件下完成。

      • 例子:

 

      • 解题:

  public int removeDuplicates(int[] nums) {

         int slow = 0;

         for(int fast=0;fast<nums.length;fast++){

             if(nums[slow] != nums[fast]){

                 slow++;

                 nums[slow] = nums[fast];

             }

         }

         return slow+1;

     }

 

 

 

 

 

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值