1.查找
根据某个给定的值,在查找表中确定一个其关键字等于给定值的元素。
关键字:是数据元素中某个数据项的值,又叫键值。也可以标识一个记录的某个数据项(字段),我们称为关键码;
》1.顺序查找
又称为线性查找,最基本的查找技术。
从头开始逐一与数据元素进行比较
可以设置哨兵,来避免每次都要检查数组越界
O(n)
》2.有序表查找
折半查找:又叫二分查找。前提必须是表中关键码有序,顺序存储。
取中间记录作为比较对象,若给定值与中间记录相等,查找成功。若给定值比中间记录小,就在中间值的左半区继续查找;反之在右半区查找;重复上述动作。
low=1
high=n
while(low<=high)
mid=(low+high)/2
O(logn),但是对于频繁需要插入和删除的数据集来说,这样就不建议使用这个方法。
》3.插值查找
根据要查找的关键字与查找表中最大最小关键字比较后的查找方法,在于插值公式的计算
只要将上面的改为mid=low+(high-low)*(key-a[low]) / (a[high]-a[low]);
a[]是数据表数组
对于表厂较大,关键字分布比较均匀的查找表效率较高
》4.线性索引查找
索引:就是把关键字和它对应的值相关联的过程
线性索引:将索引项集合组织为线性结构,也叫索引表。
稠密索引:在线性索引中,将数据集中的每个记录对应一个索引项。(按关键码有序排列,这样就可以利用上述的方法快速查找关键字)
分块索引:分块有序,把数据集的记录分为了若干块,(块内无序,块间有序)
最大关键码(存储每块中最大的关键字)。存储块中记录个数。指向块首数据元素的指针。
可以想象一下图书馆的管理
倒排索引:记录号表存储具有 相同次关键字的所有记录的记录号。(不是由记录来确定属性值,而是由属性值来确定记录的位置)
》5.二叉排序树
或者是一颗空树,或者具有(1.左子树不空的话,左子树上所有节点的值均小于它的跟节点的值。2.右子树不空的话,则右子树上节点的值均大于跟节点的值。3.它的左右子树也分别是二叉排序树)
这样的结构不仅是排序的,查找块,而且非线性结构的插入和删除也快
递归查找树T中是否存在key
指针f指向T的双亲,初始值为NULL
若查找成功,指针p指向该元素节点,返回TRUE
否则指针p指向路径上最后一个节点,返回False
二叉排序树的删除操作:找到需要删除节点的p的直接前驱,(或者后继)s,用s来替代p,然后再删除s
对于要删除的节点有以下三种情况:
1.叶子节点
2.仅有左或右子树(只有左子树,将此节点的左孩子替换自己)
3.左右子树都有(q=*p,s=(*p)->lchild, 转左,然后一直向右到尽头,while(s->rchild),此时s就指向了被删除节点的直接前驱, if(q!=*p),q->rchild=s->lchild重接q的右子树,要么q->lchild=s->lchild重接q的左子树)
4.平衡二叉树(AVL):
是一种二叉排序树,其中每一个节点的左子树和右子树的高度差至多为1;
高度平衡(要么是空树,要么左子树和右子树都是平衡二叉树,且左子树和右子树的深度差的绝对值不超过1,)将节点的左子树深度减去右子树深度的值称为;平衡因子(BF)那么取值就只能是-1,1,0;
距离插入节点最近的,且平衡因子的绝对值大于1的节点为根的子树,称为最小不平衡子树。
构建: 在构建二叉排序树时,每当插入一个节点,先检查是否因插入而破坏了树的平衡性,若是,就找出最小不平衡子树,在保持二叉排序树特性的前提下调整最小不平衡子树各节点之间的连接关系。进行相应的旋转,使之成为平衡子树。
当最小不平衡子树的BF大于1就:右旋
当最小不平衡子树的BF小于-1就:左旋
最下不平衡子树的BF与其子树的BF符号相反时:就需要对其子树节点先进行一次旋转,将符号统一,再旋转最小不平衡子树的跟节点。
typedef struct BiTnode
{
int data;
int bf; //平衡因子
struct BiTnode *lchild,*rchild;
}BiTnode,*BiTree;
//右旋操作, 以p为根的二叉排序树
void R_Rotate(BiTree *p)
{
BiTree L;
L=(*p)->lchild;
(*p)->lchild=L->rchild;//L的右子树挂接为p的左子树
L->rchild=(*p);
*p=L; //p指向新的跟节点 (也就是旋转之前左子树的根节点)
}
左旋操作
void L_Rotate(BiTree* p)
{
BiTree R;
R=(*p)->rchild;
(*P)->rchild=R->lchild; //R的左子树挂接为P的右子树
R->lchild=(*P);
*p=R; //p指向新的根节点 (就是旋转前右子树的根节点)
}
左平衡旋转的处理
#define LH +1 //左高
#define EH 0 //等高
#define RH -1 //右高
void LeftBalence(BiTree *T)
{
BiTree L,lr;
L=(*T)->lchild; //先指向左子树跟节点
switch(L->bf)
{
//检查T的左子树平衡度,在做处理
case LH: //新节点插入在T的左子树的左孩子上,要做单右旋处理
(*T)->bf=L->bf=EH;
R_Rotate(T);
break;
case RH: //新节点插入在T的左子树的右孩子上,要双旋
Lr=L->rchild; //指向T的左孩子的右子树根
switch(Lr->bf)
{
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做右旋
}
}
多路查找树:
每一个节点的孩子数可以多余两个,且每一个节点处可以存储多个元素。
1.【2-3】树
一棵多路查找树,每一个节点具有两个孩子,或三个孩子。
一个两节点包含一个元素和两个孩子(或者没哟孩子),要么没有孩子,要么就是2个
一个三节点包含一小一大两个元素和三个孩子(或没有孩子)
且2-3树的所有叶子都在同一层次上。
插入:
插入节点到一个两节点的叶子上,由于其本身只有一个元素,要将其升级为3节点,要比较当前节点和当前叶子节点的大小决定插入到左还是右。
要往3节点中插入,因为本身已经是最大容量,就要将其拆分,且将树中两元素或插入元素的三者中选择其一向上移动一层
2-3-4树,就是上面的拓展。
B树:
平衡的多路查找树,节点最大的孩子数目称为B树的阶(order)。
一个m阶的B树有以下性质:
如果跟节点不是叶节点,至少有两颗子树
每一个非根的分支节点都有k-1个元素和k个孩子,m/2<=k<=m;每一个叶子节点都有k-1个元素,
所有叶子节点位于同一层次
所有的分支节点都包 括ki < ki+1 (i=1~n-1);是关键字。Ai(i=0~n)是指向子树跟
节 点的指针,且指针A(i-1)所指子树中的所有关键字均小于Ki。An所指子树中所有节点的关键字均大于Kn
在B树上查找是顺指针查找节点和在节点中查找关键字的循环过程。
哈希表:
存储位置=f(关键字) :f是一个函数,这样就可以查找关键字而不需要比较就可以获得记录的存储位置
散列技术: 就是在记录的存储位置和它的关键字之间建立一个确定的对应关系f,使得每个关键字key对应一个存储位置f(key);
f称为散列函数,又叫哈希函数。
在存储时通过散列函数计算记录的散列地址,并按照此散列地址来存储该记录。
查找记录时,通过同样的散列函数去计算散列地址,按此来访问记录。
方法:
1.直接定址法:去关键字的某个线性函数值作为散列地址
2.数字分析法:关键字数值大,但其中有分布均匀的子集
3.平方取中法:不知道关键字的分布,位数不是很大。对数值平方,取中间几位
4.折叠法:不需要知道分布情况,位数较多的情况。从左到右分割为位数相等的几部分,叠加求和,按照散列表表长,取后几位作为散列地址
5.除留余数法:f(key)=key mod p (p<=m) 对于表长为m来说。