IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> C++知识库 -> 鼠鼠玩转C语言初阶二叉树(基本概念+选择题+函数递归+OJ题) -> 正文阅读

[C++知识库]鼠鼠玩转C语言初阶二叉树(基本概念+选择题+函数递归+OJ题)

?

今天鼠鼠带你玩转二叉树~

你间歇性的努力和蒙混过日子,都是对之前努力的清零!


目录

前言

1.树的概念

2.树的专有名词

一、二叉树是什么?(性质)

1.二叉树的概念

2.二叉树的特点:

3.特殊的二叉树

4.二叉树的性质

5.存储方式!!!

二、基本概念题目讲解

Q1.树的概念问题

Q2.求叶结点问题

2.1 已知度求未知度

2.2 特殊二叉树求叶节点个数

Q3:深度问题

3.1特殊二叉树深度

3.2?已知结点个数求深度范围

三、用递归实现树的函数

1.树的遍历(打印存储的数据)

1.1 前序遍历

1.2 中序遍历

?1.3后序遍历

1.4 已知前序,中序或者已知中序、后序,写出树的前序遍历结果

1.5已知树前序遍历结果,求树右多少种结构

1.6通过先序遍历结果构建一棵树,再中序遍历打印结点数据

2.求结点个数问题

2.1 求树结点个数

2.2 求叶节点个数

2.3 求第K层结点个数

3.深度问题

3.1 求最大深度

3.2 判断二叉树是否为平衡二叉树(一个二叉树每个节点?的左右两个子树的高度差的绝对值不超过 1 )

4.树的关系问题

4.1 翻转二叉树

4.2 检查两颗树是否相同

4.3 判断树是否为对称二叉树

4.4 判断一棵树子树是否与另一棵树相同

四、利用队列层序遍历树(栈和队列?我写的另一篇博客 讲解队列与栈)

1.层序遍历

2.利用层序遍历判断一棵树是否为完全二叉树

五、总结


前言

讲二叉树,我们首先了解一下树的相关概念和专有名词

1.树的概念

是一种非线性的数据结构,它是由n(n≥0)个有限节点组成一个具有层次关系的集合。把它叫做“树”是因为它看起来像一棵倒挂的树,也就是说它是根朝上,而叶朝下的。有一个特殊的结点,称为根结点,根节点没有前驱结点除根节点外,其余结点被分成M(M>0)个互不相交的集合T1、T2、……、Tm,其中每一个集合Ti(1<= i <= m)又是一棵结构与树类似的子树。每棵子树的根结点有且只有一个前驱,可以有0个或多个后继因此,树是递归定义的

2.树的专有名词

节点的度:一个节点含有的子树的个数称为该节点的度; 如上图:A的为6


叶节点或终端节点:度为0的节点称为叶节点; 如上图:B、C、H、I...等节点为叶节点


非终端节点或分支节点:度不为0的节点; 如上图:D、E、F、G...等节点为分支节点


双亲节点或父节点:若一个节点含有子节点,则这个节点称为其子节点的父节点; 如上图:A是B
的父节点


孩子节点或子节点:一个节点含有的子树的根节点称为该节点的子节点; 如上图:B是A的孩子节


兄弟节点:具有相同父节点的节点互称为兄弟节点; 如上图:B、C是兄弟节点


树的度:一棵树中,最大的节点的度称为树的度; 如上图:树的度为6


节点的层次:从根开始定义起,根为第1层,根的子节点为第2层,以此类推;


树的高度或深度:树中节点的最大层次; 如上图:树的高度为4


节点的祖先:从根到该节点所经分支上的所有节点;如上图:A是所有节点的祖先


子孙:以某节点为根的子树中任一节点都称为该节点的子孙。如上图:所有节点都是A的子孙


森林:由m(m>0)棵互不相交的多颗树的集合称为森林;(数据结构中的学习并查集本质就是
一个森林)


一、二叉树是什么?(性质)

1.二叉树的概念

一棵二叉树是结点的一个有限集合,该集合或者为空,或者是由一个根节点加上两棵别称为左子
树和右子树的二叉树组成。
?

2.二叉树的特点:

1. 每个结点最多有两棵子树,即二叉树不存在度大于2的结点。
2. 二叉树的子树有左右之分,其子树的次序不能颠倒。

3.特殊的二叉树

3.1.满二叉树:一个二叉树,如果每一个层的结点数都达到最大值,则这个二叉树就是满二叉
树。也就是说,如果一个二叉树的层数为K,且结点总数是(2^k) -1 ,则它就是满二叉树。
3.2.完全二叉树:完全二叉树是效率很高的数据结构,完全二叉树是由满二叉树而引出来的。对
于深度为K的,有n个结点的二叉树,当且仅当其每一个结点都与深度为K的满二叉树中编号
从1至n的结点一一对应时称之为完全二叉树。 要注意的是满二叉树是一种特殊的完全二叉
树。

4.二叉树的性质

1. 若规定根节点的层数为1,则一棵非空二叉树的第i层上最多有2^(i-1) 个结点.
2. 若规定根节点的层数为1,则深度为h的二叉树的最大结点数是2^h- 1.
3. 对任何一棵二叉树, 如果度为0其叶结点个数为 n0, 度为2的分支结点个数为 n2,则有n0=n2
+1

4. 若规定根节点的层数为1,具有n个结点的满二叉树的深度,h=LogN

5.存储方式!!!

5.1顺序存储

顺序结构存储就是使用数组来存储,一般使用数组只适合表示完全二叉树,因为不是完全二叉树
会有空间的浪费。而现实中使用中只有堆才会使用数组来存储,二叉树顺序存储在物理上是一个数组,在逻辑上是一颗二叉树。

C语言实现堆?我写的另一篇博客~

5.2 链式存储

二叉树的链式存储结构是指,用链表来表示一棵二叉树,即用链来指示元素的逻辑关系。 通常的
方法是链表中每个结点由三个域组成,数据域和左右指针域,左右指针分别用来给出该结点左孩
子和右孩子所在的链结点的存储地址 。链式结构又分为二叉链和三叉链,当前我们学习中一般都
是二叉链,后面课程学到高阶数据结构如红黑树等会用到三叉链
?

二、基本概念题目讲解

Q1.树的概念问题

1.1 在用树表示的目录结构中,从根目录到任何数据文件,有( A)通道

题目内容:

A?.唯一一条? ??B?.二条? ? ?C?.三条? ? ? D?.不一定

解析树的特点是不相交,所以不可能有多个路径同时到达一个点。

1.2 下列关于树的叙述正确的是( D

A.树中可以有环

B.树的度是指所有结点中度最小的结点的度

C.树的深度指的是结点数最多的那一层的深度

D.树的根结点是所有结点的祖先结点

1.3?下列关于二叉树的叙述错误的是( A? )

A.二叉树指的是深度为 2 的树

B.一个 n 个结点的二叉树将拥有 n-1 条边

C.一颗深度为 h 的满二叉树拥有 2^h-1 个结点(根结点深度为1)

D.二叉树有二叉链和三叉链两种表示方式

Q2.求叶结点问题

2.1 已知度求未知度

在一颗度为3的树中,度为3的结点有2个,度为2的结点有1个,度为1的结点有2个,则叶子结点有(C)个

A?.4? ? B?.5? ?C?.6? ?D?.7

解析:1.画图求解 2.数学推算?

该树总共有n个节点,则n=n0+n1+n2+n3.?

有n个节点的树的总边数为n-1条.

根据度的定义,总边数与度之间的关系为:n-1=0*n0+1*n1+2*n2+3*n3.

联立两个方程求解,可以得到n0?= n2 + 2n3 + 1,??n0=6

2.2 特殊二叉树求叶节点个数

一颗完全二叉树有1001个结点,其叶子结点的个数是(C

A.251? ?B.500? ?C.501? ?D.不能确定

解析:设度为0,1,2的结点个数分别为n0,n1,n2。可知n0+n1+n2=1001?

由二叉树性质可知 n0=n2-1,完全二叉树度为1的结点个数非0即1!

∴ n0 + 0 + n2 = 2*n0-1 = 1001 ->? n0 = 501

Q3:深度问题

3.1特殊二叉树深度

有n个元素的完全二叉树的深度是( D?

A.nlogn? ?B.nlog(n+1)? ?C.logn? ?D.log(n+1)

完全二叉树深度==满二叉树深度 把该二叉树看作满二叉树 利用公式 2^{^{^{}}}的h次方-1=n ->h=log(n+1)

3.2?已知结点个数求深度范围

设根结点的深度为1,则一个拥有n个结点的二叉树的深度一定在(? A )区间内

A.[log(n + 1),n]

B.[logn,n]

C.[log(n + 1),n - 1]

D.[log(n + 1),n + 1]

最大深度: 即每次只有一个节点,次数二叉树的高度为n,为最高的高度

最小深度: 此树为完全二叉树, 如果是完全二叉树

根据二叉树性质,完全二叉树的高低为 h = log(n+1)向上取整


三、用递归实现树的函数

首先先初始化一棵二叉树

typedef char TreeDataType;
typedef struct Tree
{
	TreeDataType Data;
	struct Tree* Left;
	struct Tree* Right;
}tree;

tree* a = (tree*)malloc(sizeof(tree));
	a->Data = 'A';
	a->Left = NULL;
	a->Right = NULL;
	tree* b = (tree*)malloc(sizeof(tree));
	b->Data = 'B';
	b->Left = NULL;
	b->Right = NULL;
	tree* c = (tree*)malloc(sizeof(tree));
	c->Data = 'C';
	c->Left = NULL;
	c->Right = NULL;
	tree* d = (tree*)malloc(sizeof(tree));
	d->Data = 'D';
	d->Left = NULL;
	d->Right = NULL;
	tree* e = (tree*)malloc(sizeof(tree));
	e->Data = 'E';
	e->Left = NULL;
	e->Right = NULL;
	tree* f = (tree*)malloc(sizeof(tree));
	f->Data = 'F';
	f->Left = NULL;
	f->Right = NULL;
	a->Left = b;
	a->Right = c;
	b->Left = d;
	b->Right = e;
	c->Left = f;

1.树的遍历(打印存储的数据)

1.1 前序遍历

遵循先根结点,后左子树,右子树的顺序打印Data

上代码~


void preorder(tree* root)
{
    //为空返回
	if (root == NULL)
	{
		printf("NULL ");
		return;
	}
        //先打印根结点
		printf("%c ", root->Data);
        //后左子树
		preorder(root->Left);
        //最后右子树
		preorder(root->Right);
}

1.2 中序遍历

遵循先左子树 后根 最后右子树

void InfixOrder(tree* root)
{
	//为空返回
	if (root == NULL)
	{
		printf("NULL ");
		return;
	}
	//先左子树
	InfixOrder(root->Left);
	//后打印根
	printf("%c ", root->Data);
	//最后右子树
	InfixOrder(root->Right);

}

?1.3后序遍历

遵循先左子树 后右子树 最后根

void BehindOrder(tree* root)
{
	//为空返回
	if (root == NULL)
	{
		printf("NULL ");
		return;
	}
	//先左子树
	BehindOrder(root->Left);
	//后右子树
	BehindOrder(root->Right);
	//最后打印根
	printf("%c ", root->Data);

}

1.4 已知前序,中序或者已知中序、后序,写出树的前序遍历结果

已知某二叉树的中序遍历序列为JGDHKBAELIMCF,后序遍历序列为JGKHDBLMIEFCA,则其前序遍历序列为(B

A?.ABDGHJKCEFILM

B?.ABDGJHKCEILMF

C?.ABDHKGJCEILMF

D?.ABDGJHKCEIMLF

解析:由后序遍历确定子树的根,后序遍历从后向前看,最后一个元素为根,和前序遍历刚好相反,从后向前看后序遍历,应该是根,右,左,根据中序遍历确定子树的左右区间

故:根为: A

A的左子树:JGDHKB???????A的右子树:ELIMCF

A的左子树的根:B????????A的右子树的根:C

B的左子树:JGDHK??B的右子树:空??C的左子树:ELIM?C的右子树:F

B的左子树的根:D?????????C的左子树根:E

D的左子树的根:G D的右子树的根:H??E的右子树的根:I

故树的结构为:

1.5已知树前序遍历结果,求树右多少种结构

如果一颗二叉树的前序遍历的结果是ABCD,则满足条件的不同的二叉树有( B)种

A?.13? ?B?.14? ?C?.15? ?D?.16

解析:用定三移一法!先将ABC的位置确定,然后移动D的位置

1.6通过先序遍历结果构建一棵树,再中序遍历打印结点数据

二叉树遍历_牛客题霸_牛客网 (nowcoder.com)

题目:编一个程序,读入用户输入的一串先序遍历字符串,根据此字符串建立一个二叉树(以指针方式存储)。 例如如下的先序遍历字符串: ABC##DE#G##F### 其中“#”表示的是空格,空格字符代表空树。建立起此二叉树以后,再对二叉树进行中序遍历,输出遍历结果。

解析:通过数组我们拿到了字符串,那么我们可以利用递归的方式去构造这棵树。非'#'我们开辟结点存字符并递归其左右子树,遇到’#‘返回空,最后返回结点地址(这句话这个地址只有头结点返回有意义)

易错点:数组下标没调用一次函数,就必须++一次。答案中我们传参传的是i的地址,如果不传地址,后果就是当你先给左子树递归调用的完成的时候,虽然i++了,但是此时i是局部变量,返回时就销毁了,你再一次调用右子树的时候i依旧不变,下一个数据会覆盖前一个位置。

以"AB##C##"为例

#include<stdio.h>
#include<stdlib.h>
typedef struct BTNode
{
    struct BTNode*left;
    struct BTNode*right;
    char val;
}BTNode;
BTNode* CreatTree(int*a,int*pi)
{
    
    if(a[*pi]=='#')
    {
        (*pi)++;
        return NULL;
    }
    BTNode* newnode=(BTNode*)malloc(sizeof(BTNode));
    newnode->val=a[*pi];
    (*pi)++;
    newnode->left=CreatTree(a,pi);
    newnode->right=CreatTree(a, pi);
    return newnode;
}
void MiddleOrder(BTNode*root)
{
    if(root==NULL)
        return;
    MiddleOrder(root->left);
    printf("%c ",root->val);
    MiddleOrder(root->right);
}
int main()
{
    char arr[101];
    scanf("%s",arr);
    int i=0;
     BTNode*root=CreatTree(arr,&i);
     MiddleOrder(root);
    return 0;
}

2.求结点个数问题

2.1 求树结点个数

int NumTreeNode(tree* root)
{
    //遇空返回0
	if (root == NULL) {
		return 0;
	}
    // 左子树结点+右子树结点+本身
	return NumTreeNode(root->Left) + NumTreeNode(root->Right) + 1;
}

2.2 求叶节点个数

int LeafSize(tree* root)
{    
    //遇空返回0
	if (root==NULL) {
		return 0;
	}
    //左右都为空返回1,否则继续递归左右子树
	return root->Left || root->Right ? LeafSize(root->Left) + LeafSize(root->Right) : 1;
}

2.3 求第K层结点个数

int TreeLevelKSize(tree* root, int k)
{
	assert(k > 0);
	int level = 1;
	//未达到指定层,则继续左右子树向下递归
	if (level < k)
	{
		return TreeLevelKSize(root->Left, k-1)+ TreeLevelKSize(root->Right, k-1);
	}
	//达到指定层,非空返回1,为空返回0
	if (level == k)
	{
		if (root != NULL)
			return 1;
		else {
			return 0;
		}
	}
}

3.深度问题

3.1 求最大深度

int MaxDepth(tree* root)
{
	if (root==NULL) {
		return 0;
	}
	int Leftdepth = MaxDepth(root->Left);
	int Rightdepth = MaxDepth(root->Right);
	return Leftdepth > Rightdepth ? Leftdepth + 1 : Rightdepth + 1;
}

3.2 判断二叉树是否为平衡二叉树(一个二叉树每个节点?的左右两个子树的高度差的绝对值不超过 1

110. 平衡二叉树 - 力扣(LeetCode)

int Maxdepth(struct TreeNode* root)
{
    if(root==NULL)
    return 0;
    int leftdepth=Maxdepth(root->left);
    int rightdepth=Maxdepth(root->right);
    return leftdepth>rightdepth?leftdepth+1:rightdepth+1;
}
bool isBalanced(struct TreeNode* root){
     //遍历到空说明前面树都满足条件了,返回真
     if(root==NULL)
     return true;
    //判断每一个结点的左右子树最大深度相差是否满足条件,
    //有一个不满足返回false停止递归,满足继续递归
    int Leftdepth = Maxdepth(root->left);
	int Rightdepth = Maxdepth(root->right);
	return abs(Leftdepth - Rightdepth) < 2 &&
		   isBalanced(root->left) &&
		   isBalanced(root->right);
}

4.树的关系问题

4.1 翻转二叉树

226. 翻转二叉树 - 力扣(LeetCode)

题目:

struct TreeNode* invertTree(struct TreeNode* root){
//遇到空结点或者左右子树都为空,直接返回
if(root==NULL||(root->left==NULL&&root->right==NULL))
return root;
//交换
struct TreeNode* tmp=root->left;
root->left=root->right;
root->right=tmp;
//递归
invertTree(root->left);
invertTree(root->right);
//返回
return root;
}

4.2 检查两颗树是否相同

100. 相同的树 - 力扣(LeetCode)

题目:

bool isSameTree(struct TreeNode* p, struct TreeNode* q){
//都为空是真
if(p==NULL&&q==NULL)
return true;
//其中一个为空,另一个不为空或者都不为空却值不同为假
if(p==NULL||q==NULL||p->val!=q->val)
return false;
//递归左右子树 左右都为真返回真
return isSameTree(p->left,q->left)&&isSameTree(p->right,q->right);
}

4.3 判断树是否为对称二叉树

101. 对称二叉树 - 力扣(LeetCode)

思路:先翻转根的左子树,然后判断左右子树是否是相同的树?,这就结合了前两题!

//翻转左子树
void invertTree(struct TreeNode* root){
if(root==NULL||(root->left==NULL&&root->right==NULL))
return;
struct TreeNode* tmp=root->left;
root->left=root->right;
root->right=tmp;
invertTree(root->left);
invertTree(root->right);
}
//判断左右子树是否是相同的树
bool isSameTree(struct TreeNode* p, struct TreeNode* q){
if(p==NULL&&q==NULL)
return true;
if(p==NULL||q==NULL||p->val!=q->val)
return false;
return isSameTree(p->left,q->left)&&isSameTree(p->right,q->right);
}

bool isSymmetric(struct TreeNode* root){
invertTree(root->left);
return isSameTree(root->left,root->right);
}

4.4 判断一棵树子树是否与另一棵树相同

572. 另一棵树的子树 - 力扣(LeetCode)

题目:

//判断两棵树是否相同
bool isSameTree(struct TreeNode* p, struct TreeNode* q){
if(p==NULL&&q==NULL)
return true;
if(p==NULL||q==NULL||p->val!=q->val)
return false;
return isSameTree(p->left,q->left)&&isSameTree(p->right,q->right);
}

bool isSubtree(struct TreeNode* root, struct TreeNode* subRoot){
//找到最后说明之前都没有,返回假
if(root==NULL)
return false;
//判断两棵树是否相同,为真返回真
if(isSameTree(root,subRoot))
return true;
//只要找到了左右有一边找到了就可以返回真
return isSubtree(root->left,subRoot)||isSubtree(root->right,subRoot);

}


四、利用队列层序遍历树(栈和队列?我写的另一篇博客 讲解队列与栈)

1.层序遍历

void LevelOrderTraverse(tree* root)
{
	printf("层序遍历:");
    //定义并初始化队列
	Queue q;
	QueueInit(&q);
    //根入队列
	if (root) {
		QueuePush(&q, root);
	}
	while (!QueueEmpty(&q)) {//非空继续遍历
		QDataType Front= QueueFront(&q);//取队头
		printf("%c ", Front->Data);
		QueuePop(&q);//出队
		//判断子节点是否为空,非空入队
		if (Front->Left) {
			QueuePush(&q, Front->Left);
		}
		if (Front->Right) {
			QueuePush(&q,Front->Right);
		}
	}
	printf("\n");
	
}

?

2.利用层序遍历判断一棵树是否为完全二叉树

完全二叉树:完全二叉树是效率很高的数据结构,完全二叉树是由满二叉树而引出来的。对
于深度为K的,有n个结点的二叉树,当且仅当其每一个结点都与深度为K的满二叉树中编号
从1至n的结点一一对应时称之为完全二叉树。 要注意的是满二叉树是一种特殊的完全二叉
树。

?通过上图,我们如果把NULL加入到队列中,通过比对完全与非完全不同处,和非完全相同处,我们可以发现完全二叉树NULL后面不会再次出现字符!而非完全NULL后面一定会再次出现字符!

从而我们可以通过判断NULL后面是否出现字符来判断是否为完全二叉树!

此时有人可能会有一种问题?就是有没有可能就是上图中的D先出入了两个NULL,而没轮到F入从而导致后面才入F,NULL后面出现字符的情况?

答案是不可能的,因为层序遍历的特点是一层层的遍历,遍历一层的时候一定会把下一层的入队。所以D E 入队了,那么F 一定也会在B C这一层遍历完前入队的,不会遍历到D那一层还没入队。

bool BinaryTreeComplete(tree* root)
{
	assert(root);
    //1.建队列,初始化
	Queue q;
	QueueInit(&q);
    //2.入头节点
	if (root) {
		QueuePush(&q, root);
	}
    //3.队列不为空就继续出入,当遇到NULL停止循环
	while (!QueueEmpty(&q)) {
		QDataType Front = QueueFront(&q);//取队头
		if (Front == NULL)
		{
			break;
		}
		QueuePop(&q);//出队
		QueuePush(&q, Front->Left);
	    QueuePush(&q, Front->Right);

	}
   //4.判断NULL是否出现字符,出现则是非完,没有则是完全,记得销毁队列
	while (!QueueEmpty(&q))
	{
		QDataType Front = QueueFront(&q);
		if (Front != NULL)
		{
			QueueDestory(&q);
			return false;
		}
		QueuePop(&q);//出队
	}
	QueueDestory(&q);
	return true;
}

五、总结

? 以上是初阶二叉树的所有整理内容了。二叉树是数据结构比较难的一部分,需要我们静下心来去画图来明白递归问题。希望这篇文章来给你带来一些启发!如果你在阅读的过程中发现了什么问题,也希望您能不吝赐教!最后制作不易,希望大家给个三连~

?

  C++知识库 最新文章
【C++】友元、嵌套类、异常、RTTI、类型转换
通讯录的思路与实现(C语言)
C++PrimerPlus 第七章 函数-C++的编程模块(
Problem C: 算法9-9~9-12:平衡二叉树的基本
MSVC C++ UTF-8编程
C++进阶 多态原理
简单string类c++实现
我的年度总结
【C语言】以深厚地基筑伟岸高楼-基础篇(六
c语言常见错误合集
上一篇文章      下一篇文章      查看所有文章
加:2022-08-19 18:45:50  更:2022-08-19 18:48:11 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/23 13:38:13-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码