日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程语言 > java >内容正文

java

聚类算法的java实现_聚类算法之BIRCH(Java实现)

發(fā)布時間:2025/3/15 java 20 豆豆
生活随笔 收集整理的這篇文章主要介紹了 聚类算法的java实现_聚类算法之BIRCH(Java实现) 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

BIRCH(Balanced Iterative Reducing and Clustering using Hierarchies)天生就是為處理超大規(guī)模(至少要讓你的內(nèi)存容不下)的數(shù)據(jù)集而設(shè)計的,它可以在任何給定的內(nèi)存下運行。關(guān)于BIRCH的更多特點先不介紹,我先講一下算法的完整實現(xiàn)細(xì)節(jié),對算法的實現(xiàn)過程搞清楚后再去看別人對該算法的評價才會感受深刻。

你不需要具備B樹的相關(guān)知識,我接下來會講得很清楚。

BIRCH算法的過程就是要把待分類的數(shù)據(jù)插入一棵樹中,并且原始數(shù)據(jù)都在葉子節(jié)點上。這棵樹看起來是這個樣子:

在這棵樹中有3種類型的節(jié)點:Nonleaf、Leaf、MinCluster,Root可能是一種Nonleaf,也可能是一種Leaf。所有的Leaf放入一個雙向鏈表中。每一個節(jié)點都包含一個CF值,CF是一個三元組$(N,\vec{LS},\vec{SS})$,其中data point instance的個數(shù),$\vec{LS}$和$\vec{SS}$是與數(shù)據(jù)點同維度的向量,$\vec{LS}$是線性和,$\vec{SS}$是平方和。比如有一個MinCluster里包含3個數(shù)據(jù)點(1,2,3),(4,5,6),(7,8,9),則

N=3,

$\vec{LS}=(1+4+7,2+5+8,3+6+9)=(12,15,18)$,

$\vec{SS}=(1+16+49,4+25+64,9+36+81)$。

就拿這個MinCluster為例,我們可以計算它的

簇中心$$\vec{X_0}=\frac{\sum_{i=1}^{N}\vec{X_i}}{N}$$

簇半徑$$R=\sqrt{\frac{\sum_{i=1}^{N}{(\vec{X_i}-\vec{X_0})}^2}{N}}$$

簇直徑$$D=\sqrt{\frac{\sum_{i=1}^{N}\sum_{j=1}^{N}{(\vec{X_i}-\vec{X_j})}^2}{N(N-1)}}$$

我們還可以計算兩個簇之間的距離$$D_2=\sqrt{\frac{\sum_{i=1}^{N_1}\sum_{j=N_1+1}^{N_1+N_2}{(\vec{X_i}-\vec{X_j})}^2}{N_1N_2}}$$

當(dāng)然你也可以使用D0,D1,D3等等,不過在這里我們使用D2。

有意思的是簇中心、簇半徑、簇直徑以及兩簇之間的距離D0到D3都可以由CF來計算,比如

簇直徑$$D=\sqrt{\frac{SS_1}{N_1}+\frac{SS_2}{N_2}-\frac{2LS_1LS_2}{N_1N_2}}$$

簇間距離$D_2=\sqrt{\frac{2N*SS-2LS^2}{N(N-1)}}$,這里的N,LS和SS是指兩簇合并后大簇的N,LS和SS。所謂兩簇合并只需要兩個對應(yīng)的CF相加那可

CF1 + CF2 = (N1 + N2 , LS1 + LS2, SS1 + SS2)

每個節(jié)點的CF值就是其所有孩子節(jié)點CF值之和,以每個節(jié)點為根節(jié)點的子樹都可以看成 是一個簇。

Nonleaf、Leaf、MinCluster都是有大小限制的,Nonleaf的孩子節(jié)點不能超過B個,Leaf最多只能有L個MinCluster,而一個MinCluster的直徑不能超過T。

算法起初,我們掃描數(shù)據(jù)庫,拿到第一個data point instance--(1,2,3),我們創(chuàng)建一個空的Leaf和MinCluster,把點(1,2,3)的id值放入Mincluster,更新MinCluster的CF值為(1,(1,2,3),(1,4,9)),把MinCluster作為Leaf的一個孩子,更新Leaf的CF值為(1,(1,2,3),(1,4,9))。實際上只要往樹中放入一個CF(這里我們用CF作為Nonleaf、Leaf、MinCluster的統(tǒng)稱),就要更新從Root到該葉子節(jié)點的路徑上所有節(jié)點的CF值。

當(dāng)又有一個數(shù)據(jù)點要插入樹中時,把這個點封裝為一個MinCluster(這樣它就有了一個CF值),把新到的數(shù)據(jù)點記為CF_new,我們拿到樹的根節(jié)點的各個孩子節(jié)點的CF值,根據(jù)D2來找到CF_new與哪個節(jié)點最近,就把CF_new加入那個子樹上面去。這是一個遞歸的過程。遞歸的終止點是要把CF_new加入到一個MinCluster中,如果加入之后MinCluster的直徑?jīng)]有超過T,則直接加入,否則譔CF_new要單獨作為一個簇,成為MinCluster的兄弟結(jié)點。插入之后注意更新該節(jié)點及其所有祖先節(jié)點的CF值。

插入新節(jié)點后,可能有些節(jié)點的孩子數(shù)大于了B(或L),此時該節(jié)點要分裂。對于Leaf,它現(xiàn)在有L+1個MinCluster,我們要新創(chuàng)建一個Leaf,使它作為原Leaf的兄弟結(jié)點,同時注意每新創(chuàng)建一個Leaf都要把它插入到雙向鏈表中。L+1個MinCluster要分到這兩個Leaf中,怎么分呢?找出這L+1個MinCluster中距離最遠(yuǎn)的兩個Cluster(根據(jù)D2),剩下的Cluster看離哪個近就跟誰站在一起。分好后更新兩個Leaf的CF值,其祖先節(jié)點的CF值沒有變化,不需要更新。這可能導(dǎo)致祖先節(jié)點的遞歸分裂,因為Leaf分裂后恰好其父節(jié)點的孩子數(shù)超過了B。Nonleaf的分裂方法與Leaf的相似,只不過產(chǎn)生新的Nonleaf后不需要把它放入一個雙向鏈表中。如果是樹的根節(jié)點要分裂,則樹的高度加1。

CF.java

package birch;

public class CF {

private int N;

private double[] LS;

private double[] SS;

public CF() {

LS=new double[BIRCH.dimen];

SS=new double[BIRCH.dimen];

}

// 根據(jù)一個data point instance創(chuàng)建一個Clustering Feature

public CF(double[] data) {

int len = data.length;

this.N = 1;

this.LS = data;

this.SS=new double[len];

for (int i = 0; i < len; i++)

this.SS[i] = Math.pow(data[i], 2);

}

//復(fù)制構(gòu)造函數(shù)(深復(fù)制)

public CF(CF cf){

this.N=cf.getN();

int len=cf.getLS().length;

this.LS=new double[len];

this.SS=new double[len];

for(int i=0;i

this.LS[i]=cf.getLS()[i];

this.SS[i]=cf.getSS()[i];

}

}

// 采用D2計算兩個CF Entry之間的距離

public double getDistanceTo(CF entry) {

double dis = 0.0;

int len = this.LS.length;

// 采用D2

for (int i = 0; i < len; i++) {

dis += this.SS[i] / this.N + entry.getSS()[i] / entry.getN() - 2

* this.LS[i] * entry.getLS()[i] / (this.N * entry.getN());

}

return Math.sqrt(dis);

}

//采用D0計算兩個簇心之間的歐氏距離

//public double getDistanceTo(CF entry) {

//int len=entry.getLS().length;

//double[] a=new double[len];

//double[] b=new double[len];

//for(int i=0;i

//a[i]=this.getLS()[i]/this.N;

//b[i]=this.getSS()[i]/this.N;

//}

//return calEuraDist(a,b,len);

//}

// 加上或減去一個CF的值

public void addCF(CF entry, boolean add) {

int opt = 1; // 默認(rèn)為相加

if (!add) // 如果add為false則為相減

opt = -1;

this.N = this.N + entry.getN() * opt;

int len = this.LS.length;

for (int i = 0; i < len; i++) {

this.LS[i] = this.LS[i] + entry.getLS()[i] * opt;

this.SS[i] = this.SS[i] + entry.getSS()[i] * opt;

}

}

//計算兩個向量的歐氏距離

public static double calEuraDist(double[] arr1,double[] arr2,int len){

double result=0.0;

for(int i=0;i

result+=Math.pow(arr1[i]-arr2[i],2.0);

}

return Math.sqrt(result);

}

public int getN() {

return N;

}

public void setN(int n) {

N = n;

}

public double[] getLS() {

return LS;

}

public void setLS(double[] lS) {

LS = lS;

}

public double[] getSS() {

return SS;

}

public void setSS(double[] sS) {

SS = sS;

}

}

MinCluster.java

package birch;

import java.util.ArrayList;

//最小簇

public class MinCluster {

private CF cf;

private ArrayList inst_marks;

public MinCluster(){

cf=new CF();

inst_marks=new ArrayList();

}

public CF getCf() {

return cf;

}

public void setCf(CF cf) {

this.cf = cf;

}

public ArrayList getInst_marks() {

return inst_marks;

}

public void setInst_marks(ArrayList inst_marks) {

this.inst_marks = inst_marks;

}

//計算簇的直徑

public static double getDiameter(CF cf){

double diameter=0.0;

int n=cf.getN();

for(int i=0;i

double ls=cf.getLS()[i];

double ss=cf.getSS()[i];

diameter=diameter+(2*n*ss-2*ls*ls);

}

diameter=diameter/(n*n-n);

return Math.sqrt(diameter);

}

//計算和另外一個簇合并后的直徑

public static double getDiameter(MinCluster cluster1,MinCluster cluster2){

CF cf=new CF(cluster1.getCf());

cf.addCF(cluster2.getCf(), true);

return getDiameter(cf);

}

public void mergeCluster(MinCluster cluster){

this.getCf().addCF(cluster.getCf(), true);

for(int i=0;i

this.getInst_marks().add(cluster.getInst_marks().get(i));

}

}

}

TreeNode.java

package birch;

public abstract class TreeNode extends CF {

private TreeNode parent;

public TreeNode() {

}

public TreeNode(double[] data) {

super(data);

}

public TreeNode getParent() {

return parent;

}

public void setParent(TreeNode parent) {

this.parent = parent;

}

public void addCFUpToRoot(CF cf){

TreeNode node=this;

while(node!=null){

node.addCF(cf, true);

node=node.getParent();

}

}

abstract void split();

abstract void absorbSubCluster(MinCluster cluster);

}

NonleafNode.java

package birch;

import java.util.ArrayList;

public class NonleafNode extends TreeNode {

private int B=5;

private ArrayList children;

public NonleafNode() {

children=new ArrayList();

}

public NonleafNode(double[] data) {

super(data);

}

// 節(jié)點分裂

public void split() {

// 找到距離最遠(yuǎn)的兩個孩子節(jié)點

int c1 = 0;

int c2 = 0;

double maxDist = 0;

int len = this.getChildren().size();

for (int i = 0; i < len - 1; i++) {

for (int j = i + 1; j < len; j++) {

double dist = this.getChildren().get(i)

.getDistanceTo(this.getChildren().get(j));

if (dist > maxDist) {

maxDist = dist;

c1 = i;

c2 = j;

}

}

}

// 以距離最遠(yuǎn)的孩子節(jié)點為中心,把B+1個孩子分為兩個大簇。其中一個簇仍留作本節(jié)點的孩子,另外一簇需要新創(chuàng)建一個節(jié)點來領(lǐng)養(yǎng)它們

NonleafNode newNode = new NonleafNode();

newNode.addChild(this.getChildren().get(c2));

//如果本節(jié)點已經(jīng)是Root節(jié)點,則需要創(chuàng)建一個新的Root節(jié)點

if(this.getParent()==null){

NonleafNode root= new NonleafNode();

root.setN(this.getN());

root.setLS(this.getLS());

root.setSS(this.getSS());

root.addChild(this);

this.setParent(root);

}

newNode.setParent(this.getParent());

((NonleafNode)this.getParent()).addChild(newNode);

for (int i = 0; i < len; i++) {

if (i != c1 && i != c2) {

if (this.getChildren().get(i)

.getDistanceTo(this.getChildren().get(c2)) < this

.getChildren().get(i)

.getDistanceTo(this.getChildren().get(c1))) {

newNode.addChild(this.getChildren().get(i));

}

}

}

for (TreeNode entry : newNode.getChildren()) {

newNode.addCF(entry, true);

this.deleteChild(entry);

this.addCF(entry, false);

}

//如果本節(jié)點分裂導(dǎo)致父節(jié)點的孩子數(shù)超過了分枝因子,引發(fā)父節(jié)點分裂

NonleafNode pn=(NonleafNode)this.getParent();

if(pn.getChildren().size()>B){

this.getParent().split();

}

}

public void absorbSubCluster(MinCluster cluster){

//從本節(jié)點的孩子中尋找與cluster最近的子節(jié)點

CF cf=cluster.getCf();

int nearIndex=0;

double minDist=Double.MAX_VALUE;

for(int i=0;i

double dist=cf.getDistanceTo(this.getChildren().get(i));

if(dist

nearIndex=i;

}

}

//讓那個最近的子節(jié)點absorb掉這個新到的cluster

this.getChildren().get(nearIndex).absorbSubCluster(cluster);

}

public ArrayList getChildren() {

return children;

}

public void setChildren(ArrayList children) {

this.children = children;

}

public void addChild(TreeNode child) {

this.children.add(child);

}

public void deleteChild(TreeNode child) {

this.children.remove(children.indexOf(child));

}

public int getB() {

return B;

}

public void setB(int b) {

B = b;

}

}

LeafNode.java

package birch;

import java.util.ArrayList;

public class LeafNode extends TreeNode {

private int L=10;

private double T=2.8;

private ArrayList children;

private LeafNode pre;

private LeafNode next;

public LeafNode() {

children=new ArrayList();

}

public LeafNode(double[] data) {

super(data);

}

// 節(jié)點分裂

public void split() {

// 找到距離最遠(yuǎn)的兩個孩子節(jié)點

int c1 = 0;

int c2 = 0;

double maxDist = 0;

int len = this.getChildren().size();

for (int i = 0; i < len - 1; i++) {

for (int j = i + 1; j < len; j++) {

double dist = this.getChildren().get(i).getCf()

.getDistanceTo(this.getChildren().get(j).getCf());

if (dist > maxDist) {

maxDist = dist;

c1 = i;

c2 = j;

}

}

}

// 以距離最遠(yuǎn)的孩子節(jié)點為中心,把B+1個孩子分為兩個大簇。其中一個簇仍留作本節(jié)點的孩子,另外一簇需要新創(chuàng)建一個節(jié)點來領(lǐng)養(yǎng)它們

LeafNode newNode = new LeafNode();

newNode.addChild(this.getChildren().get(c2));

// 如果本節(jié)點已經(jīng)是Root節(jié)點,則需要創(chuàng)建一個新的Root節(jié)點

if (this.getParent() == null) {

NonleafNode root = new NonleafNode();

root.setN(this.getN());

root.setLS(this.getLS());

root.setSS(this.getSS());

this.setParent(root);

root.addChild(this);

}

//建立新節(jié)點和本節(jié)點的父節(jié)點的父子關(guān)系

newNode.setParent(this.getParent());

((NonleafNode)this.getParent()).addChild(newNode);

//把離newNode近的孩子節(jié)點歸到newNode這個簇里面

for (int i = 0; i < len; i++) {

if (i != c1 && i != c2) {

if (this.getChildren().get(i).getCf()

.getDistanceTo(this.getChildren().get(c2).getCf()) < this

.getChildren().get(i).getCf()

.getDistanceTo(this.getChildren().get(c1).getCf())) {

newNode.addChild(this.getChildren().get(i));

}

}

}

//把離newNode近的孩子節(jié)點從本節(jié)點中刪除

for (MinCluster cluster : newNode.getChildren()) {

newNode.addCF(cluster.getCf(), true);

this.deleteChild(cluster);

this.addCF(cluster.getCf(), false);

}

// 把新增加的LeafNode添加到LeafNode雙向鏈表中

if (this.getNext() != null) {

newNode.setNext(this.getNext());

this.getNext().setPre(newNode);

}

this.setNext(newNode);

newNode.setPre(this);

// 如果本節(jié)點分裂導(dǎo)致父節(jié)點的孩子數(shù)超過了分枝因子,引發(fā)父節(jié)點分裂

NonleafNode pn = (NonleafNode) this.getParent();

if (pn.getChildren().size() > pn.getB()) {

this.getParent().split();

}

}

@Override

public void absorbSubCluster(MinCluster cluster) {

// 先試圖找到葉子節(jié)點的孩子(一些subcluster)中與cluster最近的簇

CF cf = cluster.getCf();

int nearIndex = 0;

double minDist = Double.MAX_VALUE;

int len = this.getChildren().size();

if (len > 0) {

for (int i = 0; i < len; i++) {

double dist = cf.getDistanceTo(this.getChildren().get(i)

.getCf());

if (dist < minDist) {

nearIndex = i;

}

}

// 計算兩個簇合并后的直徑

double mergeDiameter = MinCluster.getDiameter(cluster, this

.getChildren().get(nearIndex));

// 如果合并后發(fā)現(xiàn)簇的直徑超過了閾值,則把cluster作為一個單獨的孩子插入本葉子節(jié)點下

if (mergeDiameter > T) {

this.addChild(cluster);

if (this.getChildren().size() > L) {

this.split();

}

}

// 如果不超過閾值,則直接合并兩個簇

else {

this.getChildren().get(nearIndex).mergeCluster(cluster);

}

}

// 創(chuàng)建B樹之初,葉子節(jié)點還沒有children

else {

this.addChild(cluster);

}

this.addCFUpToRoot(cluster.getCf());

}

public ArrayList getChildren() {

return children;

}

public void setChildren(ArrayList children) {

this.children = children;

}

public void addChild(MinCluster child) {

this.children.add(child);

}

public void deleteChild(MinCluster child) {

this.children.remove(children.indexOf(child));

}

public LeafNode getPre() {

return pre;

}

public void setPre(LeafNode pre) {

this.pre = pre;

}

public LeafNode getNext() {

return next;

}

public void setNext(LeafNode next) {

this.next = next;

}

public int getL() {

return L;

}

public void setL(int l) {

L = l;

}

public double getT() {

return T;

}

public void setT(double t) {

T = t;

}

}

BIRCH.java

package birch;

import java.io.BufferedReader;

import java.io.File;

import java.io.FileReader;

import java.io.IOException;

public class BIRCH {

public static final int dimen=4;

LeafNode leafNodeHead=new LeafNode();

int point_num=0;//point instance計數(shù)

//逐條掃描數(shù)據(jù)庫,建立B-樹

public TreeNode buildBTree(String filename){

//先建立一個葉子節(jié)點

LeafNode leaf=new LeafNode();

TreeNode root=leaf;

//把葉子節(jié)點加入存儲葉子節(jié)點的雙向鏈表

leafNodeHead.setNext(leaf);

leaf.setPre(leafNodeHead);

//打開文件,從文件中讀取原始數(shù)據(jù)

File file = new File(filename);

if(!file.exists()){

System.out.println("Data File Not Exists.");

System.exit(2);

}

try {

FileReader fr = new FileReader(file);

BufferedReader br=new BufferedReader(fr);

String line=null;

while((line=br.readLine())!=null && line.trim()!=""){

point_num++;

String[] cont=line.split("[,|\\s+]");

//讀入point instance

double[] data=new double[dimen];

for(int i=0;i

data[i]=Double.parseDouble(cont[i]);

}

String mark=String.valueOf(point_num)+cont[data.length];

//根據(jù)一個point instance創(chuàng)建一個MinCluster

CF cf=new CF(data);

MinCluster subCluster=new MinCluster();

subCluster.setCf(cf);

subCluster.getInst_marks().add(mark);

//把新到的point instance插入樹中

root.absorbSubCluster(subCluster);

//要始終保證root是樹的根節(jié)點

while(root.getParent()!=null){

root=root.getParent();

}

}

br.close();

} catch (IOException e) {

e.printStackTrace();

}

return root;

}

//打印B-樹的所有葉子節(jié)點

public void printLeaf(LeafNode header){

//point_num清0

point_num=0;

while(header.getNext()!=null){

System.out.println("\n一個葉子節(jié)點:");

header=header.getNext();

for(MinCluster cluster:header.getChildren()){

System.out.println("\n一個最小簇:");

for(String mark:cluster.getInst_marks()){

point_num++;

System.out.print(mark+"\t");

}

}

}

}

//打印指定根節(jié)點的子樹

public void printTree(TreeNode root){

if(!root.getClass().getName().equals("birch.LeafNode")){

NonleafNode nonleaf=(NonleafNode)root;

for(TreeNode child:nonleaf.getChildren()){

printTree(child);

}

}

else{

System.out.println("\n一個葉子節(jié)點:");

LeafNode leaf=(LeafNode)root;

for(MinCluster cluster:leaf.getChildren()){

System.out.println("\n一個最小簇:");

for(String mark:cluster.getInst_marks()){

System.out.print(mark+"\t");

point_num++;

}

}

}

}

public static void main(String[] args) {

BIRCH birch=new BIRCH();

TreeNode root=birch.buildBTree("/home/orisun/test/iris.shuffled");

birch.point_num=0;

birch.printTree(root);

System.out.println();

//birch.printLeaf(birch.leafNodeHead);

//確認(rèn)被分類的point instance和掃描數(shù)據(jù)庫時錄入的point instance的個數(shù)是一致的

System.out.println(birch.point_num);

}

}

最后我們來總結(jié)一BIRCH的優(yōu)勢和劣勢。

優(yōu)點:

節(jié)省內(nèi)在。葉子節(jié)點放在磁盤分區(qū)上,非葉子節(jié)點僅僅是存儲了一個CF值,外加指向父節(jié)點和孩子節(jié)點的指針。

快。合并兩個兩簇只需要兩個CF算術(shù)相加即可;計算兩個簇的距離只需要用到(N,LS,SS)這三個值足矣。

一遍掃描數(shù)據(jù)庫即可建立B樹。

可識別噪聲點。建立好B樹后把那些包含數(shù)據(jù)點少的MinCluster當(dāng)作outlier。

由于B樹是高度平衡的,所以在樹上進(jìn)行插入或查找操作很快。

缺點:

結(jié)果依賴于數(shù)據(jù)點的插入順序。本屬于同一個簇的點可能由于插入順序相差很遠(yuǎn)而分到不同的簇中,即使同一個點在不同的時刻被插入,也會被分到不同的簇中。

對非球狀的簇聚類效果不好。這取決于簇直徑和簇間距離的計算方法。

對高維數(shù)據(jù)聚類效果不好。

由于每個節(jié)點只能包含一定數(shù)目的子節(jié)點,最后得出來的簇可能和自然簇相差很大。

BIRCH適合于處理需要數(shù)十上百小時聚類的數(shù)據(jù),但在整個過程中算法一旦中斷,一切必須從頭再來。

局部性也導(dǎo)致了BIRCH的聚類效果欠佳。當(dāng)一個新點要插入B樹時,它只跟很少一部分簇進(jìn)行了相似性(通過計算簇間距離)比較,高的efficient導(dǎo)致低的effective。

總結(jié)

以上是生活随笔為你收集整理的聚类算法的java实现_聚类算法之BIRCH(Java实现)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。

主站蜘蛛池模板: 性久久久 | 人妻熟女一区二区三区app下载 | 亚洲国产免费看 | 亚洲码视频 | av网址免费在线观看 | 国产色区 | 成片免费观看 | 波多野结衣一区二区三区高清av | 日日夜夜噜 | 欧美成人一区二区三区 | 香蕉视频 | 久久久久久久极品内射 | www.日日夜夜 | 亚洲精品一区二区口爆 | 日韩中文字幕亚洲 | 国产成人无码一区二区在线播放 | 少妇毛片一区二区三区 | 97爱爱视频| 欧美老肥妇做.爰bbww视频 | 国产欧美一区二区视频 | 国产成人午夜精品无码区久久 | 黄瓜视频在线观看污 | 岛国裸体写真hd在线 | 国产福利精品在线 | 少妇高潮一区二区三区99 | 小早川怜子久久精品中文字幕 | 日韩午夜伦 | 999热精品视频 | 97自拍视频| 日韩在线视频在线观看 | 人妻无码中文字幕免费视频蜜桃 | 天天想你在线观看完整版电影高清 | 经典一区二区三区 | 九九热视频这里只有精品 | a视频在线免费观看 | 91猎奇在线观看 | 欧美另类高清 | 国产12页 | 欧美性xxxxx极品少妇 | 三上悠亚痴汉电车 | 清冷男神被c的合不拢腿男男 | 91最新国产 | 亚洲另类天堂 | 成人综合一区 | 亚洲福利天堂 | 在线一区二区三区四区 | 亚洲欧美精品 | 欧美极品一区二区三区 | 欧美成人精品一区二区三区在线观看 | 亚洲综合图片区 | 亚色在线观看 | 免费无码不卡视频在线观看 | 95看片淫黄大片一级 | 久久久久久久性 | 欧美一级免费视频 | 亚洲欧美日韩精品久久亚洲区 | www.sesehu.com| 人妻大战黑人白浆狂泄 | 四虎一国产精品一区二区影院 | 国产第3页 | 精品亚洲一区二区三区四区五区 | 成年人免费看毛片 | 欧美一区二区网站 | 国产黄色网页 | 激情av网站 | 综合久久久久久久 | 国产在线看 | 成人片免费视频 | 国产a黄 | 乌克兰黄色片 | 成人黄色在线 | 亚洲免费av电影 | 一区二区小说 | 窝窝在线视频 | 极品白嫩丰满美女无套 | 黄色片毛片| 免费在线观看日韩 | 成人爱爱 | 在线亚洲+欧美+日本专区 | 永久av免费在线观看 | 玖玖在线免费视频 | 国产婷| 麻豆一区二区在线 | 国产古装艳史毛片hd | 香蕉成人av | 伊人网在线播放 | 中文字幕人妻一区二区三区视频 | 国产做受高潮 | 痴汉电车在线播放 | 伊人888| 国产精品久久久久久久久夜色 | 青青色在线观看 | 91黄色入口| 国产精品人人人人 | 国产一级大片在线观看 | 日韩高清黄色 | 99热这里只有精品1 亚洲人交配视频 | 高清视频一区二区 | 爱搞逼综合 |