07 算法
01 查找
查找(Searchig)就是根据给定的某个值,在查找表中确定一个其关键字等于给定值得数据元素(或记录)
1. 顺序表查找
顺序查找(Sequential Search)又叫线性查找,是最基本的查找技术,它的查找过程是:从表中第一个(或最后一个)记录开始,逐个进行记录的关键字和给定值比较,若某个记录的关键字和给定值相等,则查找成功,找到所查的记录;如果直到最后一个(或第一个)记录,其关键字和给定值比较都不等时,则表中没有所查的记录,查找不成功。
-
算法
/* 无哨兵顺序查找,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;
}
- 总结:
很显然,顺序查找技术是有很大缺点的,n很大时,查找的效率极为低下,不过优点也是有的,这个算法非常简单,对静态查找表的记录没有任何要求,在一些小型数据的查找时,是可以适用的。
2. 有序表查找
-
折半查找
折半查找(Binary Search)技术,又称为二分查找。它的前提是线性表中的记录必须是关键码有序(通常从小到大有序),线性表必须采用顺序存储。折半查找的基本思想是:在有序表中,取中间记录作为比较对象,若给定值与中间记录的关键字相等,则查找成功;若给定值小于中间记录的关键字,则在中间记录的左半区继续查找;若给定值大于中间记录的关键字,则在中间记录的右半区继续查找。不断重复上述过程,知道查找成功,或所有查找区域无记录,查找失败为止。
/* 有哨兵顺序查找 */ int Sequential_Search2(int *a,int n,int key) { int i; a[0]=key; i=n; while(a[i]!=key) { i--; } return i; }
总结:折半算法的时间复杂度为O(logn),它显然远远好于顺序查找的O(n)时间复杂度了。不过由于折半查找的前提条件是需要有序表顺序存储,对于静态查找表,一次排序后不再变化,这样的算法已经比较好了。但对于需要频繁执行插入或删除操作的数据集来说,维护有序的排序会带来不小的工作量,那就不建议使用。
-
插值查找
折半查找的优化,将折半的范围缩小,我们只需要在折半查找算法的代码中更改一下
/* 插值查找 */
int Interpolation_Search(int *a,int n,int key)
{
int low,high,mid;
low=1; /* 定义最低下标为记录首位 */
high=n; /* 定义最高下标为记录末位 */
while(low<=high)
{
mid=low+ (high-low)*(key-a[low])/(a[high]-a[low]); /* 插值 */
if (key<a[mid]) /* 若查找值比插值小 */
high=mid-1; /* 最高下标调整到插值下标小一位 */
else if (key>a[mid])/* 若查找值比插值大 */
low=mid+1; /* 最低下标调整到插值下标大一位 */
else
return mid; /* 若相等则说明mid即为查找到的位置 */
}
return 0;
}
-
斐波那契查找
也是折半查找的优化
F[0]=0; F[1]=1; for(i = 2;i < 100;i++) { F[i] = F[i-1] + F[i-2]; } /* 斐波那契查找 */ int Fibonacci_Search(int *a,int n,int key) { int low,high,mid,i,k=0; low=1; /* 定义最低下标为记录首位 */ high=n; /* 定义最高下标为记录末位 */ while(n>F[k]-1) 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; k=k-2; } else { if (mid<=n) return mid; /* 若相等则说明mid即为查找到的位置 */ else return n; } } return 0; }
总结:尽管斐波那契查找的时间复杂也为O(logn),但就平均性能来说,斐波那契查找要优于折半查找。可惜如果是最坏情况,比如key=1,那么始终都处于左侧长半区在查找,则查找效率要低于折半查找。
3. 线性索引查找
索引就是把一个关键字与它对应的记录相关联的过程,一个索引由若干个索引项构成,每个索引项至少应包含关键字和其对应的记录在存储器中的位置等信息。索引技术是组织大型数据库以及磁盘文件的一种重要技术。
线性索引就是讲索引项集合组织为线性结构,也称为索引表
-
稠密索引
稠密索引是指在线性索引中,将数据集中的每个记录对应一个索引项,因此,对于稠密索引这个 索引表来说,索引项一定是按照关键码有序的排列。
索引项有序就意味着,我们要查找关键字时候,可以用到折半、插值、斐波那契等有序查找算法,大大提高效率
-
分块索引
对于分块有序的数据集,将每块对应一个索引项,这种索引方法叫做分块索引
-
倒排索引
4. 二叉排序树
- 查找操作
- 插入操作
- 删除操作
- 总结
5. 平衡二叉树(AVL树)
- 原理
- 算法
6. 多路查找树(B树)
- 2-3 树
- 2-3-4 树
- B 树
- B+ 树
7. 散列表查找(哈希表)
- 定义
- 查找步骤
8. 散列函数的构造方法
- 直接定址法
- 数字分析法
- 平方取中法
- 折叠法
- 除留余数法
- 随机数法
9. 处理散列冲突的方法
- 开放定址法
- 再散列函数法
- 链地址法
- 公共溢出区法
10. 散列表查找实现
- 算法
- 性能分析
02 排序
1. 冒泡排序
- 最简单排序实现
- 冒泡排序算法
- 冒泡排序优化
- 复杂度分析
2. 简单选择排序
- 算法
- 复杂度分析
3. 直接插入排序
- 算法
- 复杂度分析
4. 希尔排序
- 原理
- 算法
- 复杂度分析
5. 堆排序
- 算法
- 复杂度分析
6. 归并排序
- 算法
- 复杂度分析
- 非递归实现归并排序
7. 快速排序
- 算法
- 复杂度分析
- 优化