算法设计要求
1.正确性、2.可读性、3.健壮性、4.高效率地存储
算法效率的度量
时间复杂度:随着问题规模n的增大,算法执行时间的增长率和f(n)的增长率相同简称渐近时间复杂度
频度:语句的执行次数。
空间复杂度:算法所需要空间
一
int i = 1;
int k = 0;
int n = 10;
while(i <= n-1){
k += 10 * i; /*计算该语句频度*/
i++;
}
while 循环了多少次,就是该语句的频度 while 执行一次 i 自增 1 ,当 i>n-1 时退出,就是当 i=n 时退出 while,i 一开始为 1,所以 while 总共循环了 n-1 次; 频度 :n-1
二
int i = 1;
int k = 0;
int n = 10;
do{
k += 10 * i; /*计算该语句频度*/
i++;
}while(i <= n-1);
循环了多少次,就是该语句的频度 循环体执行一次 i 自增 1 ,当 i>n-1 时退出,就是当 i=n 时退出循环体,i 一开始为 1
,所以循环体总共循环了 n-1 次; 频度 :n-1
三
int i = 1;
int k = 0;
int n = 10;
while(i <= n-1){
i++;
k += 10 * i; /*计算该语句频度*/
}
循环了多少次,就是该语句的频度 循环体执行一次 i 自增 1 ,当 i>n-1 时退出,就是当 i=n 时退出循环体,i 一开始为 1
,所以循环体总共循环了 n-1 次; 频度 :n-1
四
int k = 0;
int n = 10;
for(int i = 1; i <= n; i++){
for(int j = i; j<=n; j++){
k++; /*计算该语句频度*/
}
}
第一层循环 n 次 第二层循环 n+(n-1)+(n-2)+…+2+1 = n(n+1)/2 ,所以 k++ 执行了 n(n+1)/2 次
频度 :n(n+1)/2
五
int n = 100;
int i = 0;
while(n >= (i+1)*(i+1)){
i++; /*计算该语句频度*/
}
循环体执行 floor(sqrt(n)) 次 频度: ⌊ n ⌋ \lfloor \sqrt{n}\rfloor⌊ n ⌋
六
int x = 0;
int i,j,k;
int n = 10;
for(i = 1; i <= n; i++) {
for(j = 1; j <= i ; j++) {
for(k = 1; k <= j; k++) {
x += 1; /*计算该语句频度*/
}
}
}
第一层 n 第二层 1+2+3+4+…+n 第三层 1+(1+2)+(1+2+3)+(1+2+3+4)+…+(1+2+3+4+…+n) = n(n+1)(2n+3)/12 频度:n(n+1)(2n+3)/12
七
int i = 1;
int j = 0;
int n = 10;
while(i+j <= n){
if(i > j)/*计算该语句频度*/ j++;
else i++;
}
注意:if 语句不管真假都会判断一次,所以循环了多少次就判断了多少次 if 语句 当 i+j=n+1 时退出循环 所以循环次数为
(n+1)-1 = n 所以频度为 n
八
int x = 91;
int y = 100;
while(y > 0){
if(x > 100){ /*计算该判断语句频度*/
x -= 10;
y--;
}else{
x++;
}
}
看 while 循环体中的 if 语句频度就看 while 循环次数 开始 x=91 ,循环了 10 次,每次都执行 else ,直到
x=101 当 x=101,循环了 1 次,if 条件成立,x 又变成了 91 ,而 y=99; while
循环还没退出之前都是按照这规律循环,直到 y=0 退出 while ,一共重复了 100 遍上面的规律,每次 11 次循环,
所以该语句频度为 100*11 = 1100
注意
int k = 1;
for(int i = 1; i <= n ;i++){ //(1)
k++; //(2)
}
(1)语句频度是n+1 i 变量在第一个 for 循环中,从取 i = 0 开始执行,直到i=n时为止,至此,i
执行了n次。加上最后i=n+1跳出循环的判断,故,频度共n+1 次;(2)语句频度是n 当 i = n+1时跳出循环,所以里面的循环体一共执行了 n 次0
时间复杂度 简单的说,就是保留语句频度的最高次幂,并且把系数去掉。 如T(n)=2n^2+n+1=O(n)
判断输出序列合法性
栈中合法的序列,双端队列中一定也合法,因此判断输入受限的双端队列,输出受限的双端队列只需要额外看在栈中不合法的那些序列就可以了
中缀表达式转后缀表达式(机算)
一
2 * ( 5 - 1 )
二
5 + 60 * ( 3 - 1 ) / ( 6 - 4 ) + 3
三
(23+34*45/(5+6+7))
一
2 5 1 - *
二
5 60 3 1 - * 6 4 - / 3 + +
三
23 34 45 * 5 6 + 7 + / +
二维数组的存储结构
3.了解串的模式匹配算法。
int index_BF(String S,String A){
int i=1,j=1;
while(i<=S->length&&j<=A->length){
printf("%c=%c\n",S->data[i],A->data[j]);
if(S->data[i]==A->data[j]){
i++;
j++;
}else{
i=i-j+2; //计算出下一个比较开始下标
j=1;
}
}
if(j>=A->length){
return i-A->length;
}else{
return -1;
}
}
void get_next(String S){
int next[S->length];//定义返回值变量
next[1]=0;
int i=1, j=0;
while(i<S->length){
if(j==0||S->data[i]==S->data[j]){
i++;j++;
next[i]=j;
}else{
j=next[j];
}
}
}
数据压缩
三角矩阵:主对角线两边对称
压缩思想:使用线性结构存储主对角线下三角部分,或者上三角部分达到压缩的效果。
元素存储线性结构位置:下三角或者上三角n-1项数列求和,再加上当前行。
上三角公式:i行号,j列。
稀疏矩阵:只有少数的元素是非空的
压缩是思想:使用数组或者链表去记录每个元素的(行、列、值)达到压缩效果。(是无法随机存取的)
如:array[1]={0,0,1}
array[2]={1,2,5}
array[3]={2,0,3}
十字链表法:记录稀疏矩阵的行排序和列排序。
压缩思想:记录行标和列表是数组达到压缩效果,但是有记录了行下一个元素位置和列下一个元素位置。
可以通过行数组或者列数组,遍历行列数据。
对角矩阵:主对角线或者反对角线的两边空元素对称
压缩思想:将矩阵中所有元素从上到下,从左到右依次放线性表示。
为了以后叙述方便,我们定义几个量:
diag:对角线条数
size:方阵高度
firstRowNum= ,第一行元素数(表达式易证)
2. 掌握矩阵的转置算法和矩阵的相加算法的实现。
3. 了解广义表在m元多项式中的简单应用。
广义表
广义表具有如下重要的特性:
(1)广义表中的数据元素有相对次序;
(2)广义表的长度定义为最外层包含元素个数;
(3)广义表的深度定义为所含括弧的重数。其中原子的深度为0,空表的深度为1;
(4)广义表可以共享;一个广义表可以为其他广义表共享;这种共享广义表称为再入表;
(5)广义表可以是一个递归的表。一个广义表可以是自已的子表。这种广义表称为递归表。递归表的深度是无穷值,长度是有限值;
(6)任何一个非空广义表GL均可分解为表头head(GL) = a1和表尾tail(GL) = ( a2,…,an) 两部分。
为了简单起见,下面讨论的广义表不包括前面定义的再入表和递归表,即只讨论一般的广义表。
另外,我们规定用小写字母表示原子,用大写字母表示广义表的表名。例如:
A=() B=(e) C=(a,(b,c,d)) D=(A,B,C)=((),(e),(a,(b,c,d))) E=((a,(a,b),((a,b),c)))
其中A是一个空表,其长度为0;
B是只含有单个原子e的表,其长度为1;
C有两个元素,一个是原子a,另一个是子表,其长度为2;
D有三个元素,每个元素都是一个表,其长度为3;
E中只含有一个元素,是一个表,它的长度为1;