《数据结构(A)》第9章“查找”基本作业与设计作业

1  作业题目

9.1 已知如下所示长度为12的表

(Jan,Feb,Mar,Apr,May,June,July,Aug,Sep,Oct,Nov,Dec)

(1) 试按表中元素的顺序依次插入一棵初始为空的二叉排序树,画出插入完成后的二叉排序树,并求其在等概率的情况下查找成功的平均查找长度。

(2) 若对表中元素先进行排序构成有序表,求在等概率情况下对此有序表进行折半查找时查找成功的平均查找长度。2

(3) 按表中元素顺序构造一棵平衡二叉排序树,并求其在等概率的情况下查找成功的平均查找长度。

9.2 试从空树开始,画出按以下次序向2-3树即3阶B-树中插入关键码的建树过程:20、30、50、52、60、68、70,如果此后删除50和68,画出每一步执行后2-3树的状态。

9.3 选取哈希函数H(k)=(3k) MOD 11。用开放定址法处理冲突,di=i ((7k) MOD 10 +1) (i=1,2,3…)。试在0—10的散列地址空间中对关键字序列(22、41、53、46、30、13、01、67)构造哈希表,并求等概率情况下查找成功时的平均查找长度。

9.4 试为下列关键字建立一个装载因子不小于0.75的哈希表,并计算你所构造的哈希表的平均查找长度。(ZHAO 、QIAN、SUN、LI、ZHOU、WU、ZHANG、WANG、CHANG、CHAO、YANG、JIN)

9.5 在地址空间为0—16的散列区中,对以下关键字序列构造两个哈希表:

(Jan,Feb,Mar,Apr,May,June,July,Aug,Sep,Oct,Nov,Dec)

(1)用线性探测开放定址法处理冲突

(2)用链地址法处理

并分别求这两个哈希表在等概率情况下查找成功和不成功时的平均查找长度。设哈希函数为H(x)=  i/2  ,其中i为关键字中第一个字母在字母表中的序号。

9.6 设计一个读入一串整数构成一颗二叉排序树的程序,从二叉排序树中删除一个结点,使该二叉树仍保持二叉排序树的特性。

9.7 设定哈希函数 H(key) = key MOD 11 ( 表长=11 ),输入一组关键字序列,根据线性探测再散列解决冲突的方法建立哈希表的存储结构,显示哈希表,任意输入关键字,判断是否在哈希表中。

2  作业题目解答

【9.1题解答】

(1) 试按表中元素的顺序依次插入一棵初始为空的二叉排序树,画出插入完成后的二叉排序树,并求其在等概率的情况下查找成功的平均查找长度

 (2) 若对表中元素先进行排序构成有序表,求在等概率情况下对此有序表进行折半查找时查找成功的平均查找长度

 (3) 按表中元素顺序构造一棵平衡二叉排序树,并求其在等概率的情况下查找成功的平均查找长度。

【9.2题解答】

 【9.3题解答】

 【9.4题解答】

 【9.5题解答】

(1)用线性探测开放定址法处理冲突

 (2)用链地址法处理

【9.6题解答】

算法思路:

插入函数,按照大小先去寻找结点应该插入的位置,再对结点经行增加,并且和其他结点构建连接关系。

删除函数:现找到要删除结点的位置,分3种情况判断,右子树空、左子树空、左右都不空,分别处理每种情况的连接关系。

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#define TRUE 1
#define FALSE 0
#define ENDKEY 0

typedef int KeyType;

typedef struct  node
{
  KeyType  key; /*关键字的值*/
  struct node* lchild, * rchild;/*左右指针*/
}BSTNode, * BSTree;

int InsertBST(BSTree* bst, KeyType key)
/*若在二叉排序树中不存在关键字等于key的元素,插入该元素*/
{
  BSTree s;
  if (*bst == NULL)
  {
	s = (BSTree)malloc(sizeof(BSTNode));
	s->key = key;
	s->lchild = NULL;
	s->rchild = NULL;
	*bst = s;
  }
  else if (key < (*bst)->key)
	InsertBST(&((*bst)->lchild), key);
  else if (key > (*bst)->key)
	InsertBST(&((*bst)->rchild), key);
  return 0;
}

void  CreateBST(BSTree* bst)
/*从键盘输入元素的值,创建相应的二叉排序树*/
{
  KeyType key;
  *bst = NULL;
  scanf("%d", &key);
  while (key != ENDKEY)
  {
	InsertBST(bst, key);
	scanf("%d", &key);
  }
}

void  InOrder(BSTree bst)
/*中序遍历二叉树, root为指向二叉树(或某一子树)根结点的指针*/
{
  //printf("采用中序遍历二叉树输出\n");
  if (bst != NULL)
  {
	InOrder(bst->lchild);   /*中序遍历左子树*/
	printf("%d->", bst->key);        /*访问根结点*/
	InOrder(bst->rchild);   /*中序遍历右子树*/
  }
}

BSTree  SearchBST(BSTree bst, KeyType key)
/*在根指针bst所指二叉排序树中,递归查找某关键字等于key的元素,若查找成功,返回指向该元素结点指针,否则返回空指针*/
{
  if (!bst)
	return NULL;
  else if (bst->key == key)
	return bst;
  else if (bst->key > key)
	return SearchBST(bst->lchild, key);
  else
	return SearchBST(bst->rchild, key);
  //请完成本函数的功能
}
int DelBST(BSTree t, KeyType  k) /*在二叉排序树t中删去关键字为k的结点*/
{
  BSTNode* p, * f, * s, * q;
  p = t;
  f = NULL;
  while (p)  /*查找关键字为k的待删结点p*/
  {
	if (p->key == k)  break;  /*找到则跳出循环*/
	f = p;   /*f指向p结点的双亲结点*/
	if (p->key > k)
	  p = p->lchild;
	else
	  p = p->rchild;
  }
  if (p == NULL)  return 0;  /*若找不到,返回原来的二叉排序树*/
  if (p->lchild == NULL)  /*p无左子树*/
  {
	if (f == NULL)
	  t = p->rchild;  /*p是原二叉排序树的根*/
	else
	  if (f->lchild == p)  /*p是f的左孩子*/
		f->lchild = p->rchild;  /*将p的右子树链到f的左链上*/
	  else  /*p是f的右孩子*/
		f->rchild = p->rchild;  /*将p的右子树链到f的右链上*/
	free(p);  /*释放被删除的结点p*/
  }
  else  /*p有左子树*/
  {
	q = p;
	s = p->lchild;
	while (s->rchild)  /*在p的左子树中查找最右下结点*/
	{
	  q = s;
	  s = s->rchild;
	}
	if (q == p)
	  q->lchild = s->lchild;  /*将s的左子树链到q上*/
	else
	  q->rchild = s->lchild;
	p->key = s->key;  /*将s的值赋给p*/
	free(s);
  }
  return 1;
}  /*DelBST*/

void main()
{
  BSTree T, p;
  int keyword, temp;
  char ch, j = 'y';
  T = NULL;
  while (j != 'n')
  {
	printf("1.创建二叉排序树\n");
	printf("2.显示排序的数据(中序遍历输出)\n");
	//printf("3.查找数据\n");
	//printf("4.在查找树中插入一个数据\n");
	printf("3.在查找树中删除一个数据\n");
	printf("4.程序结束,退出\n");
	scanf(" %c", &ch); //输入操作选项
	switch (ch)
	{
	case '1':
	  printf("请输入数据,以0作为数据输入结束。\n");
	  CreateBST(&T);
	  break;
	case '2':
	  if (!T) printf("二叉排序树中没有数据。\n");
	  else { InOrder(T); printf("\b\b  \n"); }
	  break;
	  //case '3':
	  //  printf("输入待查找的数据值:\n");
	  //  scanf("%d", &keyword); //输入要查找元素的关键字
	  //  p = SearchBST(T, keyword);
	  //  if (!p) printf("%d 没有找到。\n", keyword); //没有找到
	  //  else printf("%d 查找成功。\n", keyword); //成功找到
	  //  break;
	  //case '4':
	  //  printf("输入待插入的数据:");
	  //  scanf("%d", &keyword); //输入要插入元素的关键字
	  //  temp = InsertBST(&T, keyword);
	  //  if (temp == FALSE)
	  //	printf("%d 已在二叉树中!\n", keyword); //该元素已经存在
	  //  else
	  //	printf("%d 插入成功!\n", keyword);
	  //  break;
	case '3':
	  printf("输入待删除的数据:");
	  scanf("%d", &keyword); //输入要删除元素的关键字
	  temp = DelBST(T, keyword);
	  if (temp == FALSE) printf("%d 不存在!\n", keyword); //该元素不存在
	  else printf("成功删除%d\n", keyword); //成功删除
	  break;
	default:
	  j = 'n';
	}
  }
  printf("程序结束!\n");
}

运行结果:

 

【9.7题解答】

算法思路:

   插入函数:计算每个值对应的哈希地址,如果冲突经行线性探测,直到不冲突为止。

   查找函数:先计算该值对应的哈希地址,如果该地址上的值不等于这个数,就线性探测的往下找,找到则返回成果。如果一直往下找,碰到一个地址上没有存任何值,则证明该数不存在哈希表中。

#include <stdio.h>
int main() {
  //功能描述:在哈希表中插入值,对于冲突的地址用线性探测
  int Hash[11] = { 0 };
  printf("输入需要插入哈希表的个数:");
  int n;
  scanf_s("%d", &n);
  for (int i = 0; i < n; i++) {
	printf("插入第%d个数:", i + 1);
	int a;
	scanf_s("%d", &a);
	int pos = a % 11;
	int d = 1;
	while (Hash[pos] != 0) {
	  d = 1;
	  pos = (pos + d) % 11;
	  //d++;
	}
	Hash[pos] = a;
	printf("第%d个数的哈希地址是%d\n", i + 1, pos);
  }

  //功能描述:查找某数是否在哈希表中
  printf("\n");
  printf("\n");
  printf("输入需要查找的个数:");
  scanf_s("%d", &n);
  for (int i = 0; i < n; i++) {
	printf("输入需要查找的数:");
	int a;
	scanf_s("%d", &a);
	int pos = a % 11;
	int flag = 0;
	while (Hash[pos] != 0) {
	  if (Hash[pos] == a) {
		printf("此数存在于哈希中\n");
		flag = 1;
		break;
	  }
	  pos++;
	  pos % 11;
	}
	if (flag == 0) printf("此数不存在于哈希中\n");
  }
}

运行结果:

  • 5
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
1.对于二叉排序树,下面的说法( )是正确的。 A.二叉排序树是动态树表,查找不成功时插入新结点时,会引起树的重新分裂和组合 B.对二叉排序树进行层序遍历可得到有序序列 C.用逐点插入法构造二叉排序树时,若先后插入的关键字有序,二叉排序树的深度最大 D.在二叉排序树中进行查找,关键字的比较次数不超过结点数的1/2 2.在有n个结点且为完全二叉树的二叉排序树中查找一个键值,其平均比较次数的数量级为( )。 A.O(n) B.O(log2n) C.O(n*log2n) D.O(n2) 3.静态查找与动态查找的根本区别在于( )。 A. 它们的逻辑结构不一样 B. 施加在其上的操作不同 C. 所包含的数据元素类型不一样 D. 存储实现不一样 4.已知一个有序表为{12,18,24,35,47,50,62,83,90,115,134},当折半查找值为90的元素时,经过( )次比较后查找成功。 A.2 B.3 C.4 D.5 5.已知数据序列为(34,76,45,18,26,54,92,65),按照依次插入结点的方法生成一棵二叉排序树,则该树的深度为( )。 A. 4 B. 5 C. 6 D. 7 6.设散列表表长m=14,散列函数H(k)=k mod 11 。表中已有15,38,61,84四个元素,如果用线性探测法处理冲突,则元素49的存储地址是( )。 A. 8 B. 3 C. 5 D. 9 7. 平衡二叉树的查找效率呈( )数量级。 A. 常数阶 B. 线性阶 C. 对数阶 D. 平方阶 8. 设输入序列为{20,11,12,…},构造一棵平衡二叉树,当插入值为12的结点时发生了不平衡,则应该进行的平衡旋转是( )。 A. LL B. LR C. RL D. RR 二、填空题(每空3分,共24分)。 1.在有序表A[1..18]中,采用二分查找算法查找元素值等于A[7]的元素,所比较过的元素的下标依次为 。 2.利用逐点插入法建立序列(61,75,44,99,77,30,36,45)对应的二叉排序树以后,查找元素36要进行 次元素间的比较,查找序列为 。 3. 用顺序查找法在长度为n的线性表中进行查找,在等概率情况下,查找成功的平均比较次数是 。 4. 二分查找算法描述如下: intSearch_Bin(SST ST, KT key) { low=1 ; high=ST. length; while(low<=high) { mid=(low+high)/2; if(key==ST.elem[mid].key) return mid; else if(key<ST.elem[mid].key) ; else ; } return 0; } 5.链式二叉树的定义如下: typedef struct Btn{ TElemType data; ; }BTN ,*BT; 6.在有n个叶子结点的哈夫曼树中,总结点数是 。 三、综合题(共52分)。 1. (共12分)假定关键字输入序列为19,21,47,32,8,23,41,45,40,画出建立二叉平衡树的过程。 2. (共15分)有关键字{13,28,31,15,49,36,22,50,35,18,48,20},Hash 函数为H=key mod 13,冲突解决策略为链地址法,请构造Hash表(12分),并计算平均查找长度(3分)。 ASL= 3. (共10分)设关键字码序列{20,35,40,15,30,25},给出平衡二叉树的构造过程。 4. (共15分)设哈希表长为m=13,散列函数为H(k)=k mod 11,关键字序列为5,7,16,12,11,21,31,51,17,81;试求:散列后的表中关键字分布(假定解决冲突的方法为线性探测再散列法);求平均查找长度ASL;计算该表的装填因子。 (1)按要求求哈希表(10分): 0 1 2 3 4 5 6 7 8 9 10 11 12 (2)计算ASL(3分): ASL= (3)计算装填因子(2分):装填因子=
很抱歉,我只是一个AI语言模型,无法直接为您完成作业。但我可以为您指导一下做作业的思路。 PTA数据结构与算法课程的作业5包含多道题目,涉及到树、哈希表、图等数据结构和算法的应用。建议您先仔细阅读题目,了解题目要求和限制条件,然后再进行代码实现。 以下是一些题目的思路: 1. 树的同构问题:判断两棵树是否同构,可以通过递归的方式对树进行遍历,比较两棵树的结构和值是否相同。需要注意的是,树的同构问题需要考虑到树的对称性,即对于树中的每个节点,其左右子树可以互换位置而不影响整棵树的结构。 2. 哈希表查找问题:给定一个哈希表和一个关键字,查找关键字在哈希表中的位置。可以使用哈希函数将关键字映射到哈希表中的位置,然后在该位置上查找关键字是否存在。需要注意的是,哈希表中可能存在哈希冲突的情况,因此需要使用开放地址法或链表法等解决冲突的方式。 3. 图的连通性问题:判断一个无向图是否连通,可以使用深度优先搜索或广度优先搜索遍历图中的所有节点,并标记已经访问的节点。如果遍历完成后所有节点都被标记了,则说明该图是连通的。如果图是有向图,则需要考虑到图的强连通性问题,可以使用Kosaraju算法或Tarjan算法进行求解。 希望以上思路对您有所帮助,祝您顺利完成作业

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值