查找
#include <stdio.h>
#include <stdlib.h>
#define ElemType int
// 查找表的数据结构
typedef struct {
ElemType *elem; // 元素存储空间地址
int TableLen; // 表长度
} SSTable; //ss search seq table
// 哨兵版查找
// 注意: 成功返回数据下标,失败返回0
// 由于0号下标是哨兵,找到哨兵后则证明没有返回找到值,返回0为查找失败
int Sentinel_Search_Seq (SSTable ST, ElemType key) {
ST.elem[0] = key; // 使哨兵 = 查找元素
int i;
// 下面 for 循环的写法也是正确的
// for (i = ST.TableLen; ST.elem[i] != key; --i)
// 为了方便理解,改写成while循环的
i = ST.TableLen;
while (ST.elem[i] != key) {
i = i - 1;
}
return i;
}
// 普通版查找
// 成功返回数据下标,失败返回 -1
int Search_Seq (SSTable ST, ElemType key) {
int i;
// 下面 for 循环的写法也是正确的
// for (i = 0; i < ST.TableLen && ST.elem[i] != key; ++i);
// 为了方便理解,改写成while循环的
i = 0;
while (i < ST.TableLen) {
if (ST.elem[i] == key) break;
i = i + 1;
}
return i == ST.TableLen ? - 1 : i;
}
int main () {
// 待查找的值
ElemType searchNum = 60;
// 查找到的下标
int searchResultIndex;
// 带哨兵版查找
SSTable SentinelSS;
// 注意:带哨兵的 table 长度为有效数据长度,不包含哨兵
SentinelSS.TableLen = 7;
SentinelSS.elem = (ElemType *)malloc(sizeof(ElemType) * (SentinelSS.TableLen + 1)); // + 1 是哨兵位置
// 下标0,存储哨兵
SentinelSS.elem[0] = -1;
SentinelSS.elem[1] = 40;
SentinelSS.elem[2] = 20;
SentinelSS.elem[3] = 50;
SentinelSS.elem[4] = 10;
SentinelSS.elem[5] = 60;
SentinelSS.elem[6] = 80;
SentinelSS.elem[7] = 70;
searchResultIndex = Sentinel_Search_Seq(SentinelSS, searchNum);
if (searchResultIndex == 0) {
printf("哨兵版未查找到值:%d, 查找结果为:%d\n", searchNum, searchResultIndex);
} else {
printf("哨兵版查找值:%d, 下标为:%d\n", searchNum, searchResultIndex);
}
// 普通模式查找
SSTable SS;
SS.TableLen = 7;
SS.elem = (ElemType *)malloc(sizeof(ElemType) * SS.TableLen);
SS.elem[0] = 40;
SS.elem[1] = 20;
SS.elem[2] = 50;
SS.elem[3] = 10;
SS.elem[4] = 60;
SS.elem[5] = 80;
SS.elem[6] = 70;
searchResultIndex = Search_Seq(SS, searchNum);
if (searchResultIndex == -1) {
printf("普通版未查找到值:%d, 查找结果为:%d\n", searchNum, searchResultIndex);
} else {
printf("普通版查找值:%d, 下标为:%d\n", searchNum, searchResultIndex);
}
return 0;
}
#include <stdio.h>
#include <stdlib.h>
#define ElemType int
// 查找表的数据结构
typedef struct {
ElemType *elem; // 元素存储空间地址
int TableLen; // 表长度
} SSTable; // search seq table
// 有序表的顺序查找
// 成功返回数据下标,失败返回 -1
int Search_Seq (SSTable ST, ElemType key) {
for (int i = 0; i < ST.TableLen; i++) {
if (ST.elem[i] == key) return i; // 返回目标元素在有序表中的索引位置
if (ST.elem[i] > key) return -1; // 返回-1表示未找到目标元素
}
return -1; // 如果遍历完整个有序表仍未找到目标元素,则返回-1
}
int main () {
// 待查找的值
ElemType searchNum = 60;
// 查找到的下标
int searchResultIndex;
// 普通模式查找
SSTable SS;
SS.TableLen = 7;
SS.elem = (ElemType *)malloc(sizeof(ElemType) * SS.TableLen);
SS.elem[0] = 20;
SS.elem[1] = 40;
SS.elem[2] = 50;
SS.elem[3] = 60;
SS.elem[4] = 70;
SS.elem[5] = 80;
SS.elem[6] = 90;
searchResultIndex = Search_Seq(SS, searchNum);
if (searchResultIndex == -1) {
printf("未查找到值:%d, 查找结果为:%d
", searchNum, searchResultIndex);
} else {
printf("查找到值:%d, 下标为:%d
", searchNum, searchResultIndex);
}
return 0;
}
#include <stdio.h>
#include <stdlib.h>
#define ElemType int
// 查找表的数据结构
typedef struct {
ElemType *elem; // 元素存储空间地址
int TableLen; // 表长度
} SSTable; // search seq table
// 成功返回数据下标,失败返回 -1
int Binary_Search (SSTable ST, ElemType key) {
int low = 0; // 初始化搜索范围的下界。
int high = ST.TableLen - 1; // 初始化搜索范围的上界。
int mid; // 声明一个变量来存储中间索引。
// 在下界小于等于上界的情况下执行二分查找。
while (low <= high) {
mid = (low + high) / 2; // 通过计算下界和上界的平均值来计算中间索引。
if (ST.elem[mid] == key) // 将中间索引处的元素与关键字进行比较。
return mid; // 如果元素与关键字匹配,则返回找到的索引。
else if (ST.elem[mid] > key)
high = mid - 1; // 如果元素大于关键字,则将上界更新为前半部分进行搜索。
else
low = mid + 1; // 如果元素小于关键字,则将下界更新为后半部分进行搜索。
}
// 如果循环完成仍未找到关键字,则返回 -1 表示搜索失败。
return -1;
}
int main () {
// 待查找的值
ElemType searchNum = 100;
// 查找到的下标
int searchResultIndex;
// 普通模式查找
SSTable SS;
SS.TableLen = 7;
SS.elem = (ElemType *)malloc(sizeof(ElemType) * SS.TableLen);
SS.elem[0] = 20;
SS.elem[1] = 40;
SS.elem[2] = 50;
SS.elem[3] = 60;
SS.elem[4] = 70;
SS.elem[5] = 80;
SS.elem[6] = 90;
searchResultIndex = Binary_Search(SS, searchNum);
if (searchResultIndex == -1) {
printf("未查找到值:%d, 查找结果为:%d
", searchNum, searchResultIndex);
} else {
printf("查找到值:%d, 下标为:%d
", searchNum, searchResultIndex);
}
return 0;
}
#include <stdio.h>
#include <stdlib.h>
#define MAXM 10 // 定义B树的最大的阶数
const int m = 5; // 设定B树的阶数
const int Max = m - 1; // 结点的最大关键字数量
const int Min = (m - 1) / 2; // 结点的最小关键字数量
typedef int ElemType; // ElemType为关键字类型
// B树和B树结点类型
typedef struct node {
int keynum; // 结点关键字个数
ElemType key[MAXM]; // 关键字数组,key[0]不使用
struct node *parent; // 双亲结点指针
struct node *children[MAXM]; // 孩子结点指针数组
} BTNode, *BTree;
// B树查找结果类型
typedef struct {
BTNode *pt; // 指向找到的结点
int i; // 在结点中的关键字位置;
int tag; // 查找成功与否标志
} Result;
// 链表和链表结点类型
typedef struct LNode {
BTree data; // 数据域
struct LNode *next; // 指针域
} LNode, *LinkList;
// 枚举类型(依次递增)
typedef enum status {
TRUE,
FALSE,
OK,
ERROR,
OVERFLOW,
EMPTY
} Status;
// 初始化B树
Status InitBTree(BTree &t) {
t = NULL;
return OK;
}
/**
* 在结点p中查找关键字k的插入位置i,使得p->key[i] <= k < p->key[i+1]。
* @param p - 目标结点
* @param k - 要查找的关键字
* @return int - 插入位置i,表示在结点p的第i个关键字之后插入k
*/
int SearchBTNode(BTNode *p, ElemType k) {
int i = 0;
// 从前向后逐个查找结点p中的关键字,找到第一个满足 p->key[i] <= k < p->key[i+1] 的位置
for (
i = 0;
i < p->keynum && p->key[i + 1] <= k;
i++
);
return i;
}
/**
* 在B树t上查找关键字k,返回查找结果。
* @param t - B树的根结点指针
* @param k - 要查找的关键字
* @return Result - 包含查找结果的结构体,包括指向找到的结点、关键字位置和查找成功与否标志
*/
Result SearchBTree(BTree t, ElemType k) {
BTNode *p = t, *q = NULL; // 初始化结点p和结点q,p指向待查结点,q指向p的双亲
int found_tag = 0; // 设定查找成功与否标志
int i = 0;
Result r; // 设定返回的查找结果
while (p != NULL && found_tag == 0) {
i = SearchBTNode(p, k); // 在结点p中查找关键字k,使得p->key[i] <= k < p->key[i+1]
if (i > 0 && p->key[i] == k) // 找到待查关键字
found_tag = 1; // 查找成功
else { // 查找失败
q = p; // 将当前结点p作为双亲结点q
p = p->children[i]; // 移动到子结点继续查找
}
}
if (found_tag == 1) { // 查找成功
r.pt = p; // 指向找到的结点
r.i = i; // 在结点中的关键字位置
r.tag = 1; // 查找成功标志
} else { // 查找失败
r.pt = q; // 指向双亲结点q
r.i = i; // 在结点中的关键字位置
r.tag = 0; // 查找失败标志
}
return r; // 返回关键字k的位置(或插入位置)
}
/**
* 在结点p中插入关键字k和子树指针q,并保持关键字有序。
* @param p - 要插入关键字的目标结点
* @param i - 插入位置,表示在结点p的第i个关键字之后插入k
* @param k - 要插入的关键字
* @param q - 要插入的子树指针
*/
void InsertBTNode(BTNode *&p, int i, ElemType k, BTNode *q) {
int j;
// 从结点p的末尾开始,依次后移关键字和子树指针,为新关键字和子树指针腾出位置
for (j = p->keynum; j > i; j--) {
p->key[j + 1] = p->key[j];
p->children[j + 1] = p->children[j];
}
// 插入新关键字k和子树指针q到目标位置
p->key[i + 1] = k;
p->children[i + 1] = q;
if (q != NULL)
q->parent = p; // 更新子树指针的父节点为当前结点p
p->keynum++; // 增加结点p中的关键字数量
}
/**
* 将结点p分裂成两个结点,前一半保留,后一半移入结点q。
* @param p - 待分裂的结点
* @param q - 分裂后的新结点
*/
void SplitBTNode(BTNode *&p, BTNode *&q) {
int i;
int s = (m + 1) / 2; // 计算分裂位置s,即后一半移入结点q
q = (BTNode *)malloc(sizeof(BTNode)); // 为新结点q分配空间
// 后一半关键字和子树指针从结点p移动到结点q
q->children[0] = p->children[s];
for (i = s + 1; i <= m; i++) {
q->key[i - s] = p->key[i];
q->children[i - s] = p->children[i];
}
q->keynum = p->keynum - s; // 更新新结点q的关键字数量
q->parent = p->parent; // 更新新结点q的父节点指针
// 更新子树指针的父节点指针为新结点q
for (i = 0; i <= p->keynum - s; i++)
if (q->children[i] != NULL)
q->children[i]->parent = q;
p->keynum = s - 1; // 更新结点p的关键字数量,前一半保留
}
/**
* 生成新的根结点t,原p和q为子树指针。
* @param t - 新的根结点指针
* @param k - 新的根结点的关键字
* @param p - 原根结点的左子树
* @param q - 原根结点的右子树
*/
void NewRoot(BTNode *&t, ElemType k, BTNode *p, BTNode *q) {
t = (BTNode *)malloc(sizeof(BTNode)); // 分配空间
t->keynum = 1; // 根结点的关键字数量为1
t->children[0] = p; // 左子树指针指向原p
t->children[1] = q; // 右子树指针指向原q
t->key[1] = k; // 新根结点的关键字为k
if (p != NULL) // 调整结点p和结点q的双亲指针
p->parent = t;
if (q != NULL)
q->parent = t;
t->parent = NULL; // 新根结点的双亲为空
}
/**
* 在B树t中插入关键字k,如果需要,进行结点分裂和根结点更新操作
* @param t - B树的根结点指针
* @param i - 插入位置,表示在结点t的第i个关键字之后插入k
* @param k - 要插入的关键字
* @param p - 结点t的双亲结点指针
*/
void InsertBTree(BTree &t, int i, ElemType k, BTNode *p) {
BTNode *q; // 用于指向可能需要分裂的子节点
int finish_tag, newroot_tag, s; // 设定需要新结点标志和插入完成标志
ElemType x;
if (p == NULL) // t是空树
NewRoot(t, k, NULL, NULL); // 生成仅含关键字k的根结点t
else {
x = k; // 将变量x的值设置为待插入的关键字k
q = NULL; // 将指针变量q初始化为NULL,用于指向可能需要分裂的子节点
finish_tag = 0; // 初始化finish_tag为0,表示插入尚未完成
newroot_tag = 0; // 初始化newroot_tag为0,表示不需要创建新的根节点
while (finish_tag == 0 && newroot_tag == 0) {
InsertBTNode(p, i, x, q); // 将关键字x和结点q分别插入到p->key[i+1]和p->children[i+1]
if (p->keynum <= Max)
finish_tag = 1; // 插入完成
else {
s = (m + 1) / 2;
SplitBTNode(p, q); // 分裂结点
x = p->key[s];
if (p->parent) { // 查找x的插入位置
p = p->parent;
i = SearchBTNode(p, x);
}
else // 没找到x,需要新结点
newroot_tag = 1;
}
}
if (newroot_tag == 1) // 根结点已分裂为结点p和q
NewRoot(t, x, p, q); // 生成新根结点t,p和q为子树指针
}
}
/**
* 从结点p中删除关键字p->key[i]和对应的孩子指针p->children[i]。
* @param p - 目标结点
* @param i - 要删除的关键字位置
*/
void Remove(BTNode *p, int i) {
int j;
// 使用循环将后续的关键字和孩子指针前移,覆盖要删除的关键字和孩子指针
for (j = i + 1; j <= p->keynum; j++) {
p->key[j - 1] = p->key[j];
p->children[j - 1] = p->children[j];
}
p->keynum--; // 减少结点p的关键字数量,实现删除操作
}
/**
* 查找被删除关键字 p->key[i](在非叶子结点中)的替代叶子结点,即右子树中值最小的关键字。
* @param p - 目标结点,非叶子结点
* @param i - 被删除关键字的位置
*/
void Substitution(BTNode *p, int i) {
BTNode *q;
// 从当前结点p的右子树开始,一直向左下遍历,找到右子树中的最小关键字所在的叶子结点
for (q = p->children[i]; q->children[0] != NULL; q = q->children[0])
;
p->key[i] = q->key[1]; // 将找到的最小关键字值复制到原位置,用于替代被删除的关键字
}
/**
* 将双亲结点p中的最后一个关键字移入右结点q中,
* 将左结点aq中的最后一个关键字移入双亲结点p中。
* @param p - 双亲结点
* @param i - 从p的第i个孩子开始操作
*/
void MoveRight(BTNode *p, int i) {
int j;
BTNode *q = p->children[i]; // 获取右兄弟q
BTNode *aq = p->children[i - 1]; // 获取左兄弟aq
// 将右兄弟q中的所有关键字和孩子指针向后移动一位
for (j = q->keynum; j > 0; j--) {
q->key[j + 1] = q->key[j];
q->children[j + 1] = q->children[j];
}
q->children[1] = q->children[0]; // 从双亲结点p移动关键字到右兄弟q中
q->key[1] = p->key[i]; // 复制双亲结点p中的关键字值
q->keynum++;
p->key[i] = aq->key[aq->keynum]; // 将左兄弟aq中最后一个关键字移动到双亲结点p中
p->children[i]->children[0] = aq->children[aq->keynum]; // 更新孩子指针
aq->keynum--; // 减少左兄弟aq的关键字数量
}
/**
* 将双亲结点p中的第一个关键字移入左结点aq中,
* 将右结点q中的第一个关键字移入双亲结点p中。
*
* @param p - 双亲结点
* @param i - 从p的第i个孩子开始操作
*/
void MoveLeft(BTNode *p, int i) {
int j;
BTNode *aq = p->children[i - 1]; // 获取左兄弟aq
BTNode *q = p->children[i]; // 获取右兄弟q
aq->keynum++; // 将双亲结点p中的关键字移动到左兄弟aq中
aq->key[aq->keynum] = p->key[i]; // 复制双亲结点p中的关键字值
aq->children[aq->keynum] = p->children[i]->children[0]; // 更新孩子指针
p->key[i] = q->key[1]; // 把右兄弟q中的关键字移动到双亲节点p中
q->children[0] = q->children[1]; // 更新右兄弟q的孩子指针
q->keynum--;
// 将右兄弟q中的所有关键字和孩子指针向前移动一位
for (j = 1; j <= aq->keynum; j++) {
aq->key[j] = aq->key[j + 1];
aq->children[j] = aq->children[j + 1];
}
}
/**
* 将双亲结点p、右结点q合并入左结点aq,并调整双亲结点p中的剩余关键字的位置。
*
* @param p - 双亲结点
* @param i - 从p的第i个孩子开始合并
*/
void Combine(BTNode *p, int i) {
int j;
BTNode *q = p->children[i]; // 获取右兄弟结点q
BTNode *aq = p->children[i - 1]; // 获取左兄弟结点aq
aq->keynum++; // 将双亲结点的关键字p->key[i]插入到左结点aq
aq->key[aq->keynum] = p->key[i];
aq->children[aq->keynum] = q->children[0];
for (j = 1; j <= q->keynum; j++) { // 将右结点q中的所有关键字插入到左结点aq
aq->keynum++;
aq->key[aq->keynum] = q->key[j];
aq->children[aq->keynum] = q->children[j];
}
for (j = i; j < p->keynum; j++) { // 将双亲结点p中的p->key[i]后的所有关键字向前移动一位
p->key[j] = p->key[j + 1];
p->children[j] = p->children[j + 1];
}
p->keynum--; // 修改双亲结点p的keynum值
free(q); // 释放空右结点q的空间
}
/**
* 删除结点p中的第i个关键字后,调整B树的结构。
* 如果必要,进行关键字的移动或合并操作。
* @param p - 待调整的结点
* @param i - 被删除关键字的索引
*/
void AdjustBTree(BTNode *p, int i) {
if (i == 0) { // 删除的是最左边的关键字
if (p->children[1]->keynum > Min) // 右结点可以借
MoveLeft(p, 1);
else // 右兄弟不够借,需要合并
Combine(p, 1);
} else if (i == p->keynum) { // 删除的是最右边的关键字
if (p->children[i - 1]->keynum > Min) // 左结点可以借
MoveRight(p, i);
else // 左兄弟不够借,需要合并
Combine(p, i);
} else if (p->children[i - 1]->keynum > Min) { // 删除关键字在中部且左结点够借
MoveRight(p, i);
} else if (p->children[i + 1]->keynum > Min) { // 删除关键字在中部且右结点够借
MoveLeft(p, i + 1);
} else { // 删除关键字在中部且左右结点都不够借,需要合并
Combine(p, i);
}
}
/**
* 在结点p中查找关键字k并更新i的值以指示查找结果。
* @param p - 当前要查找的结点
* @param k - 要查找的关键字
* @param i - 输出参数,指示查找结果:
* -1 表示未找到关键字k;
* 0 表示关键字k小于结点p中的第一个关键字;
* 1 到 keynum 表示找到关键字k的位置。
* @return - 如果找到关键字k,返回1;否则返回0。
*/
int FindBTNode(BTNode *p, ElemType k, int &i) {
if (k < p->key[1]) { // 如果关键字k小于结点p中的第一个关键字
i = 0; // 查找失败,设置i为0
} else { // 在结点p中查找
i = p->keynum; // 初始化i为结点p的关键字数量
while (k < p->key[i] && i > 1) // 从后往前查找关键字k的位置
i--;
if (k == p->key[i]) // 找到关键字k
return 1; // 返回查找成功标志
}
return 0; // 未找到关键字k,返回查找失败标志
}
/**
* 在结点p中查找并删除关键字k。
* @param p - 当前要查找和删除关键字的结点
* @param k - 要删除的关键字
* @return - 如果成功删除关键字k,返回1;否则返回0。
*/
int BTNodeDelete(BTNode *p, ElemType k) {
int i;
int found_tag; // 查找标志
if (p == NULL)
return 0; // 结点p为空,查找失败
found_tag = FindBTNode(p, k, i); // 在结点p中查找关键字k,返回查找结果
if (found_tag == 1) { // 查找成功
if (p->children[i - 1] != NULL) { // 删除的是非叶子结点
Substitution(p, i); // 寻找相邻关键字(右子树中最小的关键字)
BTNodeDelete(p->children[i], p->key[i]); // 递归删除关键字k
} else
Remove(p, i); // 从结点p中位置i处删除关键字k
} else
found_tag = BTNodeDelete(p->children[i], k); // 沿孩子结点递归查找并删除关键字k
if (p->children[i] != NULL)
if (p->children[i]->keynum < Min) // 删除后关键字个数小于Min
AdjustBTree(p, i); // 调整B树
return found_tag; // 返回查找和删除结果标志
}
// 构建删除框架,执行删除操作
void BTreeDelete(BTree &t, ElemType k) {
BTNode *p;
int a = BTNodeDelete(t, k); // 删除关键字k
if (a == 0) // 查找失败
printf(" 关键字%d不在B树中\n", k);
else if (t->keynum == 0) { // 调整
p = t;
t = t->children[0];
free(p);
}
}
// 递归释放B树
void DestroyBTree(BTree &t) {
int i;
BTNode *p = t;
if (p != NULL) { // B树不为空
for (i = 0; i <= p->keynum; i++) { // 递归释放每一个结点
DestroyBTree(*&p->children[i]);
}
free(p);
}
t = NULL;
}
// 初始化队列
Status InitQueue(LinkList &L) {
L = (LNode *)malloc(sizeof(LNode)); // 分配结点空间
if (L == NULL) // 分配失败
return OVERFLOW;
L->next = NULL;
return OK;
}
// 新建一个结点
LNode *CreateNode(BTNode *p) {
LNode *q;
q = (LNode *)malloc(sizeof(LNode)); // 分配结点空间
if (q != NULL) { // 分配成功
q->data = p;
q->next = NULL;
}
return q;
}
// 元素q入队列
Status Enqueue(LNode *p, BTNode *q) {
if (p == NULL)
return ERROR;
while (p->next != NULL) // 调至队列最后
p = p->next;
p->next = CreateNode(q); // 生成结点让q进入队列
return OK;
}
// 出队列,并以q返回值
Status Dequeue(LNode *p, BTNode *&q) {
LNode *aq;
if (p == NULL || p->next == NULL) // 删除位置不合理
return ERROR;
aq = p->next; // 修改被删结点aq的指针域
p->next = aq->next;
q = aq->data;
free(aq); // 释放结点aq
return OK;
}
// 队列判空
Status IfEmpty(LinkList L) {
if (L == NULL) // 队列不存在
return ERROR;
if (L->next == NULL) // 队列为空
return TRUE;
return FALSE; // 队列非空
}
// 销毁队列
void DestroyQueue(LinkList L) {
LinkList p;
if (L != NULL) {
p = L;
L = L->next;
free(p); // 逐一释放
DestroyQueue(L);
}
}
// 用队列遍历输出B树
Status Traverse(BTree t, LinkList L, int newline, int sum) {
int i;
BTree p;
if (t != NULL) {
printf(" [ ");
Enqueue(L, t->children[0]); // 入队
for (i = 1; i <= t->keynum; i++) {
printf(" %d ", t->key[i]);
Enqueue(L, t->children[i]); // 子结点入队
}
sum += t->keynum + 1;
printf("]");
if (newline == 0) { // 需要另起一行
printf("\n");
newline = sum - 1;
sum = 0;
}
else
newline--;
}
if (IfEmpty(L) == FALSE) { // l不为空
Dequeue(L, p); // 出队,以p返回
Traverse(p, L, newline, sum); // 遍历出队结点
}
return OK;
}
// 输出B树
Status PrintBTree(BTree t) {
LinkList L;
if (t == NULL) {
printf(" B树为空树");
return OK;
}
InitQueue(L); // 初始化队列
Traverse(t, L, 0, 0); // 利用队列输出
DestroyQueue(L); // 销毁队列
return OK;
}
int main() {
BTNode *t = NULL;
Result s; // 设定查找结果
int i, n;
ElemType k;
ElemType a[] = {25, 38, 49, 60, 80, 90, 99, 88, 83, 87, 70, 92, 93, 94, 73, 74, 75};
n = sizeof(a) / sizeof(ElemType);
printf("创建一棵%d阶B树:\n", m);
for (i = 0; i < n; i++) { // 逐一插入元素
s = SearchBTree(t, a[i]);
// 未查找到才插入
if (s.tag == 0)
InsertBTree(t, s.i, a[i], s.pt);
printf(" 第%d步,插入元素%d:\n ", i + 1, a[i]);
PrintBTree(t);
}
printf("\n");
printf("删除操作:\n");
k=25;
BTreeDelete(t,k);
printf(" 删除%d:\n ",k);
printf(" 删除后的B树: \n");
PrintBTree(t);
printf("\n");
k=1;
BTreeDelete(t,k);
printf(" 删除%d:\n ",k);
printf(" 删除后的B树: \n");
PrintBTree(t);
printf("\n");
printf(" 递归释放B树\n"); // 递归释放B树
DestroyBTree(t);
PrintBTree(t);
return 0;
}
#include <stdio.h>
#include <stdlib.h>
// 哈希表大小
#define TABLE_SIZE 13
// 哈希表结点的结构
typedef struct HashNode {
int value;
HashNode *next;
} HashNode;
// 函数用于检查一个整数是否是质数
int isPrime(int n) {
if (n <= 1) return 0;
if (n <= 3) return 1;
if (n % 2 == 0 || n % 3 == 0) return 0;
for (int i = 5; i * i <= n; i += 6) {
if (n % i == 0 || n % (i + 2) == 0) {
return 0;
}
}
return 1;
}
// 哈希函数
int hash(int key) {
// 【除留余数法】
int p = TABLE_SIZE; // 不大于m但最接近m的质数
while (p >= 2) {
// 是质数
if (isPrime(p)) break;
p--;
}
//【直接定址法】
// a * key + b
//【数字分析法】
//【平方取中法】
return key % p; // 使用取余运算计算哈希值
}
// 插入值到链表
void insert(HashNode* table[], int value) {
HashNode *newNode = (HashNode *)malloc(sizeof(HashNode));
HashNode **head = &table[hash(value)];
newNode->value = value;
newNode->next = *head;
*head = newNode;
}
// 查找值是否存在于链表中
int find(HashNode* table[], int value) {
// 开头结点
HashNode *current = table[hash(value)];
while (current != NULL) {
if (current->value == value) {
return 1; // 找到值
}
current = current->next;
}
return 0; // 没有找到值
}
// 从链表中删除值
void removeValue(HashNode* table[], int value) {
HashNode *head = table[hash(value)];
HashNode *current = head;
HashNode *pre = NULL;
while (current != NULL) {
if (current->value == value) {
// 仅有一个结点
if (pre == NULL) {
head = current->next;
} else {
pre->next = current->next;
}
free(current);
return;
}
// 继续遍历
pre = current;
current = current->next;
}
}
// 打印哈希表及链表内容
void printHashTable(HashNode* table[]) {
for (int i = 0; i < TABLE_SIZE; ++i) {
printf("Index %d:", i);
HashNode* current = table[i];
while (current != NULL) {
printf(" -> %d", current->value);
current = current->next;
}
printf(" -> NULL\n");
}
}
int main () {
HashNode* table[TABLE_SIZE];
// 初始化哈希表
for (int i = 0; i < TABLE_SIZE; ++i) {
table[i] = NULL;
}
// 插入值
insert(table, 19);
insert(table, 14);
insert(table, 23);
insert(table, 1);
insert(table, 68);
insert(table, 20);
insert(table, 84);
insert(table, 27);
insert(table, 55);
insert(table, 11);
insert(table, 10);
insert(table, 79);
printHashTable(table);
// 查找值
printf("Value 20 exists: %s\n", find(table, 20) ? "Yes" : "No");
printf("Value 300 exists: %s\n", find(table, 300) ? "Yes" : "No");
printf("Value 200 exists: %s\n", find(table, 200) ? "Yes" : "No");
// 删除值
int removedValue = 10;
removeValue(table, removedValue);
printf("Value %d removed\n", removedValue);
// 查找值
printf("Value 200 exists: %s\n", find(table, removedValue) ? "Yes" : "No");
printHashTable(table);
// 释放内存
for (int i = 0; i < TABLE_SIZE; ++i) {
HashNode* current = table[i];
while (current != NULL) {
HashNode* temp = current;
current = current->next;
free(temp);
}
}
return 0;
}
#include <stdio.h>
#include <stdlib.h>
// 哈希表结点的结构
typedef struct HashMap {
int p; // 不大于 TABLE_SIZE 但最接近 TABLE_SIZE 的质数
int size;
int* table;
} HashMap;
// 函数用于检查一个整数是否是质数
int isPrime(int n) {
if (n <= 1) return 0;
if (n <= 3) return 1;
if (n % 2 == 0 || n % 3 == 0) return 0;
for (int i = 5; i * i <= n; i += 6) {
if (n % i == 0 || n % (i + 2) == 0) {
return 0;
}
}
return 1;
}
// 哈希函数
int hash(int key, int size) {
return key % size; // 使用取余运算计算哈希值
}
// 初始化哈希表
HashMap* CreateHashMap (int size) {
HashMap* hash = (HashMap *)malloc(sizeof(HashMap));
int p = size; // 不大于m但最接近m的质数
while (p >= 2) {
// 是质数
if (isPrime(p)) break;
p--;
}
hash->p = p;
hash->size = size;
hash->table = (int *)malloc(sizeof(int) * hash->size);
for (int i = 0; i < size; i++) {
hash->table[i] = NULL; // 初始化哈希表
}
return hash;
}
// 线性探测插入
void HashMap_Insert_Linerar (HashMap * hashMap, int value) {
int index = hash(value, hashMap->p);
int count = 0; // 记录是否满
while (hashMap->table[index] != NULL) {
if (count == hashMap->size) {
printf("哈希表以满");
return;
}
count++;
// 线性探测,递增索引
index = (index + 1) % hashMap->size;
}
hashMap->table[index] = value;
}
// 线性探测查找
int HashMap_Search_Linerar (HashMap *hashMap, int value) {
int index = hash(value, hashMap->p);
int count = 0; // 记录是否没有
while (hashMap->table[index] != NULL) {
// 查找完整个表都没有找到
if (count == hashMap->size) return -1;
if (hashMap->table[index] == value)
return index;
index = (index + 1) % hashMap->size;
}
return -1;
}
// 平方探测插入
void HashMap_Insert_Quadratic (HashMap * hashMap, int value) {
int hashIndex = hash(value, hashMap->p);
int index = hashIndex;
int d = 1;
int count = 0; // 记录比较次数
// 0²,1²,-1²,2²,-2²,.....
// hashMap->table[index] 即代表了 d = 0 的情况
while (hashMap->table[index] != NULL) {
if (d > hashMap->size / 2) {
printf("增量【d > 表长/2】,退出循环。没有遍历到的位置也不会在遍历到了");
return;
}
count++;
// 根据 d 的正负,选择使用负平方偏移或正平方偏移来计算新的索引位置
if (d < 0) {
index = (-1 * d * d + hashIndex) % hashMap->size;
} else {
index = (d * d + hashIndex) % hashMap->size;
}
// 如果计算出的新索引为负数,将其转换为对应的正数索引,确保索引在哈希表的有效范围内
if (index < 0) index = hashMap->size + index;
d = -d; // 切换正负平方偏移
if (d >= 0) {
d++; // 正平方偏移 + 1
}
}
hashMap->table[index] = value;
}
// 平方探测查找
int HashMap_Search_Quadratic (HashMap *hashMap, int value) {
int hashIndex = hash(value, hashMap->p);
int d = 1;
int index = hashIndex;
int count = 0; // 记录比较次数
while (hashMap->table[index] != NULL) {
// 查找完整个表都没有找到
if (d > hashMap->size / 2) {
printf("增量【d > 表长/2】,退出循环。没有遍历到的位置也不会在遍历到了");
return -1;
}
if (hashMap->table[index] == value) {
return index;
}
if (d < 0) {
index = (-1 * d * d + hashIndex) % hashMap->size;
} else {
index = (d * d + hashIndex) % hashMap->size;
}
if (index < 0) index = hashMap->size + index;
d = -d; // 切换正负平方偏移
if (d >= 0) {
d++; // 正平方偏移+1
}
}
return -1; // 未找到值
}
int main () {
HashMap* linerHashMap = CreateHashMap(11);
linerHashMap->p = 7;
// 线性探测
HashMap_Insert_Linerar(linerHashMap, 87);
HashMap_Insert_Linerar(linerHashMap, 40);
HashMap_Insert_Linerar(linerHashMap, 30);
HashMap_Insert_Linerar(linerHashMap, 6);
HashMap_Insert_Linerar(linerHashMap, 11);
HashMap_Insert_Linerar(linerHashMap, 22);
HashMap_Insert_Linerar(linerHashMap, 98);
HashMap_Insert_Linerar(linerHashMap, 20);
printf("线性探测哈希表(M:%d,P:%d):", linerHashMap->size, linerHashMap->p);
for (int i = 0; i < linerHashMap->size; i++) {
printf("%d、", linerHashMap->table[i]);
}
// 平方探测
HashMap* QuadraticHashMap = CreateHashMap(27);
QuadraticHashMap->p = 13;
HashMap_Insert_Quadratic(QuadraticHashMap, 6);
HashMap_Insert_Quadratic(QuadraticHashMap, 19);
HashMap_Insert_Quadratic(QuadraticHashMap, 32);
HashMap_Insert_Quadratic(QuadraticHashMap, 45);
HashMap_Insert_Quadratic(QuadraticHashMap, 58);
HashMap_Insert_Quadratic(QuadraticHashMap, 71);
HashMap_Insert_Quadratic(QuadraticHashMap, 84);
printf("\n平方探测哈希表(M:%d,P:%d):", QuadraticHashMap->size, QuadraticHashMap->p);
for (int i = 0; i < QuadraticHashMap->size; i++) {
printf("%d、", QuadraticHashMap->table[i]);
}
printf("\n查找84的下标为:%d", HashMap_Search_Quadratic(QuadraticHashMap, 84));
return 0;
}