💡 【习题集】 ▼09 查找

This commit is contained in:
康建伟
2018-01-22 21:28:41 +08:00
parent 43b6347c66
commit 1378251869
46 changed files with 1948 additions and 0 deletions
Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 55 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 169 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 87 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

@@ -0,0 +1 @@
200.0)(190.0)(180.0)(170.0)(160.0)(150.0)(140.0)(130.0)(120.0)(110.0)(100.0)(90.0)(80.0)(70.0)(60.0)(50.0)(40.0)(30.0)(20.0)(10.0
@@ -0,0 +1 @@
10.0)(20.0)(30.0)(40.0)(50.0)(60.0)(70.0)(80.0)(90.0)(100.0)(110.0)(120.0)(130.0)(140.0)(150.0)(160.0)(170.0)(180.0)(190.0)(200.0
@@ -0,0 +1 @@
10.0)(20.0)(40.0)(60.0)(70.0)(110.0)(130.0)(150.0)(170.0)(190.0)(230.0)(250.0)(310.0)(330.0)(350.0)(380.0)(400.0)(440.0)(520.0)(590.0)(660.0)(680.0)(690.0)(720.0)(740.0)(890.0)(910.0)(930.0)(970.0)(990.0
@@ -0,0 +1 @@
1246711131517192325313335384044525966686972748991939799
@@ -0,0 +1 @@
1246711131517192325313335384044525966686972748991939799
@@ -0,0 +1 @@
610.0)(780.0)(92, 0.0)(24 0.0)(37 0.0)(81 0.0)(45 0.0)(3 0.0)(53 0.0)(12 0.0)(-92 0.0)(400.0
@@ -0,0 +1 @@
240.0)(450.0)(50, 0.0)(530.0)(1000.0)(37 0.0)(120.0)(610.0)(900.0)(70 0.0)(30.0)(300.0)(260.0)(850.0)(70.0
@@ -0,0 +1,2 @@
450.0)(240.0)(53, 0.0)(45 0.0)(1 0.0)(12 0.0)(24 0.0)(90 0.0
610.0)(780.0)(100, 0.0)(24 0.0)(37 0.0)(90 0.0)(45 0.0)(3 0.0)(53 0.0)(12 0.0
@@ -0,0 +1 @@
40.0)(20.0)(1, 0.0)(7 0.0)(8 0.0)(5 0.0)(6 0.0
@@ -0,0 +1 @@
240.0)(450.0)(50, 0.0)(530.0)(1000.0)(37 0.0)(120.0)(610.0)(900.0)(70 0.0)(30.0)(300.0)(260.0)(850.0)(70.0
@@ -0,0 +1 @@
CAICAOLILANCHACHANGWENCHAOYUNYANGLONGWANGZHAOLIUWUCHEN
@@ -0,0 +1 @@
ZHAOQIANSUNLIZHOUWUZHENWANGFENGCHENCHUWEIJIANGSHENHANYANGZHUQINYOUXU
@@ -0,0 +1 @@
19,14,23,01,68,20,84,27,55,11,10,79
File diff suppressed because one or more lines are too long
@@ -0,0 +1,43 @@
#include <stdio.h>
#include "../../../▲课本算法实现/▲09 查找/00 Base/Base.c" //**▲09 查找**//
/* 宏定义 */
#define MAX 20 //关键字个数
/* 函数原型 */
int Algo_9_25(Table T, KeyType key);
int main(int argc, char *argv[])
{
FILE *fp;
Table T;
KeyType key = 15;
int i;
printf("创建并输出一个查找表(自大至小)...\n");
fp = fopen("Data/Algo_9_25.txt", "r");
Create(fp, &T, MAX+1); //多开辟一个单位
Traverse(T, PrintKey);
printf("\n");
i = Algo_9_25(T, key);
if(i==MAX+1)
printf("关键字 %d 未找到!!\n", key);
else
printf("关键字 %d 在第 %d 个位置。\n", key, i);
printf("\n");
return 0;
}
int Algo_9_25(Table T, KeyType key)
{
int i;
T.elem[MAX+1].key = key;
for(i=1; T.elem[i].key!=key; ++i)
;
return i;
}
@@ -0,0 +1,81 @@
#include <stdio.h>
#include "../../../▲课本算法实现/▲09 查找/00 Base/Base.c" //**▲09 查找**//
/* 宏定义 */
#define MAX 20 //关键字个数
/* 函数原型 */
int Algo_9_26(Table T, KeyType key, int low, int high);
int Algo_9_27(Table T, KeyType key);
int main(int argc, char *argv[])
{
FILE *fp;
Table T;
KeyType key = 18;
int i;
printf("创建并输出一个查找表(自小至大)...\n");
fp = fopen("Data/Algo_9_26-9_27.txt", "r");
Create(fp, &T, MAX);
Traverse(T, PrintKey);
printf("\n");
printf("███ 题 9.26 验证... ███\n");
i = Algo_9_26(T, key, 1, T.length);
if(!i)
printf("关键字 %d 未找到!!\n", key);
else
printf("关键字 %d 在第 %d 个位置。\n", key, i);
printf("\n");
printf("███ 题 9.27 验证... ███\n");
i = Algo_9_27(T, key);
printf("关键字 %d 在第 %d 个区间。\n", key, i);
printf("\n");
return 0;
}
int Algo_9_26(Table T, KeyType key, int low, int high)
{
int mid;
if(low>high) //未找到时返回0
return 0;
mid = (low+high)/2;
if(T.elem[mid].key==key)
return mid;
else if(T.elem[mid].key>key)
return Algo_9_26(T, key, low, mid-1);
else
return Algo_9_26(T, key, mid+1, high);
}
int Algo_9_27(Table T, KeyType key) //实际上是查询其所在的区间
{
int low, high, mid;
if(key<T.elem[1].key)
return 0;
if(key>=T.elem[T.length].key)
return T.length;
low = 1;
high = T.length;
while(high-low>1) //查找表元素大于1
{
mid = (low + high) / 2;
if(T.elem[mid].key<=key)
low = mid;
else
high = mid;
}
return low;
}
@@ -0,0 +1,105 @@
#include <stdio.h>
#include "../../../▲课本算法实现/▲09 查找/00 Base/Base.c" //**▲09 查找**//
/* 宏定义 */
#define MAX 30 //关键字个数
/* 类型定义 */
typedef struct
{
int start; //当前块起点
int min; //当前块中元素最小值
}Index;
typedef struct
{
Table T; //所有块中元素
Index Block[MAX];
int bnum; //块的个数
}Lookup; //关键字递增的查找表
/* 函数原型 */
int Algo_9_28(Lookup ST, KeyType key);
void CreateBlock_9_28(FILE* fp, Lookup *ST);
int main(int argc, char *argv[])
{
FILE *fp;
Lookup ST;
KeyType key = 89;
int i;
printf("创建并输出一个查找表...\n");
fp = fopen("Data/Algo_9_28.txt", "r");
CreateBlock_9_28(fp, &ST);
Traverse(ST.T, PrintKey);
printf("\n");
i = Algo_9_28(ST, key);
if(!i)
printf("关键字 %d 未找到!!\n", key);
else
printf("关键字 %d 在顺序表第 %d 个位置。\n", key, i);
printf("\n");
return 0;
}
int Algo_9_28(Lookup ST, KeyType key)
{
int low, high, mid;
if(key<ST.Block[1].min) //先确定关键字在块中的位置
low = 0;
else if (key>=ST.Block[ST.bnum].min)
low = ST.bnum;
else
{
low=1, high=ST.bnum;
while(high-low>1)
{
mid = (low + high) / 2;
if(ST.Block[mid].min<=key)
low = mid;
else
high = mid;
}
}
if(low) //找到其所属的块后,继续在顺序表T中查找
{
if(low==ST.bnum)
high = ST.T.length;
else
high = ST.Block[high].start-1;
while(low<=high)
{
mid = (low+high)/2;
if(key<ST.T.elem[mid].key)
high = mid - 1;
else if(key>ST.T.elem[mid].key)
low = mid + 1;
else
return mid;
}
}
return 0; //未找到
}
void CreateBlock_9_28(FILE* fp, Lookup *ST) //创建块查找表
{
int i;
Create(fp, &ST->T, MAX); //录入所有关键字创建顺序表
for(i=1,ST->bnum=0; i<=ST->T.length; i+=5) //设定最多5个元素构成一个块
{
ST->bnum++;
ST->Block[ST->bnum].start = i;
ST->Block[ST->bnum].min = ST->T.elem[i].key;
}
}
@@ -0,0 +1,121 @@
#include <stdio.h>
#include <stdlib.h>
#include "../../../▲课本算法实现/▲01 绪论/Status.h"
#include "../../../▲课本算法实现/▲01 绪论/Scanf.c"
/* 类型定义 */
typedef struct LNode
{
int elem;
struct LNode* next;
}LNode;
typedef struct
{
LNode* h; //h固定指向循环链表中的最小关键字
LNode* t; //t在链表中浮动,每次查找结束后指向上次查找完的地方
}CLinkLIst;
/* 函数原型 */
LNode* Algo_9_29(CLinkLIst *CL, int key);
void CreateList_9_29(FILE* fp, CLinkLIst *CL);
void PrintList_9_29(CLinkLIst CL);
int main(int argc, char *argv[])
{
CLinkLIst CL;
FILE *fp;
LNode *p;
int key = 59;
fp = fopen("Data/Algo_9_29.txt","r");
CreateList_9_29(fp, &CL);
PrintList_9_29(CL);
printf("\n");
p = Algo_9_29(&CL, key);
if(p)
printf("关键字 %d 查找成功!\n", p->elem);
else
printf("查找失败!!\n");
printf("\n");
return 0;
}
LNode* Algo_9_29(CLinkLIst *CL, int key)
{
LNode *p;
while(1)
{
if(key<CL->t->elem)
{
for(p=CL->h; p->elem<key&&p->next!=CL->t; p=p->next)
; //从h往后找
CL->t = p;
if(p->elem!=key)
return NULL;
else
return p;
}
else if(key>CL->t->elem) //从t往后找
{
if(CL->t->next!=CL->h)
CL->t = CL->t->next;
else
return NULL;
}
else
return CL->t;
}
return p;
}
void CreateList_9_29(FILE* fp, CLinkLIst *CL)
{
int tmp;
LNode *p;
CL->h = CL->t = NULL;
while(Scanf(fp, "%d", &tmp)==1)
{
p = (LNode*)malloc(sizeof(LNode));
p->elem = tmp;
if(!CL->h)
CL->h = CL->t = p;
else
{
CL->t->next = p;
CL->t = CL->t->next;
}
}
CL->t->next = CL->h; //首尾相连
CL->t = CL->t->next; //t初始时指向链头
}
void PrintList_9_29(CLinkLIst CL)
{
LNode *p;
int count = 0;
p = CL.h;
if(p)
printf("%2d ", p->elem);
count++;
while(p->next!=CL.h)
{
p = p->next;
printf("%2d ", p->elem);
count++;
if(count%10==0)
printf("\n");
}
}
@@ -0,0 +1,114 @@
#include <stdio.h>
#include <stdlib.h>
#include "../../../▲课本算法实现/▲01 绪论/Status.h"
#include "../../../▲课本算法实现/▲01 绪论/Scanf.c"
/* 类型定义 */
typedef struct LNode
{
int elem;
struct LNode* pre;
struct LNode* next;
}LNode;
typedef LNode* DCLinkLIst;
/*全局变量*/
DCLinkLIst sp;
/* 函数原型 */
DCLinkLIst Algo_9_30(DCLinkLIst DL, int key);
void CreateList_9_30(FILE* fp, DCLinkLIst *DL);
void PrintList_9_30(DCLinkLIst DL);
int main(int argc, char *argv[])
{
DCLinkLIst DL;
FILE *fp;
LNode *p;
int key = 59;
fp = fopen("Data/Algo_9_30.txt","r");
CreateList_9_30(fp, &DL);
PrintList_9_30(DL);
printf("\n");
p = Algo_9_30(DL, key);
if(p)
printf("关键字 %d 查找成功!\n", p->elem);
else
printf("查找失败!!\n");
printf("\n");
return 0;
}
DCLinkLIst Algo_9_30(DCLinkLIst DL, int key)
{
while(1)
{
if(sp->elem==key)
return sp;
else if(sp->elem<key)
{
if(sp->next!=DL && sp->next->elem<=key)
sp = sp->next;
else
return NULL;
}
else
{
if(sp->pre!=DL && sp->pre->elem>=key)
sp = sp->pre;
else
return NULL;
}
}
}
void CreateList_9_30(FILE* fp, DCLinkLIst *DL)
{
int tmp;
DCLinkLIst p;
*DL = NULL;
while(Scanf(fp, "%d", &tmp)==1)
{
p = (DCLinkLIst)malloc(sizeof(LNode));
p->elem = tmp;
if(*DL==NULL)
*DL = sp = p;
else
{
sp->next = p;
sp->next->pre = sp;
sp = sp->next;
}
}
sp->next = *DL;
sp->next->pre = sp;
sp = sp->next;
}
void PrintList_9_30(DCLinkLIst DL)
{
LNode *p;
int count = 0;
p = DL;
if(p)
printf("%2d ", p->elem);
count++;
while(p->next!=DL)
{
p = p->next;
printf("%2d ", p->elem);
count++;
if(count%10==0)
printf("\n");
}
}
@@ -0,0 +1,157 @@
#include <stdio.h>
#include <limits.h>
#include "../../../▲课本算法实现/▲09 查找/06 BinarySortTree/BinarySortTree.c" //**▲09 查找**//
/* 宏定义 */
#define FAIL INT_MAX //未找到合适值时的标记
#define MINKEY INT_MIN //关键字的下限
/* 函数原型 */
void Algo_9_31(BSTree BST, int *pre, int *flag);
void Algo_9_32(BSTree BST, int x, int *a, int *b, BSTree ptr[], int *count);
void Algo_9_33(BSTree BST, int x);
void Algo_9_34(BSTree *BST, int x);
void DestoryTree_9_34(BSTree *BST);
int main(int argc, char *argv[])
{
FILE *fp;
Table T;
BSTree BST;
int x = 42;
printf("创建并输出查找表...\n");
fp = fopen("Data/Algo_9_31-9_34.txt", "r");
Create(fp, &T, 12);
printf("T = ");
Traverse(T, PrintKey);
printf("\n");
printf("构造二叉排序树,并由小到大输出其关键字:\n");
CreateBSTree(&BST, T);
printf("BST = ");
InOrderTraverse_BST(BST, PrintKey);
printf("\n\n");
printf("███ 题 9.31 验证... ███\n");
{
int pre = MINKEY;
int flag = TRUE;
Algo_9_31(BST, &pre, &flag);
printf("此树");
flag ? printf("") : printf("不是");
printf("二叉排序树!\n");
printf("\n");
}
printf("███ 题 9.32 验证... ███\n");
{
int a ,b ,count; //count用来计数,初始值设为0
BSTree ptr[12]; //数组容量与二叉排序树关键字个数相等
a = b = FAIL;
count = 0;
Algo_9_32(BST, x, &a, &b, ptr, &count);
printf("a<x<b%d < %d < %d\n", a, x, b);
printf("\n");
}
printf("███ 题 9.33 验证... ███\n");
{
printf("从大到小输出大于 %d 的关键字:", x);
Algo_9_33(BST, x);
printf("\n\n");
}
printf("███ 题 9.34 验证... ███\n");
{
printf("删除二叉排序树中关键字不小于 %d 的结点...\n", x);
Algo_9_34(&BST, x);
printf("BST = ");
InOrderTraverse_BST(BST, PrintKey);
printf("\n\n");
}
return 0;
}
void Algo_9_31(BSTree BST, int *pre, int *flag)
{
if(*flag==TRUE)
{
if(BST->lchild)
Algo_9_31(BST->lchild, pre, flag);
if(BST->data.key>=*pre)
*pre = BST->data.key;
else
*flag = FALSE;
if(BST->rchild)
Algo_9_31(BST->rchild, pre, flag);
}
}
void Algo_9_32(BSTree BST, int x, int *a, int *b, BSTree ptr[], int *count)
{ //count初值为0,用来计数,a、b初值设为标记FAIL,其含义是未找到合适的值
if(BST) //从小到大遍历
{
Algo_9_32(BST->lchild, x, a, b, ptr, count);
ptr[(*count)++] = BST;
if(*count>=2)
{
if(ptr[*count-2]->data.key<x&&x<=ptr[*count-1]->data.key)
*a = ptr[*count-2]->data.key;
if(ptr[*count-2]->data.key<=x&&x<ptr[*count-1]->data.key)
*b = ptr[*count-1]->data.key;
if(*a!=FAIL&&*b!=FAIL) //a、b均找到时结束函数
return;
}
Algo_9_32(BST->rchild, x, a, b, ptr, count);
}
}
void Algo_9_33(BSTree BST, int x)
{
if(BST) //逆中序遍历
{
Algo_9_33(BST->rchild, x);
if(BST->data.key>=x)
printf("%d ", BST->data.key);
else
return;
Algo_9_33(BST->lchild, x);
}
}
void Algo_9_34(BSTree *BST, int x)
{
BSTree p;
if(*BST)
{
if((*BST)->data.key>=x)
{
p = *BST;
*BST = p->lchild;
p->lchild = NULL;
DestoryTree_9_34(&p); //销毁当前结点及当前结点的右子树
Algo_9_34(BST, x); //继续考察左子树
}
else
Algo_9_34(&(*BST)->rchild, x); //考察右子树
}
}
void DestoryTree_9_34(BSTree *BST)
{
if(*BST)
{
DestoryTree_9_34(&(*BST)->lchild); //销毁左子树
DestoryTree_9_34(&(*BST)->rchild); //销毁右子树
free(*BST);
*BST = NULL;
}
}
@@ -0,0 +1,354 @@
#include <stdio.h>
#include <stdlib.h>
#include "../../../▲课本算法实现/▲09 查找/06 BinarySortTree/BinarySortTree.c" //**▲09 查找**//
/*宏定义*/
#define Max 15 //查找表中元素个数
/* 类型定义 */
enum {Link, Thread}; //线索标记,Link:孩子;Thread:线索
typedef BSTree ThrBSTree; //线索二叉排序树
/*全局变量*/
ThrBSTree pre; //指向当前结点前驱
ThrBSTree parent; //指向当前结点的双亲结点
/* 函数原型 */
void Algo_9_35(ThrBSTree Thrt, int a, int b);
Status Algo_9_36(ThrBSTree Thrt, BSTElemType e);
Status Algo_9_37(ThrBSTree Thrt, KeyType key);
void Create_Thr(ThrBSTree *Thrt, ThrBSTree TBST);
void InOrder_Sub_Thr(ThrBSTree p);
void Print_InOrder(ThrBSTree Thrt);
Status SearchThr_9_36(ThrBSTree TBST, KeyType key, ThrBSTree f, ThrBSTree *p);
//p指向关键字key在树中的位置,f指向p的双亲结点,若查找失败,p指向插入位置
Status DeleteThr_9_37(ThrBSTree *TBST, KeyType key);
//从线索二叉排序树中删除关键字key
void DeleteNode_9_37(ThrBSTree *p);
//删除线索二叉树中p指向的结点
int main(int argc, char *argv[])
{
FILE *fp;
Table T;
ThrBSTree TBST, Thrt;
printf("创建并输出一个查找表...\n");
fp = fopen("Data/Algo_9_35-9_37.txt", "r");
Create(fp, &T, Max);
Traverse(T, PrintKey);
printf("\n");
printf("创建中序后继线索二叉排序树,并中序输出其关键字...\n");
CreateBSTree(&TBST, T); //创建二叉排序树
Create_Thr(&Thrt, TBST); //中序后继线索化二叉排序树
Print_InOrder(Thrt);
printf("\n\n");
printf("███ 题 9.35 验证... ███\n");
{
int a, b;
a = 10;
b = 90;
printf("大于 %d 且小于 %d 的关键字:", a, b);
Algo_9_35(Thrt, a, b);
printf("\n\n");
}
printf("███ 题 9.36 验证... ███\n");
{
BSTElemType e;
e.key=28, e.weight=0.0;
printf("插入关键字 %d 后,中序输出其关键字...\n", e.key);
Algo_9_36(Thrt, e);
Print_InOrder(Thrt);
printf("\n\n");
}
printf("███ 题 9.37 验证... ███\n");
{
KeyType key = 26;
printf("删除关键字 %d 后,中序输出其关键字...\n", key);
Algo_9_37(Thrt, key);
Print_InOrder(Thrt);
printf("\n\n");
}
return 0;
}
void Algo_9_35(ThrBSTree Thrt, int a, int b) //本质是中序遍历(无递归)
{
ThrBSTree p = Thrt->lchild; //p指向二叉排序树根结点
while(p!=Thrt)
{
while(p->lchild)
p = p->lchild;
if(a<p->data.key&&p->data.key<b)
PrintKey(p->data);
else
{
if(p->data.key>=b)
return;
}
while(p->RTag==Thread && p->rchild!=Thrt)
{
p = p->rchild;
if(a<p->data.key&&p->data.key<b)
PrintKey(p->data);
else
{
if(p->data.key>=b)
return;
}
}
p = p->rchild;
}
}
Status Algo_9_36(ThrBSTree Thrt, BSTElemType e)
{
ThrBSTree p, s;
if(!SearchThr_9_36(Thrt->lchild, e.key, NULL, &p)) //查找不成功
{
s = (ThrBSTree)malloc(sizeof(BSTNode));
s->data = e;
s->lchild = NULL;
s->RTag = Thread;
if(!p) //原树为空
{
Thrt->lchild = s;
s->rchild = Thrt;
}
else if(e.key<p->data.key)
{
p->lchild = s;
s->rchild = p;
}
else
{
s->rchild = p->rchild;
p->RTag = Link;
p->rchild = s;
}
return TRUE; //插入e.key
}
else //查找成功
return FALSE;
}
Status Algo_9_37(ThrBSTree Thrt, KeyType key)
{
int tag;
if(Thrt->lchild==Thrt)
return FALSE;
else
{
parent = Thrt; //parent指向当前访问结点的双亲结点
tag = DeleteThr_9_37(&Thrt->lchild, key);
if(Thrt->lchild==NULL) //线索二叉树已为空
Thrt->lchild = Thrt;
return tag;
}
}
Status SearchThr_9_36(ThrBSTree TBST, KeyType key, ThrBSTree f, ThrBSTree *p)
{ //p指向查找路径上最后一个“能”被访问结点,f指向Thrt的双亲,初始值为NULL
if(TBST->lchild==TBST)
{
*p = f;
return FALSE;
}
if(key==TBST->data.key)
{
*p = TBST;
return TRUE;
}
else if(key<TBST->data.key)
{
if(!TBST->lchild)
{
*p = TBST;
return FALSE;
}
else
return SearchThr_9_36(TBST->lchild, key, TBST, p);
}
else
{
if(TBST->RTag==Link)
return SearchThr_9_36(TBST->rchild, key, TBST, p);
else
{
*p = TBST;
return FALSE;
}
}
}
Status DeleteThr_9_37(ThrBSTree *TBST, KeyType key)
{
if(key==(*TBST)->data.key)
{
DeleteNode_9_37(TBST); //找到了要删除的结点
return OK;
}
else if(key<(*TBST)->data.key)
{
if((*TBST)->lchild)
{
parent = *TBST;
return DeleteThr_9_37(&(*TBST)->lchild, key);
}
else
return FALSE;
}
else
{
if((*TBST)->RTag==Link)
{
parent = *TBST;
return DeleteThr_9_37(&(*TBST)->rchild, key);
}
else
return FALSE;
}
}
void DeleteNode_9_37(ThrBSTree *p)
{
ThrBSTree q, s;
if((*p)->lchild&&(*p)->RTag==Thread) //右子树为空(没有子树)
{
q = *p;
*p = (*p)->lchild;
if(*p)
{
s = *p;
while(s->RTag==Link) //往最右边寻找
s = s->rchild;
s->rchild = q->rchild;
}
free(q);
}
else if(!(*p)->lchild && (*p)->RTag==Link) //左子树为空(没有子树)
{
q = *p;
*p = (*p)->rchild;
free(q);
}
else if(!(*p)->lchild && (*p)->RTag==Thread)//左右子树均为空(没有子树)
{
q = *p;
if(parent->lchild==q)
parent->lchild = NULL;
else
{
parent->RTag = Thread;
parent->rchild = q->rchild;
}
free(q);
}
else //左右子树均不为空(前驱替换)
{
q = *p;
s = (*p)->lchild;
while(s->RTag==Link) //寻找p的直接前驱
{
q = s;
s = s->rchild;
}
(*p)->data = s->data; //用p的直接前驱取代p
if(q!=*p)
q->rchild = s->lchild;
else
{
q->lchild = s->lchild;
if(s->lchild)
{
q = s->lchild;
while(q->RTag==Link)
q = q->rchild;
q->rchild = *p;
}
}
free(s);
}
}
void Create_Thr(ThrBSTree *Thrt, ThrBSTree TBST)
{
*Thrt = (ThrBSTree)malloc(sizeof(BSTNode));
if(!TBST)
(*Thrt)->lchild = *Thrt;
else
(*Thrt)->lchild = TBST;
(*Thrt)->RTag = Thread;
(*Thrt)->rchild = *Thrt;
pre = *Thrt;
InOrder_Sub_Thr(TBST); //中序后继线索化
pre->RTag = Thread; //最后一个结点线索化
pre->rchild = *Thrt; //最后一个结点指回头结点
}
void InOrder_Sub_Thr(ThrBSTree p)
{
if(p)
{
InOrder_Sub_Thr(p->lchild); //线索化左子树
if(!pre->rchild) //为上一个结点右子树建立后继线索
{
pre->RTag = Thread;
pre->rchild = p;
}
else
pre->RTag = Link;
pre = p; //pre向前挪一步
InOrder_Sub_Thr(p->rchild); //线索化右子树
}
}
void Print_InOrder(ThrBSTree Thrt)
{
ThrBSTree p = Thrt->lchild; //p指向二叉排序树根结点
while(p!=Thrt)
{
while(p->lchild)
p = p->lchild;
PrintKey(p->data);
while(p->RTag==Thread && p->rchild!=Thrt)
{
p = p->rchild;
PrintKey(p->data);
}
p = p->rchild;
}
}
@@ -0,0 +1,120 @@
#include <stdio.h>
#include "../../../▲课本算法实现/▲09 查找/06 BinarySortTree/BinarySortTree.c" //**▲09 查找**//
/* 函数原型 */
void Algo_9_38(BSTree BST1, BSTree *BST2, void(*InsertNode)(BSTree*,BSTree)); //将二叉排序树BST2合并到BST1上
void Algo_9_39(BSTree *BST, BSTree *BST1, BSTree *BST2, int x, void(*InsertNode)(BSTree*,BSTree));//分解BST
void InsertNode_9_38(BSTree *BST, BSTree p); //将p指示的结点插入到二叉排序树BST中合适的位置
int main(int argc, char *argv[])
{
FILE *fp;
Table T1, T2;
BSTree BST1, BST2, BST3;
int x = 45;
printf("创建并输出两个查找表...\n");
fp = fopen("Data/Algo_9_38-9_39.txt", "r");
Create(fp, &T1, 8);
Create(fp, &T2, 10);
printf("T1 = ");
Traverse(T1, PrintKey);
printf("T2 = ");
Traverse(T2, PrintKey);
printf("\n");
printf("构造两棵二叉排序树,并由小到大输出其关键字:\n");
CreateBSTree(&BST1, T1);
CreateBSTree(&BST2, T2);
printf("BST1 = ");
InOrderTraverse_BST(BST1, PrintKey);
printf("\n");
printf("BST2 = ");
InOrderTraverse_BST(BST2, PrintKey);
printf("\n\n");
printf("███ 题 9.38 验证... ███\n");
printf("将 BST2 合并到 BST1 ...\n");
Algo_9_38(BST1, &BST2, InsertNode_9_38);
printf("BST1 = ");
InOrderTraverse_BST(BST1, PrintKey);
printf("\n\n");
printf("███ 题 9.39 验证... ███\n");
printf("分解 BST1 到 BST2 和 BST3 ,以 %d 为界...\n", x);
BST2 = BST3 = NULL;
Algo_9_39(&BST1, &BST2, &BST3, x, InsertNode_9_38);
printf("BST2 = ", x);
InOrderTraverse_BST(BST2, PrintKey);
printf("\n");
printf("BST3 = ", x);
InOrderTraverse_BST(BST3, PrintKey);
printf("\n\n");
return 0;
}
void Algo_9_38(BSTree BST1, BSTree *BST2, void(*InsertNode)(BSTree*,BSTree))
{ //InsertNode函数用来插入结点
BSTree l, r;
if(*BST2)
{
l = (*BST2)->lchild;
r = (*BST2)->rchild;
(*BST2)->lchild = (*BST2)->rchild = NULL; //与子结点要及时分离
Algo_9_38(BST1, &l, InsertNode);
InsertNode(&BST1, *BST2);
Algo_9_38(BST1, &r, InsertNode);
}
*BST2 = NULL;
}
void Algo_9_39(BSTree *BST, BSTree *BST1, BSTree *BST2, int x, void(*InsertNode)(BSTree*,BSTree))
{ //InsertNode函数用来插入结点
BSTree l, r;
if(*BST)
{
l = (*BST)->lchild;
r = (*BST)->rchild;
(*BST)->lchild = (*BST)->rchild = NULL; //与子结点要及时分离
Algo_9_39(&l, BST1, BST2, x, InsertNode);//先遍历左右子树
Algo_9_39(&r, BST1, BST2, x, InsertNode);
if((*BST)->data.key>=x)
InsertNode(BST1, *BST);
else
InsertNode(BST2, *BST);
}
*BST = NULL;
}
void InsertNode_9_38(BSTree *BST, BSTree p)
{
if(*BST)
{
if(p->data.key<(*BST)->data.key)
{
if((*BST)->lchild==NULL)
(*BST)->lchild = p;
else
InsertNode_9_38(&(*BST)->lchild, p);
}
else if(p->data.key>(*BST)->data.key)
{
if((*BST)->rchild==NULL)
(*BST)->rchild = p;
else
InsertNode_9_38(&(*BST)->rchild, p);
}
else
free(p);
}
else
*BST = p;
}
@@ -0,0 +1,69 @@
#include <stdio.h>
#include "../../../▲课本算法实现/▲09 查找/07 BalancedBinarySortTree/BalancedBinarySortTree.c" //**▲09 查找**//
/* 宏定义 */
#define Max 15
/* 函数原型 */
BBSTree Algo_9_40(BBSTree BBST, int k); //找出平衡二叉树中第k小的结点
int fLsize_9_40(BBSTree BBST); //计算lsize值
int main(int argc, char *argv[])
{
FILE *fp;
Table T;
BBSTree BBST, p;
int k = 5;
printf("创建并输出一个查找表...\n");
fp = fopen("Data/Algo_9_40.txt", "r");
Create(fp, &T, Max);
Traverse(T, PrintKey);
printf("\n");
printf("构造并打印二叉排序树中的关键字:");
CreateAVL(&BBST, T);
printf("打印平衡二叉树:\n");
PrintAVLTree(BBST);
printf("\n");
fLsize_9_40(BBST);
p = Algo_9_40(BBST, k);
printf("平衡二叉树中从小到大排列第 %d 个关键字为 %d 。\n", k, p->data);
printf("\n");
return 0;
}
BBSTree Algo_9_40(BBSTree BBST, int k)
{
if(!BBST)
return NULL;
else
{
if(k==BBST->lsize)
return BBST;
else if(k<BBST->lsize)
return Algo_9_40(BBST->lchild, k);
else
return Algo_9_40(BBST->rchild, k-BBST->lsize); //k值改变
}
}
int fLsize_9_40(BBSTree BBST)
{
int lnum, rnum;
if(BBST)
{
lnum = fLsize_9_40(BBST->lchild); //左子树结点个数
rnum = fLsize_9_40(BBST->rchild); //右子树结点个数
BBST->lsize = lnum + 1;
return lnum+rnum+1;
}
else
return 0;
}
@@ -0,0 +1,43 @@
#include <stdio.h>
#include "../../../▲课本算法实现/▲09 查找/09 B+Tree/B+Tree.c"
/* 宏定义 */
#define Max 15
/* 函数原型 */
Result Algo_9_41(B_Tree B_T, KeyType K);
int main(int argc, char *argv[])
{
FILE *fp;
Table T;
B_Tree B_T;
KeyType Key = 37;
Result R;
printf("创建查找表...\n");
fp = fopen("Data/Algo_9_41.txt", "r");
Create(fp, &T, Max);
Traverse(T, PrintKey);
printf("\n");
printf("构造B+树...\n");
CreateB_Tree(&B_T, T);
PrintB_Tree(B_T);
printf("\n");
printf("查找关键字 %d ...\n", Key);
R = Algo_9_41(B_T, Key);
if(R.tag)
printf("已找到关键字 %d", R.pt->key[R.i]);
else
printf("未找到关键字!!");
printf("\n\n");
return 0;
}
Result Algo_9_41(B_Tree B_T, KeyType K)
{
return SearchB_Tree(B_T, K); //已定义
}
@@ -0,0 +1,50 @@
#include <stdio.h>
#include "../../../▲课本算法实现/▲09 查找/11 TrieTree/TrieTree.c"
/* 函数原型 */
void Algo_9_42(TrieTree *TT, Record R);
void Algo_9_43(TrieTree *TT, KeysType K);
void Print(Record *r);
int main(int argc, char *argv[])
{
FILE *fp;
TrieTree TT;
Record R = {"SUN"};
KeysType K = {"YANG", 4};
printf("创建一棵键树...\n");
fp = fopen("Data/Algo_9_42-9_43.txt", "r");
CreateTrie(fp, &TT);
TraverseTrie(TT, Print);
printf("\n\n");
printf("███ 题 9.42 验证... ███\n");
printf("插入含关键字 %s 的记录...\n", R.key);
Algo_9_42(&TT, R);
TraverseTrie(TT, Print);
printf("\n\n");
printf("███ 题 9.43 验证... ███\n");
printf("删除含关键字 %s 的记录...\n", K.ch);
Algo_9_43(&TT, K);
TraverseTrie(TT, Print);
printf("\n\n");
return 0;
}
void Algo_9_42(TrieTree *TT, Record R)
{
InsertTrie(TT, R); //已定义
}
void Algo_9_43(TrieTree *TT, KeysType K)
{
DeleteTrie(TT, K); //已定义
}
void Print(Record *r)
{
printf("%s ", r->key);
}
@@ -0,0 +1,85 @@
#include <stdio.h>
#include <string.h>
#include "../../../▲课本算法实现/▲01 绪论/Status.h" //**▲01 绪论**//
#include "../../../▲课本算法实现/▲01 绪论/Scanf.c"
/* 宏定义 */
#define MAXSIZE 100
/* 类型定义 */
typedef struct
{
char s[27]; //关键字长度不超过26
}HNode;
typedef HNode HashTable[MAXSIZE];
/* 函数原型 */
void Algo_9_44(HashTable H);
Status CreateHash_9_44(FILE *fp, HashTable H);//创建哈希表
int fHash_9_44(char s[]);//返回s首字母(大写)在字母表中的位置
int main(int argc, char *argv[])
{
FILE *fp;
int p;
HashTable H;
fp = fopen("Data/Algo_9_44.txt","r");
CreateHash_9_44(fp, H);
fclose(fp);
printf("按首字母字典顺序输出哈希表中所有关键字:\n");
Algo_9_44(H);
printf("\n");
return 0;
}
/*━━━━━━━━━━━━━━━━━━━━━━┓
┃题9.44:按关键字首字母顺序输出哈希表中关键字┃
┗━━━━━━━━━━━━━━━━━━━━━━*/
void Algo_9_44(HashTable H)
{
int i, j;
for(i=1; i<=26; i++)
{
j = i;
while(strcmp(H[j].s,"")!=0)
{
if(fHash_9_44(H[j].s)==i)
printf("%s ", H[j].s);
j = (j+1)%MAXSIZE;
}
}
}
Status CreateHash_9_44(FILE *fp, HashTable H)
{
int i, p;
char tmp[26];
for(i=0; i<MAXSIZE; i++)
strcpy(H[i].s, "");
while(Scanf(fp, "%s", tmp)==1) //录入关键字到哈希表
{
p = fHash_9_44(tmp);
while(strcmp(H[p].s, "")!=0) //出现冲突
p = (p+1)%MAXSIZE;
if(strcmp(H[p].s, "")==0)
strcpy(H[p].s, tmp);
else //此处未对失败情况做限制
return ERROR;
}
return OK;
}
int fHash_9_44(char s[]) //哈希函数
{
return s[0]-'A'+1; //设定关键字首字母为大写
}
@@ -0,0 +1,104 @@
#include <stdio.h>
#include <stdlib.h>
#include "../../../▲课本算法实现/▲01 绪论/Status.h" //**▲01 绪论**//
#include "../../../▲课本算法实现/▲01 绪论/Scanf.c"
/* 宏定义 */
#define MAXSIZE 100
/* 类型定义 */
typedef struct KNode //邻接表结点类型
{
int key;
struct KNode *next;
}KNode;
typedef struct
{
KNode *first;
}HNode;
typedef HNode HashTable[MAXSIZE];
/* 函数原型 */
void Algo_9_45(FILE *fp, HashTable H); //创建哈希表
int fHash_9_45(int key); //生成i的哈希地址
void Print_9_45(HashTable H);
int main(int argc, char *argv[])
{
FILE *fp;
int p;
HashTable H;
fp = fopen("Data/Algo_9_45.txt","r");
Algo_9_45(fp, H);
fclose(fp);
printf("输出哈希表中所有关键字:\n");
Print_9_45(H);
printf("\n");
return 0;
}
/*━━━━━━━━━━━━━━━━━━━┓
┃题9.45:创建哈希表,用链地址法处理冲突┃
┗━━━━━━━━━━━━━━━━━━━*/
void Algo_9_45(FILE *fp, HashTable H)
{
int i, p;
int tmp;
KNode *r, *h;
for(i=0; i<MAXSIZE; i++)
H[i].first = NULL;
while(Scanf(fp, "%d", &tmp)==1) //录入关键字到哈希表
{
h = (KNode*)malloc(sizeof(KNode));
h->key = tmp;
h->next = NULL;
p = fHash_9_45(tmp);
if(H[p].first==NULL)
H[p].first = h;
else
{
if(H[p].first->key>tmp)
{
h->next = H[p].first;
H[p].first = h;
}
else
{
r = H[p].first;
while(r->next&&r->next->key<=tmp)
r = r->next;
h->next = r->next;
r->next = h;
}
}
}
}
int fHash_9_45(int key) //哈希函数
{
return key%13; //H(key) = key MOD 13
}
void Print_9_45(HashTable H)
{
int i;
KNode *r;
for(i=1; i<MAXSIZE; i++)
{
if(H[i].first)
{
for(r=H[i].first; r; r=r->next)
printf("%d ", r->key);
}
}
}
@@ -0,0 +1,97 @@
#include <stdio.h>
#include "../../../▲课本算法实现/▲01 绪论/Status.h" //**▲01 绪论**//
#include "../../../▲课本算法实现/▲01 绪论/Scanf.c"
/* 宏定义 */
#define MAXSIZE 20000
/* 类型定义 */
typedef struct
{
int row;
int col;
int key;
int tag; //tag=0:结点为空
}HNode;
typedef HNode HashTable[MAXSIZE];
/* 函数原型 */
int Algo_9_46(HashTable H, int row, int col);
Status CreateHash_9_46(FILE *fp, HashTable H);//创建哈希表
int fHash_9_46(int row, int col);//根据行列值生成哈希地址
int main(int argc, char *argv[])
{
FILE *fp;
int p;
HashTable H;
fp = fopen("Data/Algo_9_46.txt","r");
CreateHash_9_46(fp, H);
fclose(fp);
printf("查找测试:\n");
p = Algo_9_46(H, 622,64);
printf("下标为(%d %d)的关键字在哈希表第 %d 个位置。\n", 622, 64, p);
printf("\n");
return 0;
}
/*━━━━━━━━━━━━━━━━━━━┓
┃题9.46:查找指定行列值在哈希表中的位置┃
┗━━━━━━━━━━━━━━━━━━━*/
int Algo_9_46(HashTable H, int row, int col)
{
int p;
p = fHash_9_46(row, col);
while(H[p].tag==1&&(H[p].row!=row||H[p].col!=col))
p = (p+1)%MAXSIZE; //若出现“无效碰撞”则顺次往下查找
if(H[p].tag==1&&H[p].row==row&&H[p].col==col)
return p;
else
return -1; //此行列值下的关键字不存在时返回-1
}
Status CreateHash_9_46(FILE *fp, HashTable H)
{
int i, p;
int row, col, key;
for(i=0; i<MAXSIZE; i++)
H[i].tag = 0;
while(Scanf(fp, "%d%d%d", &row, &col, &key)==3) //录入关键字到哈希表
{
p = fHash_9_46(row, col);
while(H[p].tag==1) //出现冲突
p = (p+1)%MAXSIZE;
if(H[p].tag==0)
{
H[p].tag = 1;
H[p].row = row;
H[p].col = col;
H[p].key = key;
}
else //此处未对失败情况做限制
return ERROR;
}
return OK;
}
int fHash_9_46(int row, int col) //哈希函数
{
int a, b, c;
a = row%100; //取行列值的后两位
b = col%100;
c = a*100 + b; //c的范围在0~9999
return 2*c;
}
@@ -0,0 +1,390 @@
# 第9章 查找
## 一、基础知识题
### 9.1 若对大小均为n的有序的顺序表和无序的顺序表分别进行顺序查找,试在下列三种情况下分别讨论两者在等概率时的平均查找长度是否相同?
##### (1)查找不成功,即表中没有关键字等于给定值K的记录;
##### (2)查找成功,且表中只有一个关键字等于给定值K的记录;
##### (3)查找成功,且表中有若干个关键字等于给定值K的记录,一次查找要求找出所有记录。此时的平均查找长度应考虑找到所有记录时所用的比较次数。
> (1)相同
> (2)不相同
> (3)不相同
### 9.2 试分别画出在线性表(a,b,c,d,e,f,g)中进行折半查找,以查关键字等于e,f和g的过程。
> ![9.2](_v_images/20181214213333370_9161.png)
### 9.3 画出对长度为10的有序表进行折半查找的判定树,并求其等概率时查找成功的平均查找长度。
> ![9.3](_v_images/20181214213408549_8068.png)
>
> ASLsucc=(1*1+2*2+3*4+4*3)/10=2.9
### 9.4 假设按下述递归方法进行顺序表的查找:若表长≤10,则进行顺序查找,否则进行折半查找。试画出对表长n=50的顺序表进行上述查找时,描述该查找的判定树,并求出在等概率情况下查找成功的平均查找长度。
> ![9.4](_v_images/20181214213449099_15405.png)
>
> ASLsucc=(1*1+2*2+3*4+(4+5+6+7+8)*8+9*3)/50=5.68
### 9.5 下列算法为斐波那契查找的算法:
```c
int FibSearch(SqList r, KeyType K)
{
j=1;
while(fib(j)<n+1)
j = j + 1;
mid = n - fib(j-2) + 1; //若fib(j)=n+1,则mid=fib(j-1)
f1 = fib(j-2);
f2 = fib(j-3);
found = FALSE;
while((mid<>0) && !found)
switch
{
case K=r[mid].key:
found = TRUE;
break;
case K<r[mid].key:
if(!f2)
mid = 0;
else
{
mid = mid-f2;
t = f1 - f2;
f1 = f2;
f2 = t;
}
break;
case K>r[mid].key:
if(f1=1)
mid = 0;
else
{
mid = mid + f2;
f1 = f1 - f2;
f2 = f2 f1;
}
break;
}
if(found)
return mid;
else
return 0;
}//FibSearch
fib(i)(9.1.2)20
```
> ![9.5](_v_images/20181214213551073_28565.png)
>
> ASLsucc=(1*1+2*2+3*4+4*7+5*5+6*1)/20=3.8
### 9.6 假设在某程序中有如下一个if-then嵌套的语句
```c
if(C1)
if(C2)
if(C3)
if(Cn)
S;
```
#### 其中Ci为布尔表达式。显然,只有当所有的C<sub>i</sub>都为TRUE时,语句S才能执行。假设t(i)为判别Ci是否为TRUE所需时间,p(i)为C<sub>i</sub>是TRUE的概率,试讨论这n个布尔表达式C<sub>i</sub>(i=1,2,…,n)应如何排列才能使该程序最有效地执行?
> 暂未理解题意。如有好的见解,欢迎提交Issues。
### 9.7 已知一个有序表的表长为8N,并且表中没有关键字相同的记录。假设按如下所述方法查找一个关键字等于给定值K的记录:先在第8,16,24,…,8K,…,8N个记录中进行顺序查找,或者查找成功,或者由此确定出一个继续进行折半查找的范围。画出描述上述查找过程的判定树,并求等概率查找时查找成功的平均查找长度。
> (N+1)/2+17/8
### 9.8 已知含12个关键字的有序表及其相应权值为:
![9.8.1](_v_images/20181214214042887_18269.png)
##### (1)试按次优查找树的构造算法并加适当调整画出由这12个关键字构造所得的次优查找树,并计算它的PH值;
##### (2)画出对以上有序表进行折半查找的判定树,并计算它的PH值。
> (1)次优查找树如下图,其PH=133
> ![9.8.2](_v_images/20181214213924381_20066.png)
>
> (2)折半查找时:PH=156
### 9.9 已知如下所示长度为12的表:(Jan, Feb, Mar, Apr, May, June, July, Aug, Sep, Oct, Nov, Dec)
##### (1)试按表中元素的顺序依次插入一棵初始为空的二叉排序树,画出插入完成之后的二叉排序树,并求其在等概率的情况下查找成功的平均查找长度。
##### (2)若对表中元素先进行排序构成有序表,求在等概率的情况下对此有序表进行折半查找时查找成功的平均查找长度。
##### (3)按表中元素顺序构造一棵平衡二叉排序树,并求其在等概率的情况下查找成功的平均查找长度。
> (1)ASLsucc=42/12=3.5
> ![9.9.1](_v_images/20181214214525317_23291.png)
>
> (2)排序后的关键字如下,其平均查找长度为:ASLsucc=37/12=3.08
> Apr, Aug, Dec, Feb, Jan, July, June, Mar, May, Nov, Oct, Sept
>
> (3)ASLsucc=38/12=3.17
> ![9.9.2](_v_images/20181214214606440_10337.png)
### 9.10 可以生成如下二叉排序树的关键字的初始排列有几种?请写出其中的任意5个。
![9.10](_v_images/20181214214633281_23456.png)
> 总共30种。
>
> 例:(5,6,7,4,2,1,3)(5,4,6,7,2,1,3)(5,4,2,6,7,1,3)(5,4,2,1,6,7,3)(5,4,2,1,3,6,7)。
### 9.11 试推导含12个结点的平衡二叉树的最大深度,并画出一棵这样的树。
> ![9.11](_v_images/20181214214720912_4862.png)
> 深度为h的平衡二叉树中含有的最少结点数为Nh=Nh-1+Nh-2+1,由此可推出含有12个结点的平衡二叉树的最大深度为5.
### 9.12 在B-树定义中,特性(3)的意图是什么?试思考:若把“┌m/2┐”改为“┌2m/3┐”或“┌m/3┐”是否可行?所得到的树结构和B-树有何区别?
> 特性3的意图在于保证B-树中结点空间的利用率不低于某个下限。改为┌2m/3┐不行,因为某结点因插入关键字而使其中关键字书目为m时,无法分裂成两个子树个数大于┌2m/3┐的结点;改为┌m/3┐是可行的,但它的结点利用空间利用率较低,不过分裂不如B-树那样频繁。
### 9.13 含9个叶子结点的3阶B-树中至少有多少个非叶子结点?含10个叶子结点的3阶B-树中至多有多少个非叶子结点?
> (1)至少4个
> (2)至多8个
### 9.14 试从空树开始,画出按以下次序向2-3树即3阶B-树中插入关键码的建树过程:20,30,50,52,60,68,70。如果此后删除50和68,画出每一步执行后2-3树的状态。
> 创建过程如下:
> ![9.14.1](_v_images/20181214214910449_20293.png)
> 删除过程如下:
> ![9.14.2](_v_images/20181214214939408_12857.png)
### 9.15 试证明:高度为h的2-3树中叶子结点的数目在2h-1与3h-1之间。
> 设2-3树每层结点关键字数量为n,则n=1或n=2。
> 显然,当各结点关键字数量为1时,2-3树即为一颗完全二叉树,当其高度为h时,其叶子结点数目有最小值2h-1。
> 同理,当树中各结点关键字数量为2时,可得高度为h的2-3树叶子结点数量为3h-1。
> 故结论得证。(画图辅助证明会更直观)
### 9.16 在含有n个关键码的m阶B-树中进行查找时,最多访问多少个结点?
> B-树中查找时,总是顺着树的分支往下走,且一次走一层,所以欲使访问果的结点最多,则只需使n个关键码构成的B-树有最大高度即可。
> 对于含n个关键码的m阶B-树,其高度最多为:h=logt((n+1)/2)+1t=┌m/2┐,故其最多访问的结点数为h。
### 9.17 B+树和B-树的主要差异是什么?
> B-树:多路搜索树,每个结点存储M/2到M个关键字,非叶子结点存储指向关键字范围的子结点;所有关键字在整颗树中出现,且只出现一次,非叶子结点可以命中;
> B+树:在B-树基础上,为叶子结点增加链表指针,所有关键字都在叶子结点中出现,非叶子结点作为叶子结点的索引;B+树总是到叶子结点才命中。
### 9.18 试画一个对应于关键字集{program, programmer, programming,processor, or}的Trie树,对每个关键字从右向左取样,每次一个字母。
> 注:只写出了使用的字母
> ![9.18](_v_images/20181214215141119_17719.png)
### 9.19 选取哈希函数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)造哈希表,并求等概率情况下查找成功时的平均查找长度。
> 由题意可知:
>
> H(22)=0;
> H(41)=2;
> H(53)=5;
> H(46)=6;
> H(30)=2; -> H(30)=3;
> H(13)=6; -> H(13)=8;
> H(01)=3; -> H(01)=0; -> H(01)=8; -> H(01)=5; -> H(01)=2; -> H(01)=10;
> H(67)=3; -> H(67)=2; -> H(67)=1;
>
> 故构造函数的哈希表为:
> ![9.19](_v_images/20181214215223320_3867.png)
>
> 等概率时查找成功的平均查找长度为:
> ASL = (1+3+1+2+1+1+2+6)/8=17/8
### 9.20 试为下列关键字建立一个装载因子不小于0.75的哈希表,并计算你所构造的哈希表的平均查找长度。
##### (ZHAO, QIAN, SUN, LI, ZHOU, WU, ZHENG, WANG, CHANG, CHAO, YANG, JIN)
> 这里使用线性探测开放定址法建立哈希表
>
> (1)确定哈希表长度
> 由装载因子=记录数/表长得:表长≤12/0.75=16
>
> (2)将单词key转换为一个数字num,转换依据是:(还有其他转换依据)
>> int num = 0;
>> for(i=0; i<key.length; i++)
>> {
>> num = 37*num + (key[i]-A+1); //姓氏字串不会太长,可以遍历所有字符构造哈希值
>> }
> 由此可得:
> num(ZHAO)=1327982; num(QIAN)=873473; num(SUN)=26802; num(LI)=453;
> num(ZHOU)=1328506; num(WU)=872; num(ZHENG)=49140780; num(WANG)=1166913;
> num(CHANG)=6029601; num (CHAO)=162963; num (YANG)=1268219; num (JIN)=14037;
>
> (3)映射为哈希值,出现冲突时,顺次后移一位。
> h(ZHAO)=1327982%16=14;
> h(QIAN)=873473%16=1;
> h(SUN)=26802%16=2;
> h(LI)=453%16=5;
> h(ZHOU)=1328506%16=10;
> h(WU)=872%16=8;
> h(ZHENG)=49140780%16 = 12;
> h(WANG)=1166913%16=1; h(WANG)=2; h(WANG)= 3;
> h(CHANG)=6029601%16=1; h(CHANG)=2; h(CHANG)=3; h(CHANG) = 4;
> h(CHAO)=162963%16=3; h(CHAO)=4; h(CHAO)=5; h(CHAO) = 6;
> h(YANG)=1268219%16=11;
> h(JIN)=14037%16=5; h(JIN) = 6; h(JIN) = 7;
>
> (4)构造的哈希查找表如下图:
> ![9.20](_v_images/20181214215634299_17793.png)
> 故平均查找长度为:ASL=(1+1+3+4+1+4+3+1+1+1+1+1)/12=1.8
### 9.21 在地址空间为0~16的散列区中,对以下关键字序列构造两个哈希表:
##### (Jan, Feb, Mar, Apr, May, June, July, Aug, Sep, Oct, Nov, Dec)
##### (1)用线性探测开放定址法处理冲突;
##### (2)用链地址法处理。
##### 并分别求这两个哈希表在等概率情况下查找成功和不成功时的平均查找长度。
##### 设哈希函数为H(x)= └i/2┘,其中i为关键字中第一个字母在字母表中的序号。
> (1)处理冲突时采用序号增一的方式,结合题设可得:
> H(Jan)=5;
> H(Feb)=3;
> H(Mar)=6;
> H(Apr)=0;
> H(June)=5; H(June)=6; H(June)=7;
> H(May)=6; H(May)=7; H(May)=8;
> H(July)=5; H(July)=6; H(July)=7; H(July)=8; H(July)=9;
> H(Aug)=0; H(Aug)=1;
> H(Sep)=9; H(Sep)=10;
> H(Oct)=7; H(Oct)=8; H(Oct)=9; H(Oct)=10; H(Oct)=11;
> H(Nov)=7; H(Nov)=8; H(Nov)=9; H(Nov)=10; H(Nov)=11; H(Nov)=12;
> H(Dec)=2;
> ![9.21.1](_v_images/20181214220147072_20491.png)
>
> 查找成功时,待查找字符串肯定是题设中给出的12个字串之一,故其查找成功的平均查找长度为:
> ASL=(1+2+1+1+1+1+3+3+5+2+5+6)/12=31/12
>
> 查找失败时,待查找字符串可能是任意字串,它的首字母的取值范围是[0,13](1/2=0, 26/2=13)。
> 当待查字串的哈希值为0时,需要与0,1,2,3,4比较5次才能确定不匹配;
> 当待查字串的哈希值为1时,需要与1,2,3,4比较4次才能确定不匹配;
> ...
> 当待查字串的哈希值为4时,只需与4比较1次就能确定不匹配;
> ...
> 当待查字串的哈希值为12时,需要与12,13比较2次才能确定不匹配;
> 当待查字串的哈希值为13时,只需与13比较1次就能确定不匹配;
> 故其查找失败的平均长度为:
> ASL=(5+4+3+2+1+9+8+7+6+5+4+3+2+1)/14=60/14
>
>
> (2)按照平均查找长度的定义,公式中的Ci是指:“关键字与给定值比较的个数”则在用链地址处理冲突时,和“空指针”的比较不计在内。
> H(Jan)=5; H(June)=5; H(July)=5;
> H(Feb)=3;
> H(Mar)=6; H(May)=6;
> H(Apr)=0; H(Aug)=0;
> H(Sep)=9;
> H(Oct)=7; H(Nov)=7;
> H(Dec)=2;
> ![9.21.2](_v_images/20181214220301460_10605.png)
>
> 查找成功时,待查找字符串肯定是题设中给出的12个字串之一:
> 若给定字串是Apr,则需在0处比对一次;
> 若给定字串是Aug,则需在0处比对两次;
> ...
> 若给定字串是July,则需在5处比对三次;
> ...
> 故其查找成功的平均查找长度为:
> ASL=(1*7+2*4+3*1)/12=18/12
>
> 查找失败时,字串的哈希值取值范围仍为[0,13]:
> 若给定字串的哈希值为0,则需与Apr、Aug分别比较2次后才能确定失配;
> 若给定字串的哈希值为2,则需与Dec比较1次后就能确定失配;
> ...
> 若给定字串的哈希值为9,则需与Sep比较1次后就能确定失配。
> 故查找失败的平均长度:
> ASL=(2+1+1+3+2+2+1)/14=12/14
### 9.22 已知一个含有1000个记录的表,关键字为中国人姓氏的拼音,请给出此表的一个哈希表设计方案,要求它在等概率情况下查找成功的平均查找长度不超过3。
> 暂未想到合适的解答。如有好的见解,欢迎提交Issues。
### 9.23 设有一个关键字取值范围为正整数的哈希表,空表项的值为-1,用开放定址法解决冲突。现有两种删除策略:一是将待删表项的关键字置为-1;二是将探测序列上的关键字顺序递补,即用探测序列上下一个关键字覆盖待删关键字,并将原序列上之后一个关键字置为-1。这两种方法是否可行?为什么?给出一种可行的方法,并叙述它对查找和插入算法所产生的影响。
> 两种方案都不行。前者切断了探测链,后者可能移动了非同义词。
>
> 一种可行的解决方案是:将待删除的关键字置为0,以区别于空表项。查找和插入算法都应相应地进行调整。
### 9.24 某校学生学号由8位十进制数字组成:C1C2C3C4C5C6C7C8。C1C2为入学时年份的后两位;C3C4为系别:00~24分别代表该校的25个系;C5为0或1,0表示本科生,1表示研究生;C6C7C8为对某级某系某类学生的顺序编号:对于本科生,它不超过199,对于研究生,它不超过049,共有4个年级,四年级学生1996年入学。
##### (1)当在校生人数达极限情况时,将他们的学号散列到0~24999的地址空间,问装载因子是多少?
##### (2)求一个无冲突的哈希函数H1,它将在校生学号散列到。0~24999的地址空间。其簇聚性如何?
##### (3)设在校生总数为15000人,散列地址空间为,0~19999,你是否能找到一个(2)中要求的H1?若不能,试设计一个哈希函数H2及其解决冲突的方法,使得多数学号可只经一次散列得到(可设各系各年级本科生平均人数为130,研究生平均人数为20)。
##### (4)用算法描述语言表达H2,并写出相应的查找函数。
> 暂未想到合适的解答。如有好的见解,欢迎提交Issues。
## 二、算法设计题
### 9.25 假设顺序表按关键字自大至小有序,试改写教科书9.1.1节中的顺序查找算法,将监视哨设在高下标端。然后画出描述此查找过程的判定树,分别求出等概率情况下查找成功和不成功时的平均查找长度。
> [Question-9.25-main.c](▼习题测试文档-09/Question-9.25-main.c)
### 9.26 试将折半查找的算法改写成递归算法。
### 9.27 改写教科书9.1.2节中折半查找的算法,当r[i].key≤Kr[i+1].key(i=1,2,…,n-1)时,返回i;当K<r[1].key时,返回0;当K≥r[n].key时,返回n。
> [Question-9.26~9.27-main.c](▼习题测试文档-09/Question-9.26~9.27-main.c)
### 9.28 试编写利用折半查找确定记录所在块的分块查找算法。并讨论在块中进行顺序查找时使用“监视哨”的优缺点,以及必要时如何在分块查找的算法中实现设置“监视哨”的技巧。
> [Question-9.28-main.c](▼习题测试文档-09/Question-9.28-main.c)
### 9.29 已知一非空有序表,表中记录按关键字递增排列,以不带头结点的单循环链表作存储结构,外设两个指针h和t,其中h始终指向关键字最小的结点,t则在表中浮动,其初始位置和h相同,在每次查找之后指向刚查到的结点。查找算法的策略是:首先将给定值K和t->key进行比较,若相等,则查找成功;否则因K小于或大于t->key而从h所指结点或t所指结点的后继结点起进行查找。
##### (1)按上述查找过程编写查找算法;
##### (2)画出描述此查找过程的判定树,并分析在等概率查找时查找成功的平均查找长度(假设表长为n,待查关键码K等于每个结点关键码的概率为1/n,每次查找都是成功的,因此在查找时,t指向每个结点的概率也为1/n)。
> [Question-9.29-main.c](▼习题测试文档-09/Question-9.29-main.c)
### 9.30 将9.28题的存储结构改为双向循环链表,且外设一个指针sp,其初始位置指向关键字最小的结点,在每次查找之后指向刚查到的结点。查找算法的策略是:首先将给定值K和sp->key进行比较,若相等,则查找成功;否则依K小于或大于sp->key继续从*sp的前驱或后继结点起进行查找。编写查找算法并分析等概率查找时查找成功的平均查找长度。
> [Question-9.30-main.c](▼习题测试文档-09/Question-9.30-main.c)
### 9.31 试写一个判别给定二叉树是否为二叉排序树的算法,设此二叉树以二叉链表作存储结构。且树中结点的关键字均不同。
### 9.32 已知一棵二叉排序树上所有关键字中的最小值为-max,最大值为max,又-max<x<max。编写递归算法,求该二叉排序树上的小于x且最靠近x的值a和大于x且最靠近x的值b。
### 9.33 编写递归算法,从大到小输出给定二叉排序树中所有关键字不小于x的数据元素。要求你的算法的时间复杂度为O(log2n+m),其中n为排序树中所含结点数,m为输出的关键字个数。
### 9.34 试写一时间复杂度为O(log2n+m)的算法,删除二叉排序树中所有关键字不小于x的结点,并释放结点空间。其中n为树中所含结点数,m为被删除的结点个数。
> [Question-9.31~9.34-main.c](▼习题测试文档-09/Question-9.31~9.34-main.c)
### 9.35 假设二叉排序树以后继线索链表作存储结构,编写输出该二叉排序树中所有大于a且小于b的关键字的算法。
### 9.36 同9.35题的结构,编写在二叉排序树中插入一个关键字的算法。
### 9.37 同9.35题的结构,编写从二叉排序树中删除一个关键字的算法。
> [Question-9.35~9.37-main.c](▼习题测试文档-09/Question-9.35~9.37-main.c)
### 9.38 试写一算法,将两棵二叉排序树合并为一棵二叉排序树。
### 9.39 试写一算法,将一棵二叉排序树分裂为两棵二叉排序树,使得其中一棵树的所有结点的关键字都小于或等于x,另一棵树的任一结点的关键字均大于x。
> [Question-9.38~9.39-main.c](▼习题测试文档-09/Question-9.38~9.39-main.c)
### 9.40 在平衡二叉排序树的每个结点中增设一个lsize域,其值为它的左子树中的结点数加1。试写一时间复杂度为O(logn)的算法,确定树中第k小的结点的位置。
> [Question-9.40-main.c](▼习题测试文档-09/Question-9.40-main.c)
### 9.41 为B+树设计结点类型并写出算法,随机(而不是顺序)地查找给定的关键字K,求得它所在的叶子结点指针和它在该结点中的位置(提示:B+树中有两种类型的指针,结点结构也不尽相同,考虑利用记录的变体)。
> [Question-9.41-main.c](▼习题测试文档-09/Question-9.41-main.c)
### 9.42 假设Trie树上叶子结点的最大层次为h,同义词放在同一叶子结点中,试写在Trie树中插入一个关键字的算法。
### 9.43 同9.42的假设,试写在Trie树中删除一个关键字的算法。
> [Question-9.42~9.43-main.c](▼习题测试文档-09/Question-9.42~9.43-main.c)
### 9.44 已知某哈希表的装载因子小于1,哈希函数H(key)为关键字(标识符)的第一个字母在字母表中的序号,处理冲突的方法为线性探测开放定址法。试编写一个按第一个字母的顺序输出哈希表中所有关键字的算法。
> [Question-9.44-main.c](▼习题测试文档-09/Question-9.44-main.c)
### 9.45 假设哈希表长为m,哈希函数为H(x),用链地址法处理冲突。试编写输入一组关键字并建造哈希表的算法。
> [Question-9.45-main.c](▼习题测试文档-09/Question-9.45-main.c)
### 9.46 假设有一个1000×1000的稀疏矩阵,其中1%的元素为非零元素,现要求用哈希表作存储结构。试设计一个哈希表并编写相应算法,对给定的行值和列值确定矩阵元素在哈希表上的位置。请将你的算法与在稀疏矩阵的三元组表存储结构上存取元素的算法(不必写出)进行时间复杂度的比较。
> [Question-9.46-main.c](▼习题测试文档-09/Question-9.46-main.c)