顺序查找的时间复杂度为O(n)
/* 顺序查找,a为数组,n为要查找的数组个数,key为要查找的关键字 */
int Sequential_Search(int *a, int n, int key)
{
int i;
for(i=1;i<=n;i++)
{
if (a[i] ==key)
return i;
}
return 0;
}
/* 有哨兵顺序查找 */
int Sequential_Search2(int *a,int n,int key)
{
int i;
a[0] = key;
i = n;
while(a[i] != key)
{
i--;
}
return i; /* 返回0则说明查找失败 */
}
int Binary_Search(int *a, int n, int key)
{
int low,high,mid;
low=1;
high=n;
while(low<=high)
{
mid = (low+high)/2;
if(keya[mid])
low = mid+1;
else
return mid;
}
return 0;
}
/* 斐波那契查找 */
int Fibonacci_Search(int *a, int n, int key)
{
int low, high, mid, i, k;
low =1;
high =n;
k =0;
while(n>F[k]-1) /* 计算n位于斐波那契数列的位置 */
k++;
for(i=n;ia[mid]) /* 若查找记录大于当前分隔记录 */
{
low=mid+1; /* 最低下标调整到分隔下标mid+1处 */
k = k-2; /* 斐波那契数列下标减两位 */
}
else
{
if (mid<=n)
return mid; /* 若相等则说明mid即为查找到的位置 */
else
return n; /* 若mid>n说明是补全数值,返回n */
}
return 0;
}
}
/* 斐波那契递归函数 */
int Fbi(int i)
{
if (i < 2)
return (i==0)? 0 : 1;
return Fbi(i-1)+Fbi(i-2);
}
/* 二叉树的二叉链表结点结构定义 */
typedef struct BiTNode
{
int data;
struct BiTNode *lchild, *rchild;
}BiTNode, *BiTree;
/* 递归查找二叉排序树T中是否存在key */
/* 指针f指向T的双亲,其初始调用值为NULL */
/* 若查找成功,则指针p指向该数据元素结点,并返回true */
/* 否则指针p指向查找路径上访问的最后一个结点并返回false */
Status SearchBST(BiTree T, int key, BiTree f, BiTree *p)
{
if (! T)
{
*p = f;
return false;
}
else if (key==T->data)
{
*p = T;
return true;
}
else if (key data)
return SearchBST(T->lchild,key,T,p);
else
return SearchBST(T->rchild,key,T,p);
}
/* 当二叉排序树T中不存在关键字等于key的元素时*/
/* 插入key并返回true,否则返回false*/
Status InsertBST(BiTree *T, int key)
{
BiTree p,s;
if (!SearchBST(*T,key,NULL,&p))
{
s = (BiTree) malloc (sizeof(BiTNode));
s->data = key;
s-lchild = s->rchild = NULL;
if (!p)
*T = s; /* 插入s为新的根结点 */
else if (keydata)
p->lchild = s;
else
p->rchild = s;
return true;
}
else
return false;
}
/* 若二叉排序树T中存在关键字等于key的数据元素时,则删除该数据元素结点,*/
/* 并返回true,否则返回false */
Status DeleteBST(BiTree *T, int key)
{
if (! *T)
return false;
else
{
if (key == (*T)->data)
return Delete(T);
else if (key < (*T)->data)
return DeleteBST(& (*T)->lchild,key);
else
return DeleteBST(& (*T)->rchild,key);
}
}
/* 从二叉排序树中删除结点p,并重接它的左或右子树 */
Status Delete(BiTree *p)
{
BiTree q,s;
if ((*p)->rchild == NULL) /* 右子树空则只需重接它的左子树 */
{
q=*p;*p=(*p)->lchild;free(q);
}
else if ((*p)->lchild == NULL) /* 左子树空则只需重接它的右子树 */
{
q=*p;*p=(*p)->rchild;free(q);
}
else
{
q=*p;
s = (*p)->lchild;
while(s->rchild) /* 转左,然后向右到尽头(找待删结点的前驱)*/
{
q=s;s=s->rchild;
}
(*p)->data = s->data; /* s指向被删结点的直接前驱 */
if (q!=*p)
q->rchild = s->lchild; /* 重接q的右子树 */
else
q->lchild = s->lchild; /* 重接q的左子树 */
free(s);
}
return true;
}
/* 二叉树的二叉链表结点结构定义 */
typedef struct BiTNode /* 结点结构 */
{
int data; /* 结点数据 */
int bf; /* 结点的平衡因子 */
struct BiTNode *lchild, *rchild; /* 左右孩子指针 */
}BiTNode, *BiTree;
/* 对以p为根的二叉排序树作右旋处理, */
/* 处理之后p指向新的树根结点,即旋转处理之前的左子树的根结点 */
void R_Rotate(BiTree *P)
{
BiTree L;
L = (*P)->lchild; /* L指向P的左子树根结点 */
(*P)->lchild = L->rchild; /* L的右子树挂接为P的左子树 */
L->rchild = (*P);
*P = L; /* P指向新的根结点 */
}
/* 对以p为根的二叉排序树作左旋处理, */
/* 处理之后p指向新的树根结点,即旋转处理之前的右子树的根结点 */
void R_Rotate(BiTree *P)
{
BiTree R;
R = (*P)->rchild; /* R指向P的右子树根结点 */
(*P)->rchild = R->lchild; /* R的左子树挂接为P的右子树 */
R->lchild = (*P);
*P = R; /* P指向新的根结点 */
}
#define LH +1 /* 左高 */
#define EH 0 /* 等高 */
#define RH -1 /* 右高 */
/* 对以指针T所指结点为根的二叉树作左平衡旋转处理 */
/* 本算法结束时,指针T指向新的根结点 */
void LeftBalance(BiTree *T)
{
BiTree L, Lr;
L = (*T)->lchild; /* L指向T的左子树根结点 */
switch(L->bf)
{
/* 检查T的左子树的平衡度,并作相应的平衡处理 */
case LH: /* 新结点插入在T的左孩子的左子树上,要作单右旋处理 */
(*T)->bf = L->bf = EH;
R_Rotate(T);
break;
case RH: /* 新结点插入在T的左孩子的右子树上,要作双旋处理 */
Lr = L->rchild; /* Lr指向T的左孩子的右子树根 */
switch(Lr->bf) /* 修改T及其左孩子的平衡因子 */
{
case LH:
(*T)->bf = RH;
L->bf = EH;
break;
case EH:
(*T)->bf = L->bf = EH;
break;
case RH:
(*T)->bf = EH;
L->bf = LH;
break;
}
Lr->bf = EH;
L_Rotate(& (*T)->lchild); /* 对T的左子树作左旋平衡处理 */
R_Rotate(T); /* 对T作右旋平衡处理 */
}
}
/* 若在平衡的二叉排序树T中不存在和e有相同关键字的结点,则插入一个 */
/* 数据元素e的新结点并返回1,否则返回0.若因插入而使二叉排序树失去 */
/* 平衡,则作平衡旋转处理,布尔变量taller反映T长高与否 */
Status InsertAVL(BiTree *T, int e, Status *taller)
{
if (!*T)
{
/* 插入新结点,树“长高”,置taller为true */
*T = (BiTree) malloc (sizeof(BiTNode));
(*T)->data =e;
(*T)->lchild = (*T)->rchild = NULL;
(*T)->bf = EH;
*taller = true;
}
else
{
if (e == (*T)->data)
{
/* 树中已存在和e有相同关键字的结点则不再插入 */
*taller = false;
return false;
}
if (e<(*T)->data)
{
/* 应继续在T的左子树中进行搜索 */
if (!InsertAVL(&(*T)->lchild,e,taller)) /* 未插入 */
return false;
if (*taller) /* 已插入到T的左子树中且左子树“长高” */
{
switch((*T)->bf) /* 检查T的平衡度 */
{
case LH: /* 原本左子树比右子树高,需要作左平衡处理 */
LeftBalance(T);
*taller = false;
break;
case EH: /* 原本左右子树等高,现因左子树增高而树增高 */
(*T)->bf = LH
*taller = true;
break;
case RH: /* 原本右子树比左子树高,现在左右子树等高 */
(*T)->bf = EH;
*taller = false;
break;
}
}
}
else
{
/* 应继续在T的右子树中进行搜索 */
if (!InsertAVL(&(*T)->rchild,e,taller)) /* 未插入 */
return false;
if (*taller) /* 已插入到T的右子树中且右子树“长高” */
{
switch((*T)->bf)
{
case LH:
(*T)->bf = EH;
*taller = false;
break;
case EH:
(*T)->bf = RH
*taller = true;
break;
case RH:
RightBalance(T);
*taller = false;
break;
}
}
}
}
return true;
}
平衡二叉树的查找、插入和删除的时间复杂度都是O(logn)。
多路查找数(B树)
散列表查找(哈希表)
散列函数构造方法
直接定址法
数字分析法
平方取中法
折叠法
除留余数法
f(key) = key mod p (p<=m)
随机数法
f(key) = random(key)
处理散列冲突方法
开放定址法,也称为线性探测法,一旦发生了冲突,就去寻找下一个空的散列地址,只要散列表足够大,空的散列地址总能找到,并将记录存入。
fi(key) = (f(key) + di) MOD m (di=1,2,3,……,m-1)
二次探测法
fi(key) = (f(key) + di) MOD m (di=1^2,-1^2,2^2,-2^2,……,q^2,-q^2,q<=m/2)
在冲突时,对于位移量di采用随机函数计算得到,称为随机探测法
fi(key) = (f(key) + di) MOD m (di是一个随机数列)
再散列函数法
fi(key) = RHi(key) (i=1,2,……,k),其中RHi就是不同的散列函数
链地址法
公共溢出区法
散列表查找实现
#define SUCCESS 1
#define UNSUCCESS 0
#define HASHSIZE 12 /* 定义散列表长为数组的长度 */
#define NULLKEY -32768
typedef struct
{
int *elem; /* 数据元素存储基址,动态分配数组 */
int count; /* 当前数据元素个数 */
}HashTable;
int m = 0; /* 散列表表长,全局变量 */
/* 初始化散列表 */
Status InitHashTable(HashTable *H)
{
int i;
m = HASHSIZE;
H->count = m;
H->elem = (int *)malloc(m*sizeof(int));
for(i=0;ielem[i] = NULLKEY;
return OK;
}
/* 散列函数 */
int Hash(int key)
{
return key % m; /* 除留余数法 */
}
/* 插入关键字进散列表 */
void InsertHash(HashTable *H, int key)
{
int addr = Hash(key); /* 求散列地址 */
/* 开放定址法的线性探测 */
while(H->elem[addr] != NULLKEY)
addr = (addr+1) %m;
H->elem[addr] = key;
}
/* 散列表查找关键字 */
Status SearchHash(HashTable H, int key, int *addr)
{
*addr = Hash(key);
while(H.elem[*addr] != key) /* 如果不为空,则冲突 */
{
*addr = (*addr+1) % m; /* 开放定址法的线性探测 */
/* 如果循环回到原点 */
if (H.elem[*addr] == NULLKEY || *addr == Hash(key))
{
return UNSUCCESS; /* 说明关键字不存在 */
}
}
return SUCCESS;
}