新学期开了一门算法课,于是打算写一个算法的系列,可以给大家梳理一个完整的算法脉络,我也能熟悉一些比较难懂的算法,一举两得。
一、什么是算法
算法在我们的日常生活中其实随处可见,比如付钱的时候如何找零?扑克牌摸牌的时候按什么规则整理牌?(比如打升级和打斗地主的时候整理的方式可能不同)等等。把这些方法用指令清楚地表示出来,就是算法。算法,就是一系列解决问题的清晰指令适合用计算机实现的解决问题的方法。
问题,通常可以分解为三个部分,问题、问题描述以及问题实例。问题是需要回答的一般性提问,含若干参数;问题描述需要定义问题参数,并定义问题的解,说明解需要满足的条件;问题实例就是参数赋一组值就可以的得到一个实例。其他就不过多赘述
二、算法的性质
1、有限性、确定性
算法首先要保证每条指令的执行次数有限、即时间有限;同时每条指令应该有确定的含义,没有歧义,即算法的确定性
2、正确性
算法正确性体现在以下方面:
1)正确的算法:对任意一个输入,算法能得到一个正确的输出
2)循环不变量:与程序变量有关的一个语句,它在循环刚开始前,以及在循环的每个迭代执行后为真,特别是在循环结束后,仍然为真。
我们用一个最基本的插入排序来举例验证其算法的正确性:
首先给出算法:(就是一个很简单的插入算法)
void InsertSort(int a[], int n) {
for (int j = 1;j < n;j++) {
int i = j - 1;
int key = a[j];
while (i >= 0 && key > a[i]) {
a[i + 1] = a[i];
i--;
}
a[i+1] = key;
}
}
我们用归纳法证明这种插入算法的正确性,即在for循环第j个迭代执行前,子数组A[1.. j-1]由最初A[1..j-1]中的元素构成,不过现在是有序的。(插入排序的循环不变量)
在第一次循环迭代之前(j=1时),A[0.. j-1]只有A[0],是A[0]中原来元素,且自然有序。循环不变式成立
归纳保持:假设j次迭代前,循环不变式成立,子数组A[0.. j]由最初A[0..j]中的元素构成,不过现在是有序的。证明j+1迭代前,子数组A[0.. j+1]由最初A[0..j+1]中的元素构成且有序。加入A[j+1]后数组经过算法,显然数组仍为循环不变式
终止:循环终止时,j=n-1,根据归纳保持,子数组A[0..n]由原来A[0..n]中元素组成,但已按序排列。算法正确
三、算法的描述
算法设计要清晰的表现算法的核心内容,要简单、清晰且无二义性,需要注意的是选择算法描述的方法是和实现工具无关的
主要的方法有:自然语言,流程图,程序设计语言以及伪代码
其中,伪代码是一种简单高效且清晰的实现方法
举一个例子
求最大公约数问题,我们可以采取辗转相除法。
两数相除,除数作为下一次的被除数,余数作为下一次的除数,直到余数为0,这是的被除数即为最大公约数
用伪代码写出来是这样的,十分简洁清晰:
Euclid(n,m)
while m > 0
r = n mod m
n = m
m = r
return n;
四、总结
本篇作为引言介绍了一些算法的基本概念以及性质,之后会慢慢更新介绍一些常见的算法!