数据结构查找算法课程设计资料
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
数据结构查找算法课
程设计
存档编号:
西安********
课程设计说明书
设计题目:
查找算法性能分析
系
计算机学院
别:
计算机科学
专
业:
计科***
班
级:
王***
姓
名:
收集于网络,如有侵权请联系管理员删除
(共页)
2015年 01月07 日
*****
计算机科学专业课程设计任务书
姓名:*** 班级:
学号:****
收集于网络,如有侵权请联系管理员删除
完成日期:2015-01-09
一需求分析
1.1问题描述
查找又称检索,是指在某种数据结构中找出满足给定条件的元素。
查找是一种十分有用的操作。
而查找也有内外之分,若整个查找过程只在内存中进行称为内查找;若查找过程中需要访问外存,则称为外查找,若在查找的同时对表做修改运算(插入或删除),则相应的表成为动态查找表,反之称为静态查找表。
由于查找运算的主要运算是关键字的比较,所以通常把查找过程中对关键字的平均比较次数(也叫平均查找长度)作为一个查找算法效率优劣的标准。
平均查找程度ASL定义为:
ASL=∑PiCi(i从1到n)
其中Pi代表查找第i个元素的概率,一般认为每个元素的查找概率相等,Ci代表找到第i个元素所需要比较的次数。
查找算法有顺序查找、折半查找、索引查找、二叉树查找和散列查找(又叫哈希查找),它们的性能各有千秋,对数据的存储结构要求也不同,譬如在顺序查找中对表的结果没有严格的要求,无论用顺序表或
收集于网络,如有侵权请联系管理员删除
链式表存储元素都可以查找成功;折半查找要求则是需要顺序表;索引表则需要建立索引表;动态查找需要的树表查找则需要建立建立相应的二叉树链表;哈希查找相应的需要建立一个哈希表。
1.2基本要求
(1)输入的形式和输入值的范围;
在设计查找算法性能分析的过程中,我们调用产生随机数函数:
srand((int)time(0));
产生N个随机数。
注:折半查找中需要对产生的随机数进行排序,需要进行排序后再进行输入,N<50;
(2)输出形式;
查找算法分析过程中,只要对查找算法稍作修改就可以利用平均查找长度的公式:
ASL=∑PiCi(i从1到n)
输出各种查找算法的平均查找长度。
注:平均查找长度=总的平均查找长度/N;
(3)程序所能达到的功能
通过输出几种查找算法的ASL,我们很显然能得在数据量较小时(N<100)我们在实现静态查找时应该选择如何调用
哪种查找算法。
收集于网络,如有侵权请联系管理员删除
二概要设计
说明本程序中用到的所有抽象数据类型的定义。
主程序的流程以及各程序模块之间的层次(调用)关系。
1、数据结构
顺序查找:在进行顺序查找顺序表类型定时需要定义typedef int
KeyType;
顺序表类型为SeqList类型。
typedef NodeType SeqList
【MaxSize】;/
它的基本思路是:从表的一端开始,顺序扫描线性表,依次将扫描到的关键字和给定值k相比较,若当前扫描到的关键字与k相等,查找成功。
折半查找:在进行顺序查找顺序表类型定时需要定义typedef int
KeyType,并且需要调用排序函数对其进行排序。
折半查找类型为SeqList类型。
typedef NodeType SeqList
【MaxSize】;
折半查找又叫二分查找,效率较高,但折半查找要求被查找的表示顺序表,它的基本思路是:设R【low…..high】是当前的查找区间,首先确定该区间的中点位置mid=┖(low+high)/2 ┘,然后将待查的k 值与R【mid】.key。
①如果中点值的值是k,返回该元素的逻辑符号;
收集于网络,如有侵权请联系管理员删除
②如果中点值>k,则中点值之后的数都大于k,所以k值在该表
的左边,所以确定一个新的查找区间;
③如果中点值<k,则中点值之后的数都小于k,k值在该表的右
边,再在该表的右边确定一个新的查找区间;
④依次循环。
索引查找:/索引存储结构是在存储数据的同时还建立附加的索引表,索引表包括关键字和地址。
索引表的数据类型 KeyType key、int link,link代表对应块的起始下标。
typedef IdxType IDX[MaxSize] //索引表的类型
分块查找又称索引顺序查找,它的性能介于顺序查找和折半查找之间的一种算法,它的分块的思想是:
①将表均分成b块,前b-1块中的关键字个数为s=┏n/b┐;
②每一块的关键字不一定有序,但前一块中的最大关键字必须
小于后一块中的最小关键字;
③取各块中最大的关键字及该块在R中的起始位置。
注:索引表是一个递增有序表
分块查找的基本思路是:
①首先查找索引表,因为索引表是有序表,所以可以采用折半
查找或者顺序查找,来确定待查元素在哪一块;
收集于网络,如有侵权请联系管理员删除
②再已确定的块中进行顺序查找(因为块内元素无序,所以只
能用顺序查找)
列:设有一个线性表采用顺序存储,有20个元素,将其分成4(b=4)部分,每部分有5个元素(s=5),该索引表的存储结构如下图所示:
收集于网络,如有侵权请联系管理员删除
在如图所示的存储结构中,查找关键字k=80时,首先将k和索引表中个关键字比较,直到找到大于等于k的值,因此若关键字k=80存在则必定在第四块中,由IDX[3].link找到起始地址15,从该地址开始在R【15…19】中进行查找,直到找到关R【8】.key=k为止,如果查找不成功说明不存在关键字k=80。
二叉树查找:
线性表可以有三种查找法,其中折半查找的效率最高,但是折半查找要求元素时顺序表,而且不能用链式存储结构,因此有表的插入或删除操作时,需要移动大量元素,这时候二叉树查找的优势就体现出来了。
即动态查找时就需要用到链式存储结构。
二叉排序树(BST)又称二叉查找树,其定义为:二叉排序树或者是空树,或者是满足如下性质的二叉树:
①若它的左孩子非空,则左子树上的所有元素的值均小于根元素的值;
②若它的右孩子非空,则左子树上的所有元素的值均大于根元素的值;
③左右子树本身是一颗二叉树。
重要性质:中序遍历二叉排序树所得到中序序列是以一个递增有序序列。
收集于网络,如有侵权请联系管理员删除
二叉排序树算法思想:它可以看做是一个有序表,所以在二叉树上查找,和折半查找类似,也是一个逐步缩小查找范围的过程,运用递归查找算法SearchBST()。
哈希表查找:
在用哈希表查找时先建立一个哈希表,哈希表主要用于快速查找,哈希表的查找过程和建表过程类似。
它的算法是:
①设给定的值为k,根据建表时设定的散列函数h(k)计算哈希地
址;
②存储的个数为n,设置一个长度为M(M>n)的连续内存单元,
以线性表中的每个对象Ki为自变量,通过h(k)把Ki映射为内
存单元的地址,并把该对象存储字这个内存单元中。
哈希函数的构造有直接定址法、除留余数法和数字分析法,常用的是除留余数法,它是用关键字k除以某个不大于哈希表长度m的数p,将所得到的余数作为哈希地址。
除留余数法的哈希函数h(k): H(k)=K mod P(mod为取余运算,p<=m)
2、程序模块
顺序查找:
int SeqSearch(SeqList R,int n,KeyType k) /*函数的返回值是整型,有三个参数分别是顺序表SeqList、元素个数n和需要查找的关键字k*/ {
收集于网络,如有侵权请联系管理员删除
int i=0;
while (i<n && R[i].key!=k) /*从表头开始找*/
i++;
if(i>=n) /*未找到返回0/*
return 0;
else
return i+1; /*找到时返回逻辑符号i+1*/
}
折半查找:
int BinSearch(SeqList R,int n,KeyType k)/*函数的返回值是整型,有三个参数分别是顺序表SeqList、元素个数n和需要查找的关键字*/ {
int low=0,high=n-1,mid;
int count=0;
while(low<=high) /*当前区域存在元素时循环*/
{
count++; /*每循环一次count++*/
mid=(low+high)/2;
if(R[mid].key==k) /*如果查找成功返回其逻辑序号
mid+1*/
return mid+1;
if(R[mid].key>k) /*继续在R【low…mid-1】中查找*/
high=mid-1;
else /* 继续在R【mid+1…high】中查找*/
return count+1; /*返回的是总的平均查找长度*/ }
}
索引查找:
int IdxSearch(IDX I,int b,SeqList R,int n,KeyType k) /*索引查找函数值返回的是整型,函数有五个参数,分别是索引表I、分的块数b、顺序表R、关键字个数和关键字*/
{
int low=0,high=b-1,mid,i,count=0;
int s=n/b; /*s为每块的元素个数,应为n/b的向上取整*/
while(low<=high) /*索引表中进行折半查找、找到的位置为
high+1*/
{
count++;
mid=(low+high)/2;
if(I[mid].key>=k)
high=mid-1;
else
low=mid+1;
}
/* 应在索引表的high+1中,再在对应的线性表中进行顺序查找*/ i=I[high+1].link;
while(i<=I[high+1].link+s-1&&R[i].key!=k)
if(i<=I[high+1].link+s-1) /* 查找成功*/
{
i++;
count++;
}
return count+1;
}
int SearchBST(BSTNode *bt,KeyType k) /*二叉排序树查找函数的返回值是BSTNode类型,函数有两个参数分别是二叉排序树bt和关键字k*/
{ if(bt==NULL||bt->key==k) /*递归的终结条件*/
return 1;
if(k < bt->key)
{ return SearchBST(bt->lchild ,k) + 1; /*在左子树中的递归查找*/
}
else
{ return SearchBST(bt->rchild ,k) + 1; /*在右子树中的递归查找*/
}}
int SearchHT(HashTable ha,int p,KeyType k) /*哈希查找的返回值是整型有三个参数,分别是哈希表ha、小于哈希表长度的最小素数p和关键字k*/
{
int i=0,adr=0;
int m=50;
adr =k%p;
while (ha[adr].key!=NULLKEY && ha[adr].key!=k) /*采用线性探查法查找下一个地址*/
{
i++;
adr =(adr+1)%m; /*adr=(adr+1)mod m*/
}
if(ha[adr].key==k)
return i+1; /*查找成功*/
else
return -1; /*查找失败*/
}
3、各模块之间的调用关系以及算法设计
函数的调用关系图:
在主函数中需要定义一个SeqList R的顺序表;HashTable ha 哈希表;索引表IDX I。
用srand函数(产生随机数)随机产生50个1到100的整数并输出,因为折半查找需要的是顺序表,所以再对产生的50个随机数再进行排序。
调用SeqSearch、BinSearch、IdxSearch、SearchHT、SearchBST(CreateBST)。
依次进行输出。
注意:每次都要给sum重新赋值为零。
三详细设计
#include<stdlib.h>
#include<stdio.h>
#include<time.h>
#define MAXL 100
#define MAXI 100
#define NULLKEY -1
#define DELKEY -2
typedef int KeyType;
typedef int InfoType;
typedef struct
{
KeyType key;
int link;
}IdxType;
typedef IdxType IDX[MAXI]; typedef struct
{
KeyType key;
InfoType data;
}NodeType;
typedef NodeType SeqList[MAXL];
typedef struct node
{
KeyType key;
InfoType data;
struct node *lchild,*rchild; }BSTNode;
typedef struct
{ KeyType key;
InfoType data;
int count;
}HashTable[MAXL];
int SeqSearch(SeqList R,int n,KeyType k) //顺序查找
{ int i=0;
while(i<n && R[i].key!=k)
{ i++;
}
return i+1;
}
int BinSearch(SeqList R,int n,KeyType k) //折半查找
{
int low=0,high=n-1,mid,count=0;
while(low<=high)
{
count++;
mid=(low+high)/2;
if(R[mid].key==k)
return count+1;
if(R[mid].key>k)
high=mid-1;
else
low=mid+1;
}
return 0;
}
int IdxSearch(IDX I,int b,SeqList R,int n,KeyType k) //索引查找
{
int low=0,high=b-1,mid,i;
int count=0;
int s=n/b;
while(low<=high)
{
count++;
mid=(low+high)/2;
if(I[mid].key>=k)
high=mid-1;
else
low=mid+1;
}
i=I[high+1].link;
while(i<=I[high+1].link+s-1&&R[i].key!=k)
{
count++;
i++;
}
if(i<=I[high+1].link+s-1)
return count+1;
else
return 0;
}
int SearchHT(HashTable ha,int p,KeyType k) //散列查找
{
int i=0,adr=0;
int m=50;
adr =k%p;
while (ha[adr].key!=NULLKEY && ha[adr].key!=k)
{
i++;
adr =(adr+1)%m;
}
if(ha[adr].key==k)
return i+1;
else
return -1;
}
void InsertHT(HashTable ha,int &n,KeyType k,int p) //哈希表的插入{
int i,adr;
adr=k%p;
if(ha[adr].key==NULLKEY||ha[adr].key==DELKEY)
{
ha[adr].key=k;
ha[adr].count=1;
}
else
{
i=1;
do
{
adr=(adr+1)%p;
i++;
}while(ha[adr].key!=NULLKEY&&ha[adr].key!=DELKEY);
ha[adr].key=k;
ha[adr].count=i;
}
n++;
}
void CreateHT(HashTable ha,KeyType x[],int n,int m,int p) //哈希表的创建{
int i,n1=0;
for(i=0;i<m;i++)
{
ha[i].key=NULLKEY;
ha[i].count=0;
}
for(i=0;i<n;i++)
InsertHT(ha,n1,x[i],p);
}
int InsertBST(BSTNode * &p,KeyType k) //二叉排序树的插入
{
if(p==NULL)
{
p=(BSTNode *)malloc(sizeof(BSTNode));
p->key=k;
p->lchild=p->rchild=NULL;
return 1;
}
else if(k==p->key)
return 0;
else if(k<p->key)
return InsertBST(p->lchild,k);
else
return InsertBST(p->rchild,k);
}
BSTNode *CreateBST(KeyType a[],int n) //二叉排序树的创建{
BSTNode *bt=NULL;
int i=0;
while (i<n)
{
InsertBST(bt,a[i]);
i++;
}
return bt;
}
int SearchBST(BSTNode *bt,KeyType k) //二叉排序树查找
{
if(bt==NULL||bt->key==k)
return 1;
if(k < bt->key)
{
return SearchBST(bt->lchild ,k) + 1;
}
else
{
return SearchBST(bt->rchild ,k) + 1;
}
}
void main()
{
SeqList R;int i;int e;int a;int b;
HashTable ha;
int T[50];
IDX I;
double j,k,m,n,sum=0;
srand((int)time(0));
for(i=0;i<50;i++)
{
R[i].key=1+(int)(50.0*rand()/(RAND_MAX+1.0));
printf("%d\t",R[i].key);
}
printf("*********************************************************** ****************\n");
for(i=0;i<50;i++)
for(a=i+1;a<50;a++)
if(R[i].key>R[a].key)
{
e=R[i].key;
R[i].key=R[a].key;
R[a].key=e;
}
for(i=0;i<50;i++)
T[i]=R[i].key;
for(i=0;i<50;i++)
{
sum=sum+SeqSearch(R,50,R[i].key);
}
printf("顺序查找平均查找长度:%6.2f\n",sum/50.0);
sum=0;
for(i=0;i<50;i++)
{
sum=sum+BinSearch(R,50,R[i].key);
}
printf("折半查找平均查找长度:%6.2f\n",sum/50.0); sum=0;
for(i=0;i<5;i++)
{
I[i].link=i*10;
I[i].key=R[i*10+9].key;
}
for(i=0;i<50;i++)
{
sum=sum+IdxSearch(I,5,R,50,R[i].key);
}
printf("索引查找平均查找长度:%6.2f\n",sum/50.0); sum=0;
CreateHT(ha,b,50,53,53);
for(i=0;i<50;i++)
{
sum=sum+SearchHT(ha,53,ha[i].key);
}
printf("哈希表查找平均查找长度:%6.2f\n",sum/50.0); sum=0;
for(i=0;i<50;i++)
{
sum=sum+SearchBST(CreateBST(b,50),b[i]);;
}
printf("二叉树查找平均查找长度:%6.2f\n",sum/50.0);
}
四测试与分析
输出结果:
结果分析:
由结果显然可以看出,在线性表存储结构中折半查找的效率最高,顺序查找的效率最低,索引查找介于两者之间。
在顺序表存储结构、链式存储结构、索引表存储结构和哈希表存储结构中效率最高的是哈希表。
还有一种在动态查找时很高效的一种存储结构——树表。
几种查找的效率依次是:
五总结
数据结构总结:
为期一周的数据结构课程设计已经过去了,在这次课程设计中我学习到了很多知识,对编程也有了一定的认识。
譬如在结构体的使用在大一下学期的C语言课程中我学的不是很清楚,很多问题都没有搞懂,但在数据结构这门课程中我对结构体这一部分有了新的认识;此外还有函
数的调用以及函数的参数这方面我也弥补了在大一上学期拉下的课程。
当然这学期的数据结构主要讨论的是算法问题,算法的优劣对效率的影响很大,记得以前在数据结构贴吧里看到这一句话“好的算法可能需要不到一分钟就可以跑完,而不合适的算法100年也不一定能跑完”,在这次课程设计中我也深深的体会到了这句话的含义。
我课程设计的题目是《查找性能的分析》,的确,不同的查找方法差异很大。
当然我也遇到了很多问题:
①如何生成50个随机数时需要用到的“srand”函数;
②每种查找算法之后sum(总的平均查找长度)要重新赋值为0;
③哈希查找是需要先建立哈希表,二叉树排序树查找需要先建立二叉树;
在大二第一学期我们开设了一门数据结构课程,听学长说这门课程很重要当然也很难,我也在很积极努力的学习这门课程。
石老师是一个很负责人的老师,经常给我强调编程的重要性,讲课风格别具一格,思路清晰,举例形象生动。
在课程设计中我的编程水平很是不行,半天编不出一个程序,我也在寻找问题的根源,归根到底我还是练习的太少,投入太少,像查找算法这部分就比其余部分认识较为深刻,当石老师说哈夫曼编码就是文件压缩的原理时,我渐渐的感觉到数据结构这门课程是非常重要的也是非常使用的,其它算法的用途是什么的可以解决什么问题呢,我想这应该是我们在以后这两年中值得去思考的问题。
最后很感谢石老师的指导,在数据结构这门课程的学习中,石老师教我们如何看懂程序帮助很大,万分感谢,我会在以后的道路中谨记老师教导,勤动手、勤动脑。
还要感谢在课程设计中帮我调试程序的同学们。
学生:王旭
2015年1月10日11:30:45。