赞
踩
前言:
目录
这是数据结构的最后一篇,这篇会讲到Map和set还有哈希。学了这些,遇到莫些题,你会觉得很简单。
二叉搜索树又称二叉排序树---二叉树节点的值都是唯一的,不重复的
1.若它的左子树不为空。则左子树的所有节点的值都小于根节点的值
2,若他的右子树不为空,则右子树的所有节点的值都大于根节点的值。
插入是在二叉树的叶子节点进行插入的
- public boolean insert(int key) {
- TreeNode ret=new TreeNode(key);
- //判断此树是不是空树
- if(root==null){
- root=ret;
- return true;
- }
- TreeNode parent=null;
- TreeNode cur=root;
- while(cur!=null){
- //判断它是不是大于此节点的值
- if(cur.key<key) {//大于根节点,往右边插
- parent=cur;//记录父亲节点
- cur=cur.right;
- }else if(cur.key>key) {//小于根节点的,往左边插
- parent =cur;
- cur=cur.left;
- }
- }//此时到了叶子节点
- if(ret.key< parent.key){
- parent.left=ret;
- }else {
- parent.right=ret;
- }
- return true;
- }
若根节点不为空
如果根节点key==查找的key返回true
如果根节点key>查找的key,在左子树查找。
如果根节点key<查找的key,在右子树查找。
- public TreeNode search(int key) {
- //查找根节点是否为null
- if(root==null){
- return null;
- }
- TreeNode cur=root;
- while(cur!=null){
- if(cur.key>key){//比根节点小
- cur=cur.left;
- }else if(cur.key<key){//比根节点大
- cur=cur.right;
- }else{
- return cur;//找到
- }
- }
- return null;
- }
删除比较麻烦,要分为三大类。设待删除节点为cur .待删除的父亲节点为parent.
- //删除节点
- public void removeChild(TreeNode cur,TreeNode parent){
- //分三种情况
- //1 cur.left==null
- if(cur.left==null){
- //判断是不是根节点
- if(cur.equals(root)){
- root=root.right;
- }
- if(cur.equals(parent.left)){
- parent.left=cur.left;
- }
- if(cur.equals(parent.right)){
- parent.left=cur.right;
- }
- }else if(cur.right==null){ //2.cur.right==null
- if(cur.equals(root)){
- root=root.left;
- }
- if(cur.equals(parent.right)){
- parent.right=cur.left;
- }
- if(cur.equals(parent.left)){
- parent.left=cur.left;
- }
- }else{//3.cur.left!=null&&cur.right!=null
- //用一个叫做替罪羊
- //可以找左树的最右边,就是左边最大的,也小于根节点
- //可以找右边的最左边,就是右边最小的,也大于根节点
- TreeNode target=cur.left;//左树
- TreeNode targetParent=cur;
- while(target.right!=null){//左树的最右边
- targetParent=target;
- target=target.right;
- }
- cur.key=target.key;//将替罪羊的值赋值给cur
- //将替罪羊删除
- if(target.equals(targetParent.left)){
- targetParent.left=target.left;
- }else{
- targetParent.right=target.right;
- }
- }
- }
- }
Map和Set是一种专门用来进行搜索的容器或者数据结构,其底层是一棵二叉搜索树。其搜索的效率与其具体的实际化子类有关。可能在查找时进行一些插入和删除的操作,即动态查找。
本节介绍的Map和Set是一种适合动态查找的集合容器。
把搜索的数据称为关键字(Key)和关键字对应的称为值(Value),将其称为Key-Value的键值对
1.纯Key模型----快速查找莫个数据是否存在
2.Key-Value模型---统计文件中每个单词出现的次数。<单词,单词出现的次数>
Map是一个接口类,没有继承Collection(Set和List都继承了),该类存储的是<K,V>结构的键值对,并且K一定是唯一的。
Map.Entry<K, V>是Map内部实现的用来存放<Key,Value>键值对映射关系的内部类
方法 | 解释 |
K getKey() | 返回entry中的Key |
V getValue() | 返回Key中的Value |
- public class Test {
- public static void main(String[] args) {
- TreeMap<String,Integer>map=new TreeMap<>();
- map.put("hello",4);//h-104
- map.put("world",1);//w-119
- map.put("abc",7);//a-97
- //返回所以的Key-Value的映射关系
- Set< Map.Entry<String,Integer>>entrySet=map.entrySet();
- for (Map.Entry<String,Integer>entry:entrySet) {
- System.out.println("Key:"+entry.getKey()+" "+
- "Value"+entry.getValue());
- }
- }
- }
从中,看出了什么吗?
Key的是安找升序排序的,故:Key一定要比较,不然会报错。
方法 | 解释 |
V get(Object Key) | 返回Key对应的Value |
V getOrDefault(Object key ,v defaultValue) | 返回key对应的Value,key不存在,返回默认值 |
V put(K key V value) | 设置key对应的Value//Key一定可以比较 |
V remove(Object key) | 删除Key对应的映射关系 |
Set<K> keySet() | 返回所有Key的不重复集合 |
Collection<V>values() | 返回所有Value的可重复集合 |
boolean containsKey(Object key) | 判断是否包含Key |
boolean containsKey(Object value) | 判断是否包含value |
注意:
1.Map是一个接口,不能直接实例化对象。
2.Map中存放键值对的Key是唯一的,Value是可以重复的。
3.Key不能为空,否则就会包空指针异常。
4.Map中键值对的Key不能直接修改(如果要修改,只能先删除,再进行重新插入!)
Set继承Collection的接口类,Set中存储Key
方法 | 解释 |
boolean add(E e) | 添加元素 重复元素不会添加 |
void clear () | 清空集合 |
boolean contains(Object 0) | 判断o是否存在集合中 |
lterator<E> iterator() | 返回迭代器 |
boolean remove(Object o) | 删除集合中的o |
int size() | 返回set中元素的个数 |
boolean isEmpty() | 检测set是否为空,空返回true 不空返回false |
object [] toArray | 将set中的元素转换为数组返 |
注意:
1.set中只存储了key,并且要求key一定要唯一。
2.Set的底层是使用map来实现的。
3.set最大的功能就是对集合中的元素去重
4.set中不能插入null的key。
在笔试中出现过。可以注意下哟
138. 复制带随机指针的链表 - 力扣(LeetCode)
- class Solution {
- public Node copyRandomList(Node head) {
- HashMap<Node,Node> map=new HashMap<>();
- Node cur=head;//将链表都存到map中
- while(cur!=null){
- Node node=new Node(cur.val);//创建一个节点
- map.put(cur,node);
- cur=cur.next;
- }
- //第二次遍历链表
- cur=head;
- while(cur!=null){
- map.get(cur).next=map.get(cur.next);
- map.get(cur).random=map.get(cur.random);
- cur=cur.next;
- }
- return map.get(head);
- }
- }
这道题我就说说思路就不画图了。
1.我们用HashMap 来存放单词。key是单词。value 是单词出现的次数
2.Top-k问题。将前K个单词按照频率来建立小堆。
3.K后面的单词,依次和堆顶元素相比较,单词出现频率大于堆顶的。该单词入堆。堆顶元素出堆。如果频率出现相同。比堆顶单词首字母大。该单词入堆,堆顶元素出堆。按照单词大小建立大堆。
4.用列表保存堆中元素,之后逆转。
- class Solution {
- public List<String> topKFrequent(String[] words, int k) {
- HashMap<String, Integer> map = new HashMap<>();
- //保存字符串数组到map
- for (String x : words) {
- if (map.containsKey(x)) {
- int val = map.get(x);
- map.put(x, val + 1);
- } else {
- map.put(x, 1);
- }
- }
- //Top-K问题
- PriorityQueue<Map.Entry<String, Integer>> q1 =
- new PriorityQueue<>(new Comparator<Map.Entry<String, Integer>>() {
- @Override
- public int compare(Map.Entry<String, Integer> o1,
- Map.Entry<String, Integer> o2) {
- if (o1.getValue().compareTo(o2.getValue()) == 0) {
- //频率相同,按照单词首字母大小建立大堆
- return o2.getKey().compareTo(o1.getKey());
- }//频率不同,按照频率大小建立小堆
- return o1.getValue().compareTo(o2.getValue());
- }
- });
- //遍历map当中的entry
- for (Map.Entry<String, Integer> entry : map.entrySet()) {
- //把前k个元素建成小堆
- if (q1.size() < k) {
- q1.offer(entry);
- } else {//后k个元素,逐渐和堆顶元素进行比较
- Map.Entry<String, Integer> s1 = q1.peek();
- //频率大
- if (entry.getValue().compareTo(s1.getValue()) > 0) {
- //比堆顶元素大
- //将堆顶元素出堆
- q1.poll();
- //再将这个元素入堆
- q1.offer(entry);
- }//和堆顶元素频率相等
- else {
- if (entry.getValue().compareTo(s1.getValue()) == 0) {
- //比较单词首字母的大小
- if (s1.getKey().compareTo(entry.getKey()) > 0) {
- //比堆顶元素的首字母大,堆顶元素出堆,
- q1.poll();
- q1.offer(entry);
- }
- }
- }
- }
- }
- //将堆的元素赋值给List
- List<String> list = new ArrayList<>();
- for (int i = 0; i < k; i++) {
- Map.Entry<String, Integer> m1 = q1.poll();
- list.add(m1.getKey());
- }
- Collections.reverse(list);
- return list;
- }
- }
使元素存储位置与它的关键码之间能够建立一一映射的关系。
不同关键字通过相同哈希计算出相同的哈希地址,这种现象称为哈希冲突或哈希碰撞。
冲突的发生使必然的,我们只能尽量降低冲突。
载荷因子:填入表中的元素个数/散列表的长度(严格限制在0.7-0.8)之间
闭散列:也叫开放定址法。可以将key存放到冲突位置中的‘下一个'空位置中。
1.线性探测:
从发送冲突的位置开始,依次向后探测,直至找到下一个空位置。---冲突数据堆积在一起
2.二次探测:
找下一个空位置的方法:Hi=(Ho+i^2)%m
Hi:要插入的位置
Ho:hash(key)=key%capacity--长度。计算出来的位置
i:第几次冲突。m:长度。
hashCode() 方法的作用是获取哈希码。返回的是一个整数,作用是:确定对象在哈希表的索引下标。
equals()判断两个对象是否相等。
1.两个对象的hashcode一样,equals一定一样?
不一定
2.两个对象的equals一样,hashcode一定一样?
一定
重写equals()方法就可以比较两个对象是否相等,为什么还要重写hashcode()方法?
HashSet和HashMap在判断两个元素是否相等时,会先判断hashCode是否相等,如果
hashCode相等,才会用equals()方法比较是否相等。
总结:以上就是我总结的Map和Set,如果有错,请各位铁子留言改正,若感觉不错,一键三连。
赞
踩
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。