一、数组
- 数组是一种确定大小的存储同种数据的容器;
- 需要牢牢掌握初始化和遍历方法,特别是两种遍历方式
1. 简介
- 数组是一个存放多个数据的容器;
- 数据是同一种类型;
- 所有的数据是线性规则排列;
- 可通过位置索引来快速定位访问数据;
- 需要明确容器的长度。
广义上说,以前定义的变量也可以理解为一种容器,就比如
int a = 5;
a实际上就是一种容器,里面放着数字5。
2. 定义与初始化
- 定义:
int a[];//可以用C的方式来定义一个数组;
int[] a;//Java中更推荐用这种方式来定义;
//此时还没有new操作,a实际上是null(相当于空指针),不知道内存位置
- 初始化:
int[] a = new int[5];//表明开辟了一个大小为5个int字节的数组,
//数组内元素默认为0;
int[] b = new int[]{1,2,3};
int[] b = {1,2,3};//这两种初始化方式等价,都是用穷举的方式;
注意在声明一个数组时,并没有分配内存,此时不要指定大小,下面是错误示例;
int a[5];//error int[5] b;//error int[5] c = new int[5];//error
3. 数组索引
- 数组的length属性标识数组的长度
public class LengthTest {
public static void main(String[] args) {
int[] a = new int[5];
System.out.println("数组长度:" + a.length);
}
}
/** 输出的结果是“数组长度:5” */
- 数组访问时不能越界,否则会报ArrayIndexOutOfBoundsException异常
4. 数组遍历
- for循环:这个都会,通常需要注意索引位置
- for-each语句:
public class LengthTest {
public static void main(String[] args) {
// TODO Auto-generated method stub
int[] a = {1,3,5,7,9};
for(int i = 0; i < a.length; i++) {
System.out.println(a[i]);
}
System.out.println("=================");
for(int e: a) {
System.out.println(e);
}
/** 两者结果完全相同,for-each语句相比上面的语句
不存在也不会出现越界访问,而且更简洁*/
}
}
5. 多维数组(仅介绍二维)
- 定义:
1. int a[][] = new int a[2][3];
/** 上面表示的是一种 两行三列 的数组*/
计算机实际存储时,是按照行一个一个存储的,也就是说二维数组在内存中实际上
是线性的结构;比如上面的a[2][3],会先存储a[0][3],再接在后面存储a[1][3]。实际在遍历二维数组中也更推荐按行逐个遍历,如果按列进行遍历实际上性能会差很多。
2. /** 对于不规则的二维数组,可以按照下面的方式定义 */
int b[][];
b = new int b[3][];
b[0] = new int[3];
b[1] = new int[4];
b[2] = new int[5];
- 遍历:
public class A {
public static void main(String[] args) {
int a[][];
int k = 0;
a = new int[3][];
a[0] = new int[3];
a[1] = new int[4];
a[2] = new int[5];
for(int i = 0; i < a.length; i++) {//二维数组中a.length表示的是整个数组的行数
for(int j = 0; j < a[i].length ;j++) {//每一行的长度a[i].length
a[i][j] = k++;
}
}
for(int[] items: a) {//可以把二维数组理解成复合的数组,相当于items[]数组的每一个元素都是一个item[]数组
for(int item: items) {
System.out.println(item);
}
}
}
}
for-each循环的逻辑:
for(数据类型 变量名 :数组名) {//变量名可以自定义 含有变量名的语句; }
二、 JCF(Java Collection Frame,java容器框架)
类似于C++中的STL,Standard Template Library,标准模板库
1. 简介
- 容器:能够存放数据的空间结构;
- 数组/多维数组:只能线性存放数据;
- 列表/散列集/树/···
- 容器框架:为表示和操作容器而规定的一种标准体系结构;
在数据结构课程中我们会学习对应的数据组织方式,以及如何存储、操作这些数据;
实际应用中Java将这些逻辑结构以及对应的代码封装起来,提供接口供人使用,这样
使用者就不必十分清楚数据结构的具体实现过程,只要知道如何使用就可以。
- 优点:提高了数据存储效率,避免程序员重复劳动。
三、 列表List
- ArrayList/LinkedList/Vector
- 同步采用Vector
- 非同步情况下,根据数据操作特点选取ArrayList/LinkedList
1. ArrayList用法
- 简介:
- 基于数组实现,不支持同步;
- 可以按照索引访问,方便查询,不方便移动;
- 可以实现动态扩容,增大容量的50%;
- 常见用法:
import java.util.ArrayList;
import java.util.Iterator;
public class ArrayListTest {
public static void main(String[] args) {
ArrayList<Integer> a = new ArrayList<Integer>();
//ArryList<Integer> a是泛型表示,意思是a这个数据结构里只能容纳Integer
//的对象,其他的对象无法放入
a.add(3);
a.add(2);
a.add(1);
a.add(4);
a.add(5);
a.add(6);
a.add(new Integer(6));
/**
* ArrayList只能装对象,当add(3)时,会自动将普通int变量3
* 自动装箱为Integer(3)的对象,然后放入ArrayList容器中。
* */
System.out.print("The third element is");
System.out.println(a.get(3));//按索引访问,3表示第四个元素
a.remove(3);//删除第四个元素,后面元素往前挪动
a.add(3,9);//将9插入到第3个元素,后面元素往后挪动
System.out.println("========遍历方法======");
ArrayList<Integer> test = new ArrayList<Integer>(100000);
for(int i = 0; i < 100000; i++) {
test.add(i);
}
traverseByIterator(test);
traverseByIndex(test);
traverseByFor(test);
}
public static void traverseByIterator(ArrayList<Integer> a) {
long startTime = System.nanoTime();
System.out.println("========迭代器遍历========");
Iterator<Integer> iter1 = a.iterator();
while(iter1.hasNext()) {
iter1.next();
}
long endTime = System.nanoTime();
long duration = endTime - startTime;
System.out.println(duration + "纳秒");
}
public static void traverseByIndex(ArrayList<Integer> a) {
long startTime = System.nanoTime();
System.out.println("========索引遍历========");
for(int i = 0; i < a.size(); i++) {//size()方法可以得出数据结构的大小;
a.get(i);
}
long endTime = System.nanoTime();
long duration = endTime - startTime;
System.out.println(duration + "纳秒");
}
public static void traverseByFor(ArrayList<Integer> a) {
long startTime = System.nanoTime();
System.out.println("========for-each遍历========");
for(Integer item : a) {//数据结构a中的元素是Integer类型的变量;
}
long endTime = System.nanoTime();
long duration = endTime - startTime;
System.out.println(duration + "纳秒");
}
}
运行结果如下:
看得出来迭代器方法和随机索引速度差不多,for-each方法速度最快。
2. LinkedList用法
- 简介:
- 以双向链表实现的列表,不支持同步;
- 可被当做堆栈、队列和双端队列进行操作;
- 顺序访问搞笑,随机访问较差,中间插入和删除高效;
- 适用于经常变化的数据;
- 常见用法:
import java.util.Iterator;
import java.util.LinkedList;
public class LinkedListTest {
public static void main(String[] args) {
LinkedList<Integer> link = new LinkedList<Integer>();
link.add(3);
link.add(2);
link.add(5);
link.add(6);
link.add(6);
System.out.println("link's size is: "+ link.size());
link.addFirst(9);//在头部增加9
link.add(3, 10);//将10插入到第四个元素,之前第四个及以后元素往后挪动
link.remove(3);//将第四个元素删除
for(Integer item: link) {
System.out.println(item.toString());
}
System.out.println("=========遍历测试========");
LinkedList<Integer> link2 = new LinkedList<Integer>();
for(int i = 0; i < 100000; i++) {
link2.add(i);
}
traverseByIterator(link2);
traverseByIndex(link2);
traverseByFor(link2);
}
public static void traverseByIterator(LinkedList<Integer> a) {
long startTime = System.nanoTime();
System.out.println("========迭代器遍历========");
Iterator<Integer> iter1 = a.iterator();
while(iter1.hasNext()) {
iter1.next();
}
long endTime = System.nanoTime();
long duration = endTime - startTime;
System.out.println(duration + " 纳秒");
}
public static void traverseByIndex(LinkedList<Integer> a) {
long startTime = System.nanoTime();
System.out.println("=========随机索引遍历============");
for(int i = 0; i < a.size(); i++) {
a.get(i);
}
long endTime = System.nanoTime();
long duration = endTime - startTime;
System.out.println(duration + " 纳秒");
}
public static void traverseByFor(LinkedList<Integer> a) {
long startTime = System.nanoTime();
System.out.println("=========for-each循环遍历============");
for(Integer item: a) {
}
long endTime = System.nanoTime();
long duration = endTime - startTime;
System.out.println(duration + " 纳秒");
}
}
运行结果如下:
上面的程序整体上和ArrayList的相同,可以看出LinkedList类的随机索引遍历速度最慢。
性能和另外两个相差3个数量级,for-each循环遍历速度最快。
3. vector
- 简介:
- 和ArrayList类似,可变数组实现的列表
- vector同步,适合在多线程下使用;
- 原先不属于JCF,属于Java最早的数据结构,性能较差;
- 从jdk1.2开始,Vector被重写,并纳入到JCF;
- 官方文档建议在非同步情况下,优先采用ArrayList;