大二下小学期《数据结构》课程设计报告1

题目一: 基本查找算法比较
1) 对以下 3 种基本的查找算法的性能进行比较:顺序查找,二叉查找树,哈希。算法
包含两步:第一步:从文件中读取数据建查找表;第二步从文件中读取查找关键字
静态查找。
2) 待查找记录的个数不小于 n ( n<=1000000),关键字key 互不相同,取值范围0-109;
查询操作的次数为m(m=100000),每次查询的关键字随机生成,取值范围0-109.
3) 比较的指标为关键字的比较次数(包含建立查找表和查找操作)、内存空间和实际
运行时间。至少用5 组不同的数据作比较,至少包含完全正序(n=10000)、完全逆
序(n=10000)及随机(n=10000、100000,1000000)情况。
4) 为提高比较的可信度,待查找数据和查询关键字数据的生成及排序等预处理要设计
成一个独立功能,并将结果数据保留在data.in 文件中,格式如下:第1 行,用空
格分隔的两个非负整数,分别表示n 和m;接下来的n 行,每行一个非负整数,表
示待查询数据;接下来的m 行,每行一个非负整数,表示查询的关键字。
5) 每次查询都输出到结果文件 data.out 中,一共m 行。每行包含对应的查询关键字的
查询结果。查询结果:成功输出“Yes”, 不成功输出“No”。
6) 哈希的散列函数建议使用 key mod P,P 是大于n 的质数,注意内存限制;冲突
消解建议使用简单的线性探查法。当然,有能力的同学可以自己设计哈希函数,使
用统计结果较好的冲突消解方法,如平方探测法。

7) 对结果作简单分析,包括对各组数据得出结果波动大小的解释。



我的解答:

由题目分析得,设计2个程序,其中一个来产生随机数据和key,另外一个程序用来进行对数据的分析。由于rand()函数只能产生0~32767之间的随机数,但是题目要求随机数的范围会很大,怎么才能生成很大的随机数,又不破坏均匀性?我采用的方法是按位随机,每次产生0~9之间的随机数,做为9位数的其中一位,然后生成9次,组合起来就是一个9位的随机数。

对于线性分析,在全局定义一个很大的数组,每次程序将数据读入到数组中,用一个2重循环进行分析。对于二叉树查找,首先构造二叉排序树,然后在对每个key进行查找。对于哈希算法,我才用拉链法,取质数10007进行哈希。

如何得到每种方法的比较次数?我才用设置全局量(long long ),在3种方法的查询函数中,在有比较的时候,全局量自加一,然后在屏幕上输出程序运行完成后的各个次数,对其进行分析。

//============================================================================
// Name        : creat_rand.cpp
// Author      : menglei
// Version     : 2013.8.13  20:19
// Copyright   : Your copyright notice
// Description : 此程序产生5组随机的数据
//============================================================================

#include <iostream>
#include <fstream>
using namespace std;


int min_rand(){
	//返回一个0到9的随机数

	//srand((unsigned)time(NULL));
	return rand()%10;
}
int myRand(int bit){
	//hit表示多少位,返回一个在int范围内bit位的一个随机数
	int randdata = 0;
	while(bit--){
		randdata = 10*randdata +min_rand();
	}
	return randdata;
}

int main() {
	/*如何产生一个很大范围的随机数?
	 *采用按位结合法和丢弃法结合
	 *每位随机0到9,---按位结合
	 超过范围的数字就丢弃掉----丢弃法
	*/
	ofstream fout1("data1_in.txt");
	fout1<<"10000"<<" "<<"100000"<<endl;
	//有序的10000个数字,前面的表示n和m
	for(int i=0;i<10000;i++){
		fout1<<i<<endl;
	}
	//产生100000个key
	for(int i=0;i<100000;i++){
		fout1<<myRand(9)<<endl;
	}
	fout1.close();
	cout<<"finish_data1_in.txt"<<endl;

	ofstream fout2("data2_in.txt");//逆序
	fout2<<"10000"<<" "<<"100000"<<endl;
	for(int i=10000;i>0;i--){
		fout2<<i<<endl;
	}
	for(int i=0;i<100000;i++){
		fout2<<myRand(9)<<endl;
	}
	fout2.close();
	cout<<"finish_data2_in.txt"<<endl;

	ofstream fout3("data3_in.txt");//随机10000三种
	fout3<<"10000"<<" "<<"100000"<<endl;
	for(int i=0;i<10000;i++){
		fout3<<myRand(9)<<endl;
	}
	for(int i=0;i<100000;i++){
		fout3<<myRand(9)<<endl;
	}
	fout3.close();
	cout<<"finish_data3_in.txt"<<endl;

	ofstream fout4("data4_in.txt");//随机100000三种
	fout4<<"100000"<<" "<<"100000"<<endl;
	for(int i=0;i<100000;i++){
		fout4<<myRand(9)<<endl;
	}
	for(int i=0;i<100000;i++){
		fout4<<myRand(9)<<endl;
	}
	fout4.close();
	cout<<"finish_data4_in.txt"<<endl;

	ofstream fout5("data5_in.txt");//随机1000000三种
	fout5<<"1000000"<<" "<<"100000"<<endl;
	for(int i=0;i<1000000;i++){
		fout5<<myRand(9)<<endl;
	}
	for(int i=0;i<100000;i++){
		fout5<<myRand(9)<<endl;
	}
	fout5.close();
	cout<<"finish_data5_in.txt"<<endl;

	return 0;
}


//============================================================================
// Name        : temp1.cpp
// Author      : menglei
// Version     :
// Copyright   : Your copyright notice
// Description : 数据的分析
//============================================================================
#include <iostream>
#include <fstream>
#include <cstdlib>
using namespace std;

class node{
public:
	node(int value):value(value),left(NULL),right(NULL){};//构造函数
	node(){right = NULL;left =NULL;value = -1;}
	node*getleft(){return left;}
	node*getright(){return right;}
	int getvalue(){return value;}
	void setvalue(int t){value = t;}
	void setleft(node * l){left = l;}
	void setright(node * r){right = r;}
	node *right;
	node *left;
	int value;
};

class searchTree{
public:
	searchTree(int i){init(i);}
	void init(int);
	void deleteTree(node*);
	void insert (node * ,int);
	bool find(node *,int,long long & );
	node getRoot(){return root;}
	void midOder(node *);

private:
	node root;
};

void searchTree::init(int a){
	root.left = NULL;
	root.right = NULL;
	root.value = a;
}
void searchTree::deleteTree(node * a){
	if(a != NULL){
		deleteTree(a->getleft());
		deleteTree(a->getright());
		delete a;
	}
}
void searchTree::insert(node *n,int i){
	node * pointer = NULL;
	if(n == NULL){init(i);return ;}
	else pointer = n;
	while(1){
		if(pointer->getvalue() == i) return ;//要插入的节点value和根节点的value相同则返回
		else if(pointer->getvalue() >i){
			if(pointer->getleft() == NULL){ //左侧无节点了,插入
				pointer->left = new node(i);
				return ;
			}else
				pointer = pointer->left;
		}
		else
		{
			if(pointer->getright() == NULL){
				pointer->right = new node(i);
				return;
			}else
				pointer = pointer->right;
		}
	}
}
void searchTree::midOder(node *t){
	if(t != NULL){

		midOder(t->getleft());
		cout<<t->getvalue()<<" ";
		midOder(t->getright());
	}
}
bool searchTree::find(node *t,int v,long long &y){
	//find node value equal to 'v' in tree whose root named 't'

	if(t == NULL){y++;return false; }
	if(t->getvalue() == v){y++; return true;}
	if(t->getvalue() > v){
		y++;
		return find(t->left,v,y);}
	if(t->getvalue() < v){
		y++;
		return find(t->right, v,y);}
}

int data_array[1000001];   //all scorp
long long x,y,z;//x表示顺序查找次数,y表示二叉树,z表示哈希法
void shunxu(){
		int n,m;   int t;
		ifstream fin3("data_in.txt");
		ofstream fout3("shunxu_out.txt");
		fin3>>n>>m;
		cout<<"n和m的值分别为:"<<n<<" "<<m<<endl;//
		for(int i=0;i<n;i++){
			fin3>>data_array[i];
		}
		//顺序查找,m*n   all "NO" ?
		bool flag = false;
		for(int i=0;i<m;i++){
			fin3>>t;
			for(int j=0;j<n;j++){
				x++;
				if(t == data_array[j]){
					flag = true;
					//找到了就跳出循环
					break;}
			}
			if(flag)
				fout3<<"YES"<<endl;
			else
				fout3<<"No"<<endl;
			flag = false;
		}
		fin3.close();
		fout3.close();
		cout<<"shunxu_finished"<<endl;
}

void tree(){
		int n,m;   int t;
		ifstream fin3("data_in.txt");
		ofstream fout3("tree_out.txt");
		fin3>>n>>m;
		cout<<"n和m的值分别为:"<<n<<" "<<m<<endl;//

		//二叉树查找
		searchTree tree(t);
		node * tempNode = &tree.getRoot();
		for(int i=1;i<n;i++)
		{
			fin3>>t;
			tree.insert(tempNode,t);
		}
		bool flag;
		for(int i=0;i<m;i++){
			fin3>>t;
			flag = tree.find(tempNode,t,y);
			if(flag)
				fout3<<"YES"<<endl;
			else
				fout3<<"NO"<<endl;
		}
		fin3.close();
		fout3.close();
		//tree.midOder(tempNode);
		cout<<"tree_finished"<<endl;
}
struct cnode{
	cnode(){}
	cnode(int n){value = n;next = NULL;}
	int value;
	struct cnode *next;
};
struct cnode nodearray[10007];

void haxi(){
	int n,m,t,haxi;
	ifstream fin3("data_in.txt");
	ofstream fout3("haxi_out.txt");
	fin3>>n>>m;
	cout<<"n和m的值分别为:"<<n<<" "<<m<<endl;//

	struct cnode *temp_cnode,*t_cnode;
	for(int i=0;i<n;i++){
		//构建哈希表(拉链法)
		fin3>>t;
		haxi = t % 10007;     //10007,为比10000大的质数
		temp_cnode = new cnode(t);
		t_cnode = nodearray[haxi].next;
		nodearray[haxi].next = temp_cnode;
		temp_cnode->next = t_cnode;
	}
	for(int i=0;i<m;i++){
		//查找哈希表
		bool flag = false;
		fin3>>t;
		haxi = t % 10007;
		temp_cnode = nodearray[haxi].next;
		while(temp_cnode != NULL){
			z = z + 1;
			if(temp_cnode->value == t){
				flag = true;

				break;}
			temp_cnode = temp_cnode->next;
		}
		if(flag)
			fout3<<"YES"<<endl;
		else
			fout3<<"NO"<<endl;
	}
	fin3.close();
	fout3.close();
	cout<<"haxi_finished"<<endl;
}
int main() {
	//每次分析一组数据,每组数据的文件标为data_in.txt 。输出文件为3种
	//分别为shunxu_out.txt  tree_out.txt   haxi_out.txt
	shunxu();
	tree();
	haxi();
	cout<<"3种方法的比较次数分别为:"<<endl;
	cout<<x<<"  "<<y<<"  "<<z;
	return 0;
}



测试结果:

第一组:(正序)

顺序查找所需时间为:10

二叉排序树查找时间为:4

哈希表法所用查找时间为:1

3种方法的比较次数分别为:

999998882  847624131  99917

第二组:(逆序)

顺序查找所需时间为:9

二叉排序树查找时间为:3

哈希表法所用查找时间为:1

3种方法的比较次数分别为:

999995463  264858  99926

第三组:(随机10000)

顺序查找所需时间为:9

二叉排序树查找时间为:2

哈希表法所用查找时间为:1

3种方法的比较次数分别为:

999985668  1741928  100014

第四组:(随机100000)

顺序查找所需时间为:82

二叉排序树查找时间为:2

哈希表法所用查找时间为:1

3种方法的比较次数分别为:

9999602349  2324639  998328

第五组:(随机1000000)

顺序查找所需时间为:871

二叉排序树查找时间为:5

哈希表法所用查找时间为:3

3种方法的比较次数分别为:

99945005255  2838781  9985419


ps,第一个交的


评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值