静态查找表 :顺序查找、折半查找
#include<stdio.h>
#include<stdlib.h>
//关键字比较的宏定义
#define EQ(a,b) ( (a)==(b) )
#define LT(a,b) ( (a)< (b) ) //小于
#define LQ(a,b) ( (a)> (b) ) //大于
//-------------------静态查找表的顺序存储结构-------------------
typedef int KeyType;
const int MAXSIZE=20;
//数据元素类型定义为
typedef struct{
KeyType key; //关键字域
int others; //其他域
}SElemType;
typedef struct {
SElemType *elem;
int length;
}SSTable;
void Create(SSTable &ST, int n);
void Destory(SSTable &ST);
void Search(SSTable ST, KeyType key);
void Traverse(SSTable ST, void (*visit)(SElemType data));
void Create(SSTable &ST, int n){
printf("Init(%d):\n",n);
ST.elem = (SElemType*) malloc((n+1)*sizeof(SElemType));
ST.length = n;
for(int i=1;i<=n;i++) scanf("%d",&ST.elem[i].key);
}
void Visit(SElemType e){
printf("%d ",e.key);
}
void Traverse(SSTable ST, void (*visit)(SElemType data)){
for(int i=1;i<=ST.length;i++) visit(ST.elem[i]);
}
//-------------------顺序表的查找-------------------
/*
* 顺序查找:从表中最后一个记录开始往前找
*/
int Search_Seq(SSTable ST, KeyType key){
//若查找成功返回位置,否则返回0
ST.elem[0].key = key; //给ST.elem[0]赋值,是为了免去查找过程的每一步都去检测整个表是否查找完毕;起监视哨作用
int i;
for(i=ST.length; !EQ(ST.elem[i].key, key); --i);
return i;
}
//-------------------有序表的查找-------------------
int Search_Bin(SSTable ST, KeyType key){
//折半查找
//若查找成功返回位置,否则返回0
int low =1, high = ST.length, mid;
while (low<=high){
mid = (low+high)/2;
if(EQ(key, ST.elem[mid].key)) return mid;
else if(LT(key, ST.elem[mid].key)) high = mid-1;
else low = mid+1;
}
return 0;
}
//--------------------------------------
int main(){
SSTable ST;
Create(ST,8);
Traverse(ST,Visit);
printf("\n");
printf("%d\n",Search_Seq(ST,8));
printf("%d\n",Search_Bin(ST,8));
return 1;
}
// 2 3 4 5 6 7 8 9
动态查找表 :二叉排序树、平衡二叉树
#include<stdio.h>
#include<stdlib.h>
//关键字比较的宏定义
#define EQ(a,b) ( (a)==(b) )
#define LT(a,b) ( (a)< (b) ) //小于
#define LQ(a,b) ( (a)> (b) ) //大于
//-------------------二叉排序树:二叉链表-------------------
#define Status int
//数据元素类型定义为
typedef int KeyType;
typedef struct{
KeyType key; //关键字域
int others; //其他域
}TElemType;
typedef struct BiTNode{
TElemType data;
struct BiTNode * lchild, *rchild; //左右孩子
}BiTNode, *BiTree; //二叉树节点数据
//-------------------二叉排序树:构造-------------------
BiTree SearchBST(BiTree T, KeyType key){
//在根指针T所指的二叉排序树中递归查找
//查找成功返回指向该节点的指针,否则返回NULL
if(!T || EQ(key, T->data.key)) return T;
else if(LT(key,T->data.key)) return SearchBST(T->lchild,key);
else return SearchBST(T->rchild,key);
}
//改写SearchBST,在查找失败时返回插入位置
Status SearchBST(BiTree T, KeyType key, BiTree f, BiTree &p){
//查找成功时p返回该元素节点,函数返回True;
//否则p指向查找路径上访问的最后一个节点,函数返回flase
//f指向T的双亲,初值为NULL
if(!T) {p=f; return 0; }
else if(EQ(key, T->data.key)) { p=T; return 1;}
else if(LT(key, T->data.key)) return SearchBST(T->lchild, key, T, p);
else return SearchBST(T->rchild, key, T, p);
}
Status InsertBST(BiTree &T, TElemType e){
//当二叉树中不存在关键字等于给定值的节点时,插入e并返回True;否则返回False
BiTNode * p, *s;
if(!SearchBST(T, e.key, NULL, p)){
s = (BiTNode *)malloc(sizeof(BiTNode));
s->data = e; s->lchild = s->rchild = NULL;
if(!p) T = s; //T为空,二叉排序树是空树
else if(LT(e.key, p->data.key)) p->lchild = s;
else p->rchild = s;
return 1;
}
return 0;
}
//中序递归遍历二叉链表
Status InOrderTraverse(BiTree T, Status (*visit)(TElemType e)){
if(!T) return 1;
if(InOrderTraverse(T->lchild,visit))
if(visit(T->data))
if(InOrderTraverse(T->rchild,visit))
return 1;
return 0;
}
Status PrintElement(TElemType e){
printf("%d ",e.key); //实用时注意格式串
return 1;
}
//先序
Status PreOrderTraverse(BiTree T, Status (*visit)(TElemType e)){
if(!T) return 1;
if(visit(T->data))
if(PreOrderTraverse(T->lchild, visit))
if(PreOrderTraverse(T->rchild, visit))
return 1;
return 0;
}
//-------------------二叉排序树:删除结点-------------------
/*
* 假设待删节点为 *p, 其双亲节点为 *f. 可设 *p 是 *f 的左孩子
* 分3种情况讨论:
* 1.若p是叶子节点,直接修改其双亲节点的指针
* 2.若p只有左子树或者只有右子树,直接修改其双亲节点的左指针指向p的左(右)子树
* 3.若p的左右子树均不空:方法一:
* 方法二:
*/
Status Delete(BiTree &p){
//从二叉排序树中删除T节点
BiTree q, s;
if(!p->lchild){
q = p;
p = p->rchild;
free(q);
}else if(!p->rchild){
q = p;
p = p->lchild;
free(q);
}else{
q = p; s = p->lchild;
while (s->rchild){ q = s; s = s->rchild; }
p->data = s->data;
if(q!=p) q->rchild = p->lchild;
else q->lchild = s->lchild;
free(s);
}
}
Status DeleteBFS(BiTree &T, KeyType key){
if(!T) return 0;
if(EQ(key, T->data.key)) return Delete(T);
else if(LT(key, T->data.key)) return DeleteBFS(T->lchild, key);
else return DeleteBFS(T->rchild, key);
}
//-------------------二叉排序树:分析-------------------
/*
* 折半查找的判定树是唯一的,但是二叉排序树不唯一导致的ASL不同
* 最差:二叉树变成单支树:ASL=(n+1)/2等同于顺序查找
* 最好:二叉排序树的形态和折半查找的判定树相同
* 平均性能:和logn是同等数量级
*/
//-------------------二叉平衡树AVL树-------------------
#define LH 1 //左高
#define EH 0 //等高
#define RH -1 //右高
//二叉链表的头节点中增加一个新的存储平衡因子的域 bf
typedef struct BSTNode{
TElemType data;
int bf; //平衡因子
struct BSTNode * lchild, *rchild; //左右孩子
}BSTNode, *BSTree; //二叉树节点数据
void R_Rotate(BSTree &p){
//右旋处理
BSTree lc = p->lchild;
p->lchild = lc->rchild;
lc->rchild = p;
p = lc;
}
void L_Rotate(BSTree &p){
//左旋处理
BSTree lc = p->rchild;
p->rchild = lc->lchild;
lc->lchild = p;
p = lc;
}
void LeftBalance(BSTree &T){
BSTree lc = T->lchild, rd;
switch (lc->bf) {
case LH:T->bf = lc->bf = EH; R_Rotate(T); break; //单向右旋平衡处理
case RH:{
rd=lc->rchild;
switch (rd->bf) {
case LH: T->bf = RH; lc->bf = EH; break;
case EH: T->bf = lc->bf = EH; break;
case RH: T->bf = EH; lc->bf = LH; break;
}
rd->bf = EH;
L_Rotate(T->lchild);
R_Rotate(T);
}
}
}
void RightBalance(BSTree &T){
BSTree rc = T->rchild, ld;
switch (rc->bf) {
case RH:T->bf = rc->bf = EH; L_Rotate(T); break; //单向左旋平衡处理
case LH:{
ld=rc->lchild;
switch (ld->bf) {
case LH: T->bf = EH; rc->bf = RH; break;
case EH: T->bf = rc->bf = EH; break;
case RH: T->bf = LH; rc->bf = EH; break;
}
ld->bf = EH;
L_Rotate(T->rchild);
R_Rotate(T);
}
}
}
Status InsertAVL(BSTree &T, TElemType e, bool &taller){
//若在平衡二叉排序树T中不存在和e有相同关键字的节点,则插入一个新节点,返回1;否则返回0
//如果因为插入而使得二叉排序树失衡,则作旋转处理
//taller反映T长高与否
if(!T){ //1.如果T为空:
T = (BSTree)malloc(sizeof(BSTNode)); T->data = e; T->bf = 0;
T->lchild = T->rchild = NULL; taller = 1;
}else{ //2.如果T不为空:
if(EQ(e.key, T->data.key)){ //2.1如果T中存在和e有相同关键字的节点:不再插入
taller = 0;
return 0;
}
if(LT(e.key, T->data.key)){ //2.2如果e关键字小于T关键字:在T左子树中搜索
if(!InsertAVL(T->lchild, e, taller)) return 0; //未插入
if(taller) //插入了,使得T左子树长高了
switch (T->bf) {
case LH:LeftBalance(T); taller = 0; break; //2.2.1 原本T左子树高于右子树,T的左子树再插入一个e,需要左平衡处理,T不增高
case EH:T->bf = LH; taller = 1; break; //2.2.2 原本T左子树等高右子树,T的左子树再插入一个e,T平衡因子变1,T增高,
case RH:T->bf = EH; taller = 0; break; //2.2.3 原本T左子树低于右子树,T的左子树再插入一个e,T平衡因子变0,T不增高
}
}else{ //2.3如果e关键字大于T关键字:在T右子树中搜索
if(!InsertAVL(T->rchild, e, taller)) return 0; //未插入
if(taller) //插入了,使得T右子树长高了
switch (T->bf) {
case LH:T->bf = EH; taller = 0; break; //2.3.1 原本T左子树高于右子树,T的右子树再插入一个e,T平衡因子变0,T不增高
case EH:T->bf = RH; taller = 1; break; //2.3.2 原本T左子树等高右子树,T的右子树再插入一个e,T平衡因子变-1,T增高,
case RH:RightBalance(T); taller = 0; break; //2.3.3 原本T左子树低于右子树,T的右子树再插入一个e,需要作右平衡处理,T不增高
}
}
}
return 1;
}
//中序递归遍历二叉链表存储的平衡二叉树
Status InOrderTraverse_BST(BSTree T, Status (*visit)(TElemType e)){
if(!T) return 1;
if(InOrderTraverse_BST(T->lchild,visit))
if(visit(T->data))
if(InOrderTraverse_BST(T->rchild,visit))
return 1;
return 0;
}
Status PreOrderTraverse_BST(BSTree T, Status (*visit)(TElemType e)){
if(!T) return 1;
if(visit(T->data))
if(PreOrderTraverse_BST(T->lchild, visit))
if(PreOrderTraverse_BST(T->rchild, visit))
return 1;
return 0;
}
//--------------------------------------
int main(){
//---------二叉排序树
BiTree T = NULL;
TElemType e;
for(int i=1;i<=7;i++){
scanf("%d",&e.key); //45 24 53 45 12 24 90
InsertBST(T,e);
}
InOrderTraverse(T,PrintElement);
printf("\n");
DeleteBFS(T,90);
InOrderTraverse(T,PrintElement);
printf("\n");
PreOrderTraverse(T,PrintElement);
printf("\n\n");
//---------平衡二叉树
BSTree TT = NULL; bool taller;
for(int i=1;i<=7;i++){
scanf("%d",&e.key); //5 13 24 37 53 90 99
InsertAVL(TT,e,taller);
}
InOrderTraverse_BST(TT,PrintElement); //中序
printf("\n");
PreOrderTraverse_BST(TT,PrintElement); //先序
printf("\n");
return 1;
}
B-树
查找,插入
#include<stdio.h>
#include <cstdlib>
typedef int Status;
//-------------------B-树的节点类型说明-------------------
#define m 3
typedef int KeyType;
typedef struct BTNode{
int keynum;
struct BTNode *parent = {NULL}; //指向双亲节点
KeyType key[m+1]; //关键字,0号单元未用 1 2
struct BTNode *ptr[m+1] = {NULL}; //子树指针 0 1 2
//Record *recptr[m+1]; //记录指针向量,0号单元未用
}BTNode, *BTree;
typedef struct {
BTNode *pt; //指向找到的节点
int i; //1..m 在节点中的关键字序号
int tag; //1为查找成功,0为查找失败
}Result; //B-树的查找结果类型
//-------------------B-树的查找-------------------
int Search(BTree T, KeyType K){
for(int i=0;i<=T->keynum;i++){
if(i==0)
if(T->key[1]>K) return i;
if(i==T->keynum)
if(T->key[i]>K) return i;
if(T->key[i]<=K && K<=T->key[i+1]) return i;
}
}
Result SearchBTree(BTree T, KeyType K){
//在m阶B-树上查找关键字K,返回结果 (pt, i, tag)
//若查找成功:特征值tag=1,指针pt所指节点中第i个关键字等于K
//否则,tag=0,等于K的关键字应该插在指针pt所指节点中第i和第i+1个关键字之间
BTree p = T, q = NULL; int found = 0; int i=0;
while (p && !found){
i = Search(p, K); //在p所指节点的key域中,寻找
//返回i表示 p->key[i]<=K<=p->key[i+1]
if (i>0 && p->key[i]==K) found = 1;
else{ q=p; p=p->ptr[i]; }
}
if(found) return {q, i, 1};
else return {q, i, 0};
}
/*
B-树查找分析
查找包括两种基本操作:
1在B树种找节点
2在节点种找关键字
由于B-树通常存储在磁盘上,前一查找操作是在磁盘上进行;
后一操作是在内存中进行,即在磁盘上找到指针p所指节点后,先将节点中的信息读入内存,然后再利用顺序查找或折半查找查询等于K的关键字
显然,磁盘上查找比在内存中进行查找耗费时间多得多
因此,在磁盘上进行查找的次数、即待查关键字所在节点在B-树上的层次数,是决定B-树查找效率的首要因素
*/
//-------------------B-树的插入-------------------
/*
* B-树的生成也是从空树起,逐个插入关键字而得。
* 但是由于B-树的每个节点的关键字个数必须>=ceil(m/2)-1
* 因此,每次插入一个关键字不是在树中添加一个叶子节点,而是首先在最低层的某个非终端节点中添加一个关键字
* 若该节点的关键字个数<=m-1,则插入完成;否则要产生节点分裂
*/
//把分裂出的节点ap和关键字K插入上一层节点q中
Status Insert(BTree &q, int i, KeyType K, BTree &ap){
//将K插入到q->key[i+1];将ap插入到q->ptr[i+1] 1 2
for(int j=q->keynum+1;j>i+1;--j){
q->key[j] = q->key[j-1];
q->ptr[j] = q->ptr[j-1];
}
q->key[i + 1] = K;
q->ptr[i + 1] = ap;
q->keynum++;
return 1;
}
//插入之后,先分裂节点q为: q和ap
Status split(BTree &q, int s, BTree &ap){
//将q->key[s+1..m], q->ptr[s..m]和q->recptr[s+1..m]移入新节点 *ap
ap = (BTree)malloc(sizeof(BTNode));
ap->keynum = m-s; int i, j;
ap->parent = q->parent;
for(i=s+1, j=1;i<=m;i++,j++) ap->key[j] = q->key[i];
for(i=s, j=0;i<=m;i++,j++) ap->ptr[j] = q->ptr[i];
q->keynum = s-1;
return 1;
}
Status NewRoot(BTree &T, BTree q, KeyType x, BTree ap){
q = (BTree)malloc(sizeof(BTNode));
q->keynum = 1;
q->key[1] = x;
q->ptr[0] = T;
q->ptr[1] = ap;
T = q;
return 1;
}
Status InsertBTree(BTree &T, KeyType K, BTree q, int i){
//在m阶B-树T上节点 q 的key[i] 与 key[i+1] 之间插入关键字K
//若引起节点过大,则沿着双亲链进行必要的节点分裂调整
BTree ap = NULL;
int finished = 0; int mm = m; KeyType x = K;
while(q && !finished){
Insert(q, i, x, ap);
if(q->keynum<mm) finished = 1;
else {
int s = (mm%2==0)?mm/2:(mm/2)+1;
split(q, s, ap);
x = q->key[s];
q = q->parent;
if(q) i = Search(q, x);
}
}
//如果T为空,或者根节点被分裂,需要重新出现一个根节点
if(!finished) NewRoot(T, q, x, ap); //生成含信息(T,x,ap)的新根节点,T和ap为子树指针
return 1;
}
//对已经存在的B-树T进行插入,首先判断是否已经存在同等关键字的节点
//如果不存在,则进行插入
//否则退出
Status InsertKey(BTree &T, KeyType K){
Result R = SearchBTree(T,K);
if(R.tag!=1) InsertBTree(T, K, R.pt, R.i);
return 1;
}
//-------------------B-树的删除-------------------
//-------------------B-树的构造-------------------
//笨办法构造
Status CreateBTree(BTree &T){
T = (BTree)malloc(sizeof(BTNode));
BTree t1 = (BTree)malloc(sizeof(BTNode));
BTree t2 = (BTree)malloc(sizeof(BTNode));
BTree t3 = (BTree)malloc(sizeof(BTNode));
BTree t4 = (BTree)malloc(sizeof(BTNode));
BTree t5 = (BTree)malloc(sizeof(BTNode));
BTree t6 = (BTree)malloc(sizeof(BTNode));
BTree t7 = (BTree)malloc(sizeof(BTNode));
*t1 = {2,t6,{0,3,12},{NULL,NULL,NULL}};
*t2 = {1,t6,{0,37},{NULL,NULL}};
*t3 = {1,t7,{0,50},{NULL,NULL}};
*t4 = {2,t7,{0,61,70},{NULL,NULL,NULL}};
*t5 = {1,t7,{0,100},{NULL,NULL}};
*t6 = {1,T,{0,24},{t1,t2}};
*t7 = {2,T,{0,53,90},{t3,t4,t5}};
*T = {1,NULL,{0,45},{t6,t7}};
return 1;
}
//中序输出
Status Print(BTree T){
BTree p = T;
if (p){
for(int i=1;i<=p->keynum;i++)
printf("%d ",p->key[i]);
printf("\n");
for(int i=0;i<=p->keynum;i++)
Print(p->ptr[i]);
}
return 1;
}
//先序输出
Status Print_(BTree T){
BTree p = T;
if (p){
for(int i=0;i<=p->keynum;i++){
Print_(p->ptr[i]);
if(i<p->keynum) printf("%d ",p->key[i+1]);
}
}
return 1;
}
//--------------------------------------
int main(){
BTree T;
CreateBTree(T);
Print_(T);
printf("\n");
int in[] = {30,26,85,7};
for(int i=0;i<4;i++){
InsertKey(T,in[i]);
Print_(T);
printf("\n");
}
return 1;
}
B+树
哈希表
#include<stdio.h>
#include<stdlib.h>
typedef int Status;
//关键字比较的宏定义
#define EQ(a,b) ( (a)==(b) )
#define LT(a,b) ( (a)< (b) ) //小于
#define LQ(a,b) ( (a)> (b) ) //大于
//-------------------开放定址哈希表的存储结构-------------------
int hashsize[] = {2,3,5,7,11,13,16,19,23,29,31,37,41,43,47,53,59,61,67,71}; //哈希表容量递增表
typedef int KeyType;
const int NULLKEY=-1;
typedef struct{
KeyType key;
}ElemType;
typedef struct {
ElemType * elem; //数据元素存储基址,动态分配数组
int count; //当前数据元素个数
int sizeindex; //hashsize[sizeindex]为当前容量
}HashTable;
//-------------------开放定址哈希表-------------------
int Hash(KeyType K, int di, int size){
//使用线性探测再散列取递增序列
return (K+di)%size;
}
//开放定址哈希表的查找
Status SearchHash(HashTable H, KeyType K, int &p, int &c) {
//在哈希表中查找关键字为K的元素。若查找成功,以p指示待查数据元素在表中的位置,并返回1
// 否则,以p指示插入位置,返回0
//c用来计查找长度,初值置1
int di = 0;
int k = p = Hash(K, di++, 13);
while (H.elem[p].key != NULLKEY && !EQ(K, H.elem[p].key)){ //该位置不空,且关键字不相等
p = Hash(k, di++, hashsize[H.sizeindex]); //求得下一探测地址
c++;
}
if (EQ(K, H.elem[p].key)) return 1;
else return 0; //p返回了插入位置
}
//开放定址哈希表的插入
Status InsertHash(HashTable &H, ElemType e){
//先查找,不成功时插入数据,并返回1
int c = 1, p = 0;
if(SearchHash(H, e.key, p ,c)) return 0;
H.elem[p] = e;
++H.count;
return c;
}
Status CreateHash(HashTable &H, int n){
H.count = n;
H.sizeindex = 6;
H.elem = (ElemType*)malloc(hashsize[H.sizeindex]*sizeof(ElemType));
for(int i=0;i<hashsize[H.sizeindex];i++) (H.elem+i)->key = NULLKEY;
ElemType e;
int c=0; //查找次数
for(int i=0; i<n; i++){
scanf("%d",&e.key);
c += InsertHash(H,e);
}
return c;
}
void Print(HashTable H){
for(int i=0; i<hashsize[H.sizeindex]; i++) printf("%d ",(H.elem+i)->key);
printf("\n");
}
int main(){
HashTable H;
int c = CreateHash(H,12); //返回查找长度
Print(H);
printf("ASL:%.2f\n",float(c)/12);
return 1;
}
// 19 14 23 01 68 20 84 27 55 11 10 79