Bootstrap

浙江大学MOOC数据结构笔记(一)

什么是数据结构

空间使用

写程序实现一个函数printN,使得传入一个正整数为N的参数后,能顺序打印从1到N的全部正整数


#include<bits/stdc++.h>
using namespace std;
void printN(int N){
	int i;
	for(int i=1;i<=N;i++){
		cout<<i<<endl;
	}
	return;
} /*循环函数*/ 
void printN(int N){
	if(N){
		printN(N-1);
		cout<<N<<endl;
	} 
	return;
} /*递归函数*/ 
int main()
{
    int n;
	cin>>n;
	printN(n);
    return 0;
}

​

遇到数字较大时,在两个函数下编译器情况不同

                                                                   循环

递归

 递归函数的时间和空间的消耗较大,因为每次调动递归函数都要重新为其本身分配空间用以对参数进行保存,当算的足够多时递归函数将需要存更多的数据导致内存不足,但循环只需要对一个变量进行改变和输出的结果,不需要申请那么多的空间。

关于算法效率

写程序计算给定多项式在给定点x处的值\begin{matrix} f(x)=a_{_{0}}+a_{_{1}}x+ & & +a_{_{n-1}}x^{n-1}+a_{_{n}}x^{n} \end{matrix}

秦九韶算法:f(x)=a_{0}+x(a_{1}+x(...(a_{n-1}+x(a_{n}))...))

#include<bits/stdc++>
using namespace std;
double f(int n,double a[],double x){
	int i;
	double p=a[n];
	for(i=n;i>0;i--){
		p=a[i-1]+x*p;
	}
	return p;
} 

clock():捕捉从程序开始运行到clock()被调用时所消耗的时间。时间单位是clock tick(常数CLK_TCK:机器时钟每秒所走的时钟打点数) 

#include<bits/stdc++>
using namespace std;
clock_t start,stop;/*clock_t是clock()返回的变量类型*/
double duration/*记录被测函数运行时间,以s为单位*/
int main(){
	/*不在测试范围内的准备工作写在clock()调用之前*/
	start=clock();/*开始计时*/
	Function();/*被测函数*/
	stop=clock();/*停止计时*/
	duration=((double)(stop-start))/CLK_TCK;
	/*其他不在测试范围内的处理写在后面,eg:输出duration*/
	return 0; 
} 

若函数运行过快,时间不到一个tick,只需重复运行最后计算被测函数平均每次运行的时间

include<bits/stdc++>
using namespace std;
#define MAXX 1e7/*被测函数最大重复调用次数*/ 
clock_t start,stop;/*clock_t是clock()返回的变量类型*/
double duration/*记录被测函数运行时间,以s为单位*/
int main(){
	/*不在测试范围内的准备工作写在clock()调用之前*/
	start=clock();/*开始计时*/
	for(i=0;i<MAXX;i++){
		Function();/*被测函数*/
	} 
	stop=clock();/*停止计时*/
	duration=((double)(stop-start))/CLK_TCK/MAXX;
	
	/*其他不在测试范围内的处理写在后面,eg:输出duration*/
	return 0; 
} 

 抽象数据类型

数据类型:数据对象集;数据集合相关联的操作集

抽象:描述数据类型的方法不依赖于具体实现即c++中的模块化

什么是算法

算法

最坏情况复杂度

二分法:

给定N个从小到大排好序的整数序列List[],以及某待查找整数X,我们的目标是找到X在LIst中的下标。即若有List[i]=X,则返回i;否则返回-1表示没有找到

二分法是先找到序列的中点List[M],与X进行比较,若相等则返回中点下标;否则,若List[M]>X,则在左边的子系列中查找X;若List[M]<X,则在右边的子系列中查找X

int f(int a[],int x,int n){
 	int st=0;
 	int fi=n-1;
	int mid=(st+fi)/2;
	while(a[mid]!=x){
		if(a[mid]>x){
			fi=mid;
		}
		else{
			st=mid;
		}
			mid=(st+fi)/2;
	}
	return mid;
}

当遇到 n^2算法的代码时应尽可能改成nlogn的算法

效率(反之即增长速度):logn>n>nlogn>n^2>2^n

一个for循环的时间复杂度等于循环次数乘以循环体代码的复杂度

if-else结构的复杂度取决于if的条件判断复杂度和两个分支部分的复杂度,总体复杂度取三者中最大。

应用实例

最大子列和问题

给定N个整数的序列{A1,A2,——,AN},求函数f(i,j)=max\begin{Bmatrix} 0,\sum_{k=i}^{j}A_{k} \end{Bmatrix}

最优解:在线处理:每输入一个数据就进行即时处理,在任何一个地方中止输入,算法都能正确给出当前的解

#include<bits/stdc++>
using namespace std;
int MaxSubeqSum(int A[],int N){
	int Thissum,Maxsum;
	int i;
	ThisSum=MaxSum=0;
	for(int i=0;i<N;i++){
		ThisSum+=A[i];/*向右累加*/ 
		if(ThisSum>MaxSum)
		MaxSum=ThisSum;/*发现更大和则更新当前结果*/ 
		else if(ThisSum<0)/*如果当前子列和为负*/ 
		ThisSum=0;/*则不可能使后面的部分和增大,抛弃*/ 
	}
	return MaxSum;
} 

 分而治之:把一个比较大的复杂的问题切分成小的块,分头解决,最后把结果合并起来

悦读

道可道,非常道;名可名,非常名。 无名,天地之始,有名,万物之母。 故常无欲,以观其妙,常有欲,以观其徼。 此两者,同出而异名,同谓之玄,玄之又玄,众妙之门。

;