哈希表具有的性质
- 哈希表在使用层面上可以理解为一种集合结构
- 如果只有key, 没有伴随数据value, 可以使用HashSet结构
- 如果既有key, 又有伴随数据value, 可以使用HashMap结构
- 有无伴随数据, 是HashMap和HashSet唯一的区别,底层的实际结构是一回事
- 内部数据不重复
- 内部数据无序
- 使用哈希表进行增(put), 删(remove), 改(put), 查(get)的操作,可以认为时间复杂度为O(1),只不过这里的常数时间比较大
- 放入哈希表的东西,如果是基础类型,内部按值传递,内存占用就是这个东西的大小
- 放入哈希表的东西,如果不是基础类型,内部按引用传递,内存占用是这个东西内存地址的大小
- HashSet重复add会返回false,HashMap重复put会返回1
- TreeSet==>O(log(n))==> 基于树的搜索,只需要搜索一半即可,保证元素不重复以及元素有序,放的数字的话,默认是升序排序,TreeSet的排序
- TreeSet用法
相关的代码如下:
public static void main(String[] args) {
//这里hashSet的key是基础类型,所以是按值传递,也就是传入的是什么是多大,哈希表都会copy一份
HashSet<Integer> hashSet1 = new HashSet<>();
hashSet1.add(3);
hashSet1.remove(3);
System.out.println(hashSet1.contains(3));
System.out.println("======1======");
//这里hashSet的key是非基础类型,所以是引用传递,也就是传入的是内存地址,如下面的两次new的内存地址并不相同
Node nodeA = null;
Node nodeB = null;
nodeA = new Node(1);
nodeB = new Node(1);
HashSet<Node> hashSet2 = new HashSet<>();
hashSet2.add(nodeA);
hashSet2.add(nodeB);//true
System.out.println(hashSet2.add(nodeB));//false不可以重复加入
hashSet2.remove(nodeA);
System.out.println(hashSet2.contains(nodeA));//false
System.out.println("=======2=====");
//hashMap1的key是基础类型 -> String类型
HashMap<String, Integer> hashMap1 = new HashMap<>();
String str1 = "key";
String str2 = "key";
hashMap1.put(str2, 1);
System.out.println(hashMap1.put(str2, 1));//返回的是1
System.out.println(hashMap1.containsKey(str1));//true,这是因为key是基础类型是按照值来传递的
System.out.println(hashMap1.get(str1));//1
System.out.println(hashMap1.get(str2));//1
hashMap1.put(str2, 2);//改
System.out.println(hashMap1.get(str2));//2
hashMap1.remove(str2);
System.out.println(hashMap1.containsKey(str2));//false
System.out.println("======3======");
//hashMap2的key是非基础类型->Node类型
HashMap<Node, String> hashMap2 = new HashMap<>();
hashMap2.put(nodeA, "A节点");
System.out.println(hashMap2.containsKey(nodeA));//true
System.out.println(hashMap2.containsKey(nodeB));//false
System.out.println(hashMap2.get(nodeA));//A节点
hashMap2.put(nodeA, "B节点");
System.out.println(hashMap2.get(nodeA));//B节点
hashMap2.remove(nodeA);
System.out.println(hashMap2.containsKey(nodeA));//false
System.out.println("======4======");
}
public static class Node{
public int value;
public Node next;
public Node(int val){
value = val;
}
}
有序表具有的性质
- 有序表在使用层面上可以理解为一种集合结构
- 如果只有key, 没有伴随数据value, 可以使用TreeSet结构
- 如果既有key, 又有伴随数据value, 可以使用TreeMap结构
- 有无伴随数据, 是TreeSet和TreeMap唯一的区别,底层的实际结构是一回事
- 有序表和哈希表的区别是,有序表把key按照顺序组织起来,而哈希表完全不组织
- 红黑树、AVL树、size-balance-tree和跳表等都属于有序表结构,只是底层具体实现不同
- 放入有序表的东西,如果是基础类型,内部按值传递,内存占用就是这个东西的大小
- 放入有序表的东西,如果不是基础类型,必须提供比较器,内部按引用传递,内部占用是这个东西内存地址的大小
- 使用有序表进行增(put), 删(remove), 改(put), 查(get)的操作,可以认为时间复杂度为O(logN)
- 不管是什么底层具体实现,只要是有序表, 都有以下固定的基本功能和固定的时间复杂度,下面有代码展示
相关的代码是:
public static void main(String[] args) {
//展示有序表的常用操作
//TreeMap1的key是基础类型 -> Integer类型
TreeMap<Integer, String> treeMap1 = new TreeMap<>();
treeMap1.put(7, "我是7");
treeMap1.put(5, "我是5");
treeMap1.put(4, "我是4");
treeMap1.put(3,"我是3");
treeMap1.put(9,"我是9");
treeMap1.put(2,"我是2");
treeMap1.put(2,"我是2");
System.out.println(treeMap1.containsKey(5));//true
System.out.println(treeMap1.get(5));//我是5
System.out.println(treeMap1.firstKey());//最小的key 2
System.out.println(treeMap1.lastKey());//最大的key 9
System.out.println(treeMap1.floorKey(8));//<=8且离8最近的key 7
System.out.println(treeMap1.ceilingKey(8));//>=8且离8最近的key 9
treeMap1.remove(5);
System.out.println(treeMap1.get(5));//null
treeMap1.remove(2);
System.out.println(treeMap1.get(2));//false,说明有序表也没有重复的值
treeMap1.put(3, "改动了");
System.out.println(treeMap1.get(3));//改动了
System.out.println("===========");
//treeMap2的key是非基础类型->Node类型
Node nodeA = new Node(5);
Node nodeB = new Node(3);
Node nodeC = new Node(7);
//注:需要提供Node类型的比较器,否则会报错
TreeSet<Node> treeSet = new TreeSet<>(new NodeComparator());
treeSet.add(nodeA);
treeSet.add(nodeB);
treeSet.add(nodeC);
}
public static class Node{
public int value;
public Node next;
public Node(int val){
value = val;
}
}
public static class NodeComparator implements Comparator<Node>{
@Override
public int compare(Node o1, Node o2) {
return o1.value - o2.value;
}
}