Java容器
所有容器的物理存储只有两大类, Array和Linked.
容器分为Collection和Map两大类, Collection旗下又有三个主力, List, Set和Queue, Queue是后添加的, 专门为高并发准备的
容器详细讲解
ArrayList
最常用的容器类
import java.util.ArrayList;
ArrayList中存储的是对象的引用, 并不是对象本身.
ArrayList al = new ArrayList();
ArrayList常用方法
<>中可以指定存放的对象类型
-
添加
ArrayList<Object> al = new ArrayList<>(); al.add(new Object()); //添加方法1 al.add(1,new Object()); //添加方法2
添加方法2是在指定位置添加对象, ArrayList的下标也是从0开始.
-
是否存在
判断一个对象是否在容器中, 判断是否是同一个对象boolean x = al.contains(new Object());
-
获取对象
过get获取指定位置的对象,如果输入的下标越界,一样会报错Object i = null; i = al.get(1);
-
获取对象位置
与contains一样,判断标准是对象是否相同System.out.println(al.indexOf(i));
-
删除
al.remove(0); //根据下标移除 al.remove(i); //根据对象移除
-
替换
替换指定位置的对象al.set(1,new Object());
-
容量
System.out.println(al.size());
-
合并
ArrayList xy = new ArrayList(); //假定xy中有十个对象 al.addAll(xy);
-
清空
al.clear();
-
遍历
for遍历for (int i = 0; i < al.size(); i++) { Object o = al.get(i); System.out.println(o); }
增强for遍历
for (Object o : al) { System.out.println(o); }
迭代器遍历
import java.util.Iterator; Iterator<Object> It= al.iterator(); //写法1 while(It.hasNext()){ Object o = It.next(); System.out.println(o); } -------------------------------------------- for (Iterator<Object> It= al.iterator(); It.hasNext();) { //写法2 Object o = (Object) It.next(); System.out.println(o); }
ArrayList和List
Arraylist实现了接口list,所以可以把引用声明写为list
import java.util.ArrayList;
import java.util.List;
List x1 = new ArrayList();
因为ArrayList实现了List接口,所以List接口的方法ArrayList都实现了.
LinkedList
与ArrayList一样,LinkedList也实现了List接口, 方法也和ArrayList方法相同.
LinkedList的特点
双向链表Deque
import java.util.LinkedList;
LinkedList<Object> ll =new LinkedList<>();
//双向链表LinkedList
ll.addFirst(new Object());
//在头部插入对象
ll.addLast(new Object());
//在尾部插入对象
System.out.println(ll.getFirst());
//查看头部对象
System.out.println(ll.getLast());
//查看尾部对象
Object o1 = ll.removeFirst();
//获取头部对象
Object o2 = ll.removeLast())
//获取尾部对象
//对象被获取后, 会被移除链表!!!
队列Queue
LinkedList 除了实现了List和Deque外,还实现了Queue接口.
import java.util.Queue;
Queue是先进先出队列 FIFO(First Input First Output)
常用方法: offer、poll、peek
Queue<Object> q= new LinkedList<>();
q.offer(new Object()); //在队列尾部添加元素
Object o1 = q.poll(); //取出队头元素
System.out.print(q.peek); //查看队头元素
ArrayList和LinkedList的区别
ArrayList和LinkedList都实现了List接口,有以下的不同点:
1、ArrayList是基于索引的数据接口,它的底层是数组。它可以以O(1)时间复杂度对元素进行随机访问。与此对应,LinkedList是以元素列表的形式存储它的数据,每一个元素都和它的前一个和后一个元素链接在一起,在这种情况下,查找某个元素的时间复杂度是O(n)。
2、相对于ArrayList,LinkedList的插入,添加,删除操作速度更快,因为当元素被添加到集合任意位置的时候,不需要像数组那样重新计算大小或者是更新索引。
3、LinkedList比ArrayList更占内存,因为LinkedList为每一个节点存储了两个引用,一个指向前一个元素,一个指向下一个元素。
二叉树
二叉树是常用的数据结构.
①结点:包含一个数据元素及若干指向子树分支的信息 。
②结点的度:一个结点拥有子树的数目称为结点的度 。
③叶子结点:也称为终端结点,没有子树的结点或者度为零的结点 。
④分支结点:也称为非终端结点,度不为零的结点称为非终端结点 。
⑤树的度:树中所有结点的度的最大值 。
⑥结点的层次:从根结点开始,假设根结点为第1层,根结点的孩子结点为第2层,依此类推,如果某一个结点位于第L层,则其孩子结点位于第L+1层 。
⑦树的深度:也称为树的高度,树中所有结点的层次最大值称为树的深度 。
⑧有序树:如果树中各棵子树的次序是有先后次序,则称该树为有序树 。
⑨无序树:如果树中各棵子树的次序没有先后次序,则称该树为无序树 。
⑩森林:由m(m≥0)棵互不相交的树构成一片森林。如果把一棵非空的树的根结点删除,则该树就变成了一片森林,森林中的树由原来根结点的各棵子树构成
二叉树是递归定义的,其结点有左右子树之分.
空二叉树、只有根节点二叉树、只有左子树、只有右子树、空二叉树、完全二叉树、满二叉树
满二叉树:如果一棵二叉树只有度为0的结点和度为2的结点,并且度为0的结点在同一层上,则这棵二叉树为满二叉树.
完全二叉树:深度为k,有n个结点的二叉树当且仅当其每一个结点都与深度为k,有n个结点的满二叉树中编号从1到n的结点一一对应时,称为完全二叉树; 完全二叉树的特点是叶子结点只可能出现在层序最大的两层上,并且某个结点的左分支下子孙的最大层序与右分支下子孙的最大层序相等或大1.
插入数据
插入基本逻辑是,小、相同的放左边,大的放右边
public class Node {
// 左子节点
public Node leftNode;
// 右子节点
public Node rightNode;
// 值
public Object value;
public void add(Object v) {
if(null==value)value = v;
//当前节点是否存在
else {
//当前节点存在, 比较值大小,分配左节点还是右节点
if((Integer) v -((Integer)value) <= 0){
if(null==leftNode) {//创建左节点
leftNode = new Node();
leftNode.add(v);
}
}
else {
if(null==rightNode) {//创建右节点
rightNode = new Node();
rightNode.add(v);
}
}
}
}
}
遍历二叉树
二叉树的遍历用的最多的三种:
先序遍历(根左右)
中序遍历(左根右)
后序遍历(左右根)
如果希望遍历的顺序是从小到大应该使用中序遍历(左根右)
public class Node {
// 左子节点
public Node leftNode;
// 右子节点
public Node rightNode;
// 值
public Object value;
public List<Object> values(){
List<Object> values = new ArrayList<>();
if(null!=leftNode) {
//遍历左节点
values.addAll(leftNode.values());
}
values.add(value);
//当前节点
if(null!=rightNode) {
//遍历右节点
values.addAll(rightNode.values());
}
return values;
}
//常常使用递归来完成数据结构的遍历
HashMap
HashMap是数组+链表+红黑树(JDK 1.8)实现的, 采用哈希表来存储.
Map最大的作用就是能够将对象映射到其他对象
HashMap储存数据的方式 键值对
键不能重复, 值可以重复
import java.util.HashMap;
public static void main(String[] args) {
HashMap<String,String> hm = new HashMap<>();
hm.put("a", "1");
hm.put("b", "2");
System.out.println(hm.get("a"));
}
put存入数据, get根据键返回值
String t1 = "1";
hm.put("a", t1);
hm.put("b", t1); //不同键对应相同的值
hm.put("c", "1");
hm.put("c", "2"); //覆盖了第一次的值
HashSet
Set中的元素,不能重复, 没有顺序
HashSet<String> hS = new HashSet<String>();
hS.add("wuhu");
hS.add("wuhu");
System.out.println(hS);
遍历需要借助迭代器或增强for
HashSet<Integer> numbers = new HashSet<Integer>();
for (int i = 0; i < 20; i++) {
numbers.add(i);
}
for (Iterator<Integer> iterator = numbers.iterator(); iterator.hasNext();) {
Integer i = (Integer) iterator.next();
System.out.println(i);
}
for (Integer i : numbers) {
System.out.println(i);
}
区别
HashSet自身并没有独立的实现,而是在里面封装了一个Map.
HashSet是作为Map的key而存在的
而value是一个命名为PRESENT的static的Object对象,因为是一个类属性,所以只会有一个。
Collection
Collection是Set List Queue和Deque的接口
Queue: 先进先出队列 Deque: 双向链表
Collection和Map之间没有关系,Collection是放一个一个对象的,Map 是放键值对的
Deque 继承 Queue,间接的继承了 Collection
Collections
Collections是一个工具类
import java.util.Collections;
下面介绍主要方法
-
reverse 反转
List<Integer> numbers = new ArrayList<>(); //numbers中有10组数据 Collections.reverse(numbers); //反转
-
乱序排列
Collections.shuffle(numbers);
-
升序排列
Collections.sort(numbers);
-
交换
swap的三个参数分别是容器引用, 下标1和下标2
交换下标1和下标2位置的值Collections.swap(numbers,1,3);
-
滚动
Collections.rotate(numbers,1);
效果图:
汇总
该部分内容来自百度
JAVA的容器包括如下:
List,Map,Set ,Collection ,List ,LinkedList ,ArrayList ,Vector ,Stack ,Set
Map ,Hashtable ,HashMap ,WeakHashMap
数据容器主要分为了两类:
Collection: 存放独立元素zhi的序列。
Map:存放key-value型的元dao素对。(这对于需要利用key查找value的程序十分的重要!)
从类体系图中可以看出,Collection定义了Collection类型数据的最基本、最共性的功能接口,而List对该接口进行了拓展。
其中各个类的适用场景有很大的差别,在使用时,应该根据需要灵活的进行选择。此处介绍最为常用的四个容器:
LinkedList :其数据结构采用的是链表,此种结构的优势是删除和添加的效率很高,但随机访问元素时效率较ArrayList类低。
ArrayList:其数据结构采用的是线性表,此种结构的优势是访问和查询十分方便,但添加和删除的时候效率很低。
HashSet: Set类不允许其中存在重复的元素(集),无法添加一个重复的元素(Set中已经存在)。HashSet利用Hash函数进行了查询效率上的优化,其contain()方法经常被使用,以用于判断相关元素是否已经被添加过。
HashMap: 提供了key-value的键值对数据存储机制,可以十分方便的通过键值查找相应的元素,而且通过Hash散列机制,查找十分的方便。
Java泛型
使用ArrayList存放对象, 当没有指定类型时, 它可以存放所有类型
ArrayList al = new ArrayList();
//可以存放各种类
当指定泛型的容器, 那么泛型中只能存放该类型和该类型的子类
ArrayList<tool> tools = new ArrayList<>();
//只能存放tool和tool的子类
ArrayList<tool> tools = new ArrayList<tool>();
//该句与第一句意义相同
添加和获取类
ArrayList<tool> tools = new ArrayList<>();
tools.add(new tools());
tool tools1 = (tool)tools.get(0);
//因为get返回的对象是Object类型, 所以必须强制转换成tool型,类型不符时会报错
关于泛型的通配符
extends
ArrayList<tool> tool1 = new ArrayList<>();
ArrayList<? extends tool> tools = tool1;
//tools的泛型有可能是tool,也有可能是tool的子类; 所以tools中的对象一定能转换成tool类
//但是不能使用add向里面添加类,因为tool的子类会出问题
//tools.add(new tool()); 会报错!!!
super
ArrayList<? super tool> tool1 = new ArrayList<Object>();
//tool1中有有可能是tool,tool的子类,或者Object
//这个Object和之前得返回Object是不一样的
//super和extends是相反的,super能添加,不能取出
//但是,不能从里面取数据出来,因为其泛型可能是Object,而Object是强转tool会失败
?
ArrayList<?>
//取出只能是Object
//即不能插入.也不能取出