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

探索數(shù)據(jù)結(jié)構(gòu)之美:有序集合的內(nèi)部機(jī)制

開發(fā)
有序集合作為一種常用的數(shù)據(jù)結(jié)構(gòu),在許多應(yīng)用場(chǎng)景中發(fā)揮著重要作用,例如緩存、索引、排名等。本文將深入探討有序集合的內(nèi)部機(jī)制,分析其源代碼,并揭示其實(shí)現(xiàn)細(xì)節(jié)。

在現(xiàn)代軟件開發(fā)中,高效的數(shù)據(jù)結(jié)構(gòu)和算法設(shè)計(jì)對(duì)于構(gòu)建高性能系統(tǒng)至關(guān)重要。有序集合(Sorted Set)作為一種常用的數(shù)據(jù)結(jié)構(gòu),在許多應(yīng)用場(chǎng)景中發(fā)揮著重要作用,例如緩存、索引、排名等。本文將深入探討有序集合的內(nèi)部機(jī)制,分析其源代碼,并揭示其實(shí)現(xiàn)細(xì)節(jié)。

注意,本著對(duì)核心數(shù)據(jù)結(jié)構(gòu)的剖析,本文有序集合的所有指令操作都是以字典+跳表這兩個(gè)編碼展開討論,對(duì)于壓縮列表的實(shí)現(xiàn)細(xì)節(jié)就不會(huì)涉及。

一、詳解有序集合核心指令實(shí)現(xiàn)

1. 跳表相關(guān)導(dǎo)讀

本文著重于講解有序集合內(nèi)部核心實(shí)現(xiàn),會(huì)涉及大量跳表的知識(shí)點(diǎn),需要了解的讀者建議閱讀一下筆者下面這篇關(guān)于跳表設(shè)計(jì)與實(shí)現(xiàn)的文章:

高效索引的秘密:Redis跳表設(shè)計(jì)與實(shí)現(xiàn)

2. 元素添加指令zadd

有序集合添加指令就是zadd,它支持添加一個(gè)或者多個(gè)指令,對(duì)應(yīng)的操作示例如下,可以看到操作成功之后就會(huì)返回添加的元素?cái)?shù):

redis> ZADD myzset 1 "one"
(integer) 1
redis> ZADD myzset 1 "uno"
(integer) 1
redis> ZADD myzset 2 "two" 3 "three"
(integer) 2

對(duì)應(yīng)的指令函數(shù)源碼的實(shí)現(xiàn)是zaddCommand,該函數(shù)大體按照如下步驟進(jìn)行:

  • 檢查元素是否能被2整除來校驗(yàn)參數(shù)個(gè)數(shù)是否正確。
  • 檢查有序集合的key是否存在且類型確實(shí)是有序集合。
  • 逐個(gè)遍歷元素及其score查看該元素是否存在,如果不存在則先插入操有序集合底層的跳表中來維護(hù)元素之間的先后順序。確保這步操作成功后再將元素指針添加到有序集合的字典中,保證單元素檢索的效率。
  • 如果元素已存在,則會(huì)將該元素從跳表中刪除,保證關(guān)于這個(gè)元素的索引都清理干凈后在進(jìn)行插入,以保證跳表的正確性,因?yàn)樵匾呀?jīng)在有序集合字典中存在了,所以更新操作就不會(huì)操作字典了。

對(duì)應(yīng)我們也給出操作的源碼細(xì)節(jié),讀者可以參照筆者的上述的講解了解一下源碼的細(xì)節(jié):

//調(diào)用zaddGenericCommand并傳入0,意為告知zaddGenericCommand要返回本次操作的添加數(shù)(不包括更新)
void zaddCommand(redisClient *c) {
    zaddGenericCommand(c,0);
}

/* This generic command implements both ZADD and ZINCRBY. */
void zaddGenericCommand(redisClient *c, int incr) {
 //.......
    //拿到有序集合里面element和score有幾對(duì)
    int j, elements = (c->argc-2)/2;
    int added = 0, updated = 0;
    //檢查參數(shù)是否是基數(shù)個(gè),如果是則報(bào)錯(cuò)
    if (c->argc % 2) {
        addReply(c,shared.syntaxerr);
        return;
    }

    //創(chuàng)建score數(shù)組
    scores = zmalloc(sizeof(double)*elements);
    //遍歷score轉(zhuǎn)為double類型,將轉(zhuǎn)換后的結(jié)果存到scores數(shù)組中,后續(xù)元素的score都依次按照順序從數(shù)組中獲取
    for (j = 0; j < elements; j++) {
        if (getDoubleFromObjectOrReply(c,c->argv[2+j*2],&scores[j],NULL)
            != REDIS_OK) goto cleanup;
    }

 
    //查看這個(gè)有序集合是否在redis中存在
    zobj = lookupKeyWrite(c->db,key);
    //如果不存在則進(jìn)行初始化,然后添加到redis數(shù)據(jù)庫(kù)中
    if (zobj == NULL) {
        if (server.zset_max_ziplist_entries == 0 ||
            server.zset_max_ziplist_value < sdslen(c->argv[3]->ptr))
        {
         //創(chuàng)建有序集合對(duì)象
            zobj = createZsetObject();
        } else {
          //......
        }
        //添加到內(nèi)存數(shù)據(jù)庫(kù)中
        dbAdd(c->db,key,zobj);
    } 
    //遍歷傳入的每一個(gè)元素
    for (j = 0; j < elements; j++) {
        //拿到元素的score
        score = scores[j];

        if (zobj->encoding == REDIS_ENCODING_ZIPLIST) {
           //......
        } else if (zobj->encoding == REDIS_ENCODING_SKIPLIST) {//如果轉(zhuǎn)為跳表,則直接走跳表的邏輯
          //......
            //將元素進(jìn)行編碼轉(zhuǎn)換
            ele = c->argv[3+j*2] = tryObjectEncoding(c->argv[3+j*2]);
            //查看字典中是否存在這個(gè)元素
            de = dictFind(zs->dict,ele);
            //如果存在,則進(jìn)行更新操作
            if (de != NULL) {
           //......
             
                //比對(duì)socre與之前的結(jié)果是否一致,,如果不一致則說明該元素的排名要改變,需將其從跳表中移除再插入維護(hù)節(jié)點(diǎn)之間新的關(guān)系
                if (score != curscore) {
                    redisAssertWithInfo(c,curobj,zslDelete(zs->zsl,curscore,curobj));
                    znode = zslInsert(zs->zsl,score,curobj);
                    incrRefCount(curobj); /* Re-inserted in skiplist. */
                    dictGetVal(de) = &znode->score; /* Update score ptr. */
                    server.dirty++;
                    updated++;
                }
            } else {
                //先插入到跳表,然后再插入到字典中
                znode = zslInsert(zs->zsl,score,ele);
                incrRefCount(ele); /* Inserted in skiplist. */
                redisAssertWithInfo(c,NULL,dictAdd(zs->dict,ele,&znode->score) == DICT_OK);
                incrRefCount(ele); /* Added to dictionary. */
                server.dirty++;
                added++;
            }
        } else {
            redisPanic("Unknown sorted set encoding");
        }
    }
    //因?yàn)槲覀儌魅氲闹凳?,所以返回添加結(jié)果added
    if (incr) /* ZINCRBY */
        addReplyDouble(c,score);
    else /* ZADD */
        addReplyLongLong(c,added);

//......
}

3. 有序集合元素?cái)?shù)量查詢指令zcard

zcard常用于查看當(dāng)前有序集合的長(zhǎng)度,對(duì)應(yīng)的使用示例如下所示:

redis> ZADD myzset 1 "one"
(integer) 1
redis> ZADD myzset 2 "two"
(integer) 1
redis> ZCARD myzset
(integer) 2
redis> 

因?yàn)樯鲜龅牟僮鳎行蚣系讓佣紩?huì)通過壓縮列表或者跳表維護(hù)長(zhǎng)度,所以調(diào)用zcard的時(shí)候,本質(zhì)上就是通過length字段返回當(dāng)前有序集合的長(zhǎng)度:

void zcardCommand(redisClient *c) {
    robj *key = c->argv[1];
    robj *zobj;
    //查看key是否存在,如果不存在則返回0,如果不是有序集合則返回錯(cuò)誤碼
    if ((zobj = lookupKeyReadOrReply(c,key,shared.czero)) == NULL ||
        checkType(c,zobj,REDIS_ZSET)) return;
    //調(diào)用zsetLength返回有序集合中的元素?cái)?shù)
    addReplyLongLong(c,zsetLength(zobj));
}

4. 有序集合順序遍歷指令zrange

ZRANGE指令用于順序遍歷有序集合中所有元素,如果加上WITHSCORES關(guān)鍵字那么該指令就會(huì)返回元素及其score:

redis 127.0.0.1:6379> ZRANGE salary 0 -1 WITHSCORES             # 顯示整個(gè)有序集成員
1) "jack"
2) "3500"
3) "tom"
4) "5000"
5) "boss"
6) "10086"

redis 127.0.0.1:6379> ZRANGE salary 1 2 WITHSCORES              # 顯示有序集下標(biāo)區(qū)間 1 至 2 的成員
1) "tom"
2) "5000"
3) "boss"
4) "10086"

我們以下面這張圖為例,假設(shè)我們希望查詢索引1即orange及其之后的元素,有序集合會(huì)從最高層索引開始,依次按照下述步驟執(zhí)行:

  • 在L3的頭節(jié)點(diǎn)開始,走兩步就到達(dá)orange的索引。
  • 基于該索引定位到orange元素。
  • 基于orange的forward指針不斷向前進(jìn)即完成后續(xù)元素遍歷。

對(duì)此我們給出zrange指令實(shí)現(xiàn)的函數(shù)zrangeCommand,可以看到其底層是調(diào)用zrangeGenericCommand并傳入0進(jìn)行順序查找遍歷輸出的:

void zrangeCommand(redisClient *c) {
    //傳入0,代表找到后進(jìn)行順序遍歷輸出
    zrangeGenericCommand(c,0);
}

我們?cè)俳o出zrangeGenericCommand的核心代碼段,可以看到在進(jìn)行必要的數(shù)值類型轉(zhuǎn)換后,有序集合就會(huì)調(diào)用跳表的方法zslGetElementByRank按照我們上圖所講解的方式定位到元素,然后基于該元素的forward指針不斷步進(jìn)遍歷元素并輸出:

void zrangeGenericCommand(redisClient *c, int reverse) {
   //......
    //判斷數(shù)值轉(zhuǎn)換是否正常
    if ((getLongFromObjectOrReply(c, c->argv[2], &start, NULL) != REDIS_OK) ||
        (getLongFromObjectOrReply(c, c->argv[3], &end, NULL) != REDIS_OK)) return;
    //如果參數(shù)5個(gè)且最后一個(gè)是withscores,說明需要輸出對(duì)應(yīng)的節(jié)點(diǎn)和score
    if (c->argc == 5 && !strcasecmp(c->argv[4]->ptr,"withscores")) {
        withscores = 1;
    } else if (c->argc >= 5) {//大于5個(gè)則報(bào)錯(cuò)
        addReply(c,shared.syntaxerr);
        return;
    }
    //非空查詢和類型判斷
    if ((zobj = lookupKeyReadOrReply(c,key,shared.emptymultibulk)) == NULL
         || checkType(c,zobj,REDIS_ZSET)) return;

  //......

    if (zobj->encoding == REDIS_ENCODING_ZIPLIST) {
       //......

    } else if (zobj->encoding == REDIS_ENCODING_SKIPLIST) {
        zset *zs = zobj->ptr;
        zskiplist *zsl = zs->zsl;
        zskiplistNode *ln;
        robj *ele;

        /* Check if starting point is trivial, before doing log(N) lookup. */
        if (reverse) {
            ln = zsl->tail;
            if (start > 0)
                ln = zslGetElementByRank(zsl,llen-start);
        } else {//順序遍歷,從索引0層開始遍歷
            ln = zsl->header->level[0].forward;
            if (start > 0)//如果大于0 則定位到要查詢的元素位置,傳入start+1即走start+1步到指定位置
                ln = zslGetElementByRank(zsl,start+1);
        }
        //基于range不斷步進(jìn)完成后續(xù)遍歷
        while(rangelen--) {
            redisAssertWithInfo(c,zobj,ln != NULL);
            ele = ln->obj;
            addReplyBulk(c,ele);
            //如果傳入withscores則輸出對(duì)應(yīng)元素的score
            if (withscores)
                addReplyDouble(c,ln->score);
             //基于forward或者backward向前或者向后遍歷
            ln = reverse ? ln->backward : ln->level[0].forward;
        }
    } else {
        redisPanic("Unknown sorted set encoding");
    }
}

5. 基于給定元素值返回元素排名

獲取元素排名的指令為zrank,例如我們有序集合中有如下3個(gè)元素,查詢tom他在索引1位置,所以返回1,即排第2(索引1再加上1):

redis 127.0.0.1:6379> ZRANGE salary 0 -1 WITHSCORES        # 顯示所有成員及其 score 值
1) "peter"
2) "3500"
3) "tom"
4) "4000"
5) "jack"
6) "5000"

redis 127.0.0.1:6379> ZRANK salary tom                     # 顯示 tom 的薪水排名,第二
(integer) 1

其內(nèi)部調(diào)用的函數(shù)是zrankCommand,然后其內(nèi)部調(diào)用zrankGenericCommand傳入0,代表查詢當(dāng)前元素的順序排名:

void zrankCommand(redisClient *c) {
    //傳入0順序查詢排名
    zrankGenericCommand(c, 0);
}

zrankGenericCommand的源碼如下所示,以跳表結(jié)構(gòu)為例,該方法首先通過字典定位到這個(gè)元素的score,然后通過跳表的zslGetRank查詢這個(gè)元素,按照我們上文中一直強(qiáng)調(diào)的多級(jí)索引跳越查詢得到元素經(jīng)過多少個(gè)span,以tom也就是要走2個(gè)span,那么zslGetRank就會(huì)返回2,基于這個(gè)查詢結(jié)果減去1返回給客戶端,客戶端即可知曉tom在跳表中的索引值是1:

void zrankGenericCommand(redisClient *c, int reverse) {
   //......

    if (zobj->encoding == REDIS_ENCODING_ZIPLIST) {
           //......
    } else if (zobj->encoding == REDIS_ENCODING_SKIPLIST) {
        zset *zs = zobj->ptr;
        zskiplist *zsl = zs->zsl;
        dictEntry *de;
        double score;
        //對(duì)象類型轉(zhuǎn)換
        ele = c->argv[2] = tryObjectEncoding(c->argv[2]);
        //定位跳表
        de = dictFind(zs->dict,ele);
        if (de != NULL) {
            //從字典中定位score
            score = *(double*)dictGetVal(de);
            //從跳表中獲取rank
            rank = zslGetRank(zsl,score,ele);
            redisAssertWithInfo(c,ele,rank); /* Existing elements always have a rank. */
            if (reverse)
                addReplyLongLong(c,llen-rank);
            else //返回跨度值-1即得到元素在跳表中的索引
                addReplyLongLong(c,rank-1);
        } else {
            addReply(c,shared.nullbulk);
        }
    } else {
        redisPanic("Unknown sorted set encoding");
    }
}

6. 刪除節(jié)點(diǎn)指令zrem

當(dāng)有序集合刪除元素時(shí),除了將該元素從字典中移除,還需要將跳表中關(guān)于該元素的指針和索引全部移除,如下圖,假設(shè)我們要?jiǎng)h除orange,本質(zhì)上就是將orange和score到跳表中定位,將其元素和索引全部刪除,然后再將其從字典中刪除,并返回刪除個(gè)數(shù)。

需要補(bǔ)充的是,跳表完成刪除操作后還會(huì)檢查最高層索引,如果最高層索引沒有任何索引,那么跳表的索引層級(jí)就會(huì)減去1,可能有讀者會(huì)問為什么只檢查最高層索引,其實(shí)這和跳表的設(shè)計(jì)思想有關(guān),當(dāng)跳表為新建的節(jié)點(diǎn)生成隨機(jī)層級(jí)索引時(shí),創(chuàng)建索引的層級(jí)永遠(yuǎn)和生成的等級(jí)一致,例如:

  • 創(chuàng)建節(jié)點(diǎn)orange,生成索引級(jí)別為3,那么1、2層索引也會(huì)創(chuàng)建。
  • 生成banana生成索引為2,那么1層也會(huì)創(chuàng)建索引。

生成apple生成索引層為1,那么就只會(huì)創(chuàng)建1層索引。

這就導(dǎo)致高層索引的個(gè)數(shù)永遠(yuǎn)是最少的,最先出現(xiàn)索引空的情況永遠(yuǎn)是最高層索引,所以跳表進(jìn)行節(jié)點(diǎn)刪除后索引維護(hù)工作永遠(yuǎn)從最高層級(jí)開始。

對(duì)此我們也給出有序集合中關(guān)于zrem操作的源碼實(shí)現(xiàn),其核心流程就是筆者說的調(diào)用zslDelete從跳表中定位刪除,然后再同步刪除字典中的元素:

void zremCommand(redisClient *c) {
  //......

    if (zobj->encoding == REDIS_ENCODING_ZIPLIST) {
       //......
    } else if (zobj->encoding == REDIS_ENCODING_SKIPLIST) {
        zset *zs = zobj->ptr;
        dictEntry *de;
        double score;
        //遍歷key通過字典刪除
        for (j = 2; j < c->argc; j++) {
            //查找有序集合中是否存
            de = dictFind(zs->dict,c->argv[j]);
            //如果存在則執(zhí)行刪除操作
            if (de != NULL) {
                deleted++;

                /* Delete from the skiplist */
                score = *(double*)dictGetVal(de);
                //基于元素值和score到跳表進(jìn)行刪除
                redisAssertWithInfo(c,c->argv[j],zslDelete(zs->zsl,score,c->argv[j]));

                /* Delete from the hash table */
                //然后再?gòu)淖值渲袆h除
                dictDelete(zs->dict,c->argv[j]);
              //......
            }
        }
    } else {
        redisPanic("Unknown sorted set encoding");
    }

    //......
    //返回刪除數(shù)
    addReplyLongLong(c,deleted);
}

7. 查詢?cè)財(cái)?shù)值z(mì)score

該方法并沒有利用到跳表,而是直接傳入元素值到字典中定位拿到其score返回,在字典沖突較少的情況下時(shí)間復(fù)雜度為O(1),對(duì)應(yīng)源碼如下,比較簡(jiǎn)單,讀者可自行參閱注釋了解:

void zscoreCommand(redisClient *c) {
 //.......
    if (zobj->encoding == REDIS_ENCODING_ZIPLIST) {
   //......
    } else if (zobj->encoding == REDIS_ENCODING_SKIPLIST) {//通過字典拿到成績(jī)
        zset *zs = zobj->ptr;
        dictEntry *de;

        c->argv[2] = tryObjectEncoding(c->argv[2]);
        //將元素待入字典中定位
        de = dictFind(zs->dict,c->argv[2]);
        //不為空取出它的score返回
        if (de != NULL) {
            score = *(double*)dictGetVal(de);
            //返回score
            addReplyDouble(c,score);
        } else {
            addReply(c,shared.nullbulk);
        }
    } else {
        redisPanic("Unknown sorted set encoding");
    }
}
責(zé)任編輯:趙寧寧 來源: 寫代碼的SharkChili
相關(guān)推薦

2023-07-03 17:24:33

數(shù)據(jù)結(jié)構(gòu)

2020-10-30 09:56:59

Trie樹之美

2022-12-02 15:11:52

數(shù)據(jù)分析數(shù)據(jù)可視化

2020-10-20 08:14:08

算法與數(shù)據(jù)結(jié)構(gòu)

2024-07-11 11:35:08

數(shù)組結(jié)構(gòu)內(nèi)部機(jī)制

2020-10-12 11:48:31

算法與數(shù)據(jù)結(jié)構(gòu)

2020-06-29 07:44:36

Redis

2020-11-02 09:15:47

算法與數(shù)據(jù)結(jié)構(gòu)

2023-11-07 12:30:38

數(shù)據(jù)結(jié)構(gòu)紅黑樹

2023-03-28 07:44:23

數(shù)據(jù)結(jié)構(gòu)數(shù)組

2021-07-16 07:57:34

Python數(shù)據(jù)結(jié)構(gòu)

2024-03-29 09:12:43

Go語言工具

2020-01-16 11:23:32

Zookeeper數(shù)據(jù)結(jié)構(gòu)API

2021-07-13 07:52:03

Python數(shù)據(jù)結(jié)構(gòu)

2021-07-15 06:43:12

Python數(shù)據(jù)結(jié)構(gòu)

2017-03-01 13:58:46

Python數(shù)據(jù)結(jié)構(gòu)鏈表

2021-05-28 05:49:28

Python數(shù)據(jù)結(jié)構(gòu)與算法bisect

2020-07-14 08:53:43

Redis數(shù)據(jù)存儲(chǔ)

2011-04-11 10:14:47

HTML 5

2009-07-02 14:59:28

Java考研試題
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)

精品第一国产综合精品aⅴ| 一区二区在线观看视频在线观看| 国产精品99一区| 国产白丝一区二区三区 | 伊人性伊人情综合网| 国产精品乱码视频| 亚洲精品毛片一区二区三区| 亚洲成人三区| 日韩av在线不卡| 日韩av片免费观看| 国产盗摄——sm在线视频| 国产午夜精品一区二区三区视频| 欧美日韩精品一区二区天天拍小说| 中文字幕成人一区| 头脑特工队2免费完整版在线观看 头脑特工队2在线播放 | 精品在线观看免费| 久久久久久久久久久人体| 性猛交娇小69hd| 懂色av一区二区| 欧美日本一区二区三区四区| 春日野结衣av| 亚洲h片在线看| 国产精品污网站| 久久riav| 蜜臀av免费在线观看| 日本午夜精品视频在线观看| 97涩涩爰在线观看亚洲| 黄色a级片在线观看| 欧美猛男男男激情videos| 日韩欧美高清在线| 午夜剧场在线免费观看| 亚洲v.com| 亚洲成人av资源| 中国老女人av| 久久精品视频免费看| 国产亚洲成av人在线观看导航 | 美女毛片一区二区三区四区| 日韩精品中午字幕| 涩涩网站在线看| 日韩欧美2区| 欧美日韩在线一区| 久久久久久久久久久99| 亚洲七七久久综合桃花剧情介绍| 国产精品久久久久影院色老大| 欧美裸体网站| 你懂的视频在线| 91亚洲男人天堂| 国产精品一区在线播放| 午夜精品久久久久久久第一页按摩| 另类欧美日韩国产在线| 国产精品久久久久久影视| 日韩免费视频一区二区视频在线观看| 亚洲网站在线| 欧美激情综合色| 免费一级全黄少妇性色生活片| 亚洲色图插插| 美女久久久久久久久久久| 成人高潮免费视频| 亚洲人体av| 欧美黄色免费网站| 国产在线成人精品午夜| 亚洲作爱视频| 日本电影亚洲天堂| 一级黄色av片| 麻豆成人综合网| 91最新国产视频| 亚洲美女综合网| 国产91精品入口| 精品一区久久久久久| 四虎影视精品成人| 国产欧美日韩另类一区| 一本一生久久a久久精品综合蜜| 免费在线观看黄| 一区二区三区中文在线观看| 一本久道高清无码视频| 在线观看网站免费入口在线观看国内 | www.youjizz.com亚洲| 精品999网站| 日本乱人伦a精品| 在线观看黄色国产| 国产成人精品亚洲777人妖| 国产一级二级三级精品| 免费黄色片在线观看| 国产精品美日韩| 人人妻人人澡人人爽欧美一区| 国产色播av在线| 欧美色手机在线观看| 善良的小姨在线| 女仆av观看一区| 自拍偷拍亚洲欧美| 久久免费视频99| 日韩精品一二三四| 97久久天天综合色天天综合色hd| 欧美一级视频免费| 国产人成一区二区三区影院| 在线免费观看成人网| 91九色在线看| 欧美美女黄视频| 精品无码在线视频| 性做久久久久久久免费看| 国产精品久久久久久久久久久久久久 | 亚洲精品视频在线看| 国产成人黄色片| 电影中文字幕一区二区| 国产网站欧美日韩免费精品在线观看 | 久久免费视频在线观看| 波多野结衣不卡| 国产成人精品www牛牛影视| 欧美激情视频一区二区三区| 欧美激情午夜| 色综合久久久久久久久| 人妻体体内射精一区二区| 亚洲区小说区图片区qvod按摩| 久久精品久久久久久| 欧美精品一二三四区| 国产成人精品免费一区二区| 一区二区三区免费看| 天堂8中文在线最新版在线| 日韩一区二区三区在线视频| 韩国女同性做爰三级| 中日韩男男gay无套| 亚洲一区二区三| 午夜在线播放| 性做久久久久久免费观看| 污污视频在线免费| 精品日韩一区| 欧美诱惑福利视频| 欧美一级做性受免费大片免费| 1区2区3区国产精品| 欧美大尺度做爰床戏| 亚欧洲精品视频在线观看| 欧美大片第1页| 国产人妖一区二区| 中文字幕中文乱码欧美一区二区| 国产l精品国产亚洲区久久| 国产精品99久久免费观看| 欧美另类暴力丝袜| 国产女人18毛片水18精| 国产精品欧美久久久久无广告| av免费播放网址| 免费福利视频一区| 午夜精品久久久久久久99黑人| 精品人妻少妇嫩草av无码专区| 国产精品久久久久久亚洲伦| 丁香婷婷激情网| 精品久久久亚洲| 国产a∨精品一区二区三区不卡| 肉丝一区二区| 色综合色综合色综合| 在线免费观看黄色小视频| 国产欧美日本| 女女同性女同一区二区三区91| 天堂网在线最新版www中文网| 亚洲国产天堂久久综合| 91浏览器在线观看| 91蜜桃传媒精品久久久一区二区| 欧美日韩二三区| 日韩欧美天堂| 国产精品成人免费电影| 中文字幕日本在线观看| 欧美日韩国产首页| 午夜剧场免费在线观看| 国产毛片精品视频| 国产自产在线视频| 亚洲区小说区图片区qvod| 国产精品精品久久久| 一级毛片视频在线观看| 欧美一区二区人人喊爽| 欧美丰满熟妇bbbbbb| 丰满少妇久久久久久久| 东北少妇不带套对白| 丝袜美腿综合| 国产在线视频不卡| 青春草视频在线| 亚洲精品一区二区网址| 中文字幕免费在线看| 亚洲欧美国产毛片在线| 99久久免费看精品国产一区| 日韩影院免费视频| 在线观看视频黄色| 欧美国产不卡| 国产日韩欧美黄色| 国产精品186在线观看在线播放| 亚洲激情视频在线| 在线观看国产成人| 亚洲一级电影视频| 69视频在线观看免费| 国产麻豆精品视频| 男人操女人免费软件| 91影院成人| 精品久久蜜桃| 亚洲a成人v| 欧美一区第一页| 免费av在线播放| 亚洲激情 国产| 国产又粗又黄又爽视频| 岛国精品视频在线播放| 一本一本久久a久久| av一区二区三区| 午夜视频在线观| 午夜在线a亚洲v天堂网2018| 黑人巨大国产9丨视频| 欧洲在线一区| y111111国产精品久久婷婷| 桃花岛成人影院| 久久久亚洲精品视频| 欧美激情免费| 亚洲最新av在线| 亚州精品国产精品乱码不99按摩| 欧美精品v国产精品v日韩精品| 久久亚洲天堂网| 亚洲亚洲人成综合网络| 婷婷社区五月天| 国产日韩欧美综合一区| 中文视频在线观看| 国产一区视频导航| 国产3p在线播放| 奇米色一区二区三区四区| 亚洲 高清 成人 动漫| 欧美成人69| 在线观看日韩片| 欧美性感美女一区二区| 久久亚洲精品欧美| 99a精品视频在线观看| 91丨九色丨国产在线| а√天堂资源国产精品| 日韩av快播网址| 美女91在线看| 久久久亚洲精选| www中文字幕在线观看| 欧美精品午夜视频| а√天堂在线官网| 日韩中文字幕视频在线观看| 全色精品综合影院| 日韩av在线看| 午夜视频在线播放| 日韩精品极品视频免费观看| 欧美在线 | 亚洲| 精品国产三级a在线观看| av中文在线观看| 69堂成人精品免费视频| 一本大道伊人av久久综合| 欧美亚洲日本一区| 国产乡下妇女三片| 欧美专区在线观看一区| 波多野结衣日韩| 在线观看日韩电影| 中国一级片黄色一级片黄| 欧美性xxxxxxxx| 中文字幕乱码在线观看| 欧美日韩一区二区电影| 在线免费观看高清视频| 欧美精品亚洲一区二区在线播放| 亚洲视频在线观看免费视频| 欧美日韩国产123区| 91精品国产色综合久久不8| 欧美日韩国产在线观看| 国产露脸无套对白在线播放| 91精品国产综合久久国产大片| 国产sm主人调教女m视频| 精品久久久久av影院| 网站黄在线观看| 亚洲天堂色网站| 麻豆影院在线| 欧美精品激情在线观看| 亚洲校园激情春色| 国产精品高潮呻吟视频| 国产一区二区三区免费观看在线| 96久久精品| 日韩一级电影| 午夜老司机精品| 亚洲最大黄网| 成年人午夜视频在线观看| 视频一区视频二区在线观看| 在线能看的av网站| 粉嫩av亚洲一区二区图片| 添女人荫蒂视频| 国产精品欧美综合在线| 久久97人妻无码一区二区三区| 粉嫩av一区二区三区免费野| 波多野结衣激情视频| 欧美一二三四在线| 亚洲欧洲视频在线观看| 色系列之999| 女子免费在线观看视频www| 热99精品里视频精品| 国精品产品一区| 国产美女在线精品免费观看| 欧美日韩一区二区综合 | 99精品福利视频| 一区二区三区视频在线观看免费| 国产精品99久久久久久久vr| v8888av| 亚洲色图在线看| 亚洲免费在线观看av| 欧美精品日韩精品| 五月天丁香视频| 久久中文字幕一区| 午夜不卡影院| 97人人模人人爽人人少妇| 国产免费av一区二区三区| 久久综合亚洲精品| 日本成人在线一区| 中国xxxx性xxxx产国| 国产精品乱码人人做人人爱 | 国产日韩久久| 91精品国产91久久综合| 久久婷婷国产精品| 高清不卡一二三区| ass极品国模人体欣赏| 精品日本高清在线播放 | 日本中文字幕一区二区| 国产欧美一区二区视频 | 国产精品乱人伦| 天堂中文在线网| 精品久久99ma| 日本h片在线观看| 成人精品视频99在线观看免费| 久久超碰99| 国产亚洲天堂网| www.66久久| 久久亚洲AV无码| 欧美一区二区三区精品| 日本视频不卡| 国产精品你懂得| 精品久久91| 日本成人在线免费视频| 99国产欧美另类久久久精品| 精品在线免费观看视频| 欧美一卡2卡3卡4卡| 蜜芽在线免费观看| 国产精品羞羞答答| 成人在线免费视频观看| 久久午夜夜伦鲁鲁一区二区| 久久精品网站免费观看| 99精品在线播放| 日韩成人在线视频观看| 55av亚洲| 精品无人区一区二区三区| 亚洲国产精品一区制服丝袜| 日本wwwwwww| 亚洲一级二级在线| 免费观看的毛片| 午夜精品视频在线| 国产精品自在| 人妻熟女一二三区夜夜爱| 2020国产精品久久精品美国| 中日韩精品视频在线观看| 亚洲第一免费网站| 国产99在线观看| 久久综合九色欧美狠狠| 久久久久久亚洲精品杨幂换脸| 少妇大叫太粗太大爽一区二区| 色综合天天天天做夜夜夜夜做| 福利小视频在线观看| 国产精品久久久久久久一区探花 | 中文字幕二区三区| 日韩中文字幕视频| 深夜激情久久| 黄色片免费在线观看视频| 成人午夜激情影院| 天天操天天操天天操天天| 欲色天天网综合久久| 999久久久国产999久久久| 免费的一级黄色片| 成人av网站免费观看| 欧美一级淫片免费视频黄| 最新国产精品亚洲| 97久久综合精品久久久综合| 尤物av无码色av无码| 国产欧美精品国产国产专区 | 久久久国产精华液999999| 国内精品第一页| 日本亚洲欧美在线| 国产一区二区av| 精品99re| 国产精品97在线| 亚洲色图一区二区三区| 日韩性xxxx| 国产日韩在线播放| 亚洲国产精品一区| 亚洲精品电影院| 亚洲国产精品一区二区三区| 香蕉成人影院| 国产日韩亚洲欧美在线| 国产视频一区二区在线| 国产黄色一级大片| 日韩美女在线观看| 欧美freesex交免费视频| 大地资源二中文在线影视观看| 欧美日韩精品高清| 精精国产xxxx视频在线播放| 亚洲一区二区三区欧美| 成人avav影音| 国产又大又粗又长| 国产91精品久久久久| 自拍日韩欧美| 亚洲一级黄色录像| 亚洲精品电影网在线观看| 国产高清精品二区|