国产精品一区二区在线看_国产高清免费的视频_国产精品bbw一区二区三区_四虎影视免费看电影

首頁 > 民航

當前快看:B+ tree implemented in Java

來源:博客園 時間:2023-06-25 15:26:37


(資料圖片)

B+樹相關介紹

B+樹是一棵多叉排序樹,即每個非葉子節點可以包含多個子節點,其整體結構呈扁平化,所以其非常適配于數據庫和操作系統的文件系統中。且B+樹能夠保持數據的穩定有序,插入和刪除都擁有較穩定的對數時間復雜度

B+樹的特性:以 m 階為例,m 表示內部節點即非葉子節點可以包含的最大子節點個數 maximumNum

  • 若一個內部節點有 \(n(n <= m)\) 個子節點,則該內部節點應包含 \(n - 1\) 個關鍵字,也就是索引值
  • 除根節點和葉子節點外,其他節點至少包含 Math.ceil(m / 2)個子節點,這是因為B+樹的生成順序導致的
    • 最開始,B+樹只有一個根節點和若干不超過m個的葉子節點;
    • 逐漸添加,導致葉子節點超過m時,此時根節點的子節點個數大于m,不符合要求,需要分裂
    • 分裂則導致增加2個內部節點,其中一個內部節點個數為(m+1)/2,另一個為(m+2)/2
    • 其他內部節點也是如此規律形成,所以所有內部節點的子節點個數均大于Math.ceil(m / 2)
  • 內部節點即對應索引部分,節點中僅包含子樹中最大/最小的索引值
  • 葉子節點即對應數據部分,節點中不僅包含索引值,也包含其他的值信息
  • 最底層所有葉子節點通過雙向鏈表串聯,優化范圍查詢

B+樹實現

目前實現的B+樹的簡易版,葉子節點是存儲的Entry鍵值對,內部節點存儲的是Integer索引,后續有時間再進行泛型的通用擴展。

節點定義

抽象公共父類 Node

package bplustree;public abstract class Node {    InternalNode parent;    // 父節點    public Node() {}        public abstract boolean isValid();          // 判斷刪除節點后各B+樹節點是否滿足要求    public abstract boolean isAvailable();      // 判斷B+樹節點是否可以分裂節點給其他節點    public abstract boolean isMergeable();      // 判斷B+樹節點是否可以和其他節點合并}

內部節點定義

public class InternalNode extends Node{    int maxChildNodes;                   // 子節點個數最大值 m,m為階數    int minChildNodes;                   // 除根節點及葉子節點外,子節點個數最小值 ceil(m / 2)        int curNodesNum;                     // 內部節點當前的子節點個數    InternalNode leftSibling;            // 左兄弟節點    InternalNode rightSibling;           // 右兄弟節點    Integer[] keys;                      // 內部節點當前的索引值,最多有 m - 1 個    Node[] childPointers;                // 內部節點當前的子節點,最多有 m 個}

葉子節點定義

public class LeafNode extends Node {    int maximumNum;                      // 葉子節點最多元素個數 m - 1    int minimumNum;                          int curNum;                          // 葉子節點當前的元素個數    LeafNode leftSibling;                // 左兄弟和右兄弟形成雙向鏈表             LeafNode rightSibling;    Entry[] entries;                     // 葉子節點鍵值對,不僅存儲索引值,也存儲其他值信息}class Entry implements Comparable {    Integer key;    String value;    public Entry(Integer key, String value) {        this.key = key;        this.value = value;    }    @Override    public int compareTo(Entry o) {        return key.compareTo(o.key);    }}

B+樹定義

public class BPlusTree {    int m;    InternalNode root;         // B+樹根節點    LeafNode head;             // 葉子節點的首元素}

查詢操作

單值查詢

B+樹的查找過程:根據查找的索引值k,從根節點向葉子節點搜索,對數時間復雜度

public String search(int key) {    if (isEmpty()) {        return null;    }    // 樹查找    LeafNode leafNode = (this.root == null) ? this.head : findLeafNode(key);    Entry[] entries = leafNode.entries;        // 葉子節點內進行二分查找    int index = binarySearch(entries, leafNode.curNum, key, null);    if (index == -1) {        return null;    }    else {        return entries[index]    }}// 從根節點開始查找private LeafNode findLeafNode(Integer key) {    return findLeafNode(root, key);}// 找到索引值所在的葉子節點private LeafNode findLeafNode(InternalNode internalNode, Integer key) {    Integer[] keys = internalNode.keys;    int i;    for (i = 0; i < internalNode.curNodesNum - 1; i++) {        if (key.compareTo(keys[i]) < 0) {            break;        }    }    Object child = internalNode.childPointers[i];    if (child instanceof LeafNode) {        return (LeafNode) child;    }    else {        return findLeafNode((InternalNode) child, key);    }}
區間查詢

B+樹區間查詢左值可能在的葉子節點位置,然后通過雙向鏈表向后遍歷。

// 閉區間 [left, right]public ArrayList searchRange(int left, int right) {    List values = new ArrayList<>();    LeafNode leafNode = findLeafNode(left);    // 查找左值可能存在的位置,并從該位置向后遍歷    boolean flag = true;    while (leafNode != null && flag) {        Entry[] entries = leafNode.entries;        for (Entry entry : entries) {            if (entry == null) {                break;            }                        if ( entry.key > right) {                flag = false;                break;            }            if (left <= entry.key && right >= entry.key) {                values.add(entry.value);            }        }        leafNode = leafNode.rightSibling;    }    return values;}

插入操作

B+樹的插入操作僅在葉子節點進行:

  1. 若為空樹,則創建一個葉子節點,該葉子節點同時也是根節點,插入操作結束;
  2. 根據插入的 key 值,找到應該在的葉子節點插入;
    1. 若插入后葉子節點個數符合要求即小于m,則插入結束
    2. 若插入后葉子節點個數不符合要求即大于等于m,將該節點分裂成兩半,則判斷當前葉子節點是否為根節點
      1. 若當前葉子節點為根節點,則構建一個新的root節點,指向分裂后的兩個子節點
      2. 若當前葉子節點不為根節點,則在父節點處添加一個新的子節點,新子節點則存儲原節點一半的值,并循環向上判斷中間節點是否滿足要求
public void insert(int key, String value) {    if (isEmpty()) {        this.head = new LeafNode(this.m, new Entry(key, value));    }    else {        LeafNode leafNode = (this.root == null) ? this.head : findLeafNode(key);        // 插入葉子節點失敗,即葉子節點中存儲已到達上限        if (!leafNode.insert(new Entry(key, value))) {            leafNode.entries[leafNode.curNum++] = new Entry(key, value);            sortEntries(leafNode.entries);            // 葉子節點分裂的位置            int mid = getIndexOfMidPointer();            Entry[] halfEntry = splitEntries(leafNode, mid);            // 若葉子節點為根節點,即parent為null            if (leafNode.parent == null) {                Integer[] parent_keys = new Integer[m];                    parent_keys[0] = halfEntry[0].key;                // 創建新的 root                InternalNode parent = new InternalNode(m, parent_keys);                leafNode.parent = parent;                parent.appendChildPointer(leafNode);            }            // 若葉子節點不為根節點            else {                int newParentKey = halfEntry[0].key;                leafNode.parent.keys[leafNode.parent.curNodesNum - 1] = newParentKey;                Arrays.sort(leafNode.parent.keys, 0, leafNode.parent.curNodesNum);            }            // 分裂后的另一半葉子節點,添加到父節點            LeafNode newLeafNode = new LeafNode(this.m, halfEntry, leafNode.parent);            // 分裂后的另一半葉子節點對應的下標            int index = leafNode.parent.getIndexOfPointer(leafNode) + 1;            for (int i = index; i < leafNode.parent.childPointers.length - 1; i++) {                leafNode.parent.childPointers[i + 1] = leafNode.parent.childPointers[i];            }            leafNode.parent.childPointers[index] = newLeafNode;            // 關聯兄弟節點            newLeafNode.rightSibling = leafNode.rightSibling;            if (newLeafNode.rightSibling != null) {                newLeafNode.rightSibling.leftSibling = newLeafNode;            }            leafNode.rightSibling = newLeafNode;            newLeafNode.leftSibling = leafNode;            if (this.root == null) {                this.root = leafNode.parent;            }            else {                // 逐漸上浮,判斷插入是否會導致B+樹內部節點不符合要求                InternalNode internalNode = leafNode.parent;                while (internalNode != null) {                    if (internalNode.isOverfull()) {                        splitInternalNode(internalNode);                    }                    else {                        break;                    }                    internalNode = internalNode.parent;                }            }        }    }}/** * 葉子節點插入,導致的上層內部節點分裂 */private void splitInternalNode(InternalNode internalNode) {    InternalNode parent = internalNode.parent;    int mid = getIndexOfMidPointer();    Integer newParentKey = internalNode.keys[mid];    // 內部節點的 node 分裂    Node[] halfPointers = splitChildPointers(internalNode, mid);    // 內部節點的 key 分裂    Integer[] halfKeys = splitKeys(internalNode.keys, mid);    // 分裂后內部節點的子節點個數    internalNode.curNodesNum = linearNullSearch(internalNode.childPointers);    InternalNode sibling = new InternalNode(this.m, halfKeys, halfPointers);    for (Node pointer : halfPointers) {        if (pointer != null) {            pointer.parent = sibling;        }    }    sibling.rightSibling = internalNode.rightSibling;    internalNode.rightSibling = sibling;    sibling.leftSibling = internalNode;    if (sibling.rightSibling != null) {        sibling.rightSibling.leftSibling = sibling;    }    // root node    if (parent == null) {        Integer[] keys = new Integer[this.m];        keys[0] = newParentKey;        InternalNode newRoot = new InternalNode(this.m, keys);        newRoot.appendChildPointer(internalNode);        newRoot.appendChildPointer(sibling);        this.root = newRoot;        internalNode.parent = newRoot;        sibling.parent = newRoot;    }    else {        parent.keys[parent.curNodesNum - 1] = newParentKey;        Arrays.sort(parent.keys, 0, parent.curNodesNum);        int index = parent.getIndexOfPointer(internalNode) + 1;        parent.insertChildPointer(sibling, index);        sibling.parent = parent;    }}private Node[] splitChildPointers(InternalNode node, int split) {    Node[] pointers = node.childPointers;    Node[] newPointers = new Node[this.m + 1];    for (int i = split + 1; i < pointers.length; i++) {        newPointers[i - split - 1] = pointers[i];        node.removePointer(i);    }    return newPointers;}private Integer[] splitKeys(Integer[] keys, int split) {    Integer[] newKeys = new Integer[m];    keys[split] = null;    for (int i = split + 1; i < keys.length; i++) {        newKeys[i - split] = keys[i];        keys[i] = null;    }    return newKeys;}

刪除操作

B+樹的刪除操作僅在葉子節點進行:

  1. 若刪除后,葉子節點中的索引個數仍然滿足要求即大于等于Math.ceil(m / 2)時,將該葉子節點的其他索引左移一位,刪除結束;
  2. 若刪除后,葉子節點中的索引個數不滿足最低要求,則查詢左右兄弟節點:
    1. 若左/右兄弟節點中索引個數大于Math.ceil(m / 2),則從左/右兄弟節點中移動一個索引項到當前葉子節點中,并修改父節點的索引值,刪除結束
    2. 若左/右兄弟節點中索引個數等于Math.ceil(m / 2),則將左/右節點與當前節點合并,修改父節點的索引記錄,并向上逐級判斷內部節點是否因為頁合并導致索引項不滿足最低要求,刪除結束
public void delete(int key) {    if (isEmpty()) {        System.out.println("Invalid: The B+ tree is empty!");    }    else {        LeafNode leafNode = this.root == null ? this.head : findLeafNode(key);        int index = binarySearch(leafNode.entries, leafNode.curNum, key, null);        if (index < 0) {            System.out.println("Invalid: The key does not exist in the B+ tree!");        }        else {            leafNode.deleteAtIndex(index);            // 刪除后,葉子節點仍然滿足要求,刪除結束            if (leafNode.isValid()) {                LeafNode sibling;                InternalNode parent = leafNode.parent;                // 刪除后,葉子節點不滿足要求,左兄弟節點可以移動一個索引項到當前葉子節點                if (leafNode.leftSibling != null && leafNode.leftSibling.parent == parent && leafNode.leftSibling.isAvailable()) {                    sibling = leafNode.leftSibling;                    Entry entry = sibling.entries[sibling.curNum - 1];                    leafNode.insert(entry);                    sortEntries(leafNode.entries);                    sibling.deleteAtIndex(sibling.curNum - 1);                    // 更新 parent 的 key                    int pointIndex = getIndexOfLeafNode(parent.childPointers, leafNode);                    if (entry.key < parent.keys[pointIndex - 1]) {                        parent.keys[pointIndex - 1] = entry.key;                    }                }                // 刪除后,葉子節點不滿足要求,右兄弟節點可以移動一個索引項到當前葉子節點                else if (leafNode.rightSibling != null && leafNode.rightSibling.parent == parent && leafNode.rightSibling.isAvailable()) {                    sibling = leafNode.rightSibling;                    Entry entry = sibling.entries[0];                    leafNode.insert(entry);                    sortEntries(leafNode.entries);                    sibling.deleteAtIndex(0);                    // 更新 parent 的 key                    int pointIndex = getIndexOfLeafNode(parent.childPointers, leafNode);                    if (entry.key > parent.keys[pointIndex]) {                        parent.keys[pointIndex] = entry.key;                    }                }                // 刪除后,葉子節點不滿足要求,左兄弟節點可以與當前葉子節點合并                else if (leafNode.leftSibling != null && leafNode.leftSibling.parent == parent && leafNode.leftSibling.isMergeable()) {                    sibling = leafNode.leftSibling;                    int pointIndex = getIndexOfLeafNode(parent.childPointers, leafNode);                    parent.removeKey(pointIndex - 1);                    parent.removePointer(leafNode);                    sibling.rightSibling = leafNode.rightSibling;                    if (parent.isValid()) {                        handleDeficiency(parent);                    }                }                // 刪除后,葉子節點不滿足要求,右兄弟節點可以與當前葉子節點合并                else if (leafNode.rightSibling != null && leafNode.rightSibling.parent == parent && leafNode.rightSibling.isMergeable()) {                    sibling = leafNode.rightSibling;                    int pointIndex = getIndexOfLeafNode(parent.childPointers, leafNode);                    parent.removeKey(pointIndex);                    parent.removePointer(leafNode);                    sibling.leftSibling = leafNode.leftSibling;                    if (sibling.leftSibling == null) {                        this.head = sibling;                    }                    // 逐級向上層判斷是否滿足要求                    if (parent.isValid()) {                        handleDeficiency(parent);                    }                }                // 刪除后,B+樹為空                else if (this.root == null && this.head.curNum == 0) {                    this.head = null;                }            }        }    }}/** * 處理不滿足要求的內部節點 * @param internalNode */private void handleInvalidInternalNode(InternalNode internalNode) {    InternalNode sibling;    InternalNode parent = internalNode.parent;    // 當前內部節點為根節點    if (root == internalNode) {        for (int i = 0; i < internalNode.childPointers.length; i++) {            if (internalNode.childPointers[i] != null) {                if (internalNode.childPointers[i] instanceof InternalNode) {                    root = (InternalNode) internalNode.childPointers[i];                    root.parent = null;                }                else if (internalNode.childPointers[i] instanceof LeafNode) {                    root = null;                }            }        }    }    // 左兄弟節點可以移動索引項    else if (internalNode.leftSibling != null && internalNode.leftSibling.isAvailable()) {        sibling = internalNode.leftSibling;        Integer key = sibling.keys[internalNode.curNodesNum - 2];        Node pointer = sibling.childPointers[internalNode.curNodesNum - 1];        shiftKeys(internalNode.keys, 1);        shiftPointers(internalNode.childPointers, 1);        internalNode.keys[0] = key;        internalNode.childPointers[0] = pointer;        sibling.removePointer(pointer);    }    // 右兄弟節點可以移動索引項    else if (internalNode.rightSibling != null && internalNode.rightSibling.isAvailable()) {        sibling = internalNode.rightSibling;        Integer key = sibling.keys[0];        Node pointer = sibling.childPointers[0];        internalNode.keys[internalNode.curNodesNum - 1] = parent.keys[0];        internalNode.childPointers[internalNode.curNodesNum] = pointer;        parent.keys[0] = key;        sibling.removePointer(0);        shiftPointers(sibling.childPointers, -1);    }    // 左兄弟節點可以合并    else if (internalNode.leftSibling != null && internalNode.leftSibling.isMergeable()) {        sibling = internalNode.leftSibling;        int index = -1;        for (int i = 0; i < parent.childPointers.length; i++) {            if (parent.childPointers[i] == internalNode) {                index = i;                break;            }        }        parent.keys[index - 1] = parent.keys[index];        for (int i = index; i < parent.keys.length - 1; i++) {            parent.keys[i] = parent.keys[i + 1];        }        shiftPointers(internalNode.childPointers, (int) Math.ceil(m / 2.0));        for (int i = 0; i < (int) Math.ceil(m / 2.0); i++) {            internalNode.childPointers[i] = sibling.childPointers[i];        }        internalNode.leftSibling = sibling.leftSibling;        if (internalNode.leftSibling != null) {            internalNode.leftSibling.rightSibling = internalNode;        }        if (parent != null && parent.isValid()) {            handleInvalidInternalNode(parent);        }    }    // 右兄弟節點可以合并    else if (internalNode.rightSibling != null && internalNode.rightSibling.isMergeable()) {        sibling = internalNode.rightSibling;        int index = -1;        for (int i = 0; i < parent.childPointers.length; i++) {            if (internalNode == parent.childPointers[i]) {                index = i;                break;            }        }        parent.keys[index] = parent.keys[index + 1];        for (int i = index + 2; i < parent.keys.length; i++) {            parent.keys[i - 1] = parent.keys[i];        }        for (int i = 0; i < (int) Math.ceil(m / 2.0); i++) {            internalNode.childPointers[internalNode.curNodesNum++] = sibling.childPointers[i];        }        internalNode.rightSibling = sibling.rightSibling;        if (internalNode.rightSibling != null) {            internalNode.rightSibling.leftSibling = internalNode;        }        if (parent != null && parent.isValid()) {            handleInvalidInternalNode(parent);        }    }}

參考文章:

1. B+樹

相關稿件

當前快看:B+ tree implemented in Java

廣東公布2023高考分數線

英特爾研究院發布全新AI擴散模型,可根據文本提示生成360度全景圖

今日看點:工具-internet選項在哪里(internet選項在哪里)

我的世界怎么透視(我的世界透視mod) 焦點速看

傷物語百度云全集(傷物語百度云) 焦點熱訊

環球短訊!2023中國城市開發投資吸引力排行榜:北上深廣仍位居前四

無錫首座千噸級船閘——江陰船閘江河咽喉 13個省(市)船舶常年過閘

快訊:沈鐵迎來16年來最大幅度調圖 釋放客貨運列車運力

廣東公布高考分數線:本科歷史433分,物理439分

每日看點!“斑馬線”政策急喊卡!沈富雄轟臺交通部門超丟臉

今日熱訊:山東省檢察機關重拳出擊依法嚴懲毒品犯罪

環球觀天下!前5月全國主要發電企業電源工程完成投資2389億元

商品豬每頭虧近300、仔豬限價令價格倒掛,豬企去產能迎陣痛期|馬上評

榮耀X50外觀公布!7月5日發布 全新配色加持顯大氣 焦點熱門

北京高考分數線公布 普通本科錄取控制分數線448分 每日消息

一代沙雕包個粽子過關攻略分享_資訊推薦

天天最資訊丨腌蘿卜干的做法最好吃?

csgo武器箱鑰匙在哪買便宜 主播推薦的CS鑰匙平臺盤點

吃燒烤腌肉的最簡單方法是什么|精彩看點

世界速訊:傳《毒液》將是三部曲 《毒液3》將在本周開拍

太原劉家堡村:邂逅非遺鄉韻 留住詩意鄉愁

蘇州牛皮癬研究院

黑龍江銀屑病到哪里治療-尋常形銀霄病好轉跡象

【上海成交日報】06月24日新房成交388套;漲價房源204套-世界新動態

天天視訊!淮安有道“水上長城”

【蘇州成交日報】06月24日新房成交30套;漲價房源378套|環球熱文

鶴壁示范區教體系統開展端午主題系列活動

【快播報】《送閨蜜特制GoGo舞者服裝,學生黨也能輕松制作!》

新能源汽車裝備制造產業基地落戶棗陽 總投資102億元-世界速訊


国产精品一区二区在线看_国产高清免费的视频_国产精品bbw一区二区三区_四虎影视免费看电影

      1. <ul id="dtpp1"></ul>
      2. 亚洲国产欧美日本视频| 大香伊人久久精品一区二区 | 日本成人中文字幕在线视频| 日韩一区二区三免费高清在线观看 | 久久精品国产999大香线蕉| 日韩大片在线| 亚洲人成精品久久久| 波多野结衣久久精品| 蜜臀久久99精品久久久久久9| 蜜桃精品视频| 欧美日韩国产综合网| 九九九精品视频| 免费日韩精品中文字幕视频在线| 精品三级国产| 日韩免费精品| 欧美日韩国产一区二区三区不卡| 国产精品片aa在线观看| 黄色成人精品网站| 日韩成人精品一区| 日韩av中文字幕一区二区| 亚洲午夜av| 中文字幕在线看片| 久久99精品久久久野外观看| 男人的天堂亚洲一区| 久久美女精品| 国产999精品在线观看| 在线观看亚洲精品福利片| 日韩影院二区| 美女视频黄 久久| 日本亚洲三级在线| 日韩午夜黄色| 免费久久精品| 日韩精品免费一区二区三区| 国产精品入口久久| 91精品麻豆| 综合欧美亚洲| 视频一区在线视频| 婷婷亚洲综合| 特黄特色欧美大片| av资源中文在线| 久久中文精品| 国产精品极品国产中出| 老司机精品久久| 国产综合视频| 国内亚洲精品| 久久精品国产99久久| 不卡一二三区| 黄色在线观看www| 日韩av在线中文字幕| 精品国产精品国产偷麻豆| 你懂的国产精品| 大香伊人久久精品一区二区| 成人台湾亚洲精品一区二区| 美女精品久久| 成人日韩精品| 免费精品国产的网站免费观看| 麻豆mv在线观看| 鲁鲁在线中文| 99久久精品网站| 99视频精品| 亚洲欧美日韩在线观看a三区| 欧美日韩国产一区二区三区不卡 | 欧美日韩一区二区国产 | 成人片免费看| 99精品网站| 亚洲午夜在线| 丝袜美腿一区二区三区| 日韩精品一页| 六月丁香综合在线视频| 成人在线黄色| 日韩午夜黄色| 人人精品久久| 久久精品国产久精国产爱| www在线观看黄色| 亚洲国内欧美| 美美哒免费高清在线观看视频一区二区| 免费久久99精品国产自在现线| 亚洲精品大全| 精品国产亚洲一区二区三区| 日韩欧美看国产| 午夜精品亚洲| 国产日韩在线观看视频| 国产黄大片在线观看| 欧美在线资源| 国产精品地址| 欧美日韩国产在线观看网站| 日韩一区免费| а√天堂8资源中文在线| 亚洲国产不卡| 国产精选久久| 蜜桃tv一区二区三区| 人人精品久久| 久久久久网站| 国产一卡不卡| 欧美日韩在线播放视频| 日韩欧美中文字幕一区二区三区| 欧美国产极品| 亚洲精品网址| 国产一区日韩| 免费观看在线综合色| 成人国产精品一区二区免费麻豆| 欧美特黄一区| 成人在线免费观看91| 伊人www22综合色| 亚洲永久av| 欧美亚洲综合视频| 欧美91视频| 国产精品国产三级在线观看| 在线综合欧美| 超级白嫩亚洲国产第一| 日韩高清中文字幕一区| 欧美成人基地 | 欧美日韩免费观看视频| 日本中文字幕不卡| 香蕉人人精品| 日本久久精品| 美女精品网站| 久久久国产精品一区二区中文| 日韩欧美高清一区二区三区| 婷婷成人综合| 国产精品黑丝在线播放| 奇米777国产一区国产二区| 欧美日韩国产一区二区三区不卡 | 欧美一区二区三区免费看| 欧美高清一区| 樱桃视频成人在线观看| 另类综合日韩欧美亚洲| 亚洲午夜国产成人| 欧美日韩一二| 日韩一区二区三区免费| 国产一区二区三区网| 国产精品一页| 日本不卡一区二区| 亚洲免费影院| 亚洲女同一区| 999精品一区| 欧美天堂视频| 日韩电影免费网址| 国产精品玖玖玖在线资源| 日韩精品亚洲专区在线观看| 91精品电影| 欧美特黄视频| 免费视频国产一区| 亚洲福利国产| 亚洲国内欧美| 欧美粗暴jizz性欧美20| 视频一区中文| 亚洲男女av一区二区| 激情自拍一区| 亚洲精品99| 午夜亚洲精品| 亚洲综合婷婷| 日韩欧美2区| 国产日产一区| 另类小说一区二区三区| 国产高清精品二区| 久久精品伊人| 国产不卡精品| 99久久精品国产亚洲精品| 青青久久av| 免费不卡中文字幕在线| 欧美在线影院| 日韩精品一二三| 日本精品国产| 国产精品亚洲片在线播放| 国产极品一区| 青青青免费在线视频| 久久激情一区| 亚洲免费中文| 日韩av二区在线播放| 免费一级欧美片在线观看网站| 精品网站999| 精品国产免费人成网站| 日韩电影免费在线观看| 国内亚洲精品| 亚洲91网站| 91综合视频| 亚洲美洲欧洲综合国产一区 | 成人亚洲一区二区| 天堂资源在线亚洲| 美女尤物久久精品| 国产精品一区免费在线| 高潮一区二区| 国产视频一区在线观看一区免费| 综合亚洲视频| 国产一区二区三区久久久久久久久| 99精品美女| 日本91福利区| 三级小说欧洲区亚洲区| 日韩一区二区久久| 麻豆精品视频在线观看| 一区二区三区四区在线看| 亚洲免费专区| 午夜精品成人av| 视频一区视频二区在线观看| 另类欧美日韩国产在线| 99国产精品99久久久久久粉嫩| 国产免费av一区二区三区| 久久国产中文字幕| 奇米狠狠一区二区三区|