国产精品嫩草99av在线_一区在线视频观看_欧美高清一区_欧美 日韩 国产 一区_99精品欧美一区二区三区_久久大香伊蕉在人线观看热2_一色屋精品视频在线观看网站_在线亚洲国产精品网站_亚洲区一区二区三区_你懂的视频一区二区

當(dāng)前位置:首頁(yè) > 科技  > 軟件

深度!HashMap的底層數(shù)據(jù)結(jié)構(gòu)

來(lái)源: 責(zé)編: 時(shí)間:2023-09-18 21:41:31 395觀看
導(dǎo)讀一、HashMap基礎(chǔ)機(jī)構(gòu)HashMap 由數(shù)組和鏈表(或紅黑樹)組成。數(shù)組是 HashMap 的主體,鏈表和紅黑樹則是為了解決哈希沖突而存在的。數(shù)組中的每個(gè)元素都是一個(gè)單向鏈表的頭結(jié)點(diǎn),每個(gè)鏈表都是由若干個(gè) Node 節(jié)點(diǎn)組成的,每個(gè)節(jié)點(diǎn)

bZZ28資訊網(wǎng)——每日最新資訊28at.com

一、HashMap基礎(chǔ)機(jī)構(gòu)

HashMap 由數(shù)組和鏈表(或紅黑樹)組成。數(shù)組是 HashMap 的主體,鏈表和紅黑樹則是為了解決哈希沖突而存在的。數(shù)組中的每個(gè)元素都是一個(gè)單向鏈表的頭結(jié)點(diǎn),每個(gè)鏈表都是由若干個(gè) Node 節(jié)點(diǎn)組成的,每個(gè)節(jié)點(diǎn)都包含了鍵值對(duì)的信息,以及指向下一個(gè)節(jié)點(diǎn)的指針。當(dāng)多個(gè)鍵映射到同一個(gè)位置時(shí),它們會(huì)被存儲(chǔ)在同一個(gè)鏈表中(或者是同一個(gè)紅黑樹中)。當(dāng)鏈表長(zhǎng)度超過(guò)閾值(默認(rèn)為 8)時(shí),鏈表就會(huì)被轉(zhuǎn)換成紅黑樹,這樣可以提高查找效率。bZZ28資訊網(wǎng)——每日最新資訊28at.com

在 JDK1.8 中,HashMap 還引入了一個(gè)新的概念,叫做負(fù)載因子(load factor),它是指哈希表中鍵值對(duì)的數(shù)量與數(shù)組長(zhǎng)度的比值。當(dāng)鍵值對(duì)的數(shù)量超過(guò)了負(fù)載因子與數(shù)組長(zhǎng)度的乘積時(shí),就會(huì)觸發(fā)擴(kuò)容操作,HashMap 會(huì)自動(dòng)將數(shù)組長(zhǎng)度擴(kuò)大一倍,并將原來(lái)的鍵值對(duì)重新分配到新的數(shù)組中。這樣做的目的是為了保證散列表的性能,因?yàn)楫?dāng)負(fù)載因子過(guò)高時(shí),散列表的性能會(huì)急劇下降。bZZ28資訊網(wǎng)——每日最新資訊28at.com

二、HashMap的底層數(shù)據(jù)結(jié)構(gòu)

解答:在jdk1.8以前,HashMa采用鏈表+數(shù)組,自Jdk1.8以后,HashMap采用鏈表+數(shù)組+紅黑樹。在下圖中橫鏈(0-15)表中表示數(shù)組,豎(1-8)表示鏈表,在數(shù)組長(zhǎng)度超過(guò)8之后,hashmap將數(shù)組自動(dòng)轉(zhuǎn)為紅黑樹。bZZ28資訊網(wǎng)——每日最新資訊28at.com

bZZ28資訊網(wǎng)——每日最新資訊28at.com

HashMapJDK1.8鏈表和紅黑樹轉(zhuǎn)化bZZ28資訊網(wǎng)——每日最新資訊28at.com

三、JDK1.8對(duì)hash算法和尋址算法如何優(yōu)化的?

1、對(duì)Hash值算法的優(yōu)化

static final int hash(Object key) {        int h;        return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);    }

有一個(gè)key的Hash_1值:bZZ28資訊網(wǎng)——每日最新資訊28at.com

Hash_1: 1111 1111 1111 1111 1111 1010 0111 1100
h >>> 16 // 表示對(duì)該hash值右移16位

右移后的結(jié)果Hash_2為:bZZ28資訊網(wǎng)——每日最新資訊28at.com

Hash_2: 0000 0000 0000 0000 1111 1111 1111 1111

對(duì)上述Hash_1和Hash_2的兩個(gè)值進(jìn)行異或bZZ28資訊網(wǎng)——每日最新資訊28at.com

Hash_1: 1111 1111 1111 1111 1111 1010 0111 1100Hash_2: 0000 0000 0000 0000 1111 1111 1111 1111=====>: 1111 1111 1111 1111 0000 0101 1000 0011 =====> 轉(zhuǎn)為10進(jìn)制int值,這個(gè)值就是這個(gè)key的hash值

hash算法的優(yōu)化:對(duì)每個(gè)hash值,在它的低16位中,讓高低16位進(jìn)行異或,讓它的低16位同時(shí)保持了高低16位的特征,盡量避免一些hash值后續(xù)出現(xiàn)沖突,大家可能會(huì)進(jìn)入數(shù)組的同一位置。bZZ28資訊網(wǎng)——每日最新資訊28at.com

2、對(duì)尋址算法的優(yōu)化

bZZ28資訊網(wǎng)——每日最新資訊28at.com

(p = tab[i = (n - 1) & hash]   // (n-1) & hash ==> 數(shù)組里的一個(gè)位置

hash & (n-1) 效果是跟hash對(duì)n取模是一樣的,但是與運(yùn)算的性能要比hash對(duì)n取模要高很多。數(shù)組的長(zhǎng)度會(huì)一直是2的n次方,只要他保持?jǐn)?shù)組長(zhǎng)度是2的n次方。bZZ28資訊網(wǎng)——每日最新資訊28at.com

  • 尋址為什么不用取模?

對(duì)于上面尋址算法,由于計(jì)算機(jī)對(duì)比取模,與運(yùn)算會(huì)更快。所以為了效率,HashMap 中規(guī)定了哈希表長(zhǎng)度為 2 的 k 次方,而 2^k-1 轉(zhuǎn)為二進(jìn)制就是 k 個(gè)連續(xù)的 1,那么 hash & (k 個(gè)連續(xù)的 1) 返回的就是 hash 的低 k 個(gè)位,該計(jì)算結(jié)果范圍剛好就是 0 到 2^k-1,即 0 到 length - 1,跟取模結(jié)果一樣。bZZ28資訊網(wǎng)——每日最新資訊28at.com

也就是說(shuō),哈希表長(zhǎng)度 length 為 2 的整次冪時(shí), hash & (length - 1) 的計(jì)算結(jié)果跟 hash % length 一樣,而且效率還更好。bZZ28資訊網(wǎng)——每日最新資訊28at.com

  • 為什么不直接用 hashCode() 而是用它的高 16 位進(jìn)行異或計(jì)算新 hash 值?#

int 類型占 32 位,可以表示 2^32 種數(shù)(范圍:-2^31 到 2^31-1),而哈希表長(zhǎng)度一般不大,在 HashMap 中哈希表的初始化長(zhǎng)度是 16(HashMap 中的 DEFAULT_INITIAL_CAPACITY),如果直接用 hashCode 來(lái)尋址,那么相當(dāng)于只有低 4 位有效,其他高位不會(huì)有影響。這樣假如幾個(gè) hashCode 分別是 210、220、2^30,那么尋址結(jié)果 index 就會(huì)一樣而發(fā)生沖突,所以哈希表就不均勻分布了。bZZ28資訊網(wǎng)——每日最新資訊28at.com

尋址算法的優(yōu)化:用與運(yùn)算替代取模,提升性能。(由于計(jì)算機(jī)對(duì)比取模,與運(yùn)算會(huì)更快)bZZ28資訊網(wǎng)——每日最新資訊28at.com

四、HashMap是如何解決hash碰撞問(wèn)題

hash沖突問(wèn)題,鏈表+紅黑樹,O(n)和O(logN)。bZZ28資訊網(wǎng)——每日最新資訊28at.com

hashmap采用的就是鏈地址法(拉鏈法),jdk1.7中,當(dāng)沖突時(shí),在沖突的地址上生成一個(gè)鏈表,將沖突的元素的key,通過(guò)equals進(jìn)行比較,相同即覆蓋,不同則添加到鏈表上,此時(shí)如果鏈表過(guò)長(zhǎng),效率就會(huì)大大降低,查找和添加操作的時(shí)間復(fù)雜度都為O(n);但是在jdk1.8中如果鏈表長(zhǎng)度大于8,鏈表就會(huì)轉(zhuǎn)化為紅黑樹,時(shí)間復(fù)雜度也降為了O(logn),性能得到了很大的優(yōu)化。bZZ28資訊網(wǎng)——每日最新資訊28at.com

bZZ28資訊網(wǎng)——每日最新資訊28at.com

HashMapJDK1.8鏈表和紅黑樹轉(zhuǎn)化bZZ28資訊網(wǎng)——每日最新資訊28at.com

bZZ28資訊網(wǎng)——每日最新資訊28at.com

五、HashMap是如何進(jìn)行擴(kuò)容的

HashMap底層是一個(gè)數(shù)組,當(dāng)這個(gè)數(shù)組滿了之后,他就會(huì)自動(dòng)進(jìn)行擴(kuò)容,變成一個(gè)更大數(shù)組。bZZ28資訊網(wǎng)——每日最新資訊28at.com

1、JDK1.7下的擴(kuò)容機(jī)制

void resize(int newCapacity) {        Entry[] oldTable = table;        int oldCapacity = oldTable.length;        if (oldCapacity == MAXIMUM_CAPACITY) {            threshold = Integer.MAX_VALUE;            return;        }         Entry[] newTable = new Entry[newCapacity];        transfer(newTable, initHashSeedAsNeeded(newCapacity));        table = newTable;        threshold = (int)Math.min(newCapacity * loadFactor, MAXIMUM_CAPACITY + 1);    }

代碼中可以看到,如果原有table長(zhǎng)度已經(jīng)達(dá)到了上限,就不再擴(kuò)容了。如果還未達(dá)到上限,則創(chuàng)建一個(gè)新的table,并調(diào)用transfer方法:bZZ28資訊網(wǎng)——每日最新資訊28at.com

/**     * Transfers all entries from current table to newTable.     */    void transfer(Entry[] newTable, boolean rehash) {        int newCapacity = newTable.length;        for (Entry<K,V> e : table) {            while(null != e) {                Entry<K,V> next = e.next;              //注釋1                if (rehash) {                    e.hash = null == e.key ? 0 : hash(e.key);                }                int i = indexFor(e.hash, newCapacity); //注釋2                e.next = newTable[i];                  //注釋3                newTable[i] = e;                       //注釋4                e = next;                              //注釋5            }        }    }

transfer方法的作用是把原table的Node放到新的table中,使用的是頭插法,也就是說(shuō),新table中鏈表的順序和舊列表中是相反的,在HashMap線程不安全的情況下,這種頭插法可能會(huì)導(dǎo)致環(huán)狀節(jié)點(diǎn)。bZZ28資訊網(wǎng)——每日最新資訊28at.com

2、JDK1.8下的擴(kuò)容機(jī)制

源碼如下:bZZ28資訊網(wǎng)——每日最新資訊28at.com

final Node<K,V>[] resize() {        Node<K,V>[] oldTab = table;        int oldCap = (oldTab == null) ? 0 : oldTab.length; // 記錄原來(lái)的數(shù)組長(zhǎng)度        int oldThr = threshold;        int newCap, newThr = 0;        if (oldCap > 0) {            if (oldCap >= MAXIMUM_CAPACITY) {                threshold = Integer.MAX_VALUE;                return oldTab;            }            else if ((newCap = oldCap << 1) < MAXIMUM_CAPACITY &&                     oldCap >= DEFAULT_INITIAL_CAPACITY)                newThr = oldThr << 1; // double threshold // 重新計(jì)算TREEIFY_THRESHOLD        }        else if (oldThr > 0) // initial capacity was placed in threshold            newCap = oldThr;        else {               // zero initial threshold signifies using defaults            newCap = DEFAULT_INITIAL_CAPACITY;            newThr = (int)(DEFAULT_LOAD_FACTOR * DEFAULT_INITIAL_CAPACITY);        }        if (newThr == 0) {            float ft = (float)newCap * loadFactor;            newThr = (newCap < MAXIMUM_CAPACITY && ft < (float)MAXIMUM_CAPACITY ?                      (int)ft : Integer.MAX_VALUE);        }        threshold = newThr;        @SuppressWarnings({"rawtypes","unchecked"})            Node<K,V>[] newTab = (Node<K,V>[])new Node[newCap];        table = newTab;        if (oldTab != null) {  // 重新計(jì)算原來(lái)鏈表中的值的hash值在新表對(duì)應(yīng)的hash值            for (int j = 0; j < oldCap; ++j) {                Node<K,V> e;                if ((e = oldTab[j]) != null) {                    oldTab[j] = null;                    if (e.next == null)  // 如果元素e的下一個(gè)位置沒有值,則說(shuō)明可以存放元素                        newTab[e.hash & (newCap - 1)] = e;                     else if (e instanceof TreeNode) // 如果已經(jīng)是紅黑樹的節(jié)點(diǎn),那就對(duì)其重新劃分                        ((TreeNode<K,V>)e).split(this, newTab, j, oldCap);                    else { // preserve order                        // loHead: 下標(biāo)不變情況下的鏈表頭                        // loTail: 下標(biāo)不變情況下的鏈表尾                        // hiHead: 下標(biāo)改變情況下的鏈表頭                        // hiTail: 下標(biāo)改變情況下的鏈表尾                        // 如果                        Node<K,V> loHead = null, loTail = null;                        Node<K,V> hiHead = null, hiTail = null;                        Node<K,V> next;                        do {                            next = e.next;                            if ((e.hash & oldCap) == 0) { // 元素e的最新hash如果與原來(lái)的值與計(jì)算之后如果值為0,就說(shuō)明是使用原來(lái)的index                                // 尾插法插入元素e                                if (loTail == null)                                    loHead = e;                                else                                    loTail.next = e;                                loTail = e;                            }                            else {                                // 與運(yùn)算不等于0則說(shuō)明使用新的index                                if (hiTail == null)                                    hiHead = e;                                else                                    hiTail.next = e;                                hiTail = e;                            }                        } while ((e = next) != null);                        if (loTail != null) {                            loTail.next = null;                            newTab[j] = loHead;                        }                        if (hiTail != null) {                            hiTail.next = null;                            newTab[j + oldCap] = hiHead;                        }                    }                }            }        }        return newTab;    }

正常情況下,計(jì)算節(jié)點(diǎn)在table中的下標(biāo)的方法是:hash&(oldTable.length-1),擴(kuò)容之后,table長(zhǎng)度翻倍,計(jì)算table下標(biāo)的方法是hash&(newTable.length-1),也就是hash&(oldTable.length*2-1),于是我們有了這樣的結(jié)論:這新舊兩次計(jì)算下標(biāo)的結(jié)果,要不然就相同,要不然就是新下標(biāo)等于舊下標(biāo)加上舊數(shù)組的長(zhǎng)度。bZZ28資訊網(wǎng)——每日最新資訊28at.com

數(shù)組長(zhǎng)度為16時(shí),有兩個(gè)keyA和keyB。bZZ28資訊網(wǎng)——每日最新資訊28at.com

KeyA:n-1:   0000 0000 0000 0000 0000 0000 0000 1111hash1: 1111 1111 1111 1111 0000 1111 0000 0101&結(jié)果:  0000 0000 0000 0000 0000 0000 0000 0101 = 5KeyB:n-1:   0000 0000 0000 0000 0000 0000 0000 1111 hash1: 1111 1111 1111 1111 0000 1111 0001 0101&結(jié)果:  0000 0000 0000 0000 0000 0000 0000 0101 = 5

在數(shù)組長(zhǎng)度為16的時(shí)候,他們兩個(gè)hash值沖突會(huì)使用拉鏈發(fā)解決沖突。bZZ28資訊網(wǎng)——每日最新資訊28at.com

當(dāng)數(shù)組長(zhǎng)度擴(kuò)容到32之后,需要重新對(duì)每個(gè)hash值進(jìn)行尋址,也就是每個(gè)hash值跟新的數(shù)組length-1 進(jìn)行操作。bZZ28資訊網(wǎng)——每日最新資訊28at.com

KeyA:n-1:   0000 0000 0000 0000 0000 0000 000*1* 1111hash1: 1111 1111 1111 1111 0000 1111 0000 0101&結(jié)果:  0000 0000 0000 0000 0000 0000 0000 0101 = 5KeyB:n-1:   0000 0000 0000 0000 0000 000*1* 0000 1111 hash1: 1111 1111 1111 1111 0000 1111 0001 0101&結(jié)果:  0000 0000 0000 0000 0000 000*1* 0000 0101 = 21

判斷二進(jìn)制結(jié)果是否多出一個(gè)bit的1,如果沒有多,那就用原來(lái)的index,如果多出來(lái)了那就用index+oldCap,通過(guò)這個(gè)方式,避免了rehash的時(shí)候,用每個(gè)hash對(duì)新數(shù)組的length取模,取模性能不高,位運(yùn)算性能比較高。bZZ28資訊網(wǎng)——每日最新資訊28at.com

本文鏈接:http://m.rrqrq.com/showinfo-26-10459-0.html深度!HashMap的底層數(shù)據(jù)結(jié)構(gòu)

聲明:本網(wǎng)頁(yè)內(nèi)容旨在傳播知識(shí),若有侵權(quán)等問(wèn)題請(qǐng)及時(shí)與本網(wǎng)聯(lián)系,我們將在第一時(shí)間刪除處理。郵件:2376512515@qq.com

上一篇: Spring Cloud Gateway提供的簡(jiǎn)易網(wǎng)關(guān)實(shí)現(xiàn)方式,你使用過(guò)嗎?

下一篇: LLM構(gòu)建AI應(yīng)用 —— 工程師如何使用黑盒工具

標(biāo)簽:
  • 熱門焦點(diǎn)
Top 国产精品嫩草99av在线_一区在线视频观看_欧美高清一区_欧美 日韩 国产 一区_99精品欧美一区二区三区_久久大香伊蕉在人线观看热2_一色屋精品视频在线观看网站_在线亚洲国产精品网站_亚洲区一区二区三区_你懂的视频一区二区
成人一级黄色片| 成人免费一区二区三区在线观看 | 亚洲成人免费在线| 国产一区二区三区四| 欧美激情在线| 色婷婷国产精品| 国产精品麻豆网站| 精品一区在线看| 99热这里只有精品8| 91精品婷婷国产综合久久| 日韩一区日韩二区| 国产美女精品人人做人人爽| 伊人久久久大香线蕉综合直播 | 成人精品免费网站| 国产精品视频免费观看| 精品精品欲导航| 天天做天天摸天天爽国产一区 | 最新国产成人在线观看| 国内精品伊人久久久久av一坑| 伊人久久婷婷色综合98网| 欧美高清视频不卡网| 一区二区三区欧美日| 国产99精品在线观看| 性高湖久久久久久久久| 久久久久久综合| 狠狠色丁香婷婷综合| 国产精品日韩| 国产精品久久久久影院老司| 国产成人一级电影| 色成年激情久久综合| 自拍偷拍亚洲激情| 99久久精品99国产精品| 欧美三级韩国三级日本一级| 亚洲黄色片在线观看| 99精品久久只有精品| 欧美久久久久久久久中文字幕| 亚洲永久精品大片| 亚洲一级黄色| 国产女人aaa级久久久级| 国产精品正在播放| 欧美日韩一区小说| 日韩成人午夜精品| 亚洲一区二区在| 国产精品二区一区二区aⅴ污介绍| caoporm超碰国产精品| 日韩一区二区三区电影在线观看 | 国产精品国产成人国产三级| 粉嫩欧美一区二区三区高清影视| 欧美伊人久久久久久久久影院| 亚洲国产综合视频在线观看| 尹人成人综合网| 中文字幕av一区二区三区高 | 一区二区三区精品久久久| 欧美日韩免费观看一区| 日韩一级视频免费观看在线| 激情综合亚洲精品| 欧美日韩另类一区| 久久电影国产免费久久电影 | 99re热视频精品| 欧美一级xxx| 成人久久视频在线观看| 欧美videos中文字幕| 成人avav在线| 久久精品视频免费| 国产精品hd| 最新国产精品久久精品| 亚洲美女网站| 亚洲一区二区在线观看视频 | 国产在线精品免费av| 欧美一区午夜精品| 波多野结衣精品在线| 国产欧美日韩中文久久| 欧美日韩日本国产亚洲在线| 国产精品传媒在线| 99在线|亚洲一区二区| 亚洲一区在线电影| 在线亚洲人成电影网站色www| 精品一区二区三区免费观看| 在线播放亚洲一区| 91亚洲午夜精品久久久久久| 国产精品久久久久久久久免费丝袜 | 久久久久国产成人精品亚洲午夜| 欧美三级在线| 一区二区理论电影在线观看| 久久精品五月婷婷| 国产在线精品国自产拍免费| 欧美不卡在线视频| 欧美日韩久久| 三级久久三级久久久| 欧美日韩国产综合久久| www.日韩精品| 亚洲精品久久久蜜桃| 色老汉av一区二区三区| 国产成人精品一区二区三区网站观看| 欧美mv日韩mv国产网站| 极品裸体白嫩激情啪啪国产精品| 午夜私人影院久久久久| 3d动漫精品啪啪1区2区免费| 欧美在线视频一区二区三区| 一区二区国产盗摄色噜噜| 欧美无人高清视频在线观看| 99精品一区二区三区| 亚洲午夜精品17c| 日韩一区二区三区在线| 99国内精品| 国产传媒一区在线| 亚洲精品高清在线观看| 欧美精品九九99久久| 好看的av在线不卡观看| 美女脱光内衣内裤视频久久影院| 亚洲精品一区二区三区四区高清| 亚洲日本视频| 国产精品资源在线| 亚洲乱码国产乱码精品精小说| 欧美私人免费视频| 伊人成人在线| 国产精品综合久久| 一区二区三区在线免费播放| 日韩免费看的电影| 久久精品五月| 亚洲调教视频在线观看| 国产精品一二三区在线| 亚洲国产日日夜夜| 久久男人中文字幕资源站| 在线一区二区观看| 亚洲精品在线免费| 99精品视频中文字幕| 裸体歌舞表演一区二区| 亚洲欧美日韩电影| 精品欧美久久久| 日本精品免费观看高清观看| 欧美性色综合| 成人高清在线视频| 蜜桃av噜噜一区| 亚洲视频在线一区| 精品国精品自拍自在线| 在线欧美日韩精品| 国产精品一区二区三区四区五区| 欧美一区免费| 成人性色生活片| 久久99精品国产麻豆婷婷| 亚洲最大的成人av| 国产欧美日韩不卡| 26uuu色噜噜精品一区| 欧美日韩精品一区二区三区蜜桃| 国产精品乱看| 亚洲国产成人不卡| 欧美黄色一区| 成人av小说网| 国产成人精品三级麻豆| 免费观看成人av| 亚洲午夜激情网站| 亚洲精品免费在线观看| 国产精品理伦片| 欧美激情综合五月色丁香 | 亚洲视频欧美在线| 国产精品二区在线| 欧美一区成人| 97se狠狠狠综合亚洲狠狠| 成人福利视频网站| 国产精品一区二区久久不卡| 蜜乳av一区二区| 婷婷久久综合九色综合伊人色| 亚洲午夜av在线| 亚洲观看高清完整版在线观看| 亚洲柠檬福利资源导航| 亚洲三级在线看| 亚洲精品中文在线观看| 成人免费视频在线观看| 国产精品国产三级国产a| 国产精品久久久久国产精品日日| 欧美国产禁国产网站cc| 国产精品高潮呻吟| 亚洲老妇xxxxxx| 亚洲国产一二三| 五月综合激情婷婷六月色窝| 午夜精品福利视频网站| 日本伊人色综合网| 久久电影网电视剧免费观看| 国产麻豆视频精品| 国产成人综合在线观看| 99久久精品国产观看| 午夜精品久久99蜜桃的功能介绍| 欧美区国产区| 日韩午夜免费| 色www精品视频在线观看| 一本大道久久a久久综合婷婷| 欧美亚洲免费在线一区| 欧美日韩一区中文字幕| 精品少妇一区二区三区视频免付费| 精品国免费一区二区三区| 欧美高清一级片在线观看| 亚洲欧美电影一区二区| 亚洲成av人片在线观看| 国产在线播精品第三| 91丝袜美腿高跟国产极品老师| 国产一区二区三区四区三区四| 国产欧美精品久久| 欧美怡红院视频| 国产三级欧美三级日产三级99 |