简介
此数据结构的基于数据结构-浙江大学的视频教材的学习整理。
感谢陈越和何钦铭两位老师!
- 笔记请参考数据结构
先看一个例子:顺序输出1-N个正整数
#include <stdio.h>
void printN(int N)
{
for (int i = 0; i<N; i++) {
printf("%d ", i);
}
return;
}
void printN2(int N)
{
if (N > 0) {
printN2(N - 1);
printf("%d ", N);
}
}
int main(int argc, const char * argv[]) {
printN2(1000000);
}
可以看到,有两个做法,一个是直接使用for循环,一个是使用递归。
在N = 1,10,100,1000,10000,100000。。。。做实验
你会发现,数据量越大,递归到最后直接报内存不足。
这是因为,函数一直没有释放,函数每次调用都要入栈,每次只入不出,栈满了,导致内存不足,报错。
解决问题方法的效率,跟空间的利用率有关
这,就引出我们今天的话题----数据结构
#include <stdio.h>
//n表示n,x表示f(x)中x的值,a[]表示:[a0,a1,a2...an]
double f(int n, double a[], double x)
{
double p = a[0];
for (int i = 1; i<=n; i++) {
p += (a[i] * pow(x, i));
}
return p;
}
int main(int argc, const char * argv[]) {
double a[] = {1, 2, 3};
//计算数学式:1 + 2*2^1+ 3*2^2
printf("%f\n", f(3, a, 2));
//1*2^0 + 2*2^1 + 3*2^2 = 1 + 4 + 12 = 17
}
计算其算法复杂度:
+和-法忽略不计
n次循环
每次循环需要:a[i] * pow(x, i) = a[i] * x^i
(a[i]) 乘以 (x^i )是1次
x^i是i-1次
所以,a[i] * pow(x, i)是i次
1 + 2 + 3 +…+n = n(1+n)/2=(n+n*n)/2
忽略常数,只算最高位
那么,这个算法的时间复杂度是n^2
个人觉得这个算法挺好的,主要是思考的时候简单,老师说 ,这么写会被鄙视。。。
秦九韶算法
有个秦九韶算法,这么写的:
提取公因子x,写程序的时候,从里往外算(写)
double f2(int n, double a[], double x)
{
double p = a[n];
for (int i = n; i>0; i--) {
p = a[i - 1] + x*p;
}
return p;
}
计算其算法复杂度:
+和-法忽略不计
n次循环
每次循环需要:x*p
那么,这个算法的时间复杂度是n
同样一道题,使用不同的方法,其算法的时间复杂度是不一样的
因此,如果将问题借的更好,就是数据结构与算法研究的问题
那,什么是数据结构呢?
数据结构:
数据对象在计算机中的组织形式,包括:
逻辑结构
物理存储结构
数据对象不是孤立存在的,数据对象必定与一些列加在其上的操作相关联
完成这些操作所用的方法就是算法
抽象数据类型(Abstract Data Type)
数据类型:
数据对象集
数据集合相关联的操作集
抽象:描述数据类型的方法不依赖于具体方法
包括:
与存放数据的机器无关
与数据存储的物理结构无关
与实现操作的算法和编程语言无关
也就是:只描述数据对象集和操作“是什么”,而不关心“怎么做到”
算法
算法(Algorithm)
一个有限指令集
接收一些输入(有可能没输入)
产生输出
一定在有限步骤之后终止
每一条指令必须:有充分明确的目标,不能有歧义。计算机能处理的范围内
算法的判断标准:
空间复杂度:根据算法写成的程序在执行时占用存储单元的长度
时间复杂度:根据算法写成的程序在执行时耗费时间的长度
在计算时间复杂度的时候,+ -法忽略不计
只算阶层最高的
我们关注时间复杂度,最主要的是关注两个:
最坏情况复杂度
平均复杂度
我们不对算法做精确处理,只需要掌握其增长趋势即可。
不同的函数增长速度:
求最大子列和问题
给定{1, -3, 8, 10, -9},求里面连续相加的最大值。
{8, 10}
方案一:暴力法,一个一个加
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;
for (k = i; k<=j; k++) {
ThisSum += A[k];//ThisSum是A[i]到A[j]的子列和
}
if (ThisSum > MaxSum) {//如果ThisSum大于MaxSum,则MaxSum = ThisSum
MaxSum = ThisSum;
}
}
}
return MaxSum;
}
时间复杂度是O(N^3)
方案二:
int MaxSubseqSum2(int A[], int N)
{
int ThisSum, MaxSum = 0;
int i, j;
for (i = 0; i<N; i++) {//i是子列左端的位置
ThisSum = 0;
for (j = i; j<N; j++) {//j是子列右端的位置
ThisSum += A[j];//ThisSum是A[i]到A[j]的子列和
if (ThisSum > MaxSum) {//如果ThisSum大于MaxSum,则MaxSum = ThisSum
MaxSum = ThisSum;
}
}
}
return MaxSum;
}
时间复杂度O(N^2)
方案三:分治法
时间复杂度O(NlogN);
方案四:在线处理法
int MaxSubseqSum4(int A[], int N)
{
int ThisSum = 0, MaxSum = 0;
int i;
for (i = 0; i<N; i++) {//i是子列左端的位置
ThisSum += A[i];
if (ThisSum > MaxSum) {//如果ThisSum大于MaxSum,则MaxSum = ThisSum
MaxSum = ThisSum;
}else if (ThisSum < 0){
ThisSum = 0;
}
}
return MaxSum;
}
时间复杂度O(N)