HIT-哈工大数据结构-作业5(C++)

文件说明

文件名数据生成.cpptest.cppBST.hBST.cpp
文件内容用于生成测试数据的程序折半查找和测试主程序BST类声明BST类实现

1.设计 BST 的左右链存储结构,并实现 BST 插入(建立)、删除、查找和排 序算法。

设计的BST类

#pragma once
#include<fstream>
using namespace std;
#include<string>
#define max 10000

typedef struct celltype {
	int data;
	celltype* lchild, * rchild;
}BSTNode;//存储结构
typedef BSTNode* BSTREE;
class BST {
public:
	BST(string filename);//输入文件名构建查找树
	int bst_insert(BSTREE &T,int k);//插入函数
	BSTREE bst_search(int k, int& len);//查找
	int delete_(BSTREE &BT);//辅助删除函数,用于处理继承节点
	void bst_delete(BSTREE& BT,int k);//删除函数
	void visit(BSTREE T);//访问节点函数
	void bst_sort(BSTREE BT);//排序,实质上就是中序遍历
	void search_cost();//计算平均查找长度查找,只适用于特定数据序列类型

public:
	BSTREE T;//二叉查找树
	double len_s;//平均查找成功次数
	double len_f;//平均查找失败长度
	int f_data[max];//用于保存文件输入流的数据
	int total;//总结点数
};

插入和建立:

BST::BST(string filename)//输入文件名构建查找树
{
	ifstream ifs(filename, ios::in);//以读方式打开图文件
	if (!ifs.is_open())
	{
		cout << "文件打开失败" << endl;
		return;
	}
	int num;//输入流承载体
	int i = 0;
	total = 0;
	while (ifs >> num) {//读取文件进数组
		f_data[i++] = num;
	}
	for (int j = 0; j < i; j++)
		bst_insert(T, f_data[j]);//逐个插入
}


int BST::bst_insert(BSTREE &BT,int k)//插入函数
{
	if (BT == NULL) {//根节点为空
		BT = new BSTNode;
		BT->data = k;
		BT->lchild = NULL;
		BT->rchild = NULL;
		total++;
		return 1;//创建成功,返回1
	}
	else if (k == BT->data)
		return 0;//存在相同关键字,插入失败
	else if (k < BT->data)//左小
		return bst_insert(BT->lchild, k);
	else//右大
		return bst_insert(BT->rchild, k);
}

查找

BSTREE BST::bst_search(int k, int& len)//查找
{

	BSTREE p = T;
	while (p) {
		len++;
		if (k == p->data) {
			cout<< "找到元素:" << p->data <<endl;
			return p;//找到直接返回
		}
		if (k > p->data)
			p = p->rchild;
		else
			p = p->lchild;
	}
	if (p == NULL)
		cout << "没找到该元素" <<k<< endl;
	return p;//查找失败返回空	
}

删除

int BST::delete_(BSTREE &BT)//辅助删除函数,用于处理继承节点
{//目的是找到中序遍历,ABC,用A中最后一个元素或C中第一个元素替换掉B
	int tmp;//这里是找到右边的最小节点
	if (BT->lchild == NULL) {//没有左子树,是最小的节点
		tmp = BT->data;
		BT = BT->rchild;//替换
		return tmp;
	}//T就是最小
	else return delete_(BT->lchild);//有左子树,一直往左下找
}//因为是多重递归,要用return才能返回值到最开始调用函数中

void BST::bst_delete(BSTREE& BT,int k)//删除函数
{
	if (BT != NULL) {
		if (k < BT->data)
			bst_delete(BT->lchild, k);//一直往下查找
		else if (k > BT->data)//不能直接用search,因为返回的是局部变量,如果返回引用的话,又会导致头节点变化
			bst_delete(BT->rchild, k);
		else//找到待删除节点
			if (BT->rchild == NULL) {//右子树为空
				cout << "成功删除元素:" << BT->data << endl;
				BT = BT->lchild;
				total--;
			}
			else if (BT->lchild == NULL) {//左子树为空
				cout << "成功删除元素:" << BT->data << endl;
				BT = BT->rchild;
				total--;
			}
			else {
				cout << "成功删除元素:" << BT->data << endl;
				BT->data = delete_(BT->rchild);
				total--;
			}
	}
}

排序

void BST::visit(BSTREE BT)//访问节点函数
{
	cout << BT->data << " ";
}

void BST::bst_sort(BSTREE BT)//排序,实质上就是中序遍历
{
	int i = 0;
	if (BT != NULL) {
		bst_sort(BT->lchild);
		visit(BT);
		bst_sort(BT->rchild);
	}
}

统计查找长度

void BST::search_cost()//只适用于特定数据序列类型
{
	int s = 0;//查找成功节点个数
	int sl = 0;//查找成功总长度
	int f = 0;//查找失败节点个数
	int fl = 0;//查找失败总长度
	for (int i = 0; i <= 2048; ++i) {
		if (i % 2) {//奇数
			s++;
			bst_search(i, sl);
		}
		else {
			f++;
			bst_search(i, fl);
		}
	}
	len_s = (double)sl / s;
	len_f = (double)fl / f;
	cout << "查找成功的平均查找长度为:" << len_s << endl;
	cout << "查找失败的平均查找长度为:" << len_f << endl;

}

建立、插入、查找、删除、排序:

使用数据:(生成源程序下面有)

img

测试代码:

int main(void) {
	//测试BST——————————————————
	BST T1("input1.txt");
	cout<<"初始总节点数为" << T1.total << endl;
	int len = 0;
	T1.bst_search(2047, len);//查2047
	T1.bst_delete(T1.T,5);//先删5
	cout << "删除5后总节点数为" << T1.total << endl;
	int i = 0;
	T1.bst_search(5,i);//再找5
	T1.bst_insert(T1.T, 4);//再插入4
	cout << T1.total << endl;
	cout << "插入4后总节点数为" << T1.total << endl;
	T1.bst_sort(T1.T);
	//T1.search_cost();
}

测试结果:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-23axrooo-1677332245602)(2022120067-刘虹志-作业5.assets/1.png)]

2.实现折半查找算法。

代码:

int Bin_Search(int a[], int n, int key, int& len) {//折半查找
	int low = 0, high = n, mid;//这里直接传入BST类中的f_data数组就行了
	while (low <= high) {
		mid = (low + high) / 2;
		len++;
		if (a[mid] == key)
			return mid;//返回数组下标
		else if (a[mid] > key)
			high = mid - 1;
		else
			low = mid + 1;
	}
	return -1;
}

**3.实验比较:设计并产生实验测试数据,考察比较两种查找方法的时间性能, 并与理论结果进行比较。以下具体做法可作为参考: **

(1) 第 1 组测试数据: n=1024 个已排序的整数序列(如 0 至 2048 之间 的奇数);第 2 组测试数据:第 1 组测试数据的随机序列。

生成测试数据:

#include<iostream>
#include<fstream>
#include<cstdlib>
#include <time.h>
using namespace std;
#define max 2048

//生成0到2048的奇数序列
int main() {
	ofstream ofs1("input1.txt");
	int data[max];
	int total = 0;
	for (int i = 0; i <= max; ++i) {
		if (i % 2) {//第一组。有序奇数序列
			data[total++] = i;
			ofs1 << i << " ";//用空格、制表符、或者换行来分割数据,方便输入流读取
		}
	}
	ofs1.close();
	//第二组。无序奇数序列,把data打乱再输出就行了
	ofstream ofs2("input2.txt");
	srand((int)time(NULL));//随机数种子
	for (int i = 0; i < total; i++) {
		int index = rand() % total;
		swap(data[i], data[index]);
	}
	while (total--) {
		ofs2 << data[total] << " ";
	}
	ofs2.close();
}

输出结果:

img

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-5scLLRdd-1677332245602)(2022120067-刘虹志-作业5.assets/IL%RVW92PBRB{CFR[0M94_W.png)]

**(2) 以上述两组测试数据作为输入,分别建立 BST 查找结构。 **

建立代码

	BST T1("input1.txt");
	BST T2("input2.txt");

文件存放位置

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-exVtMA9D-1677332245603)(2022120067-刘虹志-作业5.assets/图片1.png)]

**(3) 编写程序计算所建的两棵 BST 的查找成功和查找失败的平均查找长度(主要是改造 Search 算法,对“比较”进行计数),并与理论结 果比较。 **

n=1024 个已排序的整数序列测试代码;

	BST T1("input1.txt");
	T1.search_cost();

实验结果:

n=1024 个已排序的整数序列

实际结果为

查找成功的平均查找长度为:512.5
查找失败的平均查找长度为:512.999

与理论结果相符合

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ZpSqMkrK-1677332245603)(2022120067-刘虹志-作业5.assets/图片2.png)]

n=1024 个随机的整数序列测试代码;

	BST T2("input2.txt");
	T2.search_cost();

实验结果:

n=1024 个随机的整数序列

实际结果为

查找成功的平均查找长度为:11.8633
查找失败的平均查找长度为:12.8507

与理论结果相符合

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-YnqhBnc8-1677332245604)(2022120067-刘虹志-作业5.assets/[DW6%XYG}22C]EH4ZDQH7ST.png)]

(4) 分别以上述 BST 查找结构的中序遍历序列作为折半查找算法的输入,编写程序分别计算折半查找的查找成功和查找失败的平均查找长度,并与理论结果比较。

中序遍历测试代码:

	BST T1("input1.txt");
	cout <<endl<< "T1的中序序列" << endl;
	T1.bst_sort(T1.T);
	BST T2("input2.txt");
	cout << endl << "T2的中序序列" << endl;
	T2.bst_sort(T2.T);

结果:二者的中序序列完全相同

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-2w0qMpIm-1677332245604)(2022120067-刘虹志-作业5.assets/3.png)]

前面已经证明顺序和乱序整数序列的中序输出一样,这里就只用计算一次平均查找长度

折半查找计算长度代码;

	BST T1("input1.txt");
	int sl = 0;//查找成功总长度
	int s = 0;//查找成功元素个数
	int fl = 0;//查找失败总长度
	int f = 0;//查找失败元素个数
	for (int i = 0; i <= 2048; ++i) {
		if (i % 2) {//奇数
			s++;
			Bin_Search(T1.f_data, T1.total - 1, i, sl);
		}
		else {//偶数
			f++;
			Bin_Search(T1.f_data, T1.total - 1, i, fl);
		}
	}
	double len_s = (double)sl / s;
	double len_f = (double)fl / f;
	cout << "查找成功的平均查找长度为:" << len_s << endl;
	cout << "查找失败的平均查找长度为:" << len_f << endl;

折半查找结果:

实际结果

查找成功的平均查找长度为:9.01172
查找失败的平均查找长度为:10.002

与最好情况下的折半查找理论长度基本相同

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-mo7Zl9DF-1677332245604)(2022120067-刘虹志-作业5.assets/4.png)]

(5) 以上实验能否说明:就平均性能而言,BST 的查找与折半查找差不多,为什么?

在随机数组情况下,BST的平均查找长度和折半查找差不多,时间效率都为O(logn)。

在有序数组的情况下,BST可能会形成一颗很长的右斜树或者左斜树,这时的时间效率就就和随机情况下差距很大了。

ouble)sl / s;
double len_f = (double)fl / f;
cout << “查找成功的平均查找长度为:” << len_s << endl;
cout << “查找失败的平均查找长度为:” << len_f << endl;


折半查找结果:

实际结果

查找成功的平均查找长度为:9.01172
查找失败的平均查找长度为:10.002

与最好情况下的折半查找理论长度基本相同

[外链图片转存中...(img-mo7Zl9DF-1677332245604)]



**(5) 以上实验能否说明:就平均性能而言,BST 的查找与折半查找差不多,为什么?**

在随机数组情况下,BST的平均查找长度和折半查找差不多,时间效率都为O(logn)。

在有序数组的情况下,BST可能会形成一颗很长的右斜树或者左斜树,这时的时间效率就就和随机情况下差距很大了。

但是实际上有序数组很少出现,考虑大部分情况,可以认为平均性能上,BST的查找与折半查找差不多。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值