精品欧美一区二区三区在线观看 _久久久久国色av免费观看性色_国产精品久久在线观看_亚洲第一综合网站_91精品又粗又猛又爽_小泽玛利亚一区二区免费_91亚洲精品国偷拍自产在线观看 _久久精品视频在线播放_美女精品久久久_欧美日韩国产成人在线

解密 Python 集合的實現原理

開發 前端
對于字典來說,鍵值對始終按照先來后到的順序添加在鍵值對數組中,然后將它在鍵值對數組中的索引保存在指定的哈希槽中。由于索引為 5 的哈希槽保存的是 -2,處于 Dummy 態,因此直接將它設置為 3。

楔子

本篇文章來聊一聊 Python 的集合是怎么實現的?前面我們介紹了字典的實現原理,它底層是基于哈希表實現的,而集合也是如此。

事實上,集合就類似于沒有 value 的字典。

集合的使用場景

那么集合都有哪些用處呢?

1)去重

chars = ["a", "b", "a", "c", "c"]

print(
    list(set(chars))
)  # ['b', 'a', 'c']

比如你需要監聽一個隊列,處理接收到的消息,但每一條消息都有一個編號,要保證具有相同編號的消息只能被處理一次,要怎么做呢?

顯然集合此時就派上用場了,我們可以創建一個集合,每來一條消息,就檢測它的編號是否在集合中。如果存在,則說明消息已經被處理過了,忽略掉;如果不存在,說明消息還沒有被處理,那么就將它的編號添加到集合中,然后處理消息。

2)判斷某個序列是否包含指定的多個元素

data = ["S", "A", "T", "O", "R", "I"]

# 現在要判斷 data 是否包含 "T"、"R" 和 "I"
# 如果使用列表的話
print(
    "T" in data and "R" in data and "I" in data
)  # True

# 顯然使用列表比較麻煩,并且效率也不高,于是我們可以使用集合
print(
    set(data) >= {"T", "R", "I"}
)  # True

同理,基于此方式,我們也可以檢測一個字典是否包含指定的多個 key。

data = {
    "name": "satori",
    "age": 17,
    "gender": "female"
}

# 判斷字典是否包含 name、age、gender 三個 key
print(
    data.keys() >= {"name", "age", "gender"}
)  # True

# 字典的 keys 方法會返回一個 dict_keys 對象
# 該對象具備集合的性質,可以直接和集合進行運算

顯然對于這種需求,有了集合就方便多了。

集合的 API

然后我們來羅列一下集合支持的 API,在使用集合的時候要做到心中有數。

# 如果是創建一個空集合,那么要使用 set()
# 寫成 {} 的話,解釋器會認為這是一個空字典
s = {1, 2, 3}

# 添加元素,時間復雜度是 O(1)
s.add(4)
print(s)  # {1, 2, 3, 4}

# 刪除指定的元素,如果元素不存在,會拋出 KeyError
# 時間復雜度為 O(1)
s.remove(2)
print(s)  # {1, 3, 4}

# 刪除指定的元素,如果元素不存在則什么也不做
# 時間復雜度為 O(1)
s.discard(666)
print(s)  # {1, 3, 4}

# 隨機彈出一個元素并返回,如果集合為空,會拋出 KeyError
# 時間復雜度為 O(1)
print(s.pop())  # 1
print(s)  # {3, 4}

# 清空一個集合
s.clear()
print(s)  # set()

# 還有一些 API,但我們更推薦使用操作符的方式
# 兩個集合取交集
print({1, 2} & {2, 3})  # {2}

# 兩個集合取并集
print({1, 2} | {2, 3})  # {1, 2, 3}

# 兩個集合取差集
# s1 - s2,返回在 s1、但不在 s2 當中的元素
print({1, 2, 3} - {2, 3, 4})  # {1}

# 兩個集合取對稱差集
# s1 ^ s2,返回既不在 s1、也不在 s2 當中的元素
print({1, 2, 3} ^ {2, 3, 4})  # {1, 4}

# 判斷兩個集合是否相等,也就是內部的元素是否完全一致
# 順序無所謂,只比較元素是否全部相同
print({1, 2, 3} == {3, 2, 1})  # True
print({1, 2, 3} == {1, 2, 4})  # False

# 判斷一個集合是否包含另一個集合的所有元素
# 假設有兩個集合 s1 和 s2:
#    如果 s1 的元素都在 s2 中,那么 s2 >= s1;
#    如果 s2 的元素都在 s1 中,那么 s1 >= s2;
#    如果 s1 和元素和 s2 全部相同,那么 s1 == s2;
print({1, 2, 3} > {1, 2})  # True
print({1, 2, 3} >= {1, 2, 3})  # True

以上就是集合支持的一些 API,還是很簡單的。

集合的底層結構

集合和字典的內部都使用了哈希表,但字典的哈希表采用兩個數組實現,而集合的哈希表采用一個數組實現。因此對于集合來說,這個數組不僅要存儲 entry,并且映射出的索引也是該數組的索引。

下面看一下集合的底層結構長什么樣子。

// Include/cpython/setobject.h
typedef struct {
    PyObject_HEAD

    Py_ssize_t fill;  
    Py_ssize_t used;      
    Py_ssize_t mask;
    setentry *table;
    Py_hash_t hash;          
    Py_ssize_t finger;    

    setentry smalltable[PySet_MINSIZE];
    PyObject *weakreflist;     
} PySetObject;

解釋一下這些字段的含義:

PyObject_HEAD

定長對象的頭部信息,但集合顯然是一個變長對象,所以和字典一樣,肯定有其它字段充當 ob_size。

Py_ssize_t fill

Active 態的 entry 數量加上 Dummy 態的 entry 數量。一個 entry 就是哈希表里的一個元素,類型為 setentry,因此在集合里面,一個 entry 就是一個 setentry 結構體實例。當刪除集合的 entry 時,也必須是偽刪除,因為要保證探測鏈不斷裂。如果 entry 被偽刪除了,那么它便處于 Dummy 態。

Py_ssize_t used

Active 態的 entry 數量,顯然這個 used 充當了 ob_size,也就是集合的元素個數;

Py_ssize_t mask

在看字典源碼的時候,我們也見到了 mask,它用于和哈希值進行按位與、計算索引,并且這個 mask 等于哈希表的容量減 1,為什么呢?假設哈希值等于 v,哈希表容量是 n,那么通過 v 對 n 取模即可得到一個位于 0 到 n-1 之間的數。但是取模運算的效率不高,而 v&(n-1) 的作用等價于 v%n,并且速度更快,所以 mask 的值要等于哈希表的容量減 1。但是注意,只有在 n 為 2 的冪次方的時候,v&(n-1) 和 v%n 才是完全等價的,所以哈希表的容量要求是 2 的冪次方,就是為了將取模運算優化成按位與運算。

setentry *table

指向 setentry 數組首元素的指針,這個 setentry 數組可以是下面的 smalltable,也可以是單獨申請的一塊內存;

Py_hash_t hash

集合的哈希值,只適用于不可變集合;

Py_ssize_t finger

用于 pop 方法;

setentry smalltable[8]

一個 setentry 類型的數組,集合的元素就存在里面。但我們知道,變長對象的內部不會存儲具體的元素,而是會存儲一個指針,該指針指向的內存區域才是用來存儲具體元素的。這樣當擴容的時候,只需要讓指針指向新的內存區域即可,從而方便維護。沒錯,對于集合而言,只有在容量不超過 8 的時候,元素才會存在里面;而一旦超過了 8,那么會使用 malloc 單獨申請內存;

weakreflist

弱引用列表,不做深入討論;

有了字典的經驗,再看集合會簡單很多。然后是 setentry,用于承載集合內的元素,那么它的結構長什么樣呢?相信你能夠猜到。

// Include/cpython/setobject.h
#define PySet_MINSIZE 8

typedef struct {
    PyObject *key;
    Py_hash_t hash;            
} setentry;

相比字典少了一個 value,這是顯而易見的。

因此集合的結構很清晰了,假設有一個集合 {3.14, "abc", 666},那么它的結構如下:

圖片圖片

由于集合里面只有三個元素,所以它們都會存在 smalltable 數組里面,我們通過 ctypes 來證明這一點。

from ctypes import *

class PyObject(Structure):
    _fields_ = [
        ("ob_refcnt", c_ssize_t),
        ("ob_type", c_void_p),
    ]

class SetEntry(Structure):
    _fields_ = [
        ("key", POINTER(PyObject)),
        ("hash", c_longlong)
    ]

class PySetObject(PyObject):
    _fields_ = [
        ("fill", c_ssize_t),
        ("used", c_ssize_t),
        ("mask", c_ssize_t),
        ("table", POINTER(SetEntry)),
        ("hash", c_long),
        ("finger", c_ssize_t),
        ("smalltable", (SetEntry * 8)),
        ("weakreflist", POINTER(PyObject)),
    ]


s = {3.14, "abc", 666}
# 先來打印一下哈希值
print('hash(3.14) =', hash(3.14))
print('hash("abc") =', hash("abc"))
print('hash(666) =', hash(666))
"""
hash(3.14) = 322818021289917443
hash("abc") = 8036038346376407734
hash(666) = 666
"""

# 獲取 PySetObject 結構體實例
py_set_obj = PySetObject.from_address(id(s))
# 遍歷 smalltable,打印索引和 key 的哈希值
for index, entry in enumerate(py_set_obj.smalltable):
    print(index, entry.hash)
"""
0 0
1 0
2 666
3 322818021289917443
4 0
5 0
6 8036038346376407734
7 0
"""

根據輸出的哈希值我們可以斷定,這三個元素確實存在了 smalltable 數組里面,并且 666 存在了數組索引為 2 的位置、3.14 存在了數組索引為 3 的位置、"abc" 存在了數組索引為 6 的位置。

當然,由于哈希值是隨機的,所以每次執行之后打印的結果都可能不一樣,但是整數除外,它的哈希值就是它本身。既然哈希值不一樣,那么每次映射出的索引也可能不同,但總之這三個元素是存在 smalltable 數組里面的。

然后我們再考察一下其它的字段:

s = {3.14, "abc", 666}
py_set_obj = PySetObject.from_address(id(s))
# 集合里面有 3 個元素,所以 fill 和 used 都是 3
print(py_set_obj.fill)  # 3
print(py_set_obj.used)  # 3

# 將集合元素全部刪除
# 這里不能用 s.clear(),原因一會兒說
for _ in range(len(s)):
    s.pop()
    
# 我們知道哈希表在刪除元素的時候是偽刪除
# 所以 fill 不變,但是 used 每次會減 1
print(py_set_obj.fill)  # 3
print(py_set_obj.used)  # 0

fill 字段維護的是 Active 態的 entry 數量加上 Dummy 態的 entry 數量,所以刪除元素時它的大小是不變的。但 used 字段的值每次會減 1,因為它維護的是 Active 態的 entry 的數量。所以在不涉及元素的刪除時,這兩者的大小是相等的。

另外我們說上面不能用 s.clear(),因為該方法表示清空集合,此時會重置為初始狀態,然后 fill 和 used 都會是 0,這樣就觀察不到想要的現象了。

刪除集合所有元素之后,我們再往里面添加元素,看看是什么效果:

s = {3.14, "abc", 666}
py_set_obj = PySetObject.from_address(id(s))
for _ in range(len(s)):
    s.pop()

# 添加一個元素
s.add(0)
print(py_set_obj.fill)  # 3
print(py_set_obj.used)  # 1

多次執行的話,會發現打印的結果可能是 3、1,也有可能是 4、1。至于原因,有了字典的經驗,相信你肯定能猜到。

首先添加元素之后,used 肯定為 1。至于 fill,如果添加元素的時候,正好撞上了一個 Dummy 態的 entry,那么將其替換掉,此時 fill 不變,仍然是 3。但如果沒有撞上 Dummy 態的 entry,而是添加在了新的位置,那么 fill 就是 4。

for i in range(1, 10):
    s.add(i)
print(py_set_obj.fill)  # 10
print(py_set_obj.used)  # 10
s.pop()
print(py_set_obj.fill)  # 10
print(py_set_obj.used)  # 9

在之前代碼的基礎上,繼續添加 9 個元素,然后 used 變成了 10,這很好理解,因為此時集合有 10 個元素。但 fill 也是 10,這是為什么?很簡單,因為哈希表擴容了,擴容時會刪除 Dummy 態的 entry,所以 fill 和 used 是相等的。同理,如果再繼續 pop,那么 fill 和 used 就又變得不相等了。

集合的創建

集合的結構我們已經清楚了,再來看看它的初始化過程。我們調用類 set,傳入一個可迭代對象,便可創建一個集合,這個過程是怎樣的呢?

// Objects/setobject.c
PyObject *
PySet_New(PyObject *iterable)
{
    return make_new_set(&PySet_Type, iterable);
}

static PyObject *
make_new_set(PyTypeObject *type, PyObject *iterable)
{
    assert(PyType_Check(type));
    PySetObject *so;
    // 為 PySetObject 申請內存,初始容量為 8
    so = (PySetObject *)type->tp_alloc(type, 0);
    if (so == NULL)
        return NULL;
    // 對字段做初始化
    so->fill = 0;
    so->used = 0;
    so->mask = PySet_MINSIZE - 1;
    // 哈希表容量為 8 時,元素會存在 smalltable 里面
    // 因此直接將 smalltable 賦值給 table
    so->table = so->smalltable;
    so->hash = -1;
    so->finger = 0;
    so->weakreflist = NULL;

    if (iterable != NULL) {
        // 遍歷 iterable,將迭代出的元素添加到集合中
        // 關于這個函數,我們之后再介紹
        if (set_update_internal(so, iterable)) {
            Py_DECREF(so);
            return NULL;
        }
    }

    return (PyObject *)so;
}

可以看到,集合的創建過程非常簡單。

字典和集合的哈希表的差異

字典和集合都是采用哈希表實現的,但字典的哈希表使用了兩個數組,而集合的哈希表使用了一個數組,我們對比一下兩者的差異。

假設有一個字典和一個集合,字典包含三個鍵值對,分別是 "a": 1、"b": 2、"c": 3,集合包含三個元素,分別是 "a"、"b"、"c",然后映射出的索引分別是 2、5、3。

圖片圖片

注:為了方便,這里的圖畫得沒有那么嚴謹。比如集合的哈希表,里面的元素直接用字符串代替了,但其實它存儲的是 setentry entry,而 entry 的 key 字段指向的才是字符串。當然這里我們心里清楚就好。

在介紹字典的時候我們說過,早期的字典內部的哈希表也是使用一個數組實現,除了 entry 會多存儲一個 value 之外,其它和當前的集合是類似的。

但如果只使用一個數組實現,會導致內存浪費嚴重,因為哈希表必須要保證一定的稀疏性。所以后續字典內部的哈希表采用兩個數組實現,將存儲鍵值對的數組的長度壓縮到原來的 2/3,至于映射出的索引則由另一個數組(哈希索引數組)來承載。

雖然引入新的數組會帶來額外的內存開銷(假設大小為 m 字節),但存儲鍵值對的數組不用再浪費 1/3 的空間(假設大小為 n 字節),只要 m 小于 n,那么使用兩個數組就會更加節省內存。而在介紹字典的時候我們也看到了,m 是遠小于 n 的。

那么問題來了,為什么集合不使用兩個數組呢?很簡單,因為使用一個數組實現哈希表會更簡單,雖然也更加浪費內存。而集合和字典在哈希表的實現上之所以區別對待,還是使用頻率的問題,解釋器內部極度依賴字典,比如全局變量就是使用字典存儲的。

可以說字典的效率高度影響著整個解釋器的效率,字典的內存大小高度影響著解釋器的內存占用。因此 Python 除了優化字典的搜索性能之外,還要盡可能地減少字典的內存大小。所以字典搞出了分離表、結合表,以及根據 key 是否全部是字符串來選擇使用不同的結構體表示 entry,這一切操作都是為了將字典的內存占用降到最低。

至于集合,解釋器對它的依賴就很小了,所以內部的哈希表,只采用了一個數組實現。雖然會有內存浪費,但無傷大雅。

好,回到上面的例子,如果將字典的鍵值對 "b": 2 和集合的元素 "b" 刪掉,那么它們的結構會發生什么變化呢?

圖片圖片

"b" 映射出的索引為 5,因此對于字典來說,會將索引為 5 的哈希槽的值設置為 dummy。然后是鍵值對數組,會將指定的 entry 的 me_key 和 me_value 字段全部設置為 NULL,相當于回歸到了初始狀態。

需要注意的是,數組一旦申請,那么 entry 的空間就已經有了,只是 me_key 和 me_value 字段均為 NULL。而所謂添加鍵值對,本質上也是修改指定 entry 的 me_key 和 me_value 字段。

對于集合來說,它只有一個數組,這個數組不僅要存儲鍵值對,它的索引還表示 key 映射出的索引,當然這里的 key 指的就是集合的元素。"b" 映射出的索引為 5,所以將數組中索引為 5 的 entry->key 設置為 dummy。

但要注意的是,字典的 dummy 是一個整數,值為 -2(DKIX_DUMMY),因為哈希索引數組存儲的是整數。key 映射出的索引是哈希索引數組的索引,如果對應的哈希槽存儲的值是 -2,說明當前搜索的 key 對應的 entry 被刪除了,應該繼續向后搜索。

而集合的 dummy 是一個結構體指針,定義如下:

// Objects/setobject.c
static PyObject _dummy_struct;
#define dummy (&_dummy_struct)

因為集合內部的哈希表只使用了一個數組,該數組存儲的是 setentry。如果在查找的時候,發現對應的 entry 的 key 等于 dummy,就知道該 entry 被刪除了,應該繼續向后搜索。

好,繼續回到上面的例子,假設這時候再給字典添加一個鍵值對 "d": 4,給集合添加一個元素 "d",而字符串 "d" 映射出的索引也是 5,那么結構是怎樣的呢?

圖片圖片

對于字典來說,鍵值對始終按照先來后到的順序添加在鍵值對數組中,然后將它在鍵值對數組中的索引保存在指定的哈希槽中。由于索引為 5 的哈希槽保存的是 -2,處于 Dummy 態,因此直接將它設置為 3。

同理對于集合來說也是類似的。數組索引為 5 的位置保存的值等于 dummy,處于 Dummy 態,說明該元素被刪除了,那么直接替換掉。因此整個過程的邏輯很簡單:由于索引會存在沖突,所以元素刪除之后,需要寫入一個特殊的墓碑值,也就是這里的 dummy,因為要保證探測鏈不斷裂。但如果集合后續添加元素時,正好撞上了一個 Dummy 態的 entry,那么會直接替換掉。

所以不論是字典還是集合,只要處于 Dummy 態,都可以替換掉。因為 Dummy 態存在的目的就是為了保證探測鏈不斷裂,而替換之后探測鏈依舊是完整的。

小結

以上我們就剖析了集合的底層結構以及它的創建過程,不難發現集合的實現比字典要簡單很多,并且集合沒有自己的緩存池。

責任編輯:武曉燕 來源: 古明地覺的編程教室
相關推薦

2024-08-02 11:33:49

2015-09-15 15:41:09

監控寶Docker

2021-09-10 07:41:06

Python拷貝Python基礎

2023-12-05 13:46:09

解密協程線程隊列

2022-05-25 08:31:31

ArthasInstrument

2022-11-18 18:36:24

2023-11-22 08:35:34

存儲引擎bitcask

2020-11-26 15:10:20

Python代碼函數

2022-01-26 07:25:09

PythonRSA加解密

2024-05-31 08:38:35

Python浮點數屬性

2023-11-23 08:31:51

競爭鎖共享字段

2024-01-26 07:37:51

Stream工具場景

2017-04-06 12:20:16

2017-05-16 15:33:42

Python網絡爬蟲核心技術框架

2020-09-30 14:24:58

PythonSet對象

2017-12-06 16:28:48

Synchronize實現原理

2014-06-06 09:01:07

DHCP

2024-12-23 15:05:29

2022-11-07 07:04:25

2022-09-26 08:03:52

框架ListGuava
點贊
收藏

51CTO技術棧公眾號

超碰一区二区三区| 黄色av免费在线| 久久九九精品| 亚洲品质视频自拍网| xxx国产在线观看| 天堂8中文在线| 久久色视频免费观看| 91精品综合视频| 亚洲综合一二三| 久久高清免费| 日韩成人免费视频| 一级做a爱视频| 欧美电影h版| 亚洲综合视频在线观看| 日韩欧美一区二区视频在线播放 | 91精品黄色| 日韩久久中文字幕| 亚洲精品91| 亚洲欧洲日本专区| 粗大的内捧猛烈进出视频| 亚洲午夜天堂| 亚洲在线观看免费视频| 日韩一区不卡| 天天操天天干天天爽| 精品无人码麻豆乱码1区2区| 欧美伊久线香蕉线新在线| 久久免费看少妇高潮v片特黄| 夜夜春成人影院| 精品国产成人在线影院| 久久精品无码一区二区三区毛片| 制服诱惑亚洲| 欧美日韩国产页| wwwwww欧美| 粗大黑人巨茎大战欧美成人| 国产欧美一区二区精品秋霞影院| 国产欧美一区二区三区另类精品| 99视频国产精品免费观看a| 美日韩一级片在线观看| 热久久这里只有精品| 国产一级视频在线| 欧美久久九九| 欧美成人在线网站| 成人在线观看小视频| 成人嫩草影院| 国产香蕉精品视频一区二区三区| 亚洲自拍偷拍一区二区| 澳门成人av| 亚洲成年人在线| 午夜诱惑痒痒网| 国产亚洲精aa在线看| 欧美亚洲一区二区在线观看| 99精品视频在线看| gay欧美网站| 日韩欧美精品网址| www.国产区| 亚洲成a人片| 欧洲一区二区av| 波多野结衣天堂| 国产一区二区色噜噜| 精品视频999| 中文字幕22页| 亚洲成人黄色| 欧美变态tickle挠乳网站| 久久久精品人妻一区二区三区| 日韩影片在线观看| 亚洲成av人片在线观看香蕉| 强迫凌虐淫辱の牝奴在线观看| 九九热播视频在线精品6| 亚洲精美色品网站| 老鸭窝一区二区| 欧美日韩第一| 久久大大胆人体| 青青草原在线免费观看| 在线免费高清一区二区三区| 91极品视频在线| 无码人妻丰满熟妇奶水区码| 美女尤物国产一区| 99re6在线| 欧洲视频在线免费观看| 国产精品久久久久久久浪潮网站| 人人妻人人澡人人爽精品欧美一区| 国产精品实拍| 午夜精品久久久久久| 色网综合在线观看| 日本在线观看不卡| 日韩子在线观看| 一区二区三区不卡视频| 国产免费黄视频| 成人一区视频| 精品国产髙清在线看国产毛片| 好吊视频在线观看| 亚洲第一偷拍| 日本精品免费观看| 国产视频第一页| 26uuu精品一区二区三区四区在线| 亚洲乱码一区二区三区三上悠亚| 韩国av网站在线| 欧美午夜xxx| 伊人国产精品视频| 一区二区导航| 欧美国产日本高清在线| 小泽玛利亚一区二区三区视频| 国产美女主播视频一区| 免费久久一级欧美特大黄| 免费在线观看黄色网| 精品日韩美女的视频高清 | 九九视频精品免费| 国产中文一区二区| 大片免费在线看视频| 欧美性猛交xxxx偷拍洗澡| 亚洲天堂小视频| 国产一区二区三区网| 欧美精品xxx| 国产男女无套免费网站| 国产日韩一级二级三级| 男人用嘴添女人下身免费视频| 亚洲伊人伊成久久人综合网| 亚洲男子天堂网| 日本一区二区不卡在线| 国产呦萝稀缺另类资源| 天天人人精品| 欧美成人资源| 日韩激情av在线免费观看| 欧美精品一区二区蜜桃| 蜜桃免费网站一区二区三区| 欧美精品在线一区| 91白丝在线| 精品国产麻豆免费人成网站| 亚洲一级生活片| 久久99精品一区二区三区| 欧美一区二区三区四区夜夜大片| 电影在线观看一区| 精品精品欲导航| 欧美日韩免费做爰视频| 极品少妇xxxx精品少妇偷拍| 亚洲人成网站在线播放2019| 向日葵视频成人app网址| 日韩成人av网| 成人免费区一区二区三区| 成人久久18免费网站麻豆| 天天想你在线观看完整版电影免费| 国产成人午夜性a一级毛片| 在线观看精品自拍私拍| 亚洲精品久久久久久久蜜桃| 久久美女艺术照精彩视频福利播放 | 91精产国品一二三| 综合激情婷婷| 99久久精品久久久久久ai换脸| av网站免费在线观看| 日韩一区二区不卡| 久久久久久久久久久久久久久久久 | 深夜福利网站在线观看| 在线观看国产精品入口| 97影院在线午夜| av成人 com a| 精品视频一区在线视频| 久久精品无码av| 国产精品全国免费观看高清 | 欧美精品在欧美一区二区| 亚洲精品在线国产| 久久理论片午夜琪琪电影网| 神马午夜精品95| 欧美性色19p| 91无套直看片红桃在线观看| 久久99热国产| 国产freexxxx性播放麻豆| 都市激情亚洲欧美| 欧洲日本亚洲国产区| 草碰在线视频| 6080日韩午夜伦伦午夜伦| 久久久久无码国产精品不卡| 波波电影院一区二区三区| 男人日女人bb视频| 日韩一区二区在线| 91夜夜未满十八勿入爽爽影院 | 少妇熟女视频一区二区三区| 亚洲高清不卡| 日韩欧美精品一区二区三区经典 | 日韩av网站在线观看| 中文字幕人成一区| 精品av导航| 国产精品旅馆在线| 羞羞视频在线免费国产| 日韩av中文字幕在线免费观看| 中文字幕av片| 亚洲韩国精品一区| 久久久久久九九九九九| 狠狠色狠狠色综合| 欧美 日韩 国产在线观看| 日韩久久电影| 国产原创精品| 日韩一级视频| 欧美性做爰毛片| 超碰超碰在线| 亚洲日本成人女熟在线观看| 国产乱色精品成人免费视频| 粉嫩av一区二区三区免费野| 日本中文在线视频| 久久久久久久久一| 国产清纯白嫩初高中在线观看性色| 免费日韩av| 成人短视频在线观看免费| av中文字幕一区二区| 不卡视频一区| 日韩三级成人| 国产成人精品综合| 成人三级高清视频在线看| 久久综合久久八八| 91青青在线视频| 亚洲免费视频网站| 日本高清视频免费观看| 欧美日本高清视频在线观看| 天天操夜夜操视频| 亚洲综合自拍偷拍| 国产高清视频免费在线观看| 久久久久久**毛片大全| 亚洲av永久无码精品| 激情国产一区二区| 日本在线一二三区| 日韩激情在线观看| 日本在线观看a| 精品电影一区| 国产激情片在线观看| 97精品国产| 亚洲不卡一卡2卡三卡4卡5卡精品| 999精品视频在这里| 成人在线一区二区| av成人在线播放| 国产精品成久久久久三级| 日本蜜桃在线观看视频| 国语自产精品视频在线看抢先版图片| www.久久久久.com| 久久亚洲国产精品成人av秋霞| 成人免费在线视频网| 亚洲欧美日韩高清| 久久精品a一级国产免视看成人 | 亚洲第一毛片| 日本一本中文字幕| 国产主播一区| 97超碰在线人人| 在线成人欧美| 欧美在线一区视频| 在线亚洲观看| 欧美 日韩 国产一区| 国产精品免费看| 北条麻妃在线视频观看| 国产精品一页| 男女曰b免费视频| 日本中文字幕一区二区有限公司| 免费在线观看的毛片| 日韩电影免费一区| 日本人视频jizz页码69| 久久成人18免费观看| 免费网站在线观看黄| 国产麻豆视频一区二区| xxxx国产视频| 北条麻妃国产九九精品视频| 国产精品一区二区人妻喷水| 91欧美一区二区| 亚洲午夜精品久久久久久高潮| 国产精品天天看| 色哟哟一一国产精品| 亚洲最新在线观看| 国产成人精品a视频一区| 色悠悠久久综合| 中文字幕制服诱惑| 91精品国产91久久久久久一区二区| 99久久精品国产一区色| 精品国产一区二区亚洲人成毛片| 五月婷中文字幕| 国产午夜精品视频| 性欧美video高清bbw| 98视频在线噜噜噜国产| 久久xxx视频| 91久久精品一区二区别| 色婷婷综合久久久久久| 影音欧美亚洲| 最新亚洲视频| 一道本视频在线观看| 国产精品18久久久久久久久| 漂亮人妻被黑人久久精品| 欧美激情一区二区三区在线| 久久r这里只有精品| 狠狠色狠色综合曰曰| 国产又大又长又粗| 日韩av网址在线| 欧美69xxx| 77777亚洲午夜久久多人| 欧美日韩免费电影| 国产午夜精品在线| 99精品视频在线| 日韩免费视频播放| 精品无人码麻豆乱码1区2区 | 国产一区二区影视| 欧美黄色三级网站| 四虎成人在线| 国产日韩精品推荐| 天天综合久久| 男女曰b免费视频| 成人深夜福利app| 久草手机视频在线观看| 精品日韩美女的视频高清 | 亚洲情综合五月天| 麻豆av在线免费观看| 国产欧美日韩专区发布| 中文字幕伦av一区二区邻居| 日韩一级免费看| 青娱乐精品视频在线| 欧美在线一级片| 一区二区三区国产| 一级特黄aaa大片| 亚洲日本成人网| free性m.freesex欧美| 亚洲一区二区免费在线| 欧美一级精品| 免费黄色福利视频| 成人aaaa免费全部观看| 爱爱视频免费在线观看| 欧美性videosxxxxx| 国产在线观看网站| 欧美一级免费视频| 国产精品三p一区二区| 肉大捧一出免费观看网站在线播放| 日本aⅴ精品一区二区三区 | 国内黄色精品| 成年人观看网站| 99热在这里有精品免费| 久久黄色小视频| 日韩精品中文字幕在线不卡尤物 | 国产91免费在线观看| 欧美成人免费全部观看天天性色| 少妇高潮一区二区三区99| 日韩欧美视频一区二区三区四区| 久久九九电影| 成年人在线免费看片| 色视频成人在线观看免| 欧美精品少妇| 国产91色在线播放| 亚洲尤物av| 成人一区二区三| 国产精品网站导航| 中文字幕日本人妻久久久免费 | 1769免费视频在线观看| 亚洲www视频| 欧美日韩三区| 黑森林av导航| 天天射综合影视| 美国一级片在线免费观看视频| 啪一啪鲁一鲁2019在线视频| 国产一区网站| 成年人三级黄色片| 亚洲欧美日韩成人高清在线一区| 国产女人高潮时对白| 欧美成人免费观看| 久久精品亚洲成在人线av网址| 91视频 -- 69xx| 日本一区二区三级电影在线观看| 波多野结衣视频在线观看| 中文字幕亚洲综合| 国产一区二区三区精品在线观看| 亚洲色婷婷久久精品av蜜桃| 成人av资源网站| 日本一区二区三区精品| 中文字幕一精品亚洲无线一区| 日韩在线激情| 2019日韩中文字幕mv| 91免费视频网址| 91久久国语露脸精品国产高跟| 久久国产精品久久精品| 牛牛影视一区二区三区免费看| 99色精品视频| 国产精品久久久久精k8| 国产高清不卡视频| 45www国产精品网站| 日本不卡二三区| 国产成人av片| 色欧美乱欧美15图片| 欧美日本一道| 久久狠狠久久综合桃花| 蜜桃在线一区二区三区| 国产无套粉嫩白浆内谢| 亚洲欧美日韩一区二区在线| 99久久999| 男人天堂网视频| 亚洲视频狠狠干| 欧美一区二区视频| 91在线精品视频| 久久精品麻豆| 久久久www成人免费毛片| 亚洲一级片在线看| 91欧美日韩在线| 日韩av卡一卡二| 午夜一区二区三区视频| 久久bbxx| 欧美日韩在线不卡一区| 国产精品影视在线| 中文在线a天堂| 亚州国产精品久久久| 天天做天天爱天天综合网| 国精产品一区一区三区免费视频 |