七、查找
- 概述
- 查找表:由同一类型的数据元素(或记录)构成的集合。
-
-
- 静态查找表
- 静态查找是指在静态查找表上进行的查找操作,在查找表中满足条件的数据元素的存储位置或各种属性。静态查找表的查找算法主要有:
- 顺序查找:从表的一端开始,顺序扫描线性表,依次将扫描到的关键字和给定值k进行比较,若当前扫描到的关键字与k相等,则查找成功;若扫描结束后,仍未找到关键字等于k的记录,则查找失败。
- 折半查找:对给定值k,逐步确定待查记录所在区间,每次将搜索空间减少一半,直到查找成功或失败为止。
- 分块查找:
- 动态查找表:表结构在查找过程中动态生成的这样一种查找表。实现动态查找方法:二叉排序树、平衡二叉树、B-树和B+树。
- 二叉排序树
- 定义:左子树的所有结点均小于根的值;右子树的所有节点均大于根的值;它的左右子树也分别为二叉排序树。
- 二叉排序树插入新结点的过程:
- 二叉排序树插入新节点递归算法:
-
- 二叉排序树删除结点的算法:
- 二叉排序树查找算法分析:
- 平衡二叉树
- 平衡二叉树又称为AVL树,设二叉树中结点的左子树和右子树的深度分别为HL和HR。
-
- 若在构造二叉排序树的同时,使其始终保持为AVL树,则此时的二叉排序树为平衡的二叉排序树。将一棵非平衡二叉排序树调整成平衡二叉排序树的“旋转”,分为:LL平衡旋转、RR平衡旋转、LR平衡旋转、RL平衡旋转。
-
- B-树又称基本B树或多路平衡查找树。它是构造大型文件系统索引结构的一种数据结构类型,适合在磁盘等直接存取设备上组织动态的查找表。
-
-
- B-树的查找算法思路:
- B-树的查找效率取决于以下两个因素:包含k的结点在B-树种所在的层数h;结点中ki的个数n。
- B-树的生成:
- B-树的删除:
- B+树
- B+树是B-树的变形,目的在于有效地组织文件的索引结构。
- m阶B+树与B-树的差异:
-
- B+树种可以有两种查找方式:顺序查找——类似单链表的查找,直接在数据层进行查找。随机查找——类似B-树的查找,不同的是搜索到索引层的key与k相等时,还得继续搜索下去,直到数据层为止。
-
- 哈希表
-
- 哈希表,根据设定的哈希函数H(key)和处理冲突的方法将一组关键字key映射到一个有限的连续的地址集上,并以关键字key在地址集中的“像”作为记录在表中的存储位置,这种表便称为哈希表,这一映射过程称为哈希造表或散列,所得存储位置称哈希地址或散列地址。
- 将不同的关键码映射到同一个哈希地址上,该现象称为冲突。
- 哈希函数的构造方法
- 常用的哈希函数构造方法有:直接定址法、除留余数法、乘余取整法、数字分析法、平方取中法、折叠法、随机数法。
- 直接定址法:
- 除留余数法:
- 乘余取整法:
- 数字分析法:
- 平方取中法:
- 叠加法:
- 随机数法:
- 处理冲突的方法
- 开放定址法、链地址法、再哈希法、建立一个公共溢出区
- 开放定址法:
- 链地址法:
- 再哈希法:
- 建立一个公共溢出区:
- 红黑树
- 红黑树,一种二叉查找树,但在每个结点上增加一个存储位表示结点颜色,可以是Red或Black。通过对任何一条从根到叶子的路径上各个结点着色方式的限制,红黑树确保没有一条路径会比其他路径长出两倍,因而是接近平衡的。
- 红黑树虽然本质上是一棵二叉查找树,但它在二叉查找树的基础上增加了着色和相关的性质使得红黑树相对平衡,从而保证了红黑树的查找、插入、删除的时间复杂度最坏为O(log n)。红黑树和AVL树的区别在于它使用颜色来标识结点的高度,它所追求的是局部平衡而不是AVL树中的非常严格的平衡。
- 红黑树的五个性质保证了红黑树的高度始终保持在logn:
- 红黑树的旋转操作:红黑树的旋转操作和AVL树一样,分为LL、RR、LR、RL四种旋转类型,差别在于旋转完成后改变的是结点的颜色,而不是平衡因子。
- 红黑树的插入和删除:http://blog.csdn.net/eric491179912/article/details/6179908
八、排序
- 排序概述
- 排序的分类:内部排序和外部排序(若待排序记录都在内存中,称为内部排序;若待排序记录一部分在内存,一部分在外存,则称为外部排序)。稳定排序和不稳定排序。
- 内部排序的算法:插入排序(希尔排序)、交换排序(快速排序)、选择排序(堆排序)、归并排序、基数排序。
- 插入排序
- 思想:每次将一个待排序的对象,按其关键码大小,插入到前面已经排好序的一组对象的适当位置上,直到对象全部插入为止。
- 具体实现算法:直接插入排序、折半插入排序、希尔排序
- 直接插入排序:
void InsertSort(int a[]){
int i,j;
//按照有小到大的顺序排序
for(i=2;i<a.length;i++){
//找到无序表的第一个位置
if(a[i]<a[i-1]){
a[0]=a[i];
//将无序表依次向后移动
for(j=i-1;a[0]<a[j];j--){
a[j+1]=a[j];
}
//将数据插入相应位置
a[j+1]=a[0];
}
}
}
该算法的时间复杂度是:O(n2)
- 折半插入排序:
void BInsertSort(int a[]){
int i,j,high,low;
for(i=2;i<a.length;i++){
a[0]=a[i];
low=1;
high=i-1;
int min;
while(low<=high){ //使用折半查找到插入的位置
min=(high+low)/2;
if(a[0]<a[min])
high=min-1;
else
low=min+1;
}
for(j=i-1;j=>high+1;j++) //插入的位置是在high位置之后
a[j+1]=a[j];
a[high+1]=a[0];
}
}
- 希尔排序:
void SheelSort(int a[],int dx){
//这是对直接插入排序的修改
//dx表示增量
//当j<=0时,插入位置已经找到
int i,j;
for(i=dx+1;i<a.length;i++){
if(a[i]<a[i-dx]){
a[0]=a[i];
for(j=i-dx;j>0&&a[0]<a[j];j-=dx)
a[j+dx]=a[j];
a[j+dx]=a[0];
}
}
}
- 交换排序
- 两两比较待排序记录的关键码,如果发生逆序(即排列顺序与排序后次序正好相反),则交换之,直到所有记录都排好序为止。
- 冒泡排序:
void bubbleSort(int a[]){
int i,j;
for(i=1;i<a.length-1;i++){
for(j=1;j<a.length-i;j++){
if(a[j]>a[j+1]){
a[0]=a[j];
a[j]=a[j+1];
a[j+1]=a[0];
}
}
}
}
- 快速排序:
void Partition(int a[],int low,int high){
//这只是一趟快速排序的算法
a[0]=a[low];
while(low<high){
//从高位往低位扫描,找到数值小于关键字的位置,与low位置交换
while(low<high&&a[0]<=a[high])
high--;
a[low]=a[high];
//从低位往高位扫描,找到数值大于关键字的位置,与high位置交换
while(low<high&&a[low]<=a[0])
low++;
a[high]=a[low];
}
//最后将关键字放入数组中
a[low]=a[0];
}
快速排序平均时间复杂度和最好时间复杂度为:O(log2n),最坏时间复杂度为O(n2)。
- 选择排序
- 不断从待排记录序列中选出关键字最小的记录插入已排序记录序列的后面,直到n个记录全部插入已排序记录序列中。
- 简单选择排序:
- 堆排序:借助于完全二叉树结构进行的排序,是一种树形选择排序。其特点是——在排序过程中,将R[1...N]看成是一棵完全二叉树的顺序存储结构,利用完全二叉树双亲结点和孩子结点之间的内在关系,在当前无序区中选择关键字最大(或最小)的记录。
- 建立一个堆排序的方法:
- 堆排序的过程:
- 堆排序算法实现:
void HeapAdjust(int *a,int i,int size) //调整堆
{
int lchild=2*i; //i的左孩子节点序号
int rchild=2*i+1; //i的右孩子节点序号
int max=i; //临时变量
if(i<=size/2) //如果i不是叶节点就不用进行调整
{
if(lchild<=size&&a[lchild]>a[max])
{
max=lchild;
}
if(rchild<=size&&a[rchild]>a[max])
{
max=rchild;
}
if(max!=i)
{
swap(a[i],a[max]);
}
}
}
void BuildHeap(int *a,int size) //建立堆
{
int i;
for(i=size/2;i>=1;i--) //非叶节点最大序号值为size/2
{
HeapAdjust(a,i,size);
}
}
void HeapSort(int *a,int size) //堆排序
{
int i;
BuildHeap(a,size);
for(i=size;i>=1;i--)
{
//cout<<a[1]<<" ";
swap(a[1],a[i]); //交换堆顶和最后一个元素,即每次将剩余元素中的最大者放到最后面
//BuildHeap(a,i-1); //将余下元素重新建立为大顶堆
HeapAdjust(a,1,i-1); //重新调整堆顶节点成为大顶堆
}
}
- 归并排序
- “归并”的含义是将两个或两个以上的有序表合并成一个新的有序表。
-
- 两个有序表的合并算法Merge():
- 算法分析:
- 基数排序
- 基数排序是一种借助多关键字排序的思想对单逻辑关键字进行排序的方法,即先将关键字分解成若干部分,然后通过对各部分关键字的分别排序,最终完成对全部记录的排序。
- 多关键字的排序:
- 链式基数排序:
- 排序算法总结
九、时间复杂度
- 该时间复杂度表达作用于递归过程。
- n/b表示下一回递归的数据量为n/b,a表示递归的次数为a,除了递归之外的时间复杂度为O(nd)。
作者:龙猫小爷
链接:http://www.jianshu.com/p/2469a4d9708e
來源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。