DS博客作业05--查找

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

PTA得分截图

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

1.1 查找的性能指标

  • ASL成功:找到某一记录合集中任一记录平均所要的关键字比较的次数。
  • ASL不成功:在某记录合集中找不到某一记录平均所要的关键字比较次数。
    例:
  • 比较次数:找到或者找不到某一记录的次数
  • 移动次数:例如哈希表和哈希链有冲突时需要移位找到空的位置所需要的次数
  • 时间复杂度:顺序查找:时间复杂度O(N),二分查找:时间复杂度O(logN)

1.2 静态查找

  • 顺序查找
    顺序查找:从表的一端开始,顺序扫描线性表,将扫描到的关键字与给定的K值相比较。当前扫描到的关键字与k相等,则查找成功,如果扫描结束后仍未找到关键字,等于K的记录则查找失败。
    ASL成功=(n+1)/2
    ASL不成功=n
    平均时间复杂度:O(n)

  • 二分查找
    二分查找要求线性表示有序表,以折半的方式进行查找
    二分查找,时间复杂度O(logN)

二分查找转换为二叉树的形式,进行判断查找
ASL成功=(对应层数 * 对应层的结点个数,进行累加)/总的结点个数
ASL不成功=(对应层数 * 对应层的空结点个数,进行累加)/总的空结点个数

1.3 二叉搜索树

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


ASL成功=(1+2 * 2 + 3 * 3)/6
ASL不成功=(1 * 2 + 6 * 3)/7
ASL成功=(对应层数 * 对应层的结点个数,进行累加)/总的结点个数
ASL不成功=(对应层数 * 对应层的空结点个数,进行累加)/总的空结点个数

实现插入时,一般是在底层空结点的为止插入,通过比较找到符合条件的结点,插入要符合小在左,大在右的规律。

二叉树的删除分为三种情况:
第一种是删除叶子结点,直接将该节点为空即可
第二种是删除的结点只有左子树和右子树,删除该节点,将子树放在该节点对应位置
第三种是删除的结点有左子树和右子树,删除该节点,左子树的最大结点或者右子树的最小结点替代其对应位置,检查后序序列
上图对应三种情况

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

  • 构建及构建:
void Insert(BinTree &T, int a)
{
	if (T == NULL)//该结点为空则新建
	{
		T = new TNode;
		T->data = a;
		T->left = NULL;
		T->right = NULL;
	}
	else
	{
		if (a > T->data)//进入右递归
		{
			return Insert(T->right, a);
		}
		else if (a < T->data)//进入左递归
		{
			return Insert(T->left, a);
		}
	}
}

进行边查边插入,为空时新建结点插入,小于结点值时进入左递归,大于结点值时进入右递归
时间复杂度为O(n)
删除:

BinTree Delete( BinTree BST, ElementType X )
{
    BinTree p;
    if (!BST )//树为空
    {
        printf("Not Found\n");
        return BST;
    }

    if ( BST->Data > X)//进入左递归查找
    {
        BST->Left = Delete( BST->Left, X);
    }
    else if ( BST->Data < X)//进入右递归查找
    {
        BST->Right = Delete( BST->Right, X);
    }
    else
    {
        if ( BST->Right && BST->Left )
        {
            p = FindMax( BST->Left );//找左子树的最大结点
            BST->Data = p->Data;//替代
            BST->Left = Delete( BST->Left, BST->Data );//删除左子树的最大结点
        }
        else
        {
            p = BST;
            if ( !BST->Left )//左子树为空
            {
                BST = BST->Right;
            }
            else if ( !BST->Right)//右子树为空
            {
                BST = BST->Left;
            }
            free(p);
        }
    }
    return BST;
}

边查边删除,结点值小于要删除的值时进入右递归,大于要删除的值进入左递归,找到后判断是三种情况的哪一种,若没有孩子则直接删除,若只有一个孩子,则该孩子取代它。若有两个孩子,则将左子树的最大结点和右子树的最小结点替代它
时间复杂度为O(n)
利用递归算法可以减少不必要的比较次数,以一条最优解的路线进行查找,减少时间复杂度

1.4 AVL树

AVL树可适当减少树的高度,减少查找次数,优化其结构,减少时间复杂度,提高运行效率。
特点:所有节点左右子树深度差的绝对值小于等于1
平均查找长度:最坏情况O(long2n)
平衡调整:

  • LL型调整

找到失衡结点进行分析,将失衡结点的左子树右上旋转作为根结点,原结点变为其右子树,并进行调整

  • RR型调整

找到失衡结点进行分析,将失衡结点的右子树左上旋转作为根结点,原结点变为其左子树,失衡结点的右子树的左孩子变为失衡结点的右孩子,并进行调整。

  • LR型调整

找到失衡结点进行分析,将失衡结点的左子树的右孩子上移变为根节点,失衡节点左子树变为其左孩子,失衡结点变为其右孩子,并进行调整。

  • RL型调整

找到失衡结点进行分析,将失衡结点的右子树的左孩子上移变为根节点,失衡结点右子树变为其右孩子,失衡节点变为其左孩子,并进行调整

AVL树结点个数最少满足的条件:O(1)=1,O(2)=2,O(H)=O(H-1)+O(H-2)+1
n个结点的AVL树满足:h=log2(N(h)+1)
平均查找长度为O(log2n)

map用法

可利用map形成映射进行一对一的匹配,可与树的结构进行联立,第一个可以称为关键字(key),每个关键字只能在map中出现一次,第二个可能称为该关键字的值
模板:map<模板参数,模板参数>定义名称

#include <map>  //STL头文件没有扩展名.h

插入函数:

方法一insert插入
例:
users.insert(pair<long long, string>(num, code));
users.insert(pair<long long, string>(10, 5))
方法二直接插入
例:
user[10]=code;
user[10]='5'

查找函数:

map<long long, string>users;
map<long long, string>::iterator iter;
iter = users.find(num);
if (iter == users.end())//到达结尾没找到
{
	证明没找到;
}

其他基本函数(自己认为重要的):

clear()        删除所有元素
empty()         如果map为空则返回true
erase()         删除一个元素
find()          查找一个元素
insert()        插入元素
size()          返回map中元素的个数

1.5 B-树和B+树

  • B-树
    AVL由于一个结点只能存放一个关键字,若数据量太多会导致树的高度过高,B树的一个结点则可存放多个关键字,降低树的高度,减少查找时间。
    一个m阶的B-树每个结点最多m个孩子结点,最多m-1个关键字。除了根节点外,其他结点至少m/2个孩子结点,至少m/2-1个关键字。根节点至少2个孩子。
    B-树的查找是通过定义结点的孩子指针个数,通过比较该节点中的关键字,找到对应的孩子指针所指的元素,继续进行比较。

B-树的插入
插入过程要注意关键字的个数是否超过最大值,若超过了则要分裂,若有双亲结点,则中间值上移到双亲结点,若没有则新建一个双亲结点,树的高度加一。
例:

B-树的删除
删除时要注意关键字的个数是否少于最小值。若删除关键字后该节点的关键字个数仍然满足条件,则直接删除。若删除后不满足,则可观察其是否有孩子,若有孩子,且从其借一个关键字后仍满足条件,则可从其借一个孩子,若无法借到关键字,可合并孩子,重新进行分裂。
例:

  • B+树
    与B-树的区别,若其结点有n棵子树则有n个关键字,所有的叶子结点中包含了全部关键字的信息,以及指向含这些关键字记录的指针,叶子结点本身依关键字的大小自小而则顶序链接。
    可解决索引块系统一类的功能,例如文件查找索引

1.6 散列查找

哈希表(又称散列表),是一种存储结构,适用于记录的关键字与存储的地址存在某种关系的数据。设要存储的元素个数为n,再设计长度为m的连续内存单元,通过改变下标改变对应的映射关系,元素存储在内存单元中。
哈希表的设计:主要是为了解决哈希冲突。在实际应用中,哈希冲突是难以避免的,而它主要与三个因素有关。
哈希函数的构造方法可采用直接定址法和除留余数法,除留余数法中h(k)=k mod p,p取不大于m的素数时效果最好,减少发生冲突的可能。

  • 哈希表
    利用除留余数法确定对应的下标,当该位置已有元素时,自动往后一位移动,直至遇到空位,探测次数累次增加。
    例题:

AVL成功=总的探测次数和/有效元素个数
AVL不成功=(从0开始到第p个单元格的不成功探测次数和,例如p为7,但建了大于7的单元格,只要计算0到6的单元格不成功探测次数即可)/p

  • 哈希链
    同样除留余数法确定对应的下标,但由于是建了链,当对应下标的链有元素时,采用头插法插入其中。
    例题:

AVL成功=(按层来看,一列元素为一层,向外扩张。层数 * 对应层数的元素个数总和)/总元素个数
AVL不成功=元素总个数/p

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

2.1 是否完全二叉搜索树(2分)

是否完全二叉树代码

思路:通过上图可观察到完全二叉搜索树与不完全二叉树的区别,在于空结点出现的位置,不完全二叉树的空结点位置提前了,所以从该空结点的位置入手,通过层次遍历和计数法进行计数,遇到空结点停止,之后将此时的计数和元素总数进行比较,相等证明为完全二叉树。

2.1.1 伪代码

/*建立平衡二叉树*/
void Insert(BinTree &T, int a)
{
	if (结点为空)
	{
		新建结并且初始化;
	}
	else
	{
		if (a < T值)进入右循环;
		if (a > T值)进入做循环;
	}
}
/*层次遍历*/
int falg = 0;
q.push(T);
while (!q.empty())
{
	if (遇到空结点)
	{
		flag = 1;
	}
	else
	{
		if (flag = 0)进行计数;
		左孩子入队;
		右孩子入队;
	}
}

2.1.2 提交列表

2.1.3 本题知识点

建立二叉排序树、层次遍历、flag计数法

2.2 航空公司VIP客户查询

航空公司VIP客户查询map写法
航空公司VIP客户查询哈希链写法
思路:一开始看到这个题目,想用map函数来写,也比较清楚,结果在测试时间上被卡了点,所以用哈希链的形式,先对哈希链构造结构体,之后对每个用户进行取余分组,找到对应的位置用头插法插入,并且判断对应的距离,但是测试点只能过第一个,后面两个测试点不知道是什么意思,代码也改了好久还是改不出来。

2.2.1 伪代码

/*结构体*/
typedef struct node
{
	char id[20];
	int distance;
	struct Tnode *next;
}HashTnode,*HashList;
初始化哈希链;
输入数据;
/*取余求地址*/
int adr = 0;
for (int i = 12; i <= 16; i++)
{
	换成数据;
}
/*查找用户是否已存在*/
node = h[adr]->next;
while (遍历哈希链)
{
	比较用户名;
}
/*存放数据*/
if (用户存在)
{
	比较路程;
	存放数据;
}
else
{
	新建结点;
	比较路程存放数据;
}

2.2.2 提交列表

2.2.3本题知识点

构建哈希链结构体、取余求地址方法、头插法建链、map相关知识也可以适用本题

2.3基于词频的文件相似度

基于词频的文件相似度map写法

思路:这里采用了map的写法,定义map<string, bool>m[101]的形式,当第i个文件有word词组时,m[i][word]=true,这样就可以通过比较m[i]与m[其他]里面的其他词组,之后定义二维数组存放相似的词组个数,same[i][j]表示第i个文件与第j个文件中相同的词组个数。

2.3.1 伪代码

map<string, bool>m[101];//如果第i个文件存在单词word,则m[i][word] = true;
static int same[101][101];//定义二维数组存放是否有相似
static int num[101];
输入文件个数
for (到达文件个数)
{
	while (直到遇到'#')
	{
		全部字母变为大写;
		if (字母个数小于10)
			逐个放入数组;
		if (字母总个数大于3)
			则map[i][word] = true;
	}
	for (it = m[i].begin(); it != m[i].end(); it++)
	{
		for (j = 0; j <= i; j++)
		{
			if (m[j][it->first] == true)//i中的词组在j中出现
				same[i][j] = same[j][i] += 1;
		}
	}
	记录第i个文件的词组总数放入num[i]中;
}
遍历计算相似度;

2.3.2提交列表

2.3.3本题知识点

map相关知识和运用、map与矩阵相联立解题

posted @ 2021-06-14 19:27  稶郗  阅读(46)  评论(0编辑  收藏  举报