设计一个类似堆栈的数据结构,将元素推入堆栈,并从堆栈中弹出出现频率最高的元素。
实现FreqStack类:
FreqStack()构造一个空的堆栈。
void push(int val)将一个整数val压入栈顶。
int pop()删除并返回堆栈中出现频率最高的元素。
如果出现频率最高的元素不只一个,则移除并返回最接近栈顶的元素。
实现使用一个变量maxFreq更新每次操作的最大频次
使用哈希表和栈,建立一个存储val和其对应出现频次的哈希表,在建立一个频次key和当前频次出现有哪些元素value使用栈对出现的频次的元素保存的哈希表
class FreqStack {// key是val,value是val对应的频次private Map freq;// key 存储频次,value是val入队的队列private Map> group;private int maxFreq;public FreqStack() {freq = new HashMap();group = new HashMap>();maxFreq = 0;}public void push(int val) {// freq.get(val) 记录的是val的频率freq.put(val,freq.getOrDefault(val,0)+1);// group.get(频次) 记录的是 频次对应出现的元素,putIfAbsent是key为空就group.putIfAbsent(freq.get(val), new ArrayDeque());group.get(freq.get(val)).push(val);// maxFreq 标记每次最大的频次maxFreq = Math.max(maxFreq,freq.get(val));}public int pop() {int val = group.get(maxFreq).pop();freq.put(val,freq.get(val)-1);// 最大频次的队列不为空,最大频率就始终是keyif (group.get(maxFreq).isEmpty()) {maxFreq--;}return val;}
}
HashMap类是java.util包下,HashMap的类继承了抽象Map的抽象类,实现Map接口,可以克隆复制的接口,序列化接口
public class HashMap extends AbstractMap implements Map, Cloneable, Serializable
HashMap 的 putIfAbsent(),方法会先判断指定的键 key 是否存在,不存在则将键值对插入到 HashMap 中。如果所指定的 key 不在 HashMap 中存在,则返回 null
注意,如果指定 key 之前已经和一个 null 值相关联了 ,则该方法也返回 null,因为 HashMap 的key允许有且仅有一个为 null
public V getOrDefault(Object key, V defaultValue) {Node e;return (e = this.getNode(hash(key), key)) == null ? defaultValue : e.value;}public V putIfAbsent(K key, V value) {return this.putVal(hash(key), key, value, true, true);}
HashMap的哈希函数的实现,
static final int hash(Object key) {int h;return key == null ? 0 : (h = key.hashCode()) ^ h >>> 16;}
HashMap的put方法
首次扩容,判断数组是否为空,如果数组为空,则进行第一次扩容
在自定义数组容量公式是
容量大小 = 需要的空间 / 0.75 + 1
第二步,计算索引,通过上面的哈希函数,计算键值对在数组中的索引
第三步,插入元素,如果当前位置元素为null,直接插入;如果当前位置元素不为null,并且key已经存在,则直接覆盖掉value;如果当前位置元素不为null,并且key不存在,就将数据链接到链表的末尾;若链表的长度达到8,链表就转化为红黑树,并且将数据插入到树中
第四步,再次扩容,如果数组元素的个数大于threshold,就再次进行扩容
private static final long serialVersionUID = 362498820763181265L;static final int DEFAULT_INITIAL_CAPACITY = 16;static final int MAXIMUM_CAPACITY = 1073741824;static final float DEFAULT_LOAD_FACTOR = 0.75F;static final int TREEIFY_THRESHOLD = 8;static final int UNTREEIFY_THRESHOLD = 6;static final int MIN_TREEIFY_CAPACITY = 64;transient Node[] table;transient Set> entrySet;transient int size;transient int modCount;int threshold;final float loadFactor;
HashMap的put方法,调用了putVal方法
public V put(K key, V value) {return this.putVal(hash(key), key, value, false, true);}final V putVal(int hash, K key, V value, boolean onlyIfAbsent, boolean evict) {Node[] tab;int n;if ((tab = this.table) == null || (n = tab.length) == 0) {n = (tab = this.resize()).length;}Object p;int i;if ((p = tab[i = n - 1 & hash]) == null) {tab[i] = this.newNode(hash, key, value, (Node)null);} else {Object e;Object k;if (((Node)p).hash == hash && ((k = ((Node)p).key) == key || key != null && key.equals(k))) {e = p;} else if (p instanceof TreeNode) {e = ((TreeNode)p).putTreeVal(this, tab, hash, key, value);} else {int binCount = 0;while(true) {if ((e = ((Node)p).next) == null) {((Node)p).next = this.newNode(hash, key, value, (Node)null);if (binCount >= 7) {this.treeifyBin(tab, hash);}break;}if (((Node)e).hash == hash && ((k = ((Node)e).key) == key || key != null && key.equals(k))) {break;}p = e;++binCount;}}if (e != null) {V oldValue = ((Node)e).value;if (!onlyIfAbsent || oldValue == null) {((Node)e).value = value;}this.afterNodeAccess((Node)e);return oldValue;}}++this.modCount;if (++this.size > this.threshold) {this.resize();}this.afterNodeInsertion(evict);return null;}
HashMap的get操作,根据传入的key查询到哈希函数操作之后的节点,判断这个节点是否为null,为空返回null,不为空返回节点值
public V get(Object key) {Node e;return (e = this.getNode(hash(key), key)) == null ? null : e.value;}final Node getNode(int hash, Object key) {Node[] tab;Node first;int n;if ((tab = this.table) != null && (n = tab.length) > 0 && (first = tab[n - 1 & hash]) != null) {Object k;if (first.hash == hash && ((k = first.key) == key || key != null && key.equals(k))) {return first;}Node e;if ((e = first.next) != null) {if (first instanceof TreeNode) {return ((TreeNode)first).getTreeNode(hash, key);}do {if (e.hash == hash && ((k = e.key) == key || key != null && key.equals(k))) {return e;}} while((e = e.next) != null);}}return null;}