17、顺序查找
①查找的基本概念 基本概念 查找表:由同一类型的数据元素(或记录)构成的集合 查找:查询特定元素是否在表中 查找成功:若表中存在特定元素,称查找成功,应输出该记录 查找不成功:表中不存在给定值的元素,称查找不成功 静态查找: 只查找,不改变集合内的数据元素 动态查找: 既查找,又改变(增减)集合内的数据元素 关键字: 记录中某个数据项的值,可用来识别一个记录 主关键字:可以唯一标识一个记录的关键字 次关键字:识别若干记录的关键字
查找的过程是怎样的 给定一个K值,在含有n个记录的文件中进行搜索,寻找一个关键字值等于K的记录,如找到就输出记录,否则输出查找不成功的信息 有哪些查找方法 查找方法取决于表中数据的排列方式 针对静态查找表和动态查找表的查找方法也有所不同
静态表查找 1.顺序查找(线性查找) 2.折半查找(二分或对分查找) 3.分块查找(索引顺序查找)
顺序查找 用逐一比较的方法顺序查找关键字,这显然是最直接的方法。 算法实现:
/*无哨兵顺序查找, 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;
}
优点:算法简单 缺点:查找效率低下,时间复杂度较高 最好情况:O(1) 最坏情况:O(n) 平均情况: O((n+1)/2) 最终复杂度为: O(n)
折半查找 又称二分查找。它的前提是线性表中的记录必须是关键码有序,线性表必须采用顺序存储。将key与中间元素相比,若key大,则缩小至右半部内查找;再取其中值比较,每次缩小1/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;/*最低下标调整到中位下标大一位*/
else
return mid;/* 若相等则说明mid即为查找到的位置 */
}
return 0;
}
分块查找 思路:先让数据分块有序,即分成若干个子表,要求每个子表中的数据元素值都比后一块中的数值小(但子表内部可以无序)。然后将各子表中最大关键字构成一个索引表,表中还要包含每个子表的起始地址(即头指针)。 索引表中的每个索引项包含3个数据项 1.最大关键码 2.块中记录个数 3.指向块首数据元素的指针 查找步骤分两步: 1.对索引表使用折半查找法(因为索引表是有序表) 2.确定了待查关键字所在的子表后,在子表内采用顺序查找法(因为各子表内部是无序表)
18、二叉排序树
①二叉排序树的定义
二叉排序树是一种典型的动态查找表 动态查找表:表结构在查找过程中动态生成的表,对于给定值key,若表中存在其关键字等于key的记录,则查找成功返回;否则插入关键字等于key的记录。 二叉排序树的定义: 一棵空树或者具有如下性质的非空二叉树 1·左子树的所有结点均小于根的值 2.右子树的所有结点均大于根的值 3.它的左右子树也分别为二叉排序树
②二叉排序树的查找操作 算法:
/*二叉树的二叉链表结点结构定义*/
typedef struct BiTNode/* 结点结构*/
{
int data; /* 结点数据 */
struct BiTNode *Ichild, *rchild;/* 左右孩子指针 */
}BiTNode, *BiTree;
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->Ichild, key, T, p);/*在左子树中继续查找*/
else
return SearchBST(T->rchild, key,T,p);/*在右子树中继续查找*/
}
③二叉排序树的插入操作
算法:
Status InsertBST(BiTree *T, int key)
{
BiTree p,s;
if (ISearchBST(*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->Ichild = s; /* 插入s为左孩子*/
else
p->rchild = s; /* 插入s为右孩子*/
return TRUE;
}
else
return FALSE; /*树中已有关键字相同的结点,不再插入*/
}
④二叉排序树的删除操作 二叉排序树的删除操作
叶子结点:直接删除 只有左子树:用左子树的根结点替换 只有右子树:用右子树的根结点替换 左右子树都有:用左子树最大的值替换或右子树最小的值替换
算法:
/*从二叉排序树中删除结点p,并重接它的左或右子树。*/
Status Delete(BiTree *p)
{
BiTree q,s;
if((*p)->rchild==NULL)/*右子树空则只需重接它的左子树(待删结点是叶子也走此分支)*/
{
q=*p; *p=(*p)->Ichild; free(q);
}
else if((*p)->Ichild==NULL) /*只需重接它的右子树*/
{
q=*p; *p=(*p)->rchild; free(q);
}
else /* 左右子树均不空*/
q=*p; s=(*p)->Ichild;
while(s->rchild)/*转左,然后向右到尽头(找待删结点的前驱)*/
{
q=s;
s=s->rchild;
}
(*p)->data=s->data; /* s指向被删结点的直接前驱(将被删结点前驱的值取代被删结点的值)*/
if(q!=*p)
q->rchild=s->Ichild;/*重接q的右子树*/
else
q->ichild=s->ichild; /* 重接q的左子树 */
free(s);
}
return TRUE;
}
⑤二叉排序树的总结 二叉排序树的总结 1,线性表查找可以将线性表构造成二叉排序树进行查找 2.中序遍历此二叉树,将会得到一个关键字的有序序列(即实现了排序运算) 3.如果查找不成功,能够方便地将被查元素插入到二叉树的叶子结点上,而且插入或删除时只需修改指针而不需要移动元素。 4·二叉排序树的查找效率取决于二叉排序树的形状,如果二叉排序树比较平衡,其深度和完全二叉树相同则近似折半查找。
19、平衡二叉树
①平衡二叉树的定义 平衡二叉树的定义 平衡二叉树(balanced binary tree)是由阿德尔森一维尔斯和兰迪斯(Adelson-Velskii and Landis)于1962年首先提出的,所以又称为AVL树。 定义:平衡二叉树一种满足下面性质的二叉树 (1)是一棵空树或满足(2)、(3)的非空二叉树 (2)左子树和右子树深度之差的绝对值不大于1 (3)左子树和右子树也都是平衡二叉树
平衡因子(Balance Factor):二叉树上结点的左子树的深度减去右子树的深度称为该结点的平衡因子。 因此,平衡二叉树上每个结点的平衡因子只可能是-1,0和1,否则,只要有一个结点的平衡因子的绝对值大于1,该二叉树就不是平衡二叉树。 如果一棵二叉树既是二叉排序树又是平衡二叉树称为平衡二叉排序树
②平衡化旋转
平衡二叉树的旋转 可见,一般的二叉排序树是不平衡的,需要对二叉排序树进行修正使其即保持有序性,又具有平衡性。这种修正的方法称为平衡化旋转。 在对AVL树进行插入和删除一个结点后,通常会影响到从根结点到插入(或删除)结点的路径上的某些结点。这些结点的子树可能发生变化。以插入结点为例,影响有如下可能: 1.某些结点深度发生了变化 2.某些结点平衡因子发生了变化 3.某些结点失去平衡
LL型平衡化旋转 1)LL平衡旋转:
RR型平衡化旋转 2)RR平衡旋转:
LR型平衡化旋转 3)LR平衡旋转:
RL型平衡化旋转 4) RL平衡旋转:
③平衡二叉排序树的插入操作 平衡二叉排序树的插入操作 平衡二叉排序树的插入操作是在二叉排序树的基础上完成以下工作: 1.判断插入结点后的二叉排序树是否产生不平衡 2.找出失去平衡的最小子树 3·判断旋转类型,然后做相应调整
算法思想: 1·按照二叉排序树的定义,将结点s插入 2.在查找结点s的插入位置的过程中,记录离结点s最近且平衡因子不为0的结点a,若该结点不存在,则结点a指向根结点 3.修改结点a到结点s路径上所有结点的平衡因子 4·判断是否产生不平衡,若不平衡,则确定旋转类型并做相应调整
20、多路查找树
①多路查找树的定义 多路查找树的定义 平衡二叉树便于动态查找,处理的数据都是在内存中。假如我们要操作的数据集非常大,大到内存无法处理,怎么办呢?这种情况,我们会把要处理的数据放到文件。这时处理数据就要不断的从硬盘等外部存储器读取和写入数据。而过多的读写外部存储器显然会降低系统的效率。为了降低对外存的访问次数,我们就需要新的数据结构处理这样的问题。 为了降低平衡二叉树的高度,提高效率我们可以使树中每个结点的孩子数多于2个,每个结点处可以存储多个元素,并且元素之间存在某种特定的排序关系。我们把这样的树称之为多路查找树。
②2-3树 2-3树 2-3树是多路查找树的一个特例 它是这样的多路查找树: 1.每个节点都具有2个孩子(称之为2节点)或者3个孩子(称之为3节点)。 一个2节点包含一个元素和两个孩子(或没有孩子)。 一个3节点包含两个元素和三个孩子(或没有孩子)。 2.所有的叶子结点都在同一层上
插入操作: 1·空树的插入最简单,创建一个节点即可 2.对于非空树,插入操作按照后面的步骤进行 非空树插入操作步骤: 1·在树中查找要插入的关键字,如果没找到则执行下面的插入操作 2.插入到查找到的结点指定位置 3.判断插入后的结点大小是否超出范围 a)没有超出范围,插入完毕 b)超出则做分割处理,把所在结点分为[0,m/2-1]和[m/2+1,m-1]两部分,把结点中间位置(m/2处)的元素插入的父结点,插入完毕后设置该 元素右边的孩子为刚刚分离的[m/2+1,m-1]部分 c)重复执行3步骤,直到插入后的结点没有超出范围。
删除操作: 1.找到所要删除的关键字(假设是K)所在的节点和位置。 2如果待删除的数据所在的结点不是叶子结点,找左子树最大的关键字 a)如果左子树最大关键字所在的结点有足够的关键字数目则用左子树最大的关键字替换 b)如果左边最大关键字所在的结点不够则用右子树最小的关键字替换 c)删除找到的用来替换的关键字 d)如果两边子树都没有足够的关键字数目,则删除待删关键字 3.如果是叶子结点且不是根结点,删除待删关键字 4·判断2,3中做删除操作的结点的关键字数目是否足够 a)如果所在结点的关键字数目足够则完成 b)如果所在结点的关键字数目不足够, 先看左(或右)兄弟有没有足够的关键字可借用,有则借用。 没有则做合并操作,左(或右)兄弟和父结点合并 5·是叶子结点且是根结点,直接删除
③2-3-4树 2-3-4树 是2-3树的扩展,多了包含4个结点的使用。具体要求如下: 1.每个节点都具有2个孩子(称之为2节点) , 3个孩子(称之为3节点)或者4个孩子(称之为4节点)。 一个2节点包含一个元素和两个孩子(或没有孩子)。 一个3节点包含两个元素和三个孩子(或没有孩子)。 一个4节点包含三个元素和四个孩子(或没有孩子)。 2.所有的叶子结点都在同一层上
④B树 B树的定义 B树是一种多路查找树,2-3树和2-3-4树都是B树的特例。节点最大的孩子数目称为B树的阶,因此2-3树是3阶B树, 2-3-4树是4阶B树。 一个m阶的B树具有如下性质: 1)如果根节点不是叶子节点,则其子树个数范围为[2, m]; 2)分支节点子树个数范围为[m/2(向上取整), m]: 3)所有1子节点在同一层次 4)所有分支节点包含下列信息:关键字个数n.关键字k1..,kn.指向子树根结点的指针AO....An
标签:结点,排序,二叉,学习,关键字,查找,二叉树,数据结构 From: https://www.cnblogs.com/cyxyrq-code-loading/p/17549589.html