文章目录
算法Algorithm
算法
- 一个有限指令集
- 接受一些输入(有些情况下不需要输入)
- 产生输出
- 一定在有限步骤之后终止
- 每一条指令必须:
有充分明确的目标,不可以有歧义
计算机能处理的范围之内
描述应不依赖于任何一种计算机语言以及具体的实现手段
什么是好的算法?
在分析一般算法的效率时,我们经常关注下面两种复杂度:
- 最坏情况复杂度Tworst(n)
- 平均复杂度Tavg(n)
- Tavg(n) <= Tworst(n)
空间复杂度S(n) -----space
-
根据算法写成的程序在执行时占用存储单元的长度。
这个长度往往与输入数据的规模有关。 -
空间复杂度过高的算法可能导致使用的内存超限,造成程序非正常中断。
时间复杂度T(n)----time
- 根据算法写成的程序在执行时耗费时间的长度。
这个长度往往也与输入数据的规模有关。 - 时间复杂度过高的低效算法可能导致我们在有生之年都等不到运行结果。
复杂度的渐进表示法
- T(n)=O(f(n))表示存在常数C>0,n0>0使得当n>=n0时有T(n)<=C*f(n)
(对于充分大的n而言,O(f(n))表示f(n)是T(n)的某种上界) - T(n)=Ω(g(n))表示存在常数C>0, n0>0使得当n>=n0时有T(n)>=C*g(n)
g(n)即T(n)的某种下界 - T(n)=Θ(h(n))表示同时有T(n)=O(h(n))和T(n)=Ω(h(n))
表示同时存在上界和下界,而且二者是等价的
复杂度分析小窍门
- 分析时要找:最小的上界,最大的下届
- 若两段算法分别有复杂度T1(n)=O(f1(n))和T2(n)=O(f2(n)),则:
T1(n)+T2(n)=max(O(f1(n)), O(f2(n)));
T1(n)xT2(n)=O(f1(n) x f2(n)); - 若T(n)是关于n的k阶多项式,那么T(n)=Θ(nk)
n足够大时,起作用的只有(阶数)最大的那一项,其他项可以忽略 - 一个
for
循环的时间复杂度等于循环次数乘以循环体代码的复杂度 if-else
结构的复杂度取决于if的条件判断复杂度和两个分支部分的复杂度,总体复杂度取三者中最大
选择排序算法
- 伪码描述
void SelectionSort (int List[], int N)
{ /*将N个整数List[0]...List[N-1]进行非递减排序*/
for(i=0; i<N; i++)
{
/*从List[i]到List[N-1]中找最小元,并将其位置赋给MinPosition*/
MinPosition = ScanForMin(List, i, N-1);
/*将未排序部分的最小元换到有序部分的最后位置*/
Swap(List[i], List[MinPosition]);
}
}
- 有效代码
#include <stdio.h>
#define NUM 10
int ScanForMin (int List[], int i,int N) //查找未排序部分最小元素
{
int j;
int min = i;
for(j=i+1; j<=N; j++)
{
if(List[j] < List[min])
{
min = j;
}
}
return min;
}
void Swap(int List[], int i, int MinPosition) //将未排序部分最小元素换到已排序部分最后位置
{
int temp;
temp = List[i];
List[i] = List[MinPosition];
List[MinPosition] = temp;
}
void SelectionSort (int List[], int N) //选择排序函数
{
int i;
int MinPosition = 0;
for(i=0; i<N; i++)
{
MinPosition = ScanForMin(List, i, N-1);
Swap(List, i, MinPosition);
}
}
int main(void)
{
int a[NUM] = {89,123,4,23,18,7,45,3,33,66};
int i;
SelectionSort(a,NUM);
for(i=0; i<NUM; i++)
{
printf("%d ", a[i]);
}
printf("\n");
return 0;
}
求最大连续子列和(多重for循环)
算法1:T(N) = O(N3)
int MaxSubseqSum1(int A[], int N)
{
int ThisSum, MaxSum=0;
int i, j, k;
for(i=0; i<N; i++) //i是子列左端位置
{
for(j=i; j<N; j++) // j是子列右端位置
{
ThisSum=0; //ThisSum是从A[i]到A[j]的子列和
for(k=i; k<=j; k++)
{
ThisSum += A[k];
}
if(ThisSum > MaxSum)//如果刚得到的这个子列和更大
{
MaxSum = ThisSum; //则更新结果
}
}//j循环结束
}//i循环结束
return Max
}
算法2:T(N) = O(N2)
int MaxSubseqSum2(int A[], int N)
{
int ThisSum, MaxSum=0;
int i, j;
for(i=0; i<N; i++) //i是子列左端位置
{
ThisSum=0;//ThisSum是从A[i]到A[j]的子列和
for(j=i; j<N; j++) //j是子列右端位置
{
ThisSum += A[j];
//对于相同的i,不同的j,只要在j-1次循环的基础上累加1项即可
if(ThisSum>MaxSum) //如果刚得到的这个子列和更大
{
MaxSum=ThisSum; //则更新结果
}
}//j循环结束
}//i循环结束
return MaxSum;
}
算法3:分而治之 T(N) = O(N*LogN)
- 基本思路就是将原问题拆分成若干小型问题,分别解决后再将结果合而治之,用递归实现非常方便。
int Max3(int A, int B, int C)
{
return A>B?A>C?A:C:B>C?B:C;
}
int DivideAndConquer(int List[], int left, int right)
{
//分治法求List[left]到List[right]的最大子列和
int MaxLeftSum, MaxRightSum; //存放左右子问题的解
int MaxLeftBorderSum,MaxRightBorderSum; //存放跨分界线的结果
int LeftBorderSum, RightBorderSum;
int center, i;
if(left==right)//递归终止条件,子列只有1个数字
{
if(List[left]>0)
{
return List[left];
}
else
{
return 0;
}
}
//下面是“分”的过程
center=(left+right)/2; //找到中分点
//递归求得两边子列的最大和
MaxLeftSum=DivideAndConquer(List, left, center);
MaxRightSum=DivideAndConquer(List, center+1, right);
//下面求跨分界线的最大子列和
MaxLeftBorderSum=0; LeftBorderSum=0;
for(i=center; i>=left; i--)
{
LeftBorderSum += List[i];
if(LeftBorderSum>MaxLeftBorderSum)
{
MaxLeftBorderSum=LeftBorderSum;
}
} //左边扫描结束
MaxRightBorderSum=0; RightBorderSum=0;
for(i=center+1; i<=right; i++) //从中线向右扫描
{
RightBorderSum += List[i];
if(RightBorderSum>MaxRightBorderSum)
{
MaxRightBorderSum= RightBorderSum;
}
} //右边扫描结束
//下面返回“治”的结果
return Max3(MaxLeftSum, MaxRightSum, MaxLeftBorderSum+MaxRightBorderSum);
}
int MaxSubseqSum3(int List[], int N)
{
//保持与前2种算法相同的函数接口
return DivideAndConquer(List, 0, N-1);
}
算法4:在线处理 T(N)= O(N)
“在线”的意思是指每输入一个数据就进行即时处理,在任何一个地方终止输入,算法都能正确给出当前的解。
int MaxSubseqSum4(int A[], int N)
{
int ThisSum, MaxSum;
int i;
ThisSum=MaxSum=0;
for(i=0; i<N; i++)
{
ThisSum += A[i]; //向右累加
if(ThisSum > MaxSum)
{
MaxSum = ThisSum; //发现更大的和则更新当前结果
}
else if(ThisSum < 0) //如果当前子列和为负
{
ThisSum = 0; // 则不可能使后面的部分和增大,抛弃之
}
}
return MaxSum;
}