查找
根据某一个数值,查找是否有与这数值相等的关键字的数据元素。
静态查找表:对某一个数据元素检查是否在查找表中。
动态查找表:可以对表进行插入数据和删除数据。
顺序查找表
按顺序对查找表查询是否有某一记录。
int search(int a[],int n,int key)//a:查找表,n:查找表中记录个数,key:查找的数据
{
int i;
a[0]=x;//设置哨兵用来找不到记录时退出
for(i=n-1;i>=0&&a[i]!=x;i--);
return i;
}
有序表查找
折半查找法o(logn)
必须要在数组有序的情况下,每次对要查找范围分成两边看要查找的值比中间的值大或小来决定下一个范围。
int BinarySearch(int a[],int n,int key)
{
int low=0,high=n-1,mid;
while(low<=high)
{
mid=(low+high)/2;
if(a[mid]>x)
high=mid-1;
else if(a[mid]<x)
low=mid+1;
else
return mid;
}
return 0;
}
插值查找
是对折半查找的改良方法,
mid=(low+high)/2改为mid=(high-low)*(key-a[low])/(a[high]-a[low])
改进方法原理:自己理解为,看key值在查找表中值大小比例所在的大致位置。
用于比较均衡的查找表中。
斐波那契查找
通过一个斐波那契数列,来对查找表数据进行分组。
#include<stdio.h>
void Fibonacci(int f[],int n);
int search(int a[],int n,int key);
int main()
{
int a[10];
int n=10,x,i;
for(i=0;i<n;i++)
{
scanf("%d",a+i);
}
scanf("%d",&x);
i=search(a,n,x);
printf("%d",i);
}
void Fibonacci(int f[],int n)
{
int i;
f[0]=f[1]=1;
for(i=2;i<=n;i++)
f[i]=f[i-1]+f[i-2];
}
int search(int a[],int n,int key)
{
int i,k,low,high,mid;
int f[1000];
Fibonacci(f,n);
low=0,high=n-1;
for(k=0;n>f[k]-1;k++);//求满足的斐波那契数
for(i=n;i<f[k];i++)//补齐缺少的个数
{
a[i]=a[high];
}
while(low<=high)
{
mid=low+f[k-1]-1;//按照斐波那契数分成两部分,-1是为了数组下标
if(a[mid]<key)
{
low=mid+1;
k-=2;//前面那部分不要了
/*
假设有8个数,前面部分为3,后面部分为5
斐波那契数列112358
k-1:5
k-2:3
*/
}
else if(a[mid]>key)
{
high=mid-1;
k-=1;//因为后面那部分不要
}
else
{
if(n>high)//超过原数组大小就只可能是n
return n;
else
return mid+1;
}
return 0;
}
}
线性索引查找
二叉排序树查找
二叉排序树性质:
左子树的节点小于根节点的值
右子树的节点大于根节点的值
#include<stdio.h>
typedef struct tree
{
int data;
struct tree *lchild,*rchild;
} Tree;
Tree *search(Tree *t,int key)
{
if(t==NULL)
return 0;
else if(t->data>key)
return search(t->lchild,key);
else if(t->data<key)
return search(t->rchild,key);
else
return t;
}
void insert(Tree **t,Tree *p,int key)
{
Tree *r;
if(*t==NULL)
{
r=(Tree *)malloc(sizeof(Tree));
r->data=key;
r->lchild=r->rchild=NULL;
if(key>p->data)
{
p->rchild=r;
}
else
{
p->lchild=r;
}
}
else if(t->data>key)
{
insert((*t)->lchild,*t,key);
}
else if(t->data<key)
{
insert((*t)->rchild,*t,key);
}
else
{
return;
}
}
int del(Tree **t,int key)
{
if(*t)
{
if((*t)->data<key)
{
return del((*t)->rchild,key);
}
else if((*t)->data>key)
{
return del((*t)->lchild,key);
}
else
{
deal(t,key);
return 1;
}
}
else
return 0;
}
void deal(Tree **t,int key)
{
Tree *p,*q;
if((*t)->lchild==NULL)
{
p=(*t);*t=(*t)->rchild;
free(p);
}
else if((*t)->rchild==NULL)
{
p=(*t);*t=(*t)->lchild;
free(p);
}
else//利用中序遍历顺序:左->根->右,后一个节点的右节点走完就会到前一个节点
{
p=(*t);q=(*t)->lchild;//找要被删除节点的前继节点
while(q->rchild)//一直往右走直到为空就找到了
{
p=q;
q=q->rchild;
}
(*t)->data=q->data;//直接赋值,删除q会方便点
if(p==(*t))//判断是否是t的左孩子是替换的节点
{
p->lchild=q->lchild;//因为他的右孩子是空
}
else
{
p->rchild=q->lchild;
}
free(q);
}
}
平衡二叉树
用来解决二叉排序树创建时出现左右节点的度相差过大的情况。
需要处理的情况有:
rr:要左旋
ll:要右旋
rl:先右旋再左旋,就是需要先变成rr
lr:先左旋再右旋,就是需要变成ll
左旋右旋:要处理的节点是第一个高度大于1或小于-1,左旋就是节点往左手边转,右旋相反。
二叉树
#define LH 1
#define EH 0
#define RH -1
typedef struct BitNode
{
int data;
int bf;
struct BitNode *lchild,*rchild;
} Tree;
左旋
void L_Rotate(Tree **t)
{
Tree *p;
p=(*t)->rchild;
(*t)->rchild=p->lchild;
p->lchild=(*t);
(*t)=p;//改顶点
}
右旋
void R_Rotate(Tree **t)
{
Tree *p;
p=(*t)->lchild;
(*t)->lchild=p->rchild;
p->rchild=(*t);
(*t)=p;
}
左平衡
void LeftBalance(Tree **t)
{
Tree *L,*Lr;//L:是要处理的左孩子,Lr:是要做双旋时用的
L=(*t)->lchild;
switch(L->bf)//只对L、t、Lr的bf进行改动
{
case LH://代表了节点被放在了左子树上
L->bf=(*t)->bf=EH;//右旋过后他们的bf都变为0,放在右旋之前是因为右旋会改变t的值
R_Rotate(t);
break;
case RH://代表了节点被放在了右子树上,需要双旋
Lr=L->rchild;
switch(Lr->bf)//判断节点(有孩子的话是新节点的父亲)是否有孩子,它们情况不一样
{
case LH://有左孩子
(*t)->bf=RH;
L->bf=EH;
break;
case EH://没有孩子
(*t)->bf=L->bf=EH;
break;
case:
(*t)->bf=EH;
L->bf=LH;
break;
}
Lr->bf=EH;//因为旋转过后Lr是小树的根节点
L_Rotate(&(*t)->rchild);//方便改该节点的值
R_Rotate(t);
break;
}
}
右平衡
void RightBalance(Tree **t)
{
Tree *R,*RL;
R=(*t)->rchild;
switch(R->bf)
{
case RH:
(*t)->bf=R->bf=EH;
L_Rotate(t);
break;
case LH:
RL=(*t)->rchild;
switch(RL->bf)
{
case LH:
(*t)->bf=EH;
R-bf=RH;
break;
case EH:
(*t)->bf=R->bf=EH;
break;
case RH:
(*t)->bf=LH;
R->bf=EH;
break;
}
RL->bf=EH;
R_Rotate((*t)->rchild);
L_Rotate(t);
break;
}
}
插入数据
int search_AVL(Tree **t,int *flag,int key)//flag是用来判断是否出现树高度增加的情况,1:增加 0:没有
{
Tree *p;
if((*t)==NULL)//插入数据,因为t是二级指针所以可以直接赋值插入
{
p=(Tree *)malloc(sizeof(Tree));
p->data=key;
p->lchild=p->rchild=NULL;
p->bf=EH;
(*t)=p;
*flag=1;
}
else if((*t)->data==key)
{
return 0;
}
else if((*t)->data<key)
{
if(!search_AVL(&(*t)->rchild,flag,key))
return 0;
if(*flag)
{
switch((*t)->bf)
{
case LH:
*flag=0;
(*t)->bf=EH;
break;
case EH:
*flag=1;
(*t)->bf=RH;
break;
case RH:
*flag=0;
RightBalance(t);
break;
}
}
}
else
{
if(!search_AVL(&(*t)->lchild,flag,key))
return 0;
if(*flag)
{
switch((*t)->bf)
{
case LH:
*flag=0;
LeftBalance(t);//不需要改t的bf是因为函数改了
break;
case EH:
*flag=1;
(*t)->bf=LH;
break;
case RH:
*flag=0;
(*t)->bf=EH;
break;
}
}
}
return 1;//代表插入数据了,需要判断是否超过高度
}
删除数据
多路查找树