Java数据存储类型ArrayList、HashSet、HashMap、LinkedList使用不同遍历方法效率研究By Python

Java不同数据存储类型使用不同遍历方法效率研究

GitHub代码仓库

数据存储类型

  • ArrayList
  • HashSet
  • HashMap
  • LinkedList

遍历方法

  • 传统遍历方法
for(int i=0;i<list.size();i++) {
   String str = list.get(i);
   ...
}
  • 内置迭代器
for (String str : list) {
   ...
}
  • 显式迭代器
Iterator<String> it = list.iterator();
while(it.hasNext()) {
  String str = it.next();
  ...
}

测试代码模板

  • 使用大小为 N N N的数组,遍历 M M M边,平均遍历速度定义为 T / ( N ∗ M ) T/(N*M) T/(NM)
    private static ArrayList<String> list = new ArrayList<>();
    private final static int N = 1000000, M = 1000;
    private final static String STR = "abcdefg";
  • 首先建立一个固定数组,供给3个遍历方法使用
    @BeforeClass
    public static void CreateList() {
		for (int i = 0; i < N; i++) {
		    list.add(STR);
		}
    }

使用JUnit测试单元记录时间

  • 传统遍历方法For
    @Test
    public void FOR() {
		for (int k = 0; k < M; k++) {
		    for (int i = 0; i < list.size(); i++) {
			String str = list.get(i);
		    }
		}
    }
  • 内置迭代器
    @Test
    public void Inner_Iteration() {
		for (int k = 0; k < M; k++) {
		    for (String str : list) {
			String s = str;
		    }
		}
    }
  • 显式迭代器
    @Test
    public void Explicit_Iteration() {
		for (int k = 0; k < M; k++) {
		    Iterator<String> it = list.iterator();
		    while (it.hasNext()) {
			String str = it.next();
		    }
		}
    }

根据不同的存储类型进行更改
eg. HashMap 要设置key和value

Python数据可视化

import pandas as pd
import numpy as np
from matplotlib import pyplot as plt
import seaborn as sns
%matplotlib inline
  • 以ArrayList代码为例
  • 柱状图
f, ax= plt.subplots()
ArrayList = pd.read_csv("../csv/ArrayList.csv")
sns.barplot(data=ArrayList)
ax.set_title("ArrayList")
  • 折线图
f, ax= plt.subplots()
sns.lineplot(data=ArrayList)
ax.set_title("ArrayList")
plt.ylim(0.5, 1.0)

ArrayList

  • 整体来说,在ArrayList中for的遍历速度最快内置迭代器和显式迭代器相当
  • 并且ArrayList迭代非常稳定,尤其是for
Explicit_IterationFORInner_Iteration
0.7750.5850.757
0.7850.5770.748
0.7830.5810.769
0.7750.5830.77
0.7780.6020.788
0.7840.5860.767
0.7750.5810.807
0.8140.5870.766
0.7860.6040.839
0.8150.5930.775


HashMap

  • 在HashMap中不能使用For,内置迭代器略优
Explicit_IterationInner_Iteration
0.6080.507
0.6220.613
0.5850.485
0.5870.533
0.6390.526
0.5930.555
0.5340.431
0.5810.504
0.5980.481
0.640.504


HashSet

  • 在HashSet中同样不能使用for, 基本相同,内置迭代器较不稳定
Explicit_IterationInner_Iteration
2.52.517
2.5322.477
2.6842.523
2.6973.303
2.6312.515
2.9563.016
3.2813.051
3.0742.95
3.2062.935
2.892.887


LinkedList

  • 注:在链表中可以使用for,但是根据一定的测试,随着数据规模增加,运行时间呈指数型增长,与另两种遍历方法不在一个数量级上,所以不加入统计。

  • 在LinkedList中,内置迭代器和显式迭代器效率相当,多个单次试验观察来说显式迭代器略优
Explicit_IterationInner_Iteration
1.8652.101
1.8831.929
1.91.941
1.8431.903
1.891.897
1.8351.921
1.8411.846
1.9141.902
1.8721.859
1.8161.827


数据处理和数据清洗

  • 将4中存储类型的数据整合起来
  • 将数据统一到同样的数据尺度
Base = 0

ArrayList /= 10**(Base-8)
ArrayList['Type'] = 'ArrayList'     # 8

HashMap /= 10**(Base-7)
HashMap['Type'] = 'HashMap'         # 7

HashSet /= 10**(Base-8)
HashSet['Type'] = 'HashSet'         # 8

LinkedList /= 10**(Base-8)
LinkedList['Type'] = 'LinkedList'  # 8
  • 由于不同数据类型效率差异较大
  • 作者选择通过取对数 l o g 10 ( ) log_{10}() log10()的方法
  • 然后取相反数(时间越少,效率越高)
  • 这使数据数量级接近,能容易可视化
data = pd.concat([ArrayList, HashMap, HashSet, LinkedList], ignore_index=True).drop(['FOR'], axis=1)
data[['Explicit_Iteration', 'Inner_Iteration']] = np.log10(data[['Explicit_Iteration', 'Inner_Iteration']])

整体可视化对比

  • 将内置迭代器、显式迭代器分别处理后数据对比
  • 下图的数据表示效率相对值的数量级
f, ax= plt.subplots()
sns.barplot(x='Type', y='Inner_Iteration', data=data)
ax.set_title("Inner_Iteration")

f, ax= plt.subplots()
sns.barplot(x='Type', y='Explicit_Iteration', data=data)
ax.set_title("Explicit_Iteration")

分析

本质:数组、集合、字典、链表,4种数据结构的差异在遍历方式上的体现

ArrayList

  • ArrayList本质上是一个动态数组,数组对于大量随机访问有着高效的响应速度
  • 迭代器在ArrayList这种不依赖__iter____next__方法的对象,在使用迭代器时的访存速度远不如有序访存FOR
  • 由于数组线性存储,导致ArrayList增加和删除操作效率较低
  • 因此ArrayList适用于不定长、不频繁增删的数据存储

HashMap

  • Java种的Map主要分为HashMap和TreeMap,属于非Collection接口
  • Map需要有键key和值value,内部元素无序,因此无法用For访问
  • 使用迭代器时,由于键值的唯一性,单个元素查找速度似乎较快
  • 但迭代对象时键值的集合,keySet()的迭代需要占用时间
  • 而且键值是无序的,一定程度上,不满足良好局部性的要求

HashSet

  • HashSet继承了Collection种的Set
  • HashSet调用了HashMap.put()方法,将值直接作为键
  • 所以HashSet在访问时一定优于HashMap,因为Set不需要对Keys的迭代
  • 事实证明,HashSet确实远优于HashMap,但从实用性角度来说却不如HashMap

LinkedList

  • LinkedList本质上是一个双向链表
  • 链表的特点就是容易增加和删除,但随机访问单个元素效率很低

总结

  • 不同的4种数据存储类型中3种迭代方式效率不同
  • 内置迭代器和显式迭代器效率相当,for在ArrayList中效率较高、LinkedList很差
  • HashSet的迭代效率较高,HashMap迭代效率较低
  • 单从迭代器迭代速度来说:HashSet > LinkedList > ArrayList > HashMap
  • 总体评价:
    • ArrayList:少增删,求稳定
    • HashMap:字典功能,效率低
    • HashSet:大数据非数字随机元素查找极快
    • LinkedList:增删高速,严禁用for
  • 2
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
1. ArrayList: - ArrayList是基于数组实现的动态数组,可以自动扩容,可以存储任何对象类型。 - 数组的优点是可以随机访问元素,缺点是插入和删除元素时需要移动其他元素。 - ArrayList支持快速随机访问,但插入和删除元素的效率较低。 2. LinkedList: - LinkedList是基于链表实现的,每个节点包含一个指向前驱和后继节点的指针,可以存储任何对象类型。 - 链表的优点是插入和删除元素时不需要移动其他元素,缺点是不能直接随机访问元素,需要遍历整个链表。 - LinkedList支持高效的插入和删除操作,但随机访问元素的效率较低。 3. TreeSet: - TreeSet是基于红黑树实现的有序集合,不允许重复元素,可以存储任何对象类型。 - 红黑树的优点是能够自动排序,插入和删除元素的效率较高,缺点是随机访问元素的效率较低。 - TreeSet支持高效的插入、删除和查找操作,但随机访问元素的效率较低。 4. HashSet: - HashSet是基于哈希表实现的无序集合,不允许重复元素,可以存储任何对象类型。 - 哈希表的优点是能够快速查找元素,缺点是元素的顺序是随机的。 - HashSet支持高效的插入、删除和查找操作,但不能保证元素的顺序。 5. HashMap: - HashMap是基于哈希表实现的键值对集合,键和值都可以存储任何对象类型。 - HashMap的优点是能够快速查找元素,缺点是键和值的顺序是随机的。 - HashMap支持高效的插入、删除和查找操作,但不能保证键和值的顺序。 6. TreeMap: - TreeMap是基于红黑树实现的有序键值对集合,键不能重复,值可以存储任何对象类型。 - 红黑树的优点是能够自动排序,插入和删除元素的效率较高,缺点是随机访问元素的效率较低。 - TreeMap支持高效的插入、删除和查找操作,并且按照键的顺序排列。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值