DS博客作业05--查找

这个作业属于哪个班级 数据结构--网络2011/2012
这个作业的地址 DS博客作业05--查找
这个作业的目标 学习查找的相关结构
姓名 朱芳芳

0.PTA得分截图

查找题目集总得分,请截图,截图中必须有自己名字。题目至少完成总题数的2/3,否则本次作业最高分5分。没有全部做完扣1分。

1.本周学习总结(0-5分)

1.1 查找的性能指标

ASL 成功、不成功
ASL成功: 表示成功查找到查找表中的元素,平均需要关键字比较次数( pi为查找到第i个元素的概率,概率和为1)。
ASL不成功:表示没有查找到查找表中的元素,平均需要关键字比较次数(假设共有 m 种查找失败情况,qi为第i种情况的概率,概率和为1)

1.2 静态查找

分析静态查找几种算法包括:顺序查找、二分查找的成功ASL和不成功ASL。
顺序查找
顺序查找是在一个已知无(或有序)序队列中找出与给定关键字相同的数的具体位置。原理是让关键字与队列中的数逐个比较,直到找出与给定关键字相同的数为止。
二分查找
二分查找又称折半查找,优点是比较次数少,查找速度快,平均性能好;其缺是要求待查表为有序表,且插入删除困难。因此,折半查找方法适用于不经常变动而查找频繁的有序列表。两个条件:1)序列有序;2)可以随机访问查找过程首先,假设表中元素是按升序排列,将表中间位置记录的关键字与查找关键字比较,如果两者相等,则查找成功;否则利用中间位置记录将表分成前、后两个子表,如果中间位置记录的关键字大于查找关键字,则进一步查找前一子表,否则进一步查找后一子表。重复以上过程,直到找到满足条件的记录,使查找成功,或直到子表不存在为止,此时查找不成功。

1.3 二叉搜索树

1.3.1 如何构建二叉搜索树(操作)

结合一组数据介绍构建过程,及二叉搜索树的ASL成功和不成功的计算方法。
如何在二叉搜索树做插入、删除。

构建二叉搜索树的操作如下:

创建一棵二叉排序树,从一个空树开始:
每插人一个关键字,就调用一次插人算法将它插人到当前已生成的二叉排序树中。
其插入算法过程是:

例:已知一组关键字为( 25 ,18,46,2,53,39,32,4,74,67,60,11),按表中的关键字顺序依次插人到一棵初始为空的二又排序树中,画出该二又排序树,并求在等概率的情况下查找成功和查找不成功的平均查找长度

计算ASL成功时,分子代表元素的关键字和节点比较次数的总和,由于根节点也是元素,所以结点比较次数等同于二叉搜索树从根开始的高度,分母表示所有元素(内部节点)。
计算ASL不成功时,分子表示所有查找失败节点(查找到节点为空)查找次数的总和,由于所有查找失败的节点均为外部节点,所以分子为所有外部节点。
。如何在ニ叉搜索树做插入、删除
插入:
若二叉排序树 bt 为空,则创建一个 key为 k 的节点,将它作为根结点,
否则将k和根结点的关键字比较:
若两者相等,则说明树中已有此关键字,k无须插人,直接返回假;
若 k<bt->key ,则将k插入根结点的左子树中,
否则将它插人右子树中。

删除:
删除操作必须首先进行查找,假设在查找结束时 p 指向要删除的结点,删除过程分以下几种情况:
1:p结点是叶子结点->直接删除。
2:p结点只有左子树没有右子树->直接将其左孩子替代结点p。
3:p结点只有右子树没有左子树->直接将其右孩子替代结点p。
4:p结点同时存在左右子树->找出左子树最大结点r或右子树最小结点r(该结点只有左子树或者右子树),用结点r的值代替结点p的值,然后按照2/3的情况删除结点r。

1.3.2 如何构建二叉搜索树(代码)

1.如何构建、插入、删除及代码。
2.分析代码的时间复杂度
3.为什么要用递归实现插入、删除?递归优势体现在代码哪里?
二叉搜索树的构建:对于一组给定的元素(可以是有序的也可以是无序的),拿第一个数据作为根节点,然后拿后面的数据与根节点比较,如果比根节点小(大)的话就插入作为根节点的左(右)孩子,否则做右孩子;如果根节点有左(右)孩子的话,就拿根节点的左(右)孩子做新的根节点与待插入数据进行比较,重复上述步骤直到所有数据都插入到树中。

二叉搜索树的结点插入:对于二叉搜索树的插入其实就是二叉搜索树的构建的分步,即二叉搜索树的构建可以看成是由一步步的插入完成的。操作大致上和上述二叉搜索树的构建相同,故这里就不再过多赘述。(注意:插入的元素一定在叶节点上)具体代码如下:
typedef Position BinTree; struct TNode{ ElementType Data; BinTree Left; BinTree Right; }; BinTree Insert( BinTree BST, ElementType x )//递归法插入数据 { if(!BST){ BinTree p=(BinTree)malloc(sizeof(BinTree)); p->Data=x; p->Left=p->Right=NULL; BST=p; } else if(x<BST->Data)BST->Left=Insert(BST->Left,x); else if(x>BST->Data)BST->Right=Insert(BST->Right,x); return BST; }
二叉搜索树的删除:对于二叉搜索树结点的删除有三种情况:①被删除的结点是叶子结点,则直接删去该结点,然后其双亲结点中相应的指针域的值改为NULL;②被删除的结点只有左子树或右子树,则用其左子树或右子树代替被它,然后其双亲结点的相应的指针域的值改为“指向被删除结点的左子树或右子树”;③被删除的结点既有左子树又有右子树,则以其中序遍历前驱(左子树中的最大(右端)结点)或中序遍历后继(右子树中的最小(左端)结点)代替它。然后修改其双亲结点的对应指针域为被删除结点的中序前驱或后继。具体代码如下:
typedef Position BinTree; struct TNode{ ElementType Data; BinTree Left; BinTree Right; }; BinTree Delete( BinTree BST, ElementType x ) { if(!BST){ printf("Not Found\n"); } else { //递归找到待删除结点 if(x<BST->Data)BST->Left=Delete(BST->Left,x); else if(x>BST->Data)BST->Right=Delete(BST->Right,x); else if(x==BST->Data){ if(BST->Left&&BST->Right){ //被删除结点既有左子树又有右子树 BinTree t=FindMin(BST->Right);//在右子树中找最小结点 BST->Data=t->Data; BST->Right=Delete(BST->Right,BST->Data); } else { if(!BST->Left)BST=BST->Right;//被删除结点只有右子树 else if(!BST->Right)BST=BST->Left;//被删除结点只有左子树 } } } return BST; }

。3.为什么要用递归实现插入、删除?递归优势体现在代码哪里?
由于二叉搜索树是一棵树,又树就是一种递归结构,所以代码简洁性更高,可读性更好。

1.4 AVL树

AVL树解决什么问题,其特点是什么?
结合一组数组,介绍AVL树的4种调整做法。
AVL树的高度和树的总节点数n的关系?
介绍基于AVL树结构实现的STL容器map的特点、用法。
1.4AVL树
。AVL树解决什么问题,其特点是什么?
问题:在含有 n 个结点的二叉排序树中查找操作的执行时间与树形有关,在最坏情况下执行时间为 O(n)。
特点:AVL树使得往树中 插入 或 删除 结点时通过调整树的形态来保持树的所有结点平衡(每个结点的平衡因子的绝对值小于等于1),使之既保持 BST 性质不变又保证树的高度在任何情况下均为 O(log2N),从而确保树上的查找操作在最坏情况下的时间也是O(log2N)。

。结合一组数组,介绍 AVL 树的4种调整做法。
LL型
RR型
LR型
RL型

。 AVL 树的高度和树的总节点数 n 的关系?
由于AVL树的所有结点都是平衡的(每个结点的平衡因子的绝对值小于等于1),所以
树的高度在任何情况下均为 O(log2N),即趋近与完全二叉树的高度。
。介绍基于 AVL 树结构实现的 ST 容器 map 的特点、用法。
用法:
Map 是 ST 的一个关联容器,它提供一对一(,即KEY-VALUE,键-值)的数据处理能力。 map 内部自建一颗红黑树(一种非严格意义上的平衡二叉树),这颗树具有对数据自动排序的功能,所以在 map 内部所有的数据都是有序的。
数据查找:
1:用 count 函数来判定关键字是否出现,其缺点是无法定位数据出现位置,由于 map 的特性,一对一的映射关系,就决定了 count 函数的返回值只有两个,要么是0,要么是1。
2:用 find 函数来定位数据出现位置,它返回的一个迭代器,当数据出现时,它返回数据所在位置的迭代器,如果 map 中没有要查找的数据,它返回的迭代器等于 end 函数返回的迭代器。
数据的清空与判空
清空 map 中的数据可以用 clearQ 函数。
判定 map 中是否有数据可以用 empty ()函数,它返回 true 则说明是空 map。

特点:元素按键值对存储,无放入顺序。

1.5 B-树和B+树

。 B -树和 AVL 树区别,其要解决什么问题?
二叉平衡树(包括AVL树)树和二叉排序树都是被用作内查找的数据结构,即被查找的数据集不大,可以放在内存中,而B-树和B+树则是用作外查找的数据结构,其中数据存放在外存中,数据量更加庞大。
。 B -树定义
一棵m阶B-树或者是一棵空树,或者是满足下列要求的m阶树:
1:树中每个结点最多有m棵子树(即最多含有m-1个关键字,设Max=m-1);
2:若根结点不是叶子结点,则根结点最少有两棵子树。
3:除根结点以外,所有非叶子结点最少有[m/2]棵子树(即最少含有[m/2]-1个关键字,设Min=[m/2]-1);
4:每个结点的结构为关键字个数n,
5:所有的外部结点都在同一层,并且不带信息。

。结合数据介绍 B -树的插入、删除的操作,尤其是节点的合并、分裂的情况
。 B +树定义,其要解决问题
B+树的定义:B+树可以看作是B-树的变形。与B-树不同的是:一棵m阶B+树每个结点至多都可以有m棵子树、有n棵子树的结点有n个关键字(数据域)、除根节点外,每个结点的关键字均包含双亲结点中的一个关键字、所有叶子结点包含整棵树的全部关键字及指向相应记录的指针,也就是说,对叶子结点层进行层序遍历的话,所得结果一定是有序的,可以是递增也可以是递减。结构体定义同B-树,只需要在B-树的基础上视情况修改一下MAXM的值即可。

1.6 散列查找。

。哈希表的设计主要涉及哪几个内容?
哈希表( hash table )又称散列表,其基本思路是,设要存储的元素个数为n,设置一个长度为 m ( m>n )的连续内存单元,以每个元素的关键字 k (0≤i≤n-1)为自变量,通过一个称为哈希函数( bash function )的函数 h ( k,)把k,映射为内存单元的地址(或下标) h ( k,),并把该元素存储在这个内存单元中。h(k,)称为哈希地址(& hash address )。把如此构造的线性表存储结构称为哈希表。
即:设置存储内存单元(存储元素个数n与数组大小m)
设计哈希函数(除留余数法,直接定址法,数字分析法)
解决哈希冲突(哈希表:开放地址法=》线性探测法,平方探测法;哈希链:拉链法)。
将元素存储在对应的哈希地址中。
。结合数据介绍哈希表和哈希链的构造及 ASL 成功、不成功的计算。
查找成功的平均查找长度是指查找到哈希表中已有关键字的平均探测次数,实际上,查找到一个关键字所需要的比较次数恰好等于对应的探测次数。分母是所有待查元素的个数。
而查找不成功的平均查找长度是指在哈希表中查找不到待查的元素,最后找到空位置的探测次数的平均值。分母是哈希表长度。


2.PTA题目介绍(0--5分)

介绍3题PTA题目

2.1 是否完全二叉搜索树(2分)
本题务必结合完全二叉搜索树经过层次遍历后在队列的特点去设计实现。结合图形介绍。

2.1.1 伪代码(贴代码,本题0分)
伪代码为思路总结,不是简单翻译代码。

2.1.2 提交列表

2.1.3 本题知识点
完全二叉树的概念:叶子只能出现在最下面的二层、最下层的叶子一定集中在左部的连续位置、倒数第二层若有叶子结点,一定在右部连续位置、如果结点的度为1 ,则该结点只有左孩子。
层序遍历:借助队列来进行层序遍历,每出队一个结点就将其左孩子和右孩子入队,直到队空为止。
二叉搜索树的创建:用递归对每个待插入的数据进行判断,如果比根节点小的话就将根节点的左孩子做新的根节点进行递归判断;如果比根节点大的话就将根节点的右孩子作为新的根节点进行递归判断;如果根节点为空的话则直接将该数据作为根节点的数据创建根节点。
2.2 航空公司VIP客户查询(2分)
本题结合哈希链结构设计实现。请务必自己写代码,学习如何建多条链写法。

2.2.1 伪代码(贴代码,本题0分)
伪代码为思路总结,不是简单翻译代码。

2.2.2 提交列表

2.2.3 本题知识点
哈希链表的构建
哈希链表的结构类似邻接表,需要结点类型和整体哈希表类型。在构建及接下来的结构体使用中,较多的使用到了指针的用法(包括一级和二级)

可以理解为,先利用一级指针构建数组,再利用二级指针构建链表,开辟空间后再注意令指针域指向空。
插入函数的设计
首先查找插入位置,插入位置的计算应使用哈希函数(传入关键字信息)。然后,创建一个链表结点存放数据,由于身份证号由于为18位数字字母组合,所以应选择字符数组或者字符串的存储方式。使用字符数组,存入数据时应该注意不能直接使用赋值“=”,而应该使用strcpy函数来实现字符串复制,最后链表采用头插法插入数据。
哈希散列地址函数的设计
由于身份证号的查找,若采用18位一一比对,或者采用直接寻址法,不好设计,可以采用后六位或者五位作为关键字,设计哈希函数,采用除留余数法,找到六位或者五位与哈希表大小相近的质数,最大程度解决哈希冲突。
关键字查找函数
关键字查找函数的基本思路就是,通过哈希函数输入关键字,计算哈希地址,再在哈希表对应位置进行链表遍历,采用关键字字符串比较的方式,要注意这里的关键字比较,要使用strcmp函数。
关于申请空间
这点题目没做出来,实在是不知道哪里有错。但是有一点需要注意的是,一开始的时候没有写释放空间的函数,后面检查的时候意识到这样会导致内存被占满,然后一直申请不到空间。所以记得使用malloc函数时要记得释放内存。
2.3 基于词频的文件相似度(1分)
本题设计一个倒排索引表结构实现(参考课件)。单词作为关键字。本题可结合多个stl容器编程实现,如map容器做关键字保存。每个单词对应的文档列表可以结合vector容器、list容器实现。

2.3.1 伪代码(贴代码,本题0分)
伪代码为思路总结,不是简单翻译代码。

2.3.2 提交列表
2.3.3 本题知识点
倒排索引表的构建:由于本题不需要考虑一个文档中存在多个重复单词,所以只需要用set集合来存放文档数据即可;否则可以定义一个二维数组string a[][]或动态数组vettora[]来存放文档信息。
对于字母与非字母的判断:如果是C语言的话,可以在头文件中加入<ctype.h>,如果是C++的话就在头文件中加入,然后用库中的函数isalpha即可快速判断字符是不是字母。
对于相同单词不同大小写的情况,这里可以统一转换为大写或小写,方便后续判断。
单词的提取:要从主串中提取子串单词,可以使用string库中的substr(子串起始位置,子串结尾位置)来提取单词,但需要知道单词的首字母位置和尾字母位置,所以需要加一条循环语句来找单词的尾字母位置。
对于相似单词的判断:可以用string库中的count函数来判断该单词在文档中出现过几次。因为本题不考虑一个文档中存在多个重复单词,所以doc[q].count[it]只会有两个值,如果是1的话说明文档q中存在单词it;如果是0的话说明文档q中不存在单词it。

posted @ 2021-06-14 21:47  calizo  阅读(146)  评论(0编辑  收藏  举报