范文健康探索娱乐情感热点
投稿投诉
热点动态
科技财经
情感日志
励志美文
娱乐时尚
游戏搞笑
探索旅游
历史星座
健康养生
美丽育儿
范文作文
教案论文
国学影视

面试记录HashMap核心知识,扰动函数负载因子扩容链表拆分

  作者:小傅哥
  博客:https://bugstack.cn
  沉淀、分享、成长,让自己和他人都能有所收获! 一、前言
  得益于 Doug Lea 老爷子的操刀,让HashMap 成为使用和面试最频繁的API,没办法设计的太优秀了!
  HashMap 最早出现在 JDK 1.2中,底层基于散列算法实现。HashMap 允许 null 键和 null 值,在计算哈键的哈希值时,null 键哈希值为 0。HashMap 并不保证键值对的顺序,这意味着在进行某些操作后,键值对的顺序可能会发生变化。另外,需要注意的是,HashMap 是非线程安全类,在多线程环境下可能会存在问题。
  HashMap 最早在JDK 1.2中就出现了,底层是基于散列算法实现,随着几代的优化更新到目前为止它的源码部分已经比较复杂,涉及的知识点也非常多,在JDK 1.8中包括; 1、散列表实现 、2、扰动函数 、3、初始化容量 、4、负载因子 、5、扩容元素拆分 、6、链表树化 、7、红黑树 、8、插入 、9、查找 、10、删除 、11、遍历 、12、分段锁 等等,因涉及的知识点较多所以需要分开讲解,本章节我们会先把目光放在前五项上,也就是关于数据结构的使用上。
  数据结构相关往往与数学离不开,学习过程中建议下载相应源码进行实验验证,可能这个过程有点烧脑,但学会后不用死记硬背就可以理解这部分知识。 二、资源下载
  本章节涉及的源码和资源在工程, interview-04 中,包括; 10万单词测试数据,在doc文件夹 扰动函数excel展现,在doc文件夹 测试源码部分在 interview-04 工程中
  可以通过关注公众号: bugstack虫洞栈 ,回复下载进行获取{回复下载后打开获得的链接,找到编号ID:19 }三、源码分析1. 写一个最简单的HashMap
  学习HashMap前,最好的方式是先了解这是一种怎么样的数据结构来存放数据。而HashMap经过多个版本的迭代后,乍一看代码还是很复杂的。就像你原来只穿个裤衩,现在还有秋裤和风衣。所以我们先来看看最根本的HashMap是什么样,也就是只穿裤衩是什么效果,之后再去分析它的源码。
  问题:  假设我们有一组7个字符串,需要存放到数组中,但要求在获取每个元素的时候时间复杂度是O(1)。也就是说你不能通过循环遍历的方式进行获取,而是要定位到数组ID直接获取相应的元素。
  方案:  如果说我们需要通过ID从数组中获取元素,那么就需要把每个字符串都计算出一个在数组中的位置ID。 字符串获取ID你能想到什么方式?  一个字符串最直接的获取跟数字相关的信息就是HashCode,可HashCode的取值范围太大了 [-2147483648, 2147483647] ,不可能直接使用。那么就需要使用HashCode与数组长度做与运算,得到一个可以在数组中出现的位置。如果说有两个元素得到同样的ID,那么这个数组ID下就存放两个字符串。
  以上呢其实就是我们要把字符串散列到数组中的一个基本思路,接下来我们就把这个思路用代码实现出来。 1.1 代码实现// 初始化一组字符串 List list = new ArrayList<>(); list.add("jlkk"); list.add("lopi"); list.add("小傅哥"); list.add("e4we"); list.add("alpo"); list.add("yhjk"); list.add("plop");  // 定义要存放的数组 String[] tab = new String[8];  // 循环存放 for (String key : list) {     int idx = key.hashCode() & (tab.length - 1);  // 计算索引位置     System.out.println(String.format("key值=%s Idx=%d", key, idx));     if (null == tab[idx]) {         tab[idx] = key;         continue;     }     tab[idx] = tab[idx] + "->" + key; } // 输出测试结果 System.out.println(JSON.toJSONString(tab));
  这段代码整体看起来也是非常简单,并没有什么复杂度,主要包括以下内容; 初始化一组字符串集合,这里初始化了7个。 定义一个数组用于存放字符串,注意这里的长度是8,也就是2的3次幂。这样的数组长度才会出现一个  0111  除高位以外都是1的特征,也是为了散列。接下来就是循环存放数据,计算出每个字符串在数组中的位置。 key.hashCode() & (tab.length - 1) 。在字符串存放到数组的过程,如果遇到相同的元素,进行连接操作 模拟链表的过程 。最后输出存放结果。
  测试结果 key值=jlkk Idx=2 key值=lopi Idx=4 key值=小傅哥 Idx=7 key值=e4we Idx=5 key值=alpo Idx=2 key值=yhjk Idx=0 key值=plop Idx=5 测试结果:["yhjk",null,"jlkk->alpo",null,"lopi","e4we->plop",null,"小傅哥"] 在测试结果首先是计算出每个元素在数组的Idx,也有出现重复的位置。 最后是测试结果的输出,1、3、6,位置是空的,2、5,位置有两个元素被链接起来 e4we->plop 。这就达到了我们一个最基本的要求,将串元素散列存放到数组中,最后通过字符串元素的索引ID进行获取对应字符串。这样是HashMap的一个最基本原理,有了这个基础后面就会更容易理解HashMap的源码实现。 1.2 Hash散列示意图
  如果上面的测试结果不能在你的头脑中很好地建立出一个数据结构,那么可以看以下这张散列示意图,方便理解;
  bugstack.cn Hash散列示意图 这张图就是上面代码实现的全过程,将每一个字符串元素通过Hash计算索引位置,存放到数组中。 黄色的索引ID是没有元素存放、绿色的索引ID存放了一个元素、红色的索引ID存放了两个元素。 1.3 这个简单的HashMap有哪些问题
  以上我们实现了一个简单的HashMap,或者说还算不上HashMap,只能算做一个散列数据存放的雏形。但这样的一个数据结构放在实际使用中,会有哪些问题呢? 这里所有的元素存放都需要获取一个索引位置,而如果元素的位置不够散列碰撞严重,那么就失去了散列表存放的意义,没有达到预期的性能。 在获取索引ID的计算公式中,需要数组长度是2的幂次方,那么怎么进行初始化这个数组大小。 数组越小碰撞的越大,数组越大碰撞的越小,时间与空间如何取舍。 目前存放7个元素,已经有两个位置都存放了2个字符串,那么链表越来越长怎么优化。 随着元素的不断添加,数组长度不足扩容时,怎么把原有的元素,拆分到新的位置上去。
  以上这些问题可以归纳为; 扰动函数 、初始化容量 、负载因子 、扩容方法 以及链表和红黑树 转换的使用等。接下来我们会逐个问题进行分析。2. 扰动函数
  在HashMap存放元素时候有这样一段代码来处理哈希值,这是 java 8 的散列值扰动函数,用于优化散列效果;static final int hash(Object key) {     int h;     return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16); } 2.1 为什么使用扰动函数
  理论上来说字符串的 hashCode 是一个int类型值,那可以直接作为数组下标了,且不会出现碰撞。但是这个hashCode 的取值范围是[-2147483648, 2147483647],有将近40亿的长度,谁也不能把数组初始化得这么大,内存也是放不下的。
  我们默认初始化的Map大小是16个长度  DEFAULT_INITIAL_CAPACITY = 1 << 4 ,所以获取的Hash值并不能直接作为下标使用,需要与数组长度进行取模运算得到一个下标值,也就是我们上面做的散列列子。
  那么,hashMap源码这里不只是直接获取哈希值,还进行了一次扰动计算, (h = key.hashCode()) ^ (h >>> 16) 。把哈希值右移16位,也就正好是自己长度的一半,之后与原哈希值做异或运算,这样就混合了原哈希值中的高位和低位,增大了随机性 。计算方式如下图;
  bugstack.cn 扰动函数 说白了,使用扰动函数就是为了增加随机性,让数据元素更加均衡的散列,减少碰撞。 2.2 实验验证扰动函数
  从上面的分析可以看出,扰动函数使用了哈希值的高半区和低半区做异或,混合原始哈希码的高位和低位,以此来加大低位区的随机性。
  但看不到实验数据的话,这终究是一段理论,具体这段哈希值真的被增加了随机性没有,并不知道。所以这里我们要做一个实验,这个实验是这样做; 选取10万个单词词库 定义128位长度的数组格子 分别计算在扰动和不扰动下,10万单词的下标分配到128个格子的数量 统计各个格子数量,生成波动曲线。如果扰动函数下的波动曲线相对更平稳,那么证明扰动函数有效果。 2.2.1 扰动代码测试
  扰动函数对比方法 public class Disturb {      public static int disturbHashIdx(String key, int size) {         return (size - 1) & (key.hashCode() ^ (key.hashCode() >>> 16));     }      public static int hashIdx(String key, int size) {         return (size - 1) & key.hashCode();     }  } disturbHashIdx  扰动函数下,下标值计算hashIdx  非扰动函数下,下标值计算
  单元测试 // 10万单词已经初始化到words中 @Test public void test_disturb() {     Map map = new HashMap<>(16);     for (String word : words) {         // 使用扰动函数         int idx = Disturb.disturbHashIdx(word, 128);         // 不使用扰动函数         // int idx = Disturb.hashIdx(word, 128);         if (map.containsKey(idx)) {             Integer integer = map.get(idx);             map.put(idx, ++integer);         } else {             map.put(idx, 1);         }     }     System.out.println(map.values()); }
  以上分别统计两种函数下的下标值分配,最终将统计结果放到excel中生成图表。 2.2.2 扰动函数散列图表
  以上的两张图,分别是没有使用扰动函数和使用扰动函数的,下标分配。实验数据; 10万个不重复的单词 128个格子,相当于128长度的数组
  未使用扰动函数
  bugstack.cn 未使用扰动函数
  使用扰动函数
  bugstack.cn 使用扰动函数 从这两种的对比图可以看出来,在使用了扰动函数后,数据分配的更加均匀了。 数据分配均匀,也就是散列的效果更好,减少了hash的碰撞,让数据存放和获取的效率更佳。 3. 初始化容量和负载因子
  接下来我们讨论下一个问题,从我们模仿HashMap的例子中以及HashMap默认的初始化大小里,都可以知道,散列数组需要一个2的幂次方的长度,因为只有2的幂次方在减1的时候,才会出现 01111 这样的值。
  那么这里就有一个问题,我们在初始化HashMap的时候,如果传一个17个的值 new HashMap<>(17); ,它会怎么处理呢?3.1 寻找2的幂次方最小值
  在HashMap的初始化中,有这样一段方法; public HashMap(int initialCapacity, float loadFactor) {     ...     this.loadFactor = loadFactor;     this.threshold = tableSizeFor(initialCapacity); } 阈值 threshold ,通过方法tableSizeFor 进行计算,是根据初始化来计算的。这个方法也就是要寻找比初始值大的,最小的那个2进制数值。比如传了17,我应该找到的是32(2的4次幂是16<17,所以找到2的5次幂32)。
  计算阈值大小的方法; static final int tableSizeFor(int cap) {     int n = cap - 1;     n |= n >>> 1;     n |= n >>> 2;     n |= n >>> 4;     n |= n >>> 8;     n |= n >>> 16;     return (n < 0) ? 1 : (n >= MAXIMUM_CAPACITY) ? MAXIMUM_CAPACITY : n + 1; } MAXIMUM_CAPACITY = 1 << 30,这个是临界范围,也就是最大的Map集合。 乍一看可能有点晕怎么都在向右移位1、2、4、8、16,这主要是为了把二进制的各个位置都填上1,当二进制的各个位置都是1以后,就是一个标准的2的幂次方减1了,最后把结果加1再返回即可。
  那这里我们把17这样一个初始化计算阈值的过程,用图展示出来,方便理解;
  bugstack.cn 计算阈值 3.2 负载因子static final float DEFAULT_LOAD_FACTOR = 0.75f;
  负载因子是做什么的?
  负载因子,可以理解成一辆车可承重重量超过某个阈值时,把货放到新的车上。
  那么在HashMap中,负载因子决定了数据量多少了以后进行扩容。 这里要提到上面做的HashMap例子,我们准备了7个元素,但是最后还有3个位置空余,2个位置存放了2个元素。  所以可能即使你数据比数组容量大时也是不一定能正正好好的把数组占满的,而是在某些小标位置出现了大量的碰撞,只能在同一个位置用链表存放,那么这样就失去了Map数组的性能。
  所以,要选择一个合理的大小下进行扩容,默认值0.75就是说当阈值容量占了3/4时赶紧扩容,减少Hash碰撞。
  同时0.75是一个默认构造值,在创建HashMap也可以调整,比如你希望用更多的空间换取时间,可以把负载因子调的更小一些,减少碰撞。 4. 扩容元素拆分
  为什么扩容,因为数组长度不足了。那扩容最直接的问题,就是需要把元素拆分到新的数组中。拆分元素的过程中,原jdk1.7中会需要重新计算哈希值,但是到jdk1.8中已经进行优化,不再需要重新计算,提升了拆分的性能,设计的还是非常巧妙的。 4.1 测试数据@Test public void test_hashMap() {     List list = new ArrayList<>();     list.add("jlkk");     list.add("lopi");     list.add("jmdw");     list.add("e4we");     list.add("io98");     list.add("nmhg");     list.add("vfg6");     list.add("gfrt");     list.add("alpo");     list.add("vfbh");     list.add("bnhj");     list.add("zuio");     list.add("iu8e");     list.add("yhjk");     list.add("plop");     list.add("dd0p");     for (String key : list) {         int hash = key.hashCode() ^ (key.hashCode() >>> 16);         System.out.println("字符串:" + key + " 	Idx(16):" + ((16 - 1) & hash) + " 	Bit值:" + Integer.toBinaryString(hash) + " - " + Integer.toBinaryString(hash & 16) + " 		Idx(32):" + ((         System.out.println(Integer.toBinaryString(key.hashCode()) +" "+ Integer.toBinaryString(hash) + " " + Integer.toBinaryString((32 - 1) & hash));     } }
  测试结果 字符串:jlkk  Idx(16):3  Bit值:1100011101001000010011 - 10000   Idx(32):19 1100011101001000100010 1100011101001000010011 10011 字符串:lopi  Idx(16):14  Bit值:1100101100011010001110 - 0   Idx(32):14 1100101100011010111100 1100101100011010001110 1110 字符串:jmdw  Idx(16):7  Bit值:1100011101010100100111 - 0   Idx(32):7 1100011101010100010110 1100011101010100100111 111 字符串:e4we  Idx(16):3  Bit值:1011101011101101010011 - 10000   Idx(32):19 1011101011101101111101 1011101011101101010011 10011 字符串:io98  Idx(16):4  Bit值:1100010110001011110100 - 10000   Idx(32):20 1100010110001011000101 1100010110001011110100 10100 字符串:nmhg  Idx(16):13  Bit值:1100111010011011001101 - 0   Idx(32):13 1100111010011011111110 1100111010011011001101 1101 字符串:vfg6  Idx(16):8  Bit值:1101110010111101101000 - 0   Idx(32):8 1101110010111101011111 1101110010111101101000 1000 字符串:gfrt  Idx(16):1  Bit值:1100000101111101010001 - 10000   Idx(32):17 1100000101111101100001 1100000101111101010001 10001 字符串:alpo  Idx(16):7  Bit值:1011011011101101000111 - 0   Idx(32):7 1011011011101101101010 1011011011101101000111 111 字符串:vfbh  Idx(16):1  Bit值:1101110010111011000001 - 0   Idx(32):1 1101110010111011110110 1101110010111011000001 1 字符串:bnhj  Idx(16):0  Bit值:1011100011011001100000 - 0   Idx(32):0 1011100011011001001110 1011100011011001100000 0 字符串:zuio  Idx(16):8  Bit值:1110010011100110011000 - 10000   Idx(32):24 1110010011100110100001 1110010011100110011000 11000 字符串:iu8e  Idx(16):8  Bit值:1100010111100101101000 - 0   Idx(32):8 1100010111100101011001 1100010111100101101000 1000 字符串:yhjk  Idx(16):8  Bit值:1110001001010010101000 - 0   Idx(32):8 1110001001010010010000 1110001001010010101000 1000 字符串:plop  Idx(16):9  Bit值:1101001000110011101001 - 0   Idx(32):9 1101001000110011011101 1101001000110011101001 1001 字符串:dd0p  Idx(16):14  Bit值:1011101111001011101110 - 0   Idx(32):14 1011101111001011000000 1011101111001011101110 1110 这里我们随机使用一些字符串计算他们分别在16位长度和32位长度数组下的索引分配情况,看哪些数据被重新路由到了新的地址。 同时,这里还可以观察出一个非常重要的信息,原哈希值与扩容新增出来的长度16,进行&运算,如果值等于0,则下标位置不变。如果不为0,那么新的位置则是原来位置上加16。{这个地方需要好好理解下,并看实验数据} 这样一来,就不需要在重新计算每一个数组中元素的哈希值了。 4.2 数据迁移
  bugstack.cn 数据迁移 这张图就是原16位长度数组元素,向32位扩容后数组转移的过程。 对31取模保留低5位,对15取模保留低4位,两者的差异就在于第5位是否为1,是的话则需要加上增量,为0的话则不需要改变 其中黄色区域元素 zuio 因计算结果 hash & oldCap  低位第5位为1,则被迁移到下标位置24。同时还是用重新计算哈希值的方式验证了,确实分配到24的位置,因为这是在二进制计算中补1的过程,所以可以通过上面简化的方式确定哈希值的位置。
  那么为什么 e.hash & oldCap == 0 为什么可以判断当前节点是否需要移位, 而不是再次计算hash;
  仍然是原始长度为16举例:  old:  10: 0000 1010  15: 0000 1111  &: 0000 1010     new:  10: 0000 1010  31: 0001 1111  &: 0000 1010
  从上面的示例可以很轻易的看出, 两次indexFor()的差别只是第二次参与位于比第一次左边有一位从0变为1, 而这个变化的1刚好是oldCap, 那么只需要判断原key的hash这个位上是否为1: 若是1, 则需要移动至oldCap + i的槽位, 若为0, 则不需要移动;
  这也是HashMap的长度必须保证是2的幂次方的原因, 正因为这种环环相扣的设计, HashMap.loadFactor的选值是3/4就能理解了, table.length * 3/4可以被优化为((table.length >> 2) << 2) - (table.length >> 2) == table.length - (table.length >> 2), JAVA的位运算比乘除的效率更高, 所以取3/4在保证hash冲突小的情况下兼顾了效率; 四、总结如果你能坚持看完这部分内容,并按照文中的例子进行相应的实验验证,那么一定可以学会本章节涉及这五项知识点; 1、散列表实现 、2、扰动函数 、3、初始化容量 、4、负载因子 、5、扩容元素拆分 。对我个人来说以前也知道这部分知识,但是没有验证过,只知道概念如此,正好借着写面试手册专栏,加深学习,用数据验证理论,让知识点可以更加深入的理解。 这一章节完事,下一章节继续进行HashMap的其他知识点挖掘,让懂了就是真的懂了。好了,写到这里了,感谢大家的阅读。如果某处没有描述清楚,或者有不理解的点,欢迎与我讨论交流。

道指涨超300点,特斯拉涨近5!美联储放慢加息几成定局?投资者存分歧,分析师警告称每经编辑杜宇当地时间1月20日,美股三大指数集体收涨,纳指涨2。66,本周累涨0。55标普500指数涨1。89,本周累跌0。67道指涨330。93点,涨幅1,本周累跌2。71。大型名记因离开球场4个月克劳德的状态恐劝退热火雄鹿据名记MarcStein报道,由于克劳德没有进行NBA比赛快四个月了,尽管热火和雄鹿对太阳球员杰克劳德感兴趣,但同时两队也对此情况表现出越来越担忧。这样的担忧持续,恐怕交易将迟迟不韦霍斯特C罗和伊布这么大岁数状态还很好,因他们场下很努力直播吧1月22日讯曼联新援韦霍斯特近日表示,自己一直在向C罗和伊布学习,通过不断努力让自己保持最佳状态。韦霍斯特还相信,作为足球运动员,付出就会有回报。韦霍斯特说你可以从我的数据中这是瑜伽的基础动作瑜伽的基础中年男人的苦男生的牙杯真敷衍纳尼玩得好自己写对联,没点技术劝你放弃我不厚道的笑了虚拟一切这三鬼1许多时候,背后的默默关心会比正面的直接帮助更为温暖有力。2是我给你伤害爱的恩比德怒喷奥拉朱旺现在不是该死的八九十年代了奥拉朱旺先前在采访中分别谈到了现役的两大中锋,恩比德与约基奇。谈到恩比德时,他评价道恩比德会所有的技术动作,但如何利用好这些技术动作是另一件事。为什么他要投那些三分呢?谈到约基奇时山东威海第一大企业年营收超过510亿,71岁创始人是当地首富根据2022山东综合百强企业显示,100家鲁企营业总收入同比增长15。05至73704。98亿元,入围门槛也较上一年提升22。67至237。21亿元。有13家企业营收超过千亿,山东CBA三消息新疆超外三月复出,山东全力争第四,崔晓龙能力欠缺爱国篮,爱CBA,我是洛姐,小伙伴们看完记得点赞!这个赛季前两个阶段的常规赛比赛,新疆队的大外援一直都是法尔,他是一名防守能力很强,并且进攻端也可以吃饼的内线球员,法尔非常适合新疆4换1!火箭报价奇才神射手,补强球队三分投篮能力火箭队通过一波12连败俯冲状元签,文班亚马的潜力和商业价值可见一斑,火箭老板菲尔蒂塔买下球队这些年一直处在亏损状态,如果能够顺利得到这位法国天才,有望实现扭亏为盈。火箭总经理为了将机器人是未来?这些机械部直属大学必须了解!高分低分都可以选择亚洲首富孙正义也曾在采访中说到30年后,我们将跟100亿机器人生活在一起!,而他自己更是将所有的投资全部投在了机器人的项目上。我们随着科技的进步,和生活水平的提高,人类对生活与工作用于裸盖菇素生物合成的网关脱羧酶的表征文丨异文录编辑丨异文录图形介绍如何合成L色氨酸脱羧酶PsiD启动裸盖菇中精神药物天然产物裸盖菇素的生物合成。其体外生化表征和其结构的计算机建模确定了用于前酶自催化切割的非规范丝氨酸为什么网络观点越来越极端?最近开始关注各类APP的内容和观点,一气儿卸载了好些APP。最开始是知乎,在偶然间我点到一个奇怪的内容(类似身材太好xxx你最不愿告诉别人的秘密等等之类的钓鱼问题)之后,发现我的首
西北工业大学遭网络攻击事件调查报告发布网络攻击源头系美国国家安全局今天(5日),国家计算机病毒应急处理中心和360公司分别发布了关于西北工业大学遭受境外网络攻击的调查报告。调查中,国家计算机病毒应急处理中心和360公司联合组成技术团队,全程参与了美国监听遮羞布已被掀开近年来,无孔不入的监听事件,以及各种盗取数据的行径,真当世界各国不知道吗?事实上,美国肆意侵犯隐私安全盗用本国及他国民众隐私数据,对他国领导人和各界精英进行监听的行径早已引起世界各要判刑4万年?平台创始人携20亿美元潜逃被抓,龙头已跌超七成币圈持续震动!近日,土耳其加密货币兑换服务公司Thodex的创始人在阿尔巴尼亚被捕,此人去年曾带着价值20亿美元(约138亿元人民币)的加密货币逃离,或将面临最高40564年的监禁十万亿资产规模中国平安的大象起舞路径十万亿资产规模的金融航母,在镁光灯的犀利探照下,如何轻姿漫舞?中国平安向外界提供了一个路径和样本。2022年上半年公司保持经营稳健实现改革提速,面对复杂严峻的内外部挑战,仍然收获了在银行里面买理财,本金亏了八万怎么办?在中国老百姓的眼中,把钱交给银行,存款也好,打理也好,总之想着最低程度应该是保本的,因为银行这个名称在我们的眼中,在我们的印象中,应该是安全的象征。可是,社会在发展,银行也在改革,管教孩子的36种科学方法,用对了,孩子越来越出色只会说教的父母永远养不出优秀的孩子。父母有智慧,育儿有策略,教育才会有效果。乐爸作者好妈来源哈佛好妈来源哈佛好妈),谁说二胎妈妈不能兼顾工作和生活,有了萌娃的陪伴,再多的烦恼,好妈腌辣椒的季节到了,一次买8斤腌制起来,方法简单,吃一年都不坏腌辣椒的季节到了,一次买8斤腌制起来,方法简单,吃一年都不坏。现在正是辣椒上市的季节,夏天的辣椒不仅好吃,而且价格也比较便宜。今天就给大家分享怎样在家腌辣椒,腌好的辣椒香辣过瘾,好江瀚重资产的共享充电宝拓展方式或遭淘汰中新经纬9月5日电题重资产的共享充电宝拓展方式或遭淘汰作者江瀚盘古智库高级研究员伴随着共享经济的发展,共享充电宝已经成为大家生活中习以为常的用品。然而,如今共享充电宝租金越来越高,黑龙江通报6起违反中央八项规定精神典型问题中央纪委国家监委网站讯中秋国庆将至,为进一步加强警示教育,持续加固中央八项规定堤坝,锲而不舍纠四风树新风,营造务实节俭文明廉洁的节日氛围,日前,黑龙江省纪委监委对6起违反中央八项规国务院大督查在行动丨湖南用客车带货等方式破解快递下乡最后一公里难题多地群众向国务院互联网督查平台反映,乡村快递存在不按地址投递加价收取服务费等问题。近日,国务院第九次大督查第十一督查组了解到,湖南省通过通村公路客车带货等方式破解快递下乡最后一公里切实缩小贫富过分悬殊强烈推崇华为企业的利益分配方式我在想对于一个国家而言,若贫富过于悬殊,长此下去,必将造成社会的严重动荡国家的根基,势必面临严重的威胁。因此,尽快地让更多的低收入群体富起来不断地壮大中产阶级队伍以法律的形式,给大