数据结构 查找

来源:互联网 发布:文艺美学知乎 编辑:程序博客网 时间:2024/05/20 06:28

查找表:同一数据类型的数据元素构成的集合。

主关键字:可以唯一标识一条记录的关键字称为主关键字。

次关键字:可以识别多个数据元素(或记录)的关键字。

1、顺序查找(线性查找):

/*一般顺序查找,a为数组,n为要查找的数组个数,key为要查找的关键字*/int Sequential_search(int *a,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;//设置a[0]为关键字,“哨兵”i=n;//循环从尾部开始while(a[i]!=key)i--;return i;//返回0则说明查找失败}//这样就可以避免判断i是否越界,是否小于等于n的判断,节省了时间

2、有序表查找

· 折半查找

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(key<a[mid])//若查找值比中值小high=mid-1;//最高下标调整到中值下标小一位else if(key>a[mid])low=mid+1;elsereturn 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,i<F[k]-1;i++)//将不满的数值补全a[i]=a[n];while(low<=high){mid=low+F[k-1]-1;//计算当前分隔的下标if(key<a[mid]){high=mid-1;//最高下标调整k=k-1;}else if(key>a[mid])//若查找记录大于当前分隔记录{low=mid+1;//最低下标调整到分隔下标mid+1处k=k-2;//斐波那契数列下标减两位}else{if(mid<=n)return mid;//若相等则说明mid即为查找到的位置elsereturn n;//若mid>n说明是补全数值,返回n}}return 0;}
海量数据的查找---线性索引查找

· 稠密索引:在线性索引中,将数据集中每个记录对应一个索引项(优点:计算量少,时间快。缺点:内存小的计算机性能下降)

· 分块索引:数据分成若干块,每块对应不同索引项(虽然不如折半查找,但大大增加了整体查找速度,普遍用于数据库)

· 倒排索引:记录关键字记录号。


3、二叉排序树

/*二叉排序树*///二叉链表节点结构定义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<T->data)return SearchBST(T->lchild,key,T,p);//在左子树继续查找elsereturn SearchBST(T->rchild,key,T,p);//在右子树继续查找}//二叉排序树插入操作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(key<p->data)p->lchild=s;//插入s为左孩子elsep->rchild=s;//插入s为右孩子return TRUE;}elsereturn FALSE;//树中已有关键字相同节点,不再插入}//二叉排序树删除操作//若二叉排序树T中存在关键字=key的数据元素时,则删除该数据元素站点并返回TRUE,否则返回FALSEStatus DeleteBST(BiTree *T,int key){if(!*T)//不存在关键字=key的数据元素return FALSE;else{if(key==(*T)->data)//找到关键字=key的数据元素return Delete(T);else if(key<(*T)->data)return DeleteBST(&(*T)->lchild,key);elsereturn DeleteBST(&(*T)->rchild,key);}}//从二叉排序树中删除节点p,并重接它的左or右生成树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右子树elseq->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指向新的根节点}//左旋处理void L-Rotate(BiTree *p){BiTree R;R=(*p)->rchild;//R指向P的右子树根节点(*p)->rchild=R->lchild;//R的左子树挂接为P的右子树R->lchild=(*P);*P=R;//P指向新的根节点}//左旋平衡旋转处理函数代码const LH +1;//左高const EH 0;//等高const 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.若因插入而使二叉排序树失去平衡,做平衡旋转处理,bool变量taller反应T长高与否*/Status InsertAVL(BiTree *T,int e,Status *taller){if(!*T)//当前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){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;}}

· 多路查找树(B树)

为了避免因为数据量大导致树的度非常庞大,打破一个节点只能存储一个元素的限制,为此引入多路查找树。

特殊的B树如 ① ②

① 2-3树

         其中每一个节点都有两个孩子(2节点,一个2节点包含一个元素和两个孩子(或没有孩子))

或三个孩子(3节点,一个三节点包含一小一大两个元素和三个孩子(或没有孩子))。
② 2-3-4树

        一个4节点包含小中大三个元素四个孩子(或没有孩子)。

③ B树

       节点最大的孩子数称为B树的阶(order),2-3树是3阶B树,2-3-4树是4阶B树。

④ B+树

        B树的优化树,好像没看大懂。。。


4、散列表查找(哈希表)

散裂技术是在记录和存储位置和它的关键字之间建立一个确定的对应关系f,使得每个关键字key对应一个存储位置f(key)。

/*散列表查找算法*/#define SUCCESS 1#define UNSUCCESS 0#define HASHSIZE 12//定义散列表长为数组长度#define NULLKEY -32768typedef 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;i<m;i++)H->elem[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=(*add+1)%m;//开放定址法的线性探测if(H.elem[*addr]==NULLKEY||*addr==Hash(key)){//如果循环回到原点return UNSUCCESS;//则说明关键字不存在}}return SUCCESS;}





0 0