2018.4.23 数据结构
算法:
计算=信息处理 借助某种工具,遵照一定规则,以明确而机械的形式进行
计算模型=计算机=信息处理工具
所谓算法,旨在解决特定问题的指令序列
输入:待处理的信息(问题)
输出:经处理的信息(答案)
正确性:的确可以解决指定的问题
确定性:任以算法都可以描述为一个由基本操作组成的序列
可行性:每一基本操作都可实现,且在常熟时间内完成
有穷性:对于任何输入,经过有穷次基本操作,都可以得到输出
.....
Hailstone(n)={
{1} n<=1
{n} 并 Hailstone(n/2) n 偶
{n} 并 Hailstone(3n+1) n 奇
}
int hailstone(int n)//计算序列hailstone(n)的长度
{
int length=1;//从1开始,以下按定义逐步递推,并累计步数,直至n=1
while(1<n)
{
(n%2)? n=3*n+1:n/=2;
length++;
return length;//返回hailstone
}
好算法:
正确:符合语法,能够编译,链接
能够正确处理简单的输入
能够正确处理大规模的输入
能够正确处理一般性的输入
能够正确处理退化的输入
能够正确处理任意合法的输入
健壮:能辨别不合法的输入并做适当处理,而不致非正常退出
可读:结构化+准确命名+注释+...
效率:速度更可能快;存储空间尽可能少
data Structure +Algorithm(算法) 简称 DSA
RAM:Random Access Machine
算法分析:
正确性
成本:运行时间+所需存储空间
上溢:当一个超长的数据进入到缓冲区时,超出的部分被写入到上级缓冲区,上级缓冲区,
上级缓冲区存放的可能是数据,上一条指令的指针,或者是其他程序的输出内容,这些内容被覆盖或
者破坏掉。
下溢:当一个超长的数据进入到缓冲区时,超出的部分被写入下级缓冲区,下级缓冲区存放
的是下一条指令的指针,或者是其他程序的输出内容。
起泡排序:
void bubblesort(int A[],int n)
{
for(bool sorted=false;sorted=!sorted;n--)//逐趟扫描交换,直至完全有序
for(int i=1;i<n;i++)//自左向右,逐对检查A[0,n)内各相邻元素
if(a[i-1]>a[i])
{
swap(A[i-1],A[i]);//令其互换
sorted=false;//清除(全局)有序标志
}
}
不变性:经过K轮扫描交换后,最大的K个元素必然就位
单调性:经K轮扫描交换后,问题规模缩减至n-k
正确性:经至多n趟扫描后,算法必然终止,且能给出正确解答
计算n个整数之和:
int sunI(int A[],int n) E2
{
int sum=0;
for(int i=0;i<n;i++)
sum+=A[i];
return sum;
}
减而治之:为求解一个大规模的问题,可以将其划分为两个子问题,其一是平凡,另一规模缩
减(//单调性),分别求解子问题,由子问题的解,得到原问题的解。
数组求和:线性递归
sum(int A[],int n)
{
return
(n<1) ?
0:sum(A,n-1)+A[n-1];
}
数组倒置:任给数组A[0,n),将其前后颠倒
统一接口:void reverse(int *A,int lo,int hi);
递归版:
if(lo<hi)//问题规模的奇偶性不变,需要两个递归基 E5
{
swap(A[lo],A[hi]); reverse(A,lo+1,hi-1);
}
迭代原始版:
next:
if(lo<hi)
{
swap(A[lo],A[hi]);lo++;hi--;goto next;
}
迭代精简版:
while(lo<hi) swap(A[lo++],A[hi--]);
分而治之:
为求解一个更大规模的问题,可以将其划分为若干(通常2个)子问题,规模大体相当
分别求解子问题,由子问题的解,得到原问题的解。
数组求和:二分递归
sum(int A[],int lo,int hi)//区间范围A[lo,hi]
{
if(lo==hi) return A[lo];
int mi=(lo+hi)>>1;//右移,也相当于除2
return sum(A,lo,mi)+sum(A,mi+1,hi)
}//入口形式为sum(A,0,n-1)
迭代1:从数组区间A[lo,hi)中找出最大两个整数A[x1]和A[x2]元素比较次数,要求尽可能地少
void max2(int A[],int lo,int hi,int &x1,int &x2)//1<n=hi+lo
{
for(x1=lo,int i=lo+1;i<hi;i++)//扫描A[lo,hi),找出A[x1]
if(A[x1]<A[i]) x1=i;//hi-lo-1=n-1
for(x2=lo,int i=lo+1;i<x1;i++) //扫描A[lo,x1)
if(A[x2]<A[i]) x2=i;// x1-lo-1
for(int i=x1+1;i<hi;i++)//再扫描A(x1,hi),找出A[x2]
if(A[x2]<A[i]) x2=i;//hi-x1-1
}
迭代2:问题同上
void max2(int A[],int lo,int hi,int &x1,int &x2)//1<n=hi+lo
{
if(A[x1=lo]<A[x2=lo+1]) swap(x1,x2);
for(int i=lo+2;i<hi;i++)
if(A[x2]<A[i])
if(A[x1]<A[x2=i])
swap(x1,x2);
}
递归+分治:问题同上
void max2(int A[],int lo,int hi,int &x1,int &x2)
{
if(lo+2==hi) { /*.....*/; return; }//T(2)=1
if(lo+3==hi)d
00000000 { /...../; return; }//T(3)<=3
int mi=(lo+hi)/2; //divide
int x1L,x2L; max2(A,lo,mi,x1L,x2L);
int x1R,x2R; max2(A,mi,hi,x1R,x2R);
if(A[x1L]>A[x1R])
{
x1=x1L;x2=(A[x2L]>A[x1R])? x2L:x1R;
}else
{
x1=x1R; x2=(A[x1L]>A[x2R])? x1L : x2R;
}//1+1=2
}
动态规划: XC3
fib():迭代
动态规划:颠倒计算方向,由自顶而下递归,为自底而上迭代
f=0; g=1;//fib(0),fib(1)
while(0<n--)
{
g=g+f;
f=g-f;
}
return g;