今天的笔记是第一部分:基础知识中的第1、2章内容。先来个概述,第一章主要介绍算法是什么,算法在计算中能起到什么作用。第二章主要介绍算法基础,讲了一个插入排序算法,同时介绍了如何分析算法的复杂度,还引入了分治法的思想,归并排序算法。另,包含一些练习题。
一、算法
- 算法是什么
算法就是任何定义良好的计算过程,它取一个或一组值作为输入,并产生出一个或一组值作为输出。也就是说,算法就是一系列的计算过程,用来将输入的数据转换成输出结果。
例如:我们需要把一个数列按照非递减排序。下面是关于排序问题的形式定义。
输入:n个数的一个序列{a1,a2,a3,a4,…,an}。
输出:输入序列的一个排列{a1’,a2’,a3’,a4’,…,an’},满足a1’<= a2’ <= a3’ … <= an’。 - 算法的应用
以上咱们使用算法解决排序问题,但是算法实际应用无处不在。例如:
- 分析数据库中存储的人类基因工程中30亿个化学基对的序列
- 管理和处理互联网上的海量数据,访问与检索大量信息
- 电子商务对个人订单信息保密,核心技术是公钥密码和数字签名
二、算法基础
1、插入排序法
- 插入排序是一个对少量元素进行排序的有效算法。
我们将其伪代码过程命名为INSERTION-SORT,它的参数是一个数组A[1 .. n],包含了n个待排数字。
(在伪代码中,A中元素的个数n用A.length来表示)
算法思想:每趟将一个元素,按照其中元素的大小插入到它前面已经排序的子序列中,依此重复,直到插入全部元素。**INSERTION-SORT(A)** for j = 2 to A.length key = A[j] // Insert A[j] into the sorted sequence A[1 .. j - 1] i = j - 1 while i > 0 and A[i] > key A[i + 1] = A[i] i = i - 1 A[i + 1] = key
- 插入排序算法的简单Java实现
/** * 插入排序 * * @param array */ public static void insertionSort(int[] array) { int key, j; for (int i = 1; i < array.length; i++) { key = array[i]; j = i - 1; while (j >= 0 && array[j] > key) { array[j + 1] = array[j]; j--; } array[j + 1] = key; } }
- 算法分析
算法分析是指对一个算法所需要的资源进行预测。内存,通信带宽或计算机硬件等资源偶尔会是我们主要关心的,但通常,资源是指我们希望度量的是计算时间。
我们就不把插入排序算法的分析过程一一贴出来了,插入排序算法的时间复杂度是T(n)=O(n*n)。
2、分治思想
- 将原问题分解为几个规模较小但类似于原问题的子问题,递归地求解这些子问题。然后再合并这些子问题的解来建立原问题的解。
分治模式在每层l递归时都有三个步骤:
- 分解原问题为若干子问题,这些子问题是原问题的规模较小的实例。
- 解决这些子问题,递归地求解各个子问题。然而,若子问题的规模足够小,则直接求解。
- 合并这些子问题的解成原问题的解。
- 归并排序算法
归并排序算法完全遵循分治模式。 直观上操作如下:
- 分解:将 n 个元素分成各含 n / 2个元素的子序列;
- 解决:用归并排序法对两个子序列递归地排序;
- 合并:合并两个已排序的子序列以得到排序结果。
对子序列排序时,其长度为1时递归”开始回升”。在这种情况下不要做任何工作,因为长度为1的每个序列都已排好序。归并排序的关键步骤在于合并两个已排序的子序列。
这里引入一个辅助过程MERGE(A, p, q, r),其中A为数组,p,q和r都是下标,有p <= q < r。该过程假设子数组A[p .. q]和A[q+1 .. r]都已排好序,并将它们合并成一个已排好序的子数组代替当前子数组A[p .. r]。 - 归并排序算法的实现
合并步骤:MERGE(A, p, q, r) n1 = q - p + 1 n2 = r - q let L[1 .. n1 + 1] and R[1 .. n2 + 1] be new arrays for i = 1 to n1 L[i] = A[p + i - 1] for j = 1 to n2 R[j] = A[q + j] L[n1 + 1] = MAX R[n2 + 1] = MAX i = 1 j = 1 for k = p to r if L[i] <= R[j] A[k] = L[i] i = i + 1 else A[k] = R[j] j = j + 1
排序步骤:MERGE(A, p, q, r) n1 = q - p + 1 n2 = r - q let L[1 .. n1 + 1] and R[1 .. n2 + 1] be new arrays for i = 1 to n1 L[i] = A[p + i - 1] for j = 1 to n2 R[j] = A[q + j] L[n1 + 1] = MAX R[n2 + 1] = MAX i = 1 j = 1 for k = p to r if L[i] <= R[j] A[k] = L[i] i = i + 1 else A[k] = R[j] j = j + 1
- 归并排序算法Java实现
/** * 归并排序 * * @param array */ public static void mergeSort(int[] array) { mergeSort(array, 0, array.length - 1); } private static void mergeSort(int[] array, int p, int r) { int q; if (p < r) { q = (p + r) >> 1; mergeSort(array, p, q); mergeSort(array, q + 1, r); merge(array, p, q, r); } } private static void merge(int[] array, int p, int q, int r) { int lLen = q - p + 1; int rLen = r - q; int[] left = new int[lLen + 1]; int[] right = new int[rLen + 1]; int i, j; for (i = 0; i < lLen; i++) left[i] = array[p + i]; for (j = 0; j < rLen; j++) right[j] = array[q + j + 1]; left[i] = Integer.MAX_VALUE; right[j] = Integer.MAX_VALUE; i = j = 0; for (int k = p; k <= r; k++) { if (left[i] <= right[j]) array[k] = left[i++]; else array[k] = right[j++]; } }
习题
- 插入排序改写成递归过程
INSERTION-SORT-RECURSIVE(A, p) if p > 1 key = A[p] p = p - 1 INSERTION-SORT-RECURSIVE(A, p) INSERTION-ELEMENT(A, p, key) INSERTION-ELEMENT(A, p, key) while p > 0 and A[p] > key A[p + 1] = A[p] p = p - 1 A[p + 1] = key
- 二分查找伪码
**BINARY-SEARCH(A, v)** front = 1 end = A.length while front < end middle = (front + end) / 2 if A[middle] < v front = middle + 1 else if A[middle] > v end = middle - 1 else return middle return -1
- 设计算法:查找集合S中是否存在两个元素和等于x的元素。
思路:先排序,后查找**CHECK-SUM(S, x)** A = MERGE-SORT(S) for i = 1 to A.length v = x - A[i] if BINARY-SEARCH(A, v) > 0 return true return false
感谢大家花时间阅读本人博客,在接下来每周会更新一篇算法导论的算法设计博文。当中有什么问题还请大家指正,相互学习,相互促进!