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

一文帶你速通 HashMap 底層核心數據結構紅黑樹

開發(fā) 后端
面試季,日常收到那些正在校招的讀者問到HashMap底層的紅黑樹這個數據結構,所以筆者就以此文詳細介紹一下紅黑樹的特性和實現。

一、什么是紅黑樹

在權威書籍中,對于紅黑樹的解釋是這樣的:

  • 每個節(jié)點或者紅色,或者是黑色。
  • 根節(jié)點為黑色。
  • 每一個葉子節(jié)點都是黑色。
  • 如果一個節(jié)點是紅色,那么他的孩子節(jié)點都是黑色。
  • 從任意一個節(jié)點,經過的黑色節(jié)點是一樣的。

在《算法4》一書中認為紅黑樹和2-3樹是等價的。

二、2-3樹詳解

2-3樹的2節(jié)點和3節(jié)點

很多人認為紅黑樹是2-3樹的另一種實現,所以在正式的介紹紅黑樹之前,我們不妨了解2-3樹,先來說說2-3樹的2節(jié)點,其性質如下:

  • 滿足二分搜索樹的基本性質。(左節(jié)點小于節(jié)點,右節(jié)點大于節(jié)點)
  • 節(jié)點分為2節(jié)點和3節(jié)點,2節(jié)點即可以掛兩個子節(jié)點。3節(jié)點即可掛3節(jié)點。

如下圖所示,這就是典型的2-3樹的2節(jié)點,可以看到2節(jié)點即父節(jié)點存放一個元素的節(jié)點,這種節(jié)點只能掛兩個元素。

同理我們再給出3節(jié)點的圖例,可以看出3節(jié)點的就是由兩個節(jié)點拼接成的節(jié)點,其左中右分別可以掛一個子節(jié)點,由此我們才稱它為3節(jié)點。

2-3樹是絕對平衡樹

絕對平衡樹的定義即任何時刻任意節(jié)點,左節(jié)點和右節(jié)點的層數都是一樣的。那么2-3樹是如何實現絕對平衡的呢?假設我們要將下面的節(jié)點存放到2-3樹中:

42 37 12 18 6 11 5

首先添加42,由于2-3樹為空,所以直接插入即可。

再插入37 ,因為37比42小,所以理應插入到42的左節(jié)點中,但是左節(jié)點為空,所以它只能作為42的鄰節(jié)點,由此構成一個3節(jié)點。

再插入12,此時構成了一個4節(jié)點,不符合2-3樹節(jié)點的特征。

所以我們需要將4節(jié)點進程拆解,將37的左右鄰接節(jié)點全部拆為子節(jié)點:

在添加18,比37小,比12大,所以要插入到12的右子節(jié)點,但是右子節(jié)點為空,所以18就和12合并變?yōu)?節(jié)點

再添加6構成一個4節(jié)點需要拆解,導致失衡:

所以我們對這個4節(jié)點進程拆解,可以看到37的左右節(jié)點還是失衡。

所以我們將12向上合并,和37構成3節(jié)點,最終2-3樹得以平衡。

三、紅黑樹詳解

紅黑樹和2-3樹的關系

前文我們提到紅黑樹可以理解為2-3樹的另一種變體,我們以2-3樹的2節(jié)點為例,對應成紅黑樹的標識就是將2節(jié)點的左邊染紅并作為右節(jié)點的子節(jié)點,注意,筆者這里雖說12作為37的子節(jié)點,但是在紅黑樹的性質中,這兩個節(jié)點邏輯上可以理解為一個節(jié)點,這樣的理解便于我們后續(xù)了解紅黑樹的黑平衡。

對應的,我們根據上面描述我們給出這樣一棵2-3樹,將其轉為紅黑樹:

可以看到,轉為紅黑樹只需將2-3樹的3節(jié)點的左節(jié)點染紅,例如上圖的6、12組成的3節(jié)點,我們只需將6染紅,作為黑節(jié)點12的左節(jié)點即可。

紅黑樹的性質詳解

了解了紅黑樹這個數據結構的圖例之后,我們來總結一下紅黑樹的特性:

從任意節(jié)點到另外一個葉子節(jié)點,經過的黑節(jié)點是一樣的。

嚴格意義上,紅黑樹是一個絕對的“黑平衡樹”,即我們將紅節(jié)點和其父節(jié)點當作一個整體,我們就會發(fā)現,這個紅黑樹的層級是絕對平衡的。而將"將紅節(jié)點和其父節(jié)(黑節(jié)點)點當作一個整體"的過程,就是2-3樹。

紅黑樹最大高度為2N(logN),所以添加復雜度估算為O(logN)

紅黑樹如何添加元素

(1) 添加一個比插入位置大的節(jié)點

以2-3數為例,假設我們樹中只有一個節(jié)點37,此時插入一個42,按照2-3樹的做法,會將42插入到37的右子節(jié)點,但此時2-3數還沒有右子節(jié)點,所以就將其添加到自己的右邊,構成3節(jié)點。

若是紅黑樹,42和37進行比對之后發(fā)現,42大于37,最終42就會以右子節(jié)點的姿態(tài)在37的右邊,很明顯這違背了紅黑樹的特征,所有的紅節(jié)點都必須位于左節(jié)點。所以我們需要對其進行左旋,并將右上節(jié)點染黑,左下節(jié)點染紅。

對于上述的左旋轉我們不妨來一個比較實際的例子,如下圖所示,假設經過一輪的插入之后37作為42的根節(jié)點,很明顯此時紅黑樹的狀態(tài)是失衡的(從黑平衡角度來看,37左邊有1層,42為2層,是失衡的)。

所以我們需要進行一次左旋轉,因為紅黑樹的性質保證黑節(jié)點37的右子樹都大于37,所以左旋時,先找到紅節(jié)點42的最小節(jié)點作為37的右子節(jié)點,于是37指向41:

因為41頂替了紅節(jié)點42,42直接上升為父節(jié)點,自此以此保證黑平衡的左旋就完成了:

完整的代碼如下:

/**
     * 插入的節(jié)點構成3節(jié)點,但是紅節(jié)點在左邊,需要進行左旋
     *
     * @param node
     * @return
     */
    private Node leftRotate(Node node) {
//        找到node節(jié)點的左節(jié)點
        Node x = node.right;
        //左旋
        node.right = x.left;
        x.left = node;
        //顏色翻轉
        x.color = node.color;
        node.color = RED;
        return x;
    }

(2) 連續(xù)添加兩個節(jié)點都在左邊

如下圖,構成了一個左傾斜的節(jié)點,導致失衡。

對此我們就需要進行一個右旋的操作,如下圖,因為紅黑樹的有序性,這使得42這個根節(jié)點大于左邊的所有節(jié)點,所以我們將左節(jié)點中最大的節(jié)點作為42的左節(jié)點,讓37作為根節(jié)點,完成黑平衡,如下圖。

可以看到雖然完成了右旋轉的操作,但是最終的左右節(jié)點都是紅的,導致紅黑樹并不是黑平衡的,所以這里就需要一次顏色翻轉。這里我們先貼出右旋轉的代碼,在介紹顏色翻轉邏輯:

private Node rightRotate(Node node) {
        Node x = node.left;

        node.left = x.right;
        x.right = node;

        node.color = RED;
        x.color = node.color;

        return x;
    }

(3) 添加節(jié)點后子節(jié)點都變紅

在上文右旋操作導致,顏色錯誤進而出現紅黑樹違背黑平衡的情況,所以我們需要進行顏色翻轉,如下圖,我們將子節(jié)點都為紅的節(jié)點染黑,再將父節(jié)點染紅(父節(jié)點會將筆者后續(xù)的遞歸邏輯中變黑)。

這樣依賴37左節(jié)點層級為1,右節(jié)點層級也為1(黑平衡要求我們將左紅節(jié)點和黑節(jié)點看作一個整體)

(4) 添加節(jié)點成為LR型

如下圖,LR型就是37 12 13這樣的插入順序,對此我們只需左旋再右旋最后顏色翻轉一下即可

四、手寫一個紅黑樹

針對上述的圖解,我們給出實現紅黑樹的幾個問題點:

  • 紅黑樹是由一個個節(jié)點構成,所以我們需要聲明節(jié)點內部類,內部類擁有顏色、左節(jié)點指針、右節(jié)點指針、key、value、顏色等幾個屬性。
  • 有了節(jié)點內部類,我們就需要對紅黑樹類添加相關屬性描述了,首先是紅黑樹的容量、其次紅黑樹的操作都需要從樹根開始,所以我們需要首節(jié)點root、以及容量size。
  • 紅黑樹插入都需要和每個key進行比較,所以紅黑樹類的k要求可以比較,所以我們定義的紅黑樹要求是泛型類,并且泛型key必須是可比較的,所以這個k泛型需要繼承Comparable。

完成這些鋪墊之后,我們就需要進行插入操作的邏輯分析了,我們不妨對上文長篇論述的插入過程進行整理一下:

  • 插入的節(jié)點在當前節(jié)點右邊,導致紅節(jié)點在右邊,需要進行左旋轉保證黑平衡。
  • 連續(xù)插入兩個節(jié)點都在當前節(jié)點左邊,導致向左傾斜,需要進行右旋轉保持平衡。
  • 第一次插入的節(jié)點在當前節(jié)點左邊,然后再插入一個節(jié)點在紅黑樹右邊導致紅黑樹失衡。我們需要先左旋一下,再右旋一下。
  • 當前節(jié)點的左節(jié)點和右節(jié)點都是紅色的,需要將顏色翻轉為黑色。

分析之后我們發(fā)現3這個一點包含了1、2的操作,所以我們編寫3、4兩個點的邏輯就可以實現上面的所有功能了,如下圖:

注意紅黑樹要求根節(jié)點為黑色,所以我們完成上述的操作之后,需要手動將根節(jié)點變?yōu)楹谏?/p>

對核心邏輯完成梳理之后,我們就可以開始對紅黑樹展開編碼了。首先我們需要創(chuàng)建紅黑樹類,可以看到我們聲明的k泛型繼承Comparable:

public class RedBlackTree<K extends Comparable<K>, V>

對于節(jié)點顏色只有紅黑兩種,所以我們將其常量化:

 private static final boolean RED = true;
 private static final boolean BLACK = false;

然后我們再根據上文的描述給出紅黑樹每個節(jié)點的成員變量:

private class Node<K, V> {
        private K key;
        private V val;
        private Node left, right;
        private boolean color;

        public Node(K key, V val) {
            this.key = key;
            this.val = val;
            this.left = null;
            this.right = null;
            this.color = RED;
        }
    }

然后在進行紅黑樹容量、首節(jié)點、構造方法聲明:

private Node root;
private int size;

public RedBlackTree() {
        this.root = null;
        this.size = 0;
    }

終于我們可以正式實現節(jié)點添加邏輯,首選是左旋的邏輯,這一點我們在上文圖解添加過程時已經寫好了偽代碼,補充完成即可。

/**
     * 插入的節(jié)點構成3節(jié)點,但是紅節(jié)點在左邊,需要進行左旋
     *
     * @param node
     * @return
     */
    private Node leftRotate(Node node) {
//        找到node節(jié)點的左節(jié)點
        Node x = node.right;
        //左旋
        node.right = x.left;
        x.left = node;
        //顏色翻轉
        x.color = node.color;
        node.color = RED;
        return x;
    }

右旋邏輯:

private Node rightRotate(Node node) {
        Node x = node.left;

        node.left = x.right;
        x.right = node;

        node.color = RED;
        x.color = node.color;

        return x;
    }

顏色翻轉:

 private void flipColors(Node node) {
        node.color = RED;
        node.left.color = BLACK;
        node.right.color = BLACK;
    }

完成后我們就可以根據上文分析的添加邏輯,編寫3、4邏輯整合,首先為了代碼復用,我們編寫一下顏色判斷的邏輯,注意若節(jié)點不存在,我們也認定這個節(jié)點為黑:

private boolean isRed(Node<K, V> node) {
        if (node == null) {
            return false;
        }
        return node.color == RED;
    }

然后完成添加邏輯,可以看到筆者通過遞歸將3、4邏輯完成的紅黑樹的添加操作,完成添加操作并旋轉平衡后的當前節(jié)點。

private Node<K, V> add(Node<K, V> node, K key, V val) {

        if (node == null) {
            size++;
            return new Node(key, val);

        }

        if (key.compareTo(node.key) < 0) {
            node.left = add(node.left, key, val);
        } else if (key.compareTo(node.key) > 0) {
            node.right = add(node.right, key, val);
        } else {
            node.val = val;
        }

//        左節(jié)點不為紅,右節(jié)點為紅,左旋
        if (isRed(node.right) && !isRed(node.left)) {
            node = leftRotate(node);
        }

//        左鏈右旋
        if (isRed(node.left) && isRed(node.left.left)) {
            node = rightRotate(node);
        }

//        顏色翻轉
        if (isRed(node.left) && isRed(node.right)) {
            flipColors(node);
        }

        return node;
    }

完成核心邏輯后,我們就將根節(jié)點變黑即可,考慮封裝性,我們將上文方法封裝成一個add允許外部傳鍵值進來。

public void add(K key, V val) {
        root = add(root, key, val);
        root.color = BLACK;
    }

補充剩余邏輯

獲取容量和獲取根節(jié)點:

 public int getSize() {
        return size;
    }

    private Node getRoot() {
        return root;
    }

用層次遍歷法測試結果

我們希望測試紅黑樹添加的準確性,所以我們用嘗試用代碼添加以下幾個節(jié)點

150 172 194 271 293 370

完成后的樹應該如下圖所示

為了驗證筆者代碼的準確性,我們編寫一段層次遍歷的測試代碼,按層次順序以及顏色輸出節(jié)點

public void levelOrder() {
        Node root = this.getRoot();
        ArrayDeque<Node> queue = new ArrayDeque();
        queue.add(root);
        while (!queue.isEmpty()) {
            Node node = queue.pop();
            System.out.println("key:" + node.key + "  val: " + node.val + " color:" + (node.color == RED ? "red" : "black"));
            if (node.left != null) {
                queue.add(node.left);
            }
            if (node.right != null) {
                queue.add(node.right);
            }
        }


    }

測試代碼,可以看到輸出結果正確

 public static void main(String[] args) {
        RedBlackTree<Integer, String> rbTree = new RedBlackTree<>();

        rbTree.add(150, "");
        rbTree.add(172, "");
        rbTree.add(194, "");
        rbTree.add(271, "");
        rbTree.add(293, "");
        rbTree.add(370, "");
        rbTree.levelOrder();


        /**
         * 輸出結果
         * 
         * key:271  val:  color:black
         * key:172  val:  color:red
         * key:370  val:  color:black
         * key:150  val:  color:black
         * key:194  val:  color:black
         * key:293  val:  color:red
         */
    }

五、Java中HashMap關于紅黑樹的使用

插入

我們都知道Java中的HashMap在底層數組容量為64且當前這個bucket的鏈表長度達到8時會觸發(fā)擴容,對此我們不妨寫一段代碼測試一下,代碼如下所示,可以看到筆者為了更好的演示,將每一個map的value值聲明為當前key在hashMap底層數組中的索引位置。所以我們在map.put("590", "Idx:12");打上斷點

HashMap<String, String> map = new HashMap<String, String>(64);
  map.put("24", "Idx:2");
  map.put("46", "Idx:2");
  map.put("68", "Idx:2");
  map.put("29", "Idx:7");
  map.put("150", "Idx:12");
  map.put("172", "Idx:12");
  map.put("194", "Idx:12");
  map.put("271", "Idx:12");
 

  map.put("293", "Idx:12");
  map.put("370", "Idx:12");
  map.put("392", "Idx:12");
  map.put("491", "Idx:12");
  //轉紅黑樹
  map.put("590", "Idx:12");

核心代碼如下所示,我們傳入的590的key會在i為12的鏈表中不斷查找空閑的位置,然后完成插入,循環(huán)過程中會記錄當前鏈表元素個數binCount ,經過判斷binCount >TREEIFY_THRESHOLD - 1即8-1=7,然后調用treeifyBin看看是擴容還是轉紅黑樹

final V putVal(int hash, K key, V value, boolean onlyIfAbsent,
                   boolean evict) {
        Node<K,V>[] tab; Node<K,V> p; int n, i;
        if ((tab = table) == null || (n = tab.length) == 0)
            n = (tab = resize()).length;
            //計算出hashMap這個key對應索引Ii的位置
        if ((p = tab[i = (n - 1) & hash]) == null)
            tab[i] = newNode(hash, key, value, null);
        else {
       ....略

   //核心邏輯在這里,我們傳入的590的key會在i為12的鏈表中不斷查找空閑的位置,然后完成插入,循環(huán)過程中會記錄當前鏈表元素個數binCount ,經過判斷binCount >TREEIFY_THRESHOLD - 1即8-1=7,然后調用treeifyBin轉紅黑樹
                for (int binCount = 0; ; ++binCount) {
                    if ((e = p.next) == null) {
                        p.next = newNode(hash, key, value, null);
                        if (binCount >= TREEIFY_THRESHOLD - 1)
                            treeifyBin(tab, hash);
                        break;
                    }
                 .....
                }
            }
          .........略
    }

我們再來看看treeifyBin,可以看到如果數組容量小于64直接擴容,反之就是將當前節(jié)點轉為樹節(jié)點然后調用treeify轉紅黑樹,關于紅黑樹的邏輯上文已經詳細說明了這里就不多贅述了。

 final void treeifyBin(Node<K,V>[] tab, int hash) {
        int n, index; Node<K,V> e;
        //如果數組容量小于64直接擴容
        if (tab == null || (n = tab.length) < MIN_TREEIFY_CAPACITY)
            resize();
        else if ((e = tab[index = (n - 1) & hash]) != null) {
            TreeNode<K,V> hd = null, tl = null;
            do {
            //將節(jié)點轉為樹節(jié)點,hd即為head指向當前鏈表頭節(jié)點,然后后續(xù)節(jié)點一次轉為樹節(jié)點和前驅節(jié)點彼此指向,從而構成一個雙向鏈表
                TreeNode<K,V> p = replacementTreeNode(e, null);
                if (tl == null)
                    hd = p;
                else {
                    p.prev = tl;
                    tl.next = p;
                }
                tl = p;
            } while ((e = e.next) != null);
//如果hd不為空說明需要轉紅黑樹,調用treeify
            if ((tab[index] = hd) != null)
                hd.treeify(tab);
        }
    }

HashMap中的紅黑樹是如何完成查詢的呢?(重點)

HashMap源碼如下,首先通過hashCode找到桶的位置,然后判斷這個桶是否只有一個元素,如果沒有則直接返回,反之調用getTreeNode從紅黑樹中找到對應的元素

final Node<K,V> getNode(int hash, Object key) {
        Node<K,V>[] tab; Node<K,V> first, e; int n; K k;
        if ((tab = table) != null && (n = tab.length) > 0 &&
        //計算hash對應的節(jié)點first 
            (first = tab[(n - 1) & hash]) != null) {
            //如果有且只有一個則直接返回
            if (first.hash == hash && 
                ((k = first.key) == key || (key != null && key.equals(k))))
                return first;
            if ((e = first.next) != null) {
            //如果是紅黑樹則調用getTreeNode
                if (first instanceof TreeNode)
                    return ((TreeNode<K,V>)first).getTreeNode(hash, key);
                do {
                    if (e.hash == hash &&
                        ((k = e.key) == key || (key != null && key.equals(k))))
                        return e;
                } while ((e = e.next) != null);
            }
        }
        return null;
    }

我們步入getTreeNode會看到find方法,可以看到它查詢紅黑樹的元素邏輯很簡單,根據紅黑樹的有序性找到和查詢元素hash值相同、equals為true的節(jié)點返回即可。

final TreeNode<K,V> find(int h, Object k, Class<?> kc) {
            TreeNode<K,V> p = this;
            do {
                int ph, dir; K pk;
                TreeNode<K,V> pl = p.left, pr = p.right, q;
                //比對元素hash值大于h,p指向p的左子節(jié)點進行下一次比對
                if ((ph = p.hash) > h)
                    p = pl;
                    //比對值小于查詢節(jié)點的hash,p指向右子節(jié)點進行下一次比對
                else if (ph < h)
                    p = pr;
                    //如果key一樣且equals為true直接返回這個元素
                else if ((pk = p.key) == k || (k != null && k.equals(pk)))
                    return p;
                else if (pl == null)
                    p = pr;
                else if (pr == null)
                    p = pl;
                else if ((kc != null ||
                          (kc = comparableClassFor(k)) != null) &&
                         (dir = compareComparables(kc, k, pk)) != 0)
                    p = (dir < 0) ? pl : pr;
                else if ((q = pr.find(h, k, kc)) != null)
                    return q;
                else
                    p = pl;
            } while (p != null);
            return null;
        }

小結

本文通過圖解加實現為讀者演示了紅黑樹的特點和工作流程,可以看到紅黑樹的邏輯起始并沒有那么復雜,只要讀者專注核心概念,用一些簡單的示例畫圖了解過程,再通過需求分析所有邏輯和設計之后,編碼就沒有那么困難了。既使遇到問題,我們也可以抓住數據結構的特點,配合使用debug+中序遍歷也能解決邏輯漏洞。從而加深對數據結構的理解。

在此我們再對二分搜索樹、AVL樹、紅黑樹三者使用場景進行一下說明:

  • 隨機添加節(jié)點:若節(jié)點存在大量隨機性,使用二分搜索樹即可,相比于紅黑樹的2O(nLogN)復雜度,二分搜索樹的O(logN)性能更佳,但是二分搜索樹可能存在退化成鏈表的情況,需謹慎考慮。
  • 僅作查詢:對于查詢AVL最合適不過。他的平衡高度為logn比紅黑樹的“黑平衡”那種2logn的平衡要出色很多,在添加少,查詢多的情況下,使用AVL樹更合適。
  • 綜合操作:若需要增刪改查等綜合操作,建議使用紅黑樹,紅黑樹雖然不是最優(yōu)但是綜合上是最優(yōu)的。
責任編輯:趙寧寧 來源: 寫代碼的SharkChili
相關推薦

2023-03-31 08:24:29

數據結構算法數目

2020-02-02 15:14:24

HTTP黑科技前端

2019-09-03 10:40:23

數據結構HTML編程

2020-05-20 09:55:42

Git底層數據

2023-09-22 11:17:50

紅黑樹結構數據結構

2023-09-15 08:14:48

HashMap負載因子

2023-08-29 08:31:13

B+樹數據索引

2019-09-27 08:53:47

Redis數據C語言

2019-10-12 08:36:48

Java程序員數據結構

2021-08-29 07:41:48

數據HashMap底層

2020-07-09 07:00:00

HashMap

2020-03-31 14:40:24

HashMap源碼Java

2025-01-14 17:00:00

SpringBoot開發(fā)代碼

2023-12-06 16:28:56

2020-11-05 09:03:32

紅黑樹面試數據

2024-10-30 11:30:02

2025-02-11 15:56:18

2020-10-08 14:32:57

大數據工具技術

2020-09-17 07:37:09

紅黑樹數據結構

2021-05-29 10:11:00

Kafa數據業(yè)務
點贊
收藏

51CTO技術棧公眾號

97中文在线| 色悠悠国产精品| 免费国产黄色网址| 国产精品视频二区三区| 国产做a爰片久久毛片| 欧美激情喷水视频| 国产123在线| 成人污版视频| 精品国产电影一区| 亚洲一区三区| 天天色综合av| 久久99久久久久| 97在线免费视频| 中文字幕在线观看免费高清| 亚洲91网站| 欧美中文一区二区三区| 国产精品69久久久| 嫩草香蕉在线91一二三区| 不卡一区中文字幕| 91九色在线观看| 国内av在线播放| 日韩视频一区| 九色91av视频| 天美传媒免费在线观看| 欧美色图五月天| 日韩精品中文字幕在线一区| 一区二区在线免费看| 依依综合在线| 午夜视频一区在线观看| 国产日产欧美一区二区| av大片在线看| 久久久精品国产免费观看同学| 99re国产视频| 在线免费一级片| 日日夜夜免费精品| 91精品国产色综合| 久久精品性爱视频| 欧美激情第二页| 久久伊人精品视频| 萌白酱视频在线| 国内精品久久久久久久影视简单| 亚洲激情视频在线观看| 熟女人妻一区二区三区免费看| 中文幕av一区二区三区佐山爱| 色诱视频网站一区| 欧美爱爱视频免费看| 黄色小说在线播放| 亚洲一区二区三区四区不卡| 国产精品夜夜夜爽张柏芝| 成a人v在线播放| 国产亚洲精品资源在线26u| 欧美国产二区| 黄色av网站在线免费观看| 久久日韩粉嫩一区二区三区 | 精品成人久久久| 午夜视频精品| 欧美国产日韩精品| 国产在线视频在线观看| 亚洲精品123区| 性色av一区二区三区| 男人天堂中文字幕| 国产日韩一区二区三区在线| 97超碰蝌蚪网人人做人人爽| 毛片视频网站在线观看| 国产日韩欧美一区在线| 亲子乱一区二区三区电影| 老熟妇仑乱一区二区av| 日韩精品国产欧美| 国产免费一区视频观看免费 | 久久久久久久福利| 黄色一区二区三区四区| 国内久久久精品| 波多野结衣国产| 日韩精品免费视频人成| 国产精品毛片a∨一区二区三区|国 | 国产亚洲欧美日韩在线观看一区二区 | 超碰最新在线| 香蕉久久一区二区不卡无毒影院 | 亚洲精品国产精品国自产观看浪潮| 久久久老熟女一区二区三区91| 美日韩黄色大片| 超碰超碰人人人人精品| 高清av一区二区| 精品九九九九| 国产51人人成人人人人爽色哟哟| 日本一区二区三区视频视频| 只有这里有精品| 丁香花视频在线观看| 日韩欧美中文字幕在线观看 | 福利所第一导航| 你懂的国产精品| 欧美激情a在线| 国产精品免费精品一区| 日韩成人伦理电影在线观看| 亚洲中国色老太| 香蕉久久一区二区三区| 国产精品伦一区二区三级视频| 成人手机在线播放| 久久sese| 精品三级在线看| 无码少妇精品一区二区免费动态| 欧美成人tv| 国产精品激情av在线播放| www.天堂av.com| 国产日韩精品一区| 日本一本中文字幕| 日韩有码欧美| 亚洲乱码一区av黑人高潮| 欧美特级一级片| 丝袜亚洲另类欧美| 成人片在线免费看| 欧美成人高清在线| 欧美午夜xxx| 在线观看欧美一区二区| 日韩片欧美片| 日韩av大片在线| 国精产品一品二品国精品69xx | 精品美女久久久久| 国产一区三区三区| 日日夜夜精品网站| 九色porny丨首页入口在线| 3d成人动漫网站| av黄色在线免费观看| 亚洲免费成人| 国产精品久久久久久久小唯西川 | av亚洲免费| 96精品视频在线| 国产成人手机在线| 亚洲美女在线一区| 亚洲精品手机在线观看| 国产日产一区| 人妖精品videosex性欧美| 成人免费视频国产免费麻豆| 亚洲日本在线天堂| 亚洲 欧美 另类人妖| 国产区精品区| 热久久这里只有| 欧美挠脚心网站| 黄色一区二区在线观看| 又黄又色的网站| 欧美日本亚洲韩国国产| 成人午夜激情网| 午夜视频成人| 欧美乱妇一区二区三区不卡视频| 日韩毛片无码永久免费看| 麻豆91精品| 人偷久久久久久久偷女厕| a日韩av网址| 亚洲色无码播放| 日本黄色中文字幕| 国产女人水真多18毛片18精品视频| 凹凸国产熟女精品视频| 老牛影视av一区二区在线观看 | 欧美大陆国产| 日韩中文字幕在线观看| 在线视频你懂得| 亚洲欧洲精品一区二区精品久久久| 99视频在线视频| 久久一区二区三区电影| 国产主播在线一区| 二区三区在线观看| 欧美不卡视频一区| 国产成人在线观看网站| 91原创在线视频| 人妻内射一区二区在线视频| 国内亚洲精品| 91免费人成网站在线观看18| 大片免费在线观看| 精品国产精品网麻豆系列| 日本三级午夜理伦三级三| 99久久99久久免费精品蜜臀| 亚洲中文字幕无码中文字| 女人丝袜激情亚洲| 国产日本欧美一区二区三区| √天堂8在线网| 亚洲缚视频在线观看| 久久中文字幕免费| 国产精品久久久久久久久免费丝袜 | 丁香婷婷综合网| 免费毛片小视频| 久久亚洲专区| 国产亚洲精品美女久久久m| 中文av在线全新| 久久精品电影网站| 秋霞av鲁丝片一区二区| 色琪琪一区二区三区亚洲区| 国产suv精品一区二区68| 夫妻av一区二区| 日本999视频| 欧美一区二区| 欧美日本国产精品| 国产成人免费av一区二区午夜| 国内偷自视频区视频综合| 番号在线播放| 亚洲成人激情图| 中文字幕理论片| 亚洲第一在线综合网站| 国产免费嫩草影院| 99视频超级精品| 一区二区久久精品| 久久av最新网址| 日韩亚洲欧美一区二区| 精品国产午夜肉伦伦影院| 国产精品亚洲一区二区三区| 99riav视频在线观看| 在线观看不卡av| 日韩在线观看视频一区| 制服丝袜中文字幕一区| 国产高清中文字幕| 一区二区三区毛片| 无码人中文字幕| 91麻豆swag| 好吊操视频这里只有精品| 青青青伊人色综合久久| 国产男女在线观看| 欧美日韩伊人| 亚洲成人动漫在线| 欧美一区二区三| 欧美二区在线| 免费看久久久| 国产精品xxx在线观看www| 精品国产亚洲一区二区三区在线 | 国内精品偷拍| 亚洲va欧美va在线观看| 国产精品麻豆成人av电影艾秋| 91av在线视频观看| www.色在线| 色综合久久88| 在线看三级电影| 日韩一中文字幕| 色哟哟免费在线观看| 亚洲午夜久久久久久久| 人成免费电影一二三区在线观看| 日韩亚洲欧美综合| 国产后入清纯学生妹| 3d动漫精品啪啪一区二区竹菊| 亚洲一卡二卡在线观看| 欧美中文字幕久久| 姑娘第5集在线观看免费好剧| 色综合一区二区三区| 国产精品一区二区三区四| 精品国产精品三级精品av网址| 久久精品国产亚洲AV无码麻豆| 亚洲精品老司机| 久草成人在线视频| 亚洲动漫第一页| 日韩字幕在线观看| 黄色精品一区二区| 国产日产精品一区二区三区| 欧美日韩中文字幕在线| 中文字幕亚洲高清| 色综合久久久久久久久| 无码人妻黑人中文字幕| 欧美系列在线观看| 夜夜躁狠狠躁日日躁av| 制服丝袜激情欧洲亚洲| 国产精品爽爽久久| 日韩精品一区二区三区swag| 国产成人自拍一区| 日韩黄色在线免费观看| 国产在线你懂得| 色噜噜久久综合伊人一本| av黄色在线| 性欧美视频videos6一9| 黑人巨大亚洲一区二区久| 国产精品专区h在线观看| 国产精品白丝久久av网站| 99热在线国产| 婷婷亚洲成人| 亚洲日本无吗高清不卡| 天天综合国产| 成熟丰满熟妇高潮xxxxx视频| 国产农村妇女毛片精品久久莱园子| 亚洲少妇第一页| 国产伦精品一区二区三区免费迷| 一级黄色免费视频| 久久精品一区八戒影视| 秋霞欧美一区二区三区视频免费| 亚洲激情成人在线| 97免费在线观看视频| 欧美日韩久久久久久| 国产xxxx在线观看| 亚洲欧美成人在线| 91麻豆一二三四在线| 国产91成人video| 亚洲精品大片| 精品国产区在线| 日韩欧美中文| 欧美三级一级片| 另类综合日韩欧美亚洲| 成人在线视频免费播放| 中文在线一区二区| 国产成人愉拍精品久久| 3d成人h动漫网站入口| 色视频精品视频在线观看| 久久久97精品| 日韩成人亚洲| 精品视频第一区| 亚洲一区二区| 噼里啪啦国语在线观看免费版高清版| 国产精品综合网| 国产综合精品久久久久成人av| 一区二区三区欧美亚洲| 嫩草影院一区二区三区| 亚洲第一色在线| 国产福利在线播放麻豆| 青青久久av北条麻妃黑人| av动漫精品一区二区| 亚洲一区免费看| 丝袜亚洲另类丝袜在线| 国产免费一区二区三区最新6| 中文字幕乱码日本亚洲一区二区| 日韩乱码一区二区| 91麻豆精品国产自产在线| 久久久久久青草| 8x海外华人永久免费日韩内陆视频| 精品国产一区二区三区性色av| 欧美一区二区三区四区夜夜大片| 国产精品v亚洲精品v日韩精品| 波多结衣在线观看| 久久久久国产精品免费免费搜索| 日本免费一二三区| 精品精品国产高清一毛片一天堂| 免费看美女视频在线网站| 日韩av黄色在线观看| 久久a爱视频| 每日在线观看av| 国产成人免费在线视频| 顶臀精品视频www| 欧美乱妇15p| 黄色网在线免费观看| 91精品久久久久久久久久久久久| 精品盗摄女厕tp美女嘘嘘| 日韩中文字幕二区| 久久新电视剧免费观看| 久久久久久久久久免费视频| 亚洲爱爱爱爱爱| 国产探花在线观看| 1卡2卡3卡精品视频| 欧美在线亚洲综合一区| 182午夜视频| 亚洲欧美日韩一区二区 | 欧美一区 二区 三区| 欧美精品久久| 三级不卡在线观看| 亚洲天堂岛国片| 欧美日韩国产精选| 日本在线www| 91青草视频久久| 狠狠色丁香久久综合频道| 337p日本欧洲亚洲大胆张筱雨| 一区二区三区在线观看国产| 黄色av中文字幕| 性欧美亚洲xxxx乳在线观看| 亚洲丁香日韩| 亚洲三级视频网站| 亚洲色图欧美在线| 亚洲国产成人在线观看| 国内精品一区二区三区| 曰本一区二区三区视频| 日韩有码免费视频| 中文字幕成人网| jizz中国少妇| 97精品久久久中文字幕免费| 亚洲调教一区| 色悠悠久久综合网| 日韩美女久久久| 日本激情视频网站| 欧美在线精品免播放器视频| 欧美日韩国产一区二区三区不卡| 中文字幕中文在线| 夜夜爽夜夜爽精品视频| 青草久久伊人| 成人黄色在线播放| 亚洲视频一二| 欧洲av一区二区三区| 在线成人免费观看| sm性调教片在线观看| 日韩欧美在线电影| 国产91在线看| 波多野结衣在线观看视频| 蜜臀久久99精品久久久无需会员| 老司机aⅴ在线精品导航| 亚洲精品怡红院| 亚洲主播在线播放| 成人欧美亚洲| 99久久精品久久久久久ai换脸| 久久一区视频| 欧美日韩免费做爰视频| 亚洲人成电影网站色…| 欧美电影院免费观看| 欧美日韩亚洲第一| 亚洲另类一区二区| 欧美扣逼视频| 99国产高清| 日韩av高清在线观看| 国产亚洲欧美精品久久久久久| 一区二区在线视频| 国产精品毛片视频| 日本中文字幕二区|