数据结构学习笔记01----C语言回顾C语言回顾
例一:求从1到N的正整数的和
void Test::PrintN1(int N)
{
/*打印从1到N的全部正整数*/
int i;
for (i = 1; i <= N; i++) {
cout << ("%d", i)<< endl;
}
}
void Test::PrintN2(int N)
{
/*打印从1到N的全部正整数*/
if (N > 0) {
PrintN2(N - 1);
cout << ("%d", N) << endl;
}
}
这两个函数实现的功能是一样的,但二者运行的时间,效率和空间是不同的。第一个只是用的循环,其使用空间少。而第二个程序使用了递归,当一个函数调用另一个函数的时候,它需要物理空间,也就是会使用栈。也就是说在执行的过程中需要不断的使用物理空间保存上一次调用时的状态,故其效率相对较低。
例二:计算多项式
#define MAXN 10 /* 多项式最大项数,即多项式阶数+1 */
#define MAXK 100000 /* 被测函数最大重复调用次数*/
double Test::f1(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;
}
double Test::f2(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;
}
void Test::Tets01()
{
/* 此函数用于测试被测函数(*f)的运行时间*/
int i;
double a[MAXN]; /* 存储多项式的系数*/
/* 为本题的多项式系数赋值,即a[i]=i */
for (i = 0; i<MAXN; i++) a[i] = (double)i;
start = clock();
for (i = 0; i<MAXK; i++) /* 重复调用函数以获得充分多的时钟打点数*/
this->f1(MAXN - 1, a, 1.1);
stop = clock();
duration = ((double)(stop - start)) / CLK_TCK;
printf("ticks1= %f\n", (double)(stop - start));
printf("duration1= %6.2e\n", duration);
start = clock();
for (i = 0; i<MAXK; i++) /* 重复调用函数以获得充分多的时钟打点数*/
this->f2(MAXN - 1, a, 1.1);
stop = clock();
duration = ((double)(stop - start)) / CLK_TCK;
printf("ticks2= %f\n", (double)(stop - start));
printf("duration2= %6.2e\n", duration);
}
其运行结果为:
每一次的运行结果都有些差异,但是从两个duration中可以看出不同的实现方法,程序的运行时间大约是10倍的关系。
例三:求连续序列的最大值,即求一个连续序列中所有子序列中的最大值
方法一:
分析:子序列的起点和终点是不知道的,可以表示为:
起点:i = a[0]到a[7]
终点:j = a[i]到a[7]
那么我们可以用个二重循环,进行描述子序列的起点和终点,然后再嵌套进去一个循环进行对子序列求和比较,进而得到子序列的最大值。
int Test::MaxSubseqSum1(int List[], int N)
{
int i, j, k;
int ThisSum, MaxSum = 0;
for (i = 0; i<N; i++) { /* i是子列左端位置 */
for (j = i; j<N; j++) { /* j是子列右端位置 */
ThisSum = 0; /* ThisSum是从List[i]到List[j]的子列和 */
for (k = i; k <= j; k++)
ThisSum += List[k];
if (ThisSum > MaxSum) /* 如果刚得到的这个子列和更大 */
MaxSum = ThisSum; /* 则更新结果 */
} /* j循环结束 */
} /* i循环结束 */
return MaxSum;
}
方法二:在第三重循环时进行累加判断,即(少了一重循环):
int Test::MaxSubseqSum2(int List[], int N)
{
int i, j;
int ThisSum, MaxSum = 0;
for (i = 0; i<N; i++) { /* i是子列左端位置 */
ThisSum = 0; /* ThisSum是从List[i]到List[j]的子列和 */
for (j = i; j<N; j++) { /* j是子列右端位置 */
/*对于相同的i,不同的j,只要在j-1次循环的基础上累加1项即可*/
ThisSum += List[j];
if (ThisSum > MaxSum) /* 如果刚得到的这个子列和更大 */
MaxSum = ThisSum; /* 则更新结果 */
} /* j循环结束 */
} /* i循环结束 */
return MaxSum;
}
方法三:
假设数组为:a[8] = {-5,3,-2,4,-6,1,6,-2}
我们考虑:①:这个数组中第一个元素或最后一个元素若是小于0,那它根本不用参与运算,参与了也只会拉低其最大值。
②:第三个元素-2有用,原因在于其,后面在加上4会比3大;而若以4为起点,那么-6就没有价值。
基于此,代码可更新为:
int Test::MaxSubseqSum3(int List[], int N)
{
int i;
int ThisSum, MaxSum;
ThisSum = MaxSum = 0;
for (i = 0; i<N; i++) {
ThisSum += List[i]; /* 向右累加 */
if (ThisSum > MaxSum)
MaxSum = ThisSum; /* 发现更大和则更新当前结果 */
else if (ThisSum < 0) /* 如果当前子列和为负 */
ThisSum = 0; /* 则不可能使后面的部分和增大,抛弃之 即重新寻找起点*/
}
return MaxSum;
}
测试程序与测试结果为:
void Test::Test02(int * list, int N)
{
Test test;
cout << "MaxSubseqSum1:" << test.MaxSubseqSum1(list, N) << endl;
cout << "MaxSubseqSum2:" << test.MaxSubseqSum2(list, N) << endl;
cout << "MaxSubseqSum3:" << test.MaxSubseqSum3(list, N) << endl;
}