【数据结构】数组

数组

从本质上讲,数组与顺序表、链表、栈和队列一样,都用来存储具有 “一对一” 逻辑关系数据的线性存储结构。只因各编程语言都默认将数组作为基本数据类型,使初学者对数组有了 “只是基本数据类型,不是存储结构” 的误解。

不仅如此,数组和其他线性存储结构不同,顺序表、链表、栈和队列存储的都是不可再分的数据元素(如数字 5、字符 ‘a’ 等),而数组既可以用来存储不可再分的数据元素,也可以用来存储像顺序表、链表这样的数据结构。

public class Demo01 {
    public static void main(String[] args) {
        /**
         * 1、数组的概念:用来存储一组相同数据类型的数
         * 2、Java中数组的定义
         * 数据类型[] 数组名
         * 3、初始化:数据类型[] 数组名 = new int[6];
         * 数据类型[] 数组名 = {1,2,3,4,5};
         * 4、数组在内存中分配的是连续的空间
         */
        String[] fruits = {"apple", "pear", "watermelon", "banana", "Pineapple"};
     /*   for (int i = 0; i < fruits.length; i++) {
            System.out.println(fruits[i]);
        }*/
       /* Arrays.stream(fruits).forEach(item -> System.out.print(item));

        int[] nums = new int[1000];
        Random random = new Random();
        for (int i = 0; i < 1000; i++) {
            nums[i] = random.nextInt(100000);
        }
        Arrays.stream(nums).map(item -> item + 10).filter(item -> item % 2 > 0).forEach(System.out::println);
*/
        // 1、对每个数据+10
        // 2、过滤奇数
        // Integer.parseInt("".substring(-4));

        String str = "ababccddeesss";// 字符串中只包含小写子母
        // 统计每个字符出现的次数
        int[] counts = new int[26];
        for (int i = 0; i < str.length(); i++) {
            char c = str.charAt(i);
            counts[c - 'a']++;
        }
        for (int item : counts) {
            System.out.println(item);
        }
        Map<Character, Integer> map = new HashMap<>();
/*        for (int i = 0; i < str.length(); i++) {
            char c = str.charAt(i);
            if (!map.containsKey(c)) {
                map.put(c, 1);
            } else {
                map.put(c, map.get(c) + 1);
            }
        }*/
    }
}

1、数组基础

<1> 用来存储一组类型相同的数据
<2> 在内存中,分配连续的空间,数组创建时要指定容量(大小)
<3> 数据类型[] 数组名 int[] arr = new int[10] int[] arr2 = {1,2,3,4}
<4>索引—访问数组时通过索引进行操作
<5> 索引从0开始,最大为 arr.length -1
<6> 常见的错误: NullPointException ArrayIndexOutOfBoundsException
<7> 常见的数组: 字符串, 对象数组,哈希表

2、索引

使用数组时,最重要的就是数组的索引,通过索引可以对数组进行改和查操作。

在这里插入图片描述
索引:可以有语义,也可以没有语义(理解)。

数组最大的优点:快速查询。

数组最好应用于索引有语义的情况。

并非所有有语义的数字都可以作为数组的索引,例如:610521199610111188

数组也是可以处理“索引没有语义”的情况。

产生的问题

在这里插入图片描述

  • 索引没有语意,如何表示没有元素?

  • 如何添加元素?如何删除元素?

3、可变数组

基于Java中的数组,进行二次封装,制作属于我们自己的数组(可变数组)。

在这里插入图片描述

4、向数组中添加元素

在这里插入图片描述

5、向指定位置添加元素

向指定位置添加元素

在这里插入图片描述
把77插入到索引为1的位置

在这里插入图片描述

6、向数组头添加元素

7、获取指定位置的元素和修改指定位置的元素

8、包含、搜索和删除元素

删除指定位置元素

在这里插入图片描述
删除索引为1的元素

针对上面的逻辑,我们可以删除指定的元素 public void removeElement(int e);

注意:我们的数组中可能存在重复的元素,此方法只删除第一次找到的元素。

9、使用泛型(“任意”类型的数组)

不可以是基本数据类型,只能是类对象 。

基本数据类型: 8种

byte char boolean int short float double long

每种基本数据类型都有一个对应的包装类。

10、动态数组

在这里插入图片描述

11、简单的时间复杂度分析

在算法领域,使用复杂度分析的内容来评价你写的代码性能如何。

leetCode、牛客网上的题目不只要求做出来,还要求在指定的时间内完成。

通常情况下我们只需要简单的时间复杂度分析就足够了。

  • O(1), O(n) , O(Ign) ,O(nlogn) ,O(n^2)

  • 大O描述的是算法的运行时间和输入数据之间的关系

public static int sum(int [] nums){
	int sum = 0;
	for(int num: nums) sum += num;
	return sum;
}

O(n):n是nums中的元素个数,算法和n呈线性关系

为什么要用大0,叫做O(n)?
忽略常数。 实际时间T=c1*n+ c2

T=2n+ 2 O(n)
T = 2000
n + 10000 O(n)
T=1nn+0 O(n^2)

渐进时间复杂度,描述n趋近于无穷的情况

12、分析动态数组的时间复杂度

添加操作 O(n)

在这里插入图片描述

删除操作 O(n)

在这里插入图片描述

修改操作

set(index,e) O(1)

查找操作

get(index) O(1)
contains(e) O(n)
find(e) O(n)

综合

  • 增 O(n)

  • 删 O(n)

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

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

13、resize的复杂度分析(均摊复杂度)

resize O(n)

9次addLast操作,触发resize, 总共进行了17次基本操作

平均,每次addLast操作,进行2次基本操作

假设capacity = n,n+1次addLast,触发resize,总共进行2n+1次基本操作

平均,每次addLast操作, 进行2次基本操作

这样均摊计算:时间复杂度为O(1)

14、复杂度的震荡

当我们同时进行addLast和removeLast的操作

出现问题的原因:removeLast 时 resize 过于着急 (Eager)

解决方案:Lazy

在这里插入图片描述


版权声明:本文为qq_46381044原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。