第一周:预备知识—算法与数据结构
解决问题的策略效率与什么有关?
数据组织方式
图书馆插入新书和查找书籍,用不同的数据组织方式,对应的操作就会有不同的时间复杂度。
数据组织方式好坏的分析,与它所相关的操作有直接联系。
空间利用效率
观察两段用于输出1到N的数字的代码
其一循环算法:
void PrintN(int N) { int i; for (i = 1; i <= N; i++) { printf("%d\n", i); } return; }
其二递归算法:
void PrintN(int N) { if (N) { PrintN(N - 1); printf("%d\n", N); } return; }
第二段代码在数据过大时由于不断堆栈,空间爆炸,异常终止。
算法巧妙程度
计算多项式在给定点x处的值,两段代码
其一: f(x)=a0+a1x+⋯+an−1xn−1+anxn
double f(int n, double a[], double x) { int i; double p = a[0]; for (i = 1; i <= n; i++) { p += (a[i] * pow(x,i)); } return p; }
其二; f(x)=a0+x(a1+x(⋯(an−1+x(an))))
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; }
两段代码在运行时间上有很大区别,究其原因,将乘法视为关键操作,幂次视作多次乘法,则第一段代码算法 O(n2) , 第二段代码 O(n) .
测试(比较)算法运行效率小方法
#include<stdio.h>
#include<time.h>
#include<math.h>
#define MAX 100
double poly1(int n, double a[], double x) // 坊间算法
{
double p = 0;
for (int i = 0; i <= n; i++) {
p += a[i] * pow(x, i);
}
return p;
}
double poly2(int n, double a[], double x) // 专业算法
{
double p = a[0];
for (int i = n; i > 0; i--) {
p += a[i - 1] + p * x;
}
return p;
}
int main()
{
double coef[MAX], x = 1.1;
clock_t start, stop;
for (int i = 0; i < MAX; i++) {
coef[i] = i / 3.0;
}
start = clock();
for (int i = 0; i < MAX; i++)
poly1(MAX - 1, coef, x);
stop = clock();
printf("Polynomial Algorithm 1---plain Algorithm\n"
"used ticks: %f\n\n", (double)(stop - start));
start = clock();
for (int i = 0; i < MAX; i++)
poly2(MAX - 1, coef, x);
stop = clock();
printf("Polynomial Algorithm 2---professional Algorithm\n"
"used ticks: %f\n\n", (double)(stop - start));
return 0;
}
数据结构与抽象数据结构
数据结构
- 数据对象在计算机中的组织方式
- 逻辑结构
- 物理存储结构
- 数据对象与施加于其上的操作相关联
- 实现操作的就是算法
抽象数据结构
- 数据结构
- 数据对象集
- 与数据对象集相关的操作集
- 抽象
- 与物理存储方式无关
- 与实现的算法和编程语言无关
只定义了对象集和操作集,不涉及如何实现。如下例:
算法与最大子列和问题
熟悉问题,只敲了代码,在QuizCode里有
初识PTA
PTA是数据结构这门课采用的OJ系统。
- 会将各个样例的特征标在Wrong Answer的标签旁边,便于Debug。
- 函数填空题会将一些部分隐藏起来,因此看上去没有不代表没有,需仔细读题。
最大子列和(课堂算法)代码
课上讲的算法 O(nlogn) 实现
#include<stdio.h>
#include<stdlib.h> // for malloc
int MaximumSubSum(int Data[], int s, int e); // 寻找最大和
int max(int a, int b, int c);
int MaxCrossing(int Data[], int s, int e); // Conquer 寻找跨越中间元素的最大和
int main()
{
int * Data = NULL, Size = 0;
scanf("%d", &Size);
Data = malloc(sizeof(int) * Size); // 动态分配内存
for (int i = 0; i < Size; i++) {
scanf("%d", &Data[i]);
}
int Max = MaximumSubSum(Data, 0, Size - 1); // 寻找
printf("%d\n", Max);
return 0;
}
int MaximumSubSum(int Data[], int s, int e)
{
if (s == e) { // Base Case 只有一个元素
if (Data[s] <= 0) {
return 0;
}
else {
return Data[s];
}
}
int mid = (s + e) / 2;
int Max1 = MaximumSubSum(Data, s, mid);
int Max2 = MaximumSubSum(Data, mid + 1, e); // Divide, 递归求解
int Max3 = MaxCrossing(Data, s, e); // Conquer
return max(Max1, Max2, Max3);
}
int max(int a, int b, int c)
{
int result = a;
if (result < b) {
result = b;
}
if (result < c) {
result = c;
}
return result;
}
int MaxCrossing(int Data[], int s, int e)
{
int mid = (s + e) / 2, maxl = 0, maxr = 0, curr = 0;
for (int i = mid; i >= s; i--) { // 左侧最大
curr += Data[i];
if (curr > maxl) {
maxl = curr;
}
}
curr = 0; // initialize
for (int i = mid + 1; i <= e; i++) {// 右侧最大
curr += Data[i];
if (curr > maxr) {
maxr = curr;
}
}
return maxl + maxr; // 和为最大
}
算法 O(n) 实现
#include<stdio.h>
int main()
{
int Size = 0, max = 0, curr = 0, Data = 0; // O(1) extra space
scanf("%d", &Size);
for (int i = 0; i < Size; i++) {
scanf("%d", &Data);
curr += Data;
if (curr > max) { // refresh max
max = curr;
}
if (curr < 0) { // discard curr
curr = 0;
}
}
printf("%d\n", max);
return 0;
}
最大子列和(课后习题)代码
O(n) 实现
#include<stdio.h>
#include<stdlib.h> // for malloc
int main()
{
int Bool = 0, Size = 0, max = 0, curr = 0, curr_s = 0, curr_e = 0, s = 0, e = 0;
int * Data; // O(n) extra space
scanf("%d", &Size);
Data = malloc(sizeof(int) * (Size + 1));
for (int i = 0; i < Size; i++) {
scanf("%d", &Data[i]);
}
curr_s = curr_e = s = e = Data[0];
for (int i = 0; i < Size; i++) {
curr += Data[i];
curr_e = Data[i];
if (curr < 0) {
curr = 0;
curr_s = Data[i + 1];
}
if (curr > max) {
max = curr;
s = curr_s;
e = curr_e;
}
}
if (max == 0) { // 为0特判
s = Data[0];
e = Data[Size - 1];
for (int i = 0; i < Size; i++) {
if (Data[i] == 0) {
s = e = 0;
break;
}
}
}
printf("%d %d %d\n", max, s, e);
return 0;
}