2021-6-20数据结构实验3预习

线性表,二叉排序树低频词过滤系统

一,内容要求:

  1. 对于一篇给定的英文文章,分别利用线性表和二叉排序树来实现单词频率的统计,实现低频词的过滤,并比较两种方法的效率。具体要求如下:2. 读取英文文章文件(Infile.txt),识别其中的单词。3. 分别利用线性表和二叉排序树构建单词的存储结构。当识别出一个单词后,若线性表或者二叉排序树中没有该单词,则在适当的位置上添加该单词;若该单词已经被识别,则增加其出现的频率。4. 统计结束后,删除出现频率低于五次的单词,并显示该单词和其出现频率。5. 其余单词及其出现频率按照从高到低的次序输出到文件中(Outfile.txt),同时输出用两种方法完成该工作所用的时间。计算查找表的ASL值,分析比较两种方法的效率。

二,部分主要代码:
线性表:
1,读取英文文章文件(Infile.txt),识别其中的单词:

SeqList<Cha> t;
f.open("Infile.txt", ios::in);
 if (!f) {
  cout << "不存在文件Infile.txt" << endl;
 }
 else {
  cout << "存在文件Infile.txt" << endl;
  while (f.peek()!= EOF) {
   f >>tem.name;
   t.Insert(1, tem);
  }
 }
 f.close(); 

2,利用线性表和二叉排序树构建单词的存储结构。当识别出一个单词后,若线性表或者二叉排序树中没有该单词,则在适当的位置上添加该单词;若该单词已经被识别,则增加其出现的频率。

SeqList<Cha> s;//定义顺序表对象;
SeqList<Cha> t;//中转
for (int i = 0; i < t.GetLength(); ++i) {
      tem = t.Get(i + 1);
      s.Insert1(1, tem);//把tem插入位置一
     }
 PrintList(s);

3,删除出现频率低于五次的单词,并显示该单词和其出现频率。

for (int i = 0; i < s.GetLength(); ++i) {//先遍历
      cout << s.GetLength() << endl;
      tem = s.Get(i + 1);
      if (tem.fq < 5) {
       cout << "被删:" << endl;
       PrintSd(s.Get(i + 1));
       s.Delete(i + 1);
       i--;//!!!!!!删了这位置数据,后面所有数据会前移动,如果让i++,会跳过新移到这位置的数据;
      }
     }

4,其余单词及其出现频率按照从高到低的次序输出到文件中(Outfile.txt),同时输出用两种方法完成该工作所用的时间。

clock_t start, finish;
     start = clock();
     s.QuickSort(0, s.GetLength() - 1);
     ofstream g("Outfile.txt");
     if (!g) {
      cout << "不能打开文件Outfile.txt" << endl;
      exit(1);
     }
     int i = 1;
     int len = s.GetLength();
     if (len >= 2) {
      while (i <= len - 1) {
       tem = s.Get(i);
       g << tem.name << " ";//单词之间的间隔;
       ++i;
      }
      tem = s.Get(i);
      g << tem.name;
     }
     else {
      if (len == 1) {
       tem = s.Get(1);
       g << tem.name;      }
      else {
       cout << "无记录" << endl;
      }
     }
     g.close();
     cout << "保存完毕" << endl;
     finish = clock();
     cout << finish - start << "/" << CLOCKS_PER_SEC << " (s) " << endl;

5,计算查找表的ASL值。

template < class T >
void SeqList<T>::Asl() {
 double tem;
 tem = (length + 1) / 2;
 cout << "若查找成功,ASL=" <<tem<< endl;
 tem = length;
 cout << "若查找不成功,ASL=" << tem << endl;
}

二叉排序树:
1,读取英文文章文件(Infile.txt),识别其中的单词:

SeqList<Cha> t;
f.open("Infile.txt", ios::in);
 if (!f) {
  cout << "不存在文件Infile.txt" << endl;
 }
 else {
  cout << "存在文件Infile.txt" << endl;
  while (f.peek()!= EOF) {
   f >>tem.name;
   t.Insert(1, tem);
  }
 }
 f.close(); 

2,利用线性表和二叉排序树构建单词的存储结构。当识别出一个单词后,若线性表或者二叉排序树中没有该单词,则在适当的位置上添加该单词;若该单词已经被识别,则增加其出现的频率。

 BSTree<Cha> bst1(t);//中转
 bst = bst1;
 bst.Cout();

template < class T >
BSTNode* BSTree<T>::Insert(BSTNode* root, BSTNode* s) {//二叉排序树递归插入函数
 if (root ==NULL) return s;//递归停止条件
 else {
  if (s->cha.fq < root->cha.fq) {//寻找合适的位置
   root->lchild = Insert(root->lchild, s);  }
  else {
   root->rchild = Insert(root->rchild, s);
  }
 }
 return root;
}template < class T >
BSTree<T>::BSTree(SeqList<T> sq) {//二叉排序树带参构造函数
 root = NULL;
 for (int i = 0; i < sq.GetLength(); ++i) {//遍历线性表
  BSTNode* s = new BSTNode;//s为插入的结点
  s->cha = sq.Get(i + 1);
  s->lchild = NULL;
  s->rchild = NULL;
  root = Insert(root, s);
 }
}

3,统计结束后,删除出现频率低于五次的单词,并显示该单词和其出现频率。

template < class T >
void BSTree<T>::Release(BSTNode* root) {
 if (root == NULL) {
  return;
 }
 Release(root->lchild);
 Release(root->rchild);
 delete root;
}
template < class T >void BSTree<T>::Cout(){
 cout << "单词名       频率" << endl;
 cout << "----------------------------" << endl;
 Inorder(Getroot());
 cout << "----------------------------" << endl;}

template < class T >
void BSTree<T>::Inorder(BSTNode* root) {
 if (root == NULL) {
  return;
 }
 Inorder(root->lchild);
 cout << root->cha.name << setw(9) << root->cha.fq << endl;
 Inorder(root->rchild);
}

4,其余单词及其出现频率按照从高到低的次序输出到文件中(Outfile.txt),同时输出用两种方法完成该工作所用的时间。

clock_t start, finish;
 start = clock();
     
 bst.outfile2(bst.Getroot());

 cout << "保存完毕" << endl;
 finish = clock();
 cout << finish - start << "/" << CLOCKS_PER_SEC << " (s) " << endl;

5,计算查找表的ASL值

template < class T >
void BSTree<T>::Asl() {
	BSTNode* t = this->Getroot();
	if (t == NULL)return;

	queue<BSTNode*> a;//暂时存需拓展的树根结点
	queue<BSTNode*> parent;//暂时存已经拓展的结点
	BSTNode* p;
	int n = 0; //所有元素个数
	int m = 0; //所有补上的叶结点数
	int i = 1;//树的层数
	int  w[10] = { 0 };//每层元素个数
	int r[10] = { 0 };//每层补上的叶结点数
	int fu[10] = { 0 };//每层父节点(已经拓展的结点)数量,辅助清parent队列
	int flag = 1;


	a.push(t);
	while (!a.empty())
	{
		p = a.front();
		a.pop();//删第一个

		if (p->rchild == NULL || p->lchild == NULL) {
			r[i]++;//每层补上的叶结点数
			m++;
		}

		w[i]++;   //每层元素个数
		n++;      //结点个数
		if (a.empty())
		{
			if (flag == 1) {//只用一次的换行,给第一层用
				i++;
				flag++;
			}
			//if (p->lchild == NULL && p->rchild == NULL)break;//跳出while循环;
		}

		if (p->lchild != NULL || p->rchild != NULL)
		{
			if (p->lchild != NULL)a.push(p->lchild);
			if (p->rchild != NULL)a.push(p->rchild);
			parent.push(p);
			if (fu[1] == 0)
				fu[1] = 1;//根节点
			else
				fu[i]++; //父节点数量
		}
		//一层结束,父节点队列出队,清parent
		//左节点不为空,右节点为空,  且p等于左节点
		if ((parent.front()->lchild != NULL) && p == parent.front()->lchild)
		{
			for (int j = 0; j < fu[i]; j++)
				parent.pop();
			i++;//一层结束
		}
		//右节点不为空,左节点为空,  且p等于右节点
		else if ((parent.front()->rchild != NULL) && p == parent.front()->rchild)
		{
			for (int j = 0; j < fu[i]; j++)
				parent.pop();
			i++;//一层结束
		}
	}


	int s = 0, z = 0;
	for (int j = 0; j <= i; j++)//共i+1层
	{
		s += j * w[j];//所有(层元素个数*层数)的总数
		z += j * r[j];// 所有(层补上的叶结点数* 层数)的总数

	}
	cout << "查找成功时的平均检索长度(ASL)=" << endl;
	cout << s << '/' << n << endl;
	cout << "查找失败时的平均检索长度(ASL)=" << endl;
	cout << z << '/' << m << endl;

}

三,效果截图
在这里插入图片描述

Infile.txt:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述排好的outfile.txt

在这里插入图片描述

二叉排序树同理
在这里插入图片描述
四,总结:
完整代码由一个单词结构体Cha,一个顺序表,一个二叉树结点结构体BSTNode,一个二叉排序树类BSTree组成和主函数。
主函数中注意switch的case的break不要漏,不然无法返回上一级菜单;顺序表的删除注意不要漏掉遍历的元素,因为每删除一个,后面的元素都会变一次位置。用文件流读入数据时注意最后不要留空行,不然最后一个元素会被读取两次,解决:重新搞一个txt文件读取。

完整代码:

#include<iostream>
#include<string>
#include<fstream>
#include<iomanip>
#include<ctime>
#include<queue>
#include<vector>
#define MaxSize 100
using namespace std;


typedef struct {
	string name; //单词名
	double fq;     //对应频率
}Cha;
vector<Cha> v(0);//存放要输出到文件的数据;

typedef struct BiNode {
	Cha cha;
	struct BiNode* lchild, * rchild;
} BSTNode;


template < class T >
class SeqList
{
public:
	SeqList() { length = 0; }       //无参构造函数
	SeqList(T a[], int n);       //有参构造函数
	~SeqList();             //析构函数为空
	int Search(string x);//名字查找
	void Insert(int i, T x);  //在顺序表中第i个位置插入值为x的元素(i为逻辑号)
	void Insert1(int i, T x);
	void Delete(int i);//删除顺序表的第i个元素(i为逻辑号)
	void QuickSort(int low, int high);//降序排列
	void Asl();//ASL
	int GetLength() { return length; }  //求顺序表的长度
	T Get(int i);  //取顺序表的第i个元素(i为逻辑号)

private:
	T data[MaxSize];      //存放数据的数组
	int length;            //顺序表的长度
};

template < class T >
SeqList<T>::SeqList(T a[], int n) { //有参构造函数
	if (n > MaxSize) cout << "参数错误" << endl;
	for (int i = 0; i < n; ++i) {
		data[i] = a[i];
	}
	length = n;//初始化
}

template < class T >
int SeqList<T>::Search(string x) {
	for (int i = 0; i < length; ++i) {
		if (data[i].name == x) {
			data[i].fq++;
			return 1;
		}
	}
	return 0;
}

template < class T >
void SeqList<T>::Insert(int i, T x) {//i为逻辑号
	cout << x.name << endl;
	if (Search(x.name)) {
		return;
	}
	else {
		if (length >= MaxSize) cout << "上溢" << endl;
		if (i > length + 1) cout << "位置错误" << endl;
		for (int j = length; j >= i; --j) {  //遍历调整元素位置; 
			data[j] = data[j - 1];
		}
		data[i - 1].fq = 1;
		data[i - 1].name = x.name;//同时改变length
		++length;
	}
}

template < class T >
void SeqList<T>::Insert1(int i, T x) {
	if (length >= MaxSize) cout << "上溢" << endl;
	if (i<1 || i>length + 1) cout << "位置错误" << endl;
	for (int j = length; j >= i; --j) {  //遍历调整元素位置; 
		data[j] = data[j - 1];
	}
	data[i - 1] = x;//同时改变length
	++length;
}


template < class T >
void SeqList<T>::Delete(int i) {
	if (length == 0) cout << "下溢" << endl;
	if (i<1 || i>length) cout << "位置错误" << endl;
	T x = data[i - 1];
	for (int j = i; j < length; ++j) {
		data[j - 1] = data[j]; //删除的元素后的元素全部前移动一位,以达到删除的目的; 
	}
	--length;//同时改变length
	return;
}


template < class T >
void PrintList(SeqList<T> d) { //全部输出; 

	cout << "       单词数: " << d.GetLength() << endl;

	if (d.GetLength() > 0) {//有则输出
		cout << "单词名       频率" << endl;
		cout << "----------------------------" << endl;
		for (int i = 1; i <= d.GetLength(); ++i) {
			Cha s = d.Get(i);
			cout << s.name << setw(9) << s.fq << endl;
		}
		cout << "----------------------------" << endl;
	}
	else {//无
		cout << "无记录" << endl;
	}
}


template < class T >
void PrintSd(T s) {  //输出指定位置元素; 
	cout << "单词名       频率" << endl;
	cout << "----------------------------" << endl;
	cout << s.name << setw(9) << s.fq << endl;
	cout << "----------------------------" << endl;
}



template < class T >
void SeqList<T>::QuickSort(int low, int high) {
	if (low < high)  //递归终止条件
	{

		int i = low, j = high;

		T x = data[low];

		while (i < j) {

			while (i < j && data[j].fq <= x.fq) j--;  //先从右边开始

			if (i < j) data[i++] = data[j];

			while (i < j && data[i].fq >= x.fq) i++;

			if (i < j) data[j--] = data[i];

		}
		data[i] = x;  //i已经排列好

		QuickSort(low, i - 1);//递归  
		QuickSort(i + 1, high);
	}
}

template < class T >
void SeqList<T>::Asl() {
	double tem;
	tem = (length + 1) / 2;
	cout << "若查找成功,ASL=" << tem << endl;
	tem = length;
	cout << "若查找不成功,ASL=" << tem << endl;
}

template < class T >
T SeqList<T>::Get(int i) { //取顺序表的第i个元素
	if (i > 0 && i <= length) //保证i不会引起数组overflow; 
		return data[i - 1];

}

template < class T >
SeqList<T>::~SeqList() {

}






template < class T >
class BSTree {
public:
	BSTree() { root = NULL; };
	BSTree(SeqList<T> sq);//二叉排序树带参构造函数
	~BSTree() {}
	void Release(BSTNode* root);//释放root为根的树
	BSTNode* Getroot() { return root; }
	BSTNode* Insert(BSTNode* root, BSTNode* s);//二叉排序树递归插入函数
	void Inorder(BSTNode* root);//中序遍历
	void Cout();//输出
	void Asl();//求Asl()
	void outfile2(BSTNode* root);//输出到文件并输出执行时间
private:
	BSTNode* root;

};

template < class T >
BSTNode* BSTree<T>::Insert(BSTNode* root, BSTNode* s) {//二叉排序树递归插入函数
	s->lchild = NULL;
	s->rchild = NULL;
	if (root == NULL) return s;//递归停止条件
	else {
		if (s->cha.fq < root->cha.fq) {//寻找合适的位置
			root->lchild = Insert(root->lchild, s);
		}
		else {
			root->rchild = Insert(root->rchild, s);
		}
	}
	return root;
}


template < class T >
BSTree<T>::BSTree(SeqList<T> sq) {//二叉排序树带参构造函数
	root = NULL;
	for (int i = 0; i < sq.GetLength(); ++i) {//遍历线性表
		BSTNode* s = new BSTNode;//s为插入的结点
		s->cha = sq.Get(i + 1);
		s->lchild = NULL;
		s->rchild = NULL;
		root = Insert(root, s);
	}
}


template < class T >
void BSTree<T>::Release(BSTNode* root) {//释放root为根的树
	if (root == NULL) {
		return;
	}
	Release(root->lchild);
	Release(root->rchild);
	delete root;
	root == NULL;
}
template < class T >
void BSTree<T>::Inorder(BSTNode* root) {//中序遍历
	if (root == NULL) {
		return;
	}
	Inorder(root->lchild);
	v.push_back(root->cha);
	cout << root->cha.name << setw(9) << root->cha.fq << endl;
	Inorder(root->rchild);
}

template < class T >
void BSTree<T>::outfile2(BSTNode* root) {//输出到文件并输出执行时间
	if (root == NULL)return;
	ofstream g("Outfile.txt");


	if (!g) {
		cout << "不能打开文件Outfile.txt" << endl;
		exit(1);
	}
	v.clear();
	this->Inorder(root);
	reverse(v.begin(), v.end());
	for (int i = 0; i < v.size(); ++i) {
		g << v[i].name << " ";//单词之间的间隔;

	}


	g.close();
	cout << "保存完毕" << endl;
}

template < class T >

void BSTree<T>::Cout() {
	cout << "单词名       频率" << endl;
	cout << "----------------------------" << endl;
	Inorder(Getroot());
	cout << "----------------------------" << endl;

}

template < class T >
void BSTree<T>::Asl() {
	BSTNode* t = this->Getroot();
	if (t == NULL)return;

	queue<BSTNode*> a;//暂时存需拓展的树根结点
	queue<BSTNode*> parent;//暂时存已经拓展的结点
	BSTNode* p;
	int n = 0; //所有元素个数
	int m = 0; //所有补上的叶结点数
	int i = 1;//树的层数
	int  w[10] = { 0 };//每层元素个数
	int r[10] = { 0 };//每层补上的叶结点数
	int fu[10] = { 0 };//每层父节点(已经拓展的结点)数量,辅助清parent队列
	int flag = 1;


	a.push(t);
	while (!a.empty())
	{
		p = a.front();
		a.pop();//删第一个

		if (p->rchild == NULL || p->lchild == NULL) {
			r[i]++;//每层补上的叶结点数
			m++;
		}

		w[i]++;   //每层元素个数
		n++;      //结点个数
		if (a.empty())
		{
			if (flag == 1) {//只用一次的换行,给第一层用
				i++;
				flag++;
			}
			//if (p->lchild == NULL && p->rchild == NULL)break;//跳出while循环;
		}

		if (p->lchild != NULL || p->rchild != NULL)
		{
			if (p->lchild != NULL)a.push(p->lchild);
			if (p->rchild != NULL)a.push(p->rchild);
			parent.push(p);
			if (fu[1] == 0)
				fu[1] = 1;//根节点
			else
				fu[i]++; //父节点数量
		}
		//一层结束,父节点队列出队,清parent
		//左节点不为空,右节点为空,  且p等于左节点
		if ((parent.front()->lchild != NULL) && p == parent.front()->lchild)
		{
			for (int j = 0; j < fu[i]; j++)
				parent.pop();
			i++;//一层结束
		}
		//右节点不为空,左节点为空,  且p等于右节点
		else if ((parent.front()->rchild != NULL) && p == parent.front()->rchild)
		{
			for (int j = 0; j < fu[i]; j++)
				parent.pop();
			i++;//一层结束
		}
	}


	int s = 0, z = 0;
	for (int j = 0; j <= i; j++)//共i+1层
	{
		s += j * w[j];//所有(层元素个数*层数)的总数
		z += j * r[j];// 所有(层补上的叶结点数* 层数)的总数

	}
	cout << "查找成功时的平均检索长度(ASL)=" << endl;
	cout << s << '/' << n << endl;
	cout << "查找失败时的平均检索长度(ASL)=" << endl;
	cout << z << '/' << m << endl;

}



int main() {
	ifstream f;//调用外部文件用;
	int w;//键盘输入的数据位置;
	int op, sw; //switch选case的凭依; 
	Cha tem; // 辅助SeqList<Sd> s的函数Insert()使用; 
	SeqList<Cha> s;//定义顺序表对象;
	SeqList<Cha> t;//中转
	BSTree<Cha> bst;
	string na;//辅助输入名字;
	int whil = 1;
	int whi = 1; //菜单进入和跳出的条件;
	int wh = 1;//菜单case1循环输入;

	f.open("Infile.txt", ios::in);
	if (!f) {
		cout << "不存在文件Infile.txt" << endl;
	}
	else {
		cout << "存在文件Infile.txt" << endl;
		while (f.peek() != EOF) {
			f >> tem.name;
			t.Insert(1, tem);
		}
	}
	f.close();

	while (whil) {
		whi = 1;//重置;
		cout << "     主菜单      " << endl;
		cout << "     1.顺序表" << endl;
		cout << "     2.二叉排列树" << endl;
		cout << "     3.退出" << endl;
		cout << "     输入(1~3)         " << endl;
		cin >> sw;
		switch (sw) {
		case 1:
			while (whi) {
				cout << "     主菜单      " << endl;
				cout << "     1.识别并统计单词" << endl;
				cout << "     2.删除显示低频单词" << endl;
				cout << "     3.输出所有单词" << endl;
				cout << "     4.计算输出ASL" << endl;
				cout << "     5.输出输出到文件的执行时间" << endl;
				cout << "     6.返回" << endl;
				cout << "     输入(1~6)         " << endl;
				cin >> op;
				switch (op) {
				case 1:
					for (int i = 0; i < t.GetLength(); ++i) {
						tem = t.Get(i + 1);
						s.Insert1(1, tem);//把tem插入位置一
					}
					PrintList(s);
					break;
				case 2:
					for (int i = 0; i < s.GetLength(); ++i) {//先遍历
						cout << s.GetLength() << endl;
						tem = s.Get(i + 1);
						if (tem.fq < 5) {
							cout << "被删:" << endl;
							PrintSd(s.Get(i + 1));
							s.Delete(i + 1);
							i--;//!!!!!!删了这位置数据,后面所有数据会前移动,如果让i++,会跳过新移到这位置的数据;
						}
					}

					break;
				case 3:
					PrintList(s);
					break;
				case 4:
					s.Asl();
					break;
				case 5: {
					clock_t start, finish;
					start = clock();
					s.QuickSort(0, s.GetLength() - 1);
					ofstream g("Outfile.txt");
					if (!g) {
						cout << "不能打开文件Outfile.txt" << endl;
						exit(1);
					}
					int i = 1;
					int len = s.GetLength();
					if (len >= 2) {
						while (i <= len - 1) {
							tem = s.Get(i);
							g << tem.name << " ";//单词之间的间隔;
							++i;
						}
						tem = s.Get(i);
						g << tem.name;
					}
					else {
						if (len == 1) {
							tem = s.Get(1);
							g << tem.name;

						}
						else {
							cout << "无记录" << endl;
						}
					}
					g.close();
					cout << "保存完毕" << endl;
					finish = clock();
					cout << finish - start << "/" << CLOCKS_PER_SEC << " (s) " << endl;
					break;
				}
				case 6:
					whi = 0;
					break;
				default:continue;
				}
			}
			break;
		case 2:
			while (whi) {
				cout << "     主菜单      " << endl;
				cout << "     1.识别并统计单词" << endl;
				cout << "     2.删除显示低频单词" << endl;
				cout << "     3.输出所有单词" << endl;
				cout << "     4.计算输出ASL" << endl;
				cout << "     5.输出输出到文件的执行时间" << endl;
				cout << "     6.返回" << endl;
				cout << "     输入(1~6)         " << endl;
				cin >> op;
				switch (op) {
				case 1: {
					BSTree<Cha> bst1(t);//中转
					bst = bst1;
					bst.Cout();
					break;
				}
				case 2: {
					s = t;
					for (int i = 0; i < s.GetLength(); ++i) {//先遍历
						cout << s.GetLength() << endl;
						tem = s.Get(i + 1);
						if (tem.fq < 5) {
							cout << "被删:" << endl;
							PrintSd(s.Get(i + 1));
							s.Delete(i + 1);
							i--;//!!!!!!删了这位置数据,后面所有数据会前移动,如果让i++,会跳过新移到这位置的数据;
						}
					}
					BSTree<Cha> bst1(s);
					bst = bst1;
					break;
				}

				case 3:
					bst.Cout();
					break;
				case 4:
					bst.Asl();
					break;
				case 5: {
					clock_t start, finish;
					start = clock();
					bst.outfile2(bst.Getroot());
					finish = clock();
					cout << finish - start << "/" << CLOCKS_PER_SEC << " (s) " << endl;
					break;
				}
				case 6:
					whi = 0;
					break;
				default:continue;
				}
			}
			break;//!!!!!!不可无,不然无法返回上一级目录;
		case 3:
			whil = 0;
			break;
		default: continue;

		}

	}
	bst.Release(bst.Getroot());//人为析构,自己析构的话case 1构建了,然后又析构了,别的case用不了;
	return 0;
}

  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值