第1章 引论 - 数据结构与算法分析 c语言描述

article/2025/8/20 6:52:09

 前言:此类型的文章皆为本人在阅读此书后给出的关于此书的理解,以及知识的梳理复习。若对文章有不解之处,或者文章有错欢迎评论区留言。

1.1 本书讨论的内容

        有一组N个数,要找出其中第k个最大者,我们称之为选择问题(selection problem)。一种解法是将这N个数读进一个数组中,通过简单的算法如冒泡排序以递减顺序排序,则第k个位置即是要找的数。一个递减排序的冒泡排序,从最后一位开始把最大的向前放置。

void BubbleSort(int arr[], int size)
{int i, j, tmp;for (i = 0; i < size - 1; i++)for (j = size - 1; j > i; j--){if (arr[j] > arr[j - 1]){tmp = arr[j];arr[j] = arr[j - 1];arr[j - 1] = tmp;}}
}

还有一种排序保证前 i+2 个元素为递减顺序,遇到下一个元素时将其排到正确的位置。

void BubbleSort(int arr[], int size)
{int i, j, tmp;for (i = 0; i < size - 1; i++)for (j = i; j >= 0; j--){if (arr[j] < arr[j + 1]){tmp = arr[j];arr[j] = arr[j + 1];arr[j + 1] = tmp;}}
}

·由此可以引出一种稍微好点的算法,先把前k个元素读入数组并递减排序,接着在将剩下的元素逐个读入。当读取新元素时,如果它小于数组中第k个元素则忽略,否则就将其放到数组中正确的位置上,同时挤出那个位置上的元素。当算法结束时,第k个位置上的元素即作为答案返回。

        这两种算法都很简单,此时要问哪个算法更好?哪个更重要?使用100万个元素的随机文件,在k=5000000的条件下模拟发现,两个算法在合理时间都不能结束。处理若干天才能完成。第7章将给出一个在1秒左右解决问题的算法。可以发现这两种算法相比于后者都是不切实际的。

        第二个问题是解决字谜。输入由含字母的二维数组和单词列表组成,目标是找出字谜中的单词,单词可以水平、垂直或者沿对角线。如图

1234
1this
2wats
3oahg
4fgdt

该字谜由单词 this、two、fat 和 that组成。this从(1,1)到(1,4)。two从(1,1)到(3,1)。

        现在有两种直观算法求解该问题。对单词表中的每个单词,检查有序三元组(行,列,方向)来验证这个单词是否存在。这需要大量嵌套的for循环。

        或者,对于每个尚未进行到字谜最后的有序四元组(行,列,方向,字符数)测试所指的单词是否在单词表中。也会导致大量嵌套的for循环。

        两种方法都不难编码,而且课求解许多现实的字谜游戏。然而若把字谜变为只给出谜板,而单词表基本上是一本英语词典,则上面两种解法需要相当多的时间。故这两种方法也不可接收,不过这样的问题还是有可能在数秒内解决的。

        在许多问题中,有一个重要观念是:写出可以工作的程序还不够,如果此程序在巨大的数据集中运行,那么运行时间就成了很重要的问题。我们将在本书中看到对于大量的输入如何估计程序运行时间,尤其是如何在未具体编码时比较两个程序的运行时间。还将看到彻底改进程序速度以及确定瓶颈的方法。

1.2 数学知识复习

1.2.1 指数 -

1.2.2 对数 - 略,但需注意计算机科学中,除非有特别声明,所有的对数都是以2为低的。

1.2.3 级数 -

1.2.4 模运算

        如果A-B能被N整除,那么我们就说A与B模N同余(congruent),记作A ≡ B(mod N)。换句话说就是 A除以N的余数 和 B除以N的余数 相同即 A mod N = B mod N。于是,81 ≡ 61 ≡ 1(mod 10)跟等号情形一样,若A ≡ B(mod N),则有 A+C≡B+C(mod N) 和 AD ≡ BD(mod N)。

1.2.5 证明方法

        证明数据结构分析中的结论最常用的两个方法是归纳法和反正法。

        归纳法证明

        归纳法的证明有两个标准部分,一是证明 基准情形(base case),就是确定定理对某个小的值的正确性。二是 归纳假设(inductive hypothesis)。假设定理到某个有限数k的所有情况都是成立的,然后再证明定理对下个值(通常为k+1)也成立。

        以斐波那契数列为例 F_{0} = 1F_{1} = 1F_{2} = 2F_{3} = 3F_{4} = 5,……,F_{i} = F_{i-1} +F_{i-2},证明对 i\geq 1F_{i}<(\frac{5}{3})^{i}。基准情形有 F_{1}=1<\frac{5}{3}F_{2}=1<\frac{9}{25}。假设对于i=1,2,... ,k,成立,这就是归纳假设。现在需要证明 F_{k+1}<(\frac{5}{3})^{k+1}。根据定义我们有

        F_{k+1}=F_{k}+F_{k-1}。则 F_{k+1}<(\frac{5}{3})^{k} + (\frac{5}{3})^{k-1} 化简后得 F_{k+1}<(\frac{3}{5} + \frac{9}{25})(\frac{5}{3})^{k+1}

可得F_{k+1}<(\frac{24}{25})(\frac{5}{3})^{k+1}<(\frac{5}{3})^{k+1}。也即证明完成,由于打印在文章中的证明难以阅读,之后的许多证明将不再进行,定理将会直接给出,有兴趣的读者可自行看书或查找资料。

        定理1.3        如果 N\geqslant 1,则 \sum_{i=1}^{N}i^{2} = \frac{N(N+1)(2N+1)}{6}

同样用归纳法可以证明。

        反证法证明

        反证法是先假设定理不成立,然后得出与已知条件不符合的结论,从而说明定理不成立的假设是错的。一个经典例子是 证明存在无穷多个素数。为证明它,先假设定理不成立,那么就由此假设引出了一个已知条件,即存在某个最大素数P_{k},令P_{1},P_{2},...,P_{k}是依序排列的所有素数。令数N=P_{1}P_{2}P_{3}...P_{k}+1,那么显然N>P_{k},而P_{1},P_{2},...,P_{k}都不能整除N,因为每一个整数,或者是素数,或者是素数的乘积,显然N不是素数的乘积,那么N是素数与已知条件不符,因此,P_{k}是最大的素数的原假设不成立,也就是定理 存在无穷多个素数成立。

        1.3 递归简论

        数学函数有时以不太标准的形式定义。作为一个例子,在非负整数集上定义一个函数F,它满足F(0)=0F(X)=2F(X-1)+X^{2}。当函数用它自己来定义时就称为递归的(recursive)。但重要的是要记住,C提供的是遵循递归思想的一种企图。不是所有数学函数都能有效的(或正确地)由C的递归模拟实现。下图给出函数F的递归实现。

int F(int x)
{if (x == 0)return 0;elsereturn 2 * F(x - 1) + x * x;
}

函数内,前两行处理基准情形,即此时可以直接算出函数值而不递归。就像如果没有“F(0)=0”这个条件,“F(X)=2F(X-1)+X^{2}”在数学上就没有意义一样,在C中递归函数若没有基准情形,也是没意义的。

        关于递归,有几个重要且可能会搞混的地方。一是它是否就是 循环逻辑(circular logic)?答案是:虽然用了函数本身去定义函数,但并未用函数本身定义该函数的一个特定的实例,也就是说用F(5)得到F(5)的值才是循环的。通过使用F(4)得到F(5)的值不是循环的,除非F(4)的求值又要用到对F(5)的计算。

        假设以参数3调用函数F,则要计算 2*F(2)+2*2,就要调用F(2),那么又要计算2*F(1)+1*1,此时要计算F(0),我们先知道了F(0)=0,这属于基准情形,然后就会得到F(1)从而得到F(2),F(3),否则将一直递归下去。接下来看一个无终止递归程序

int Bad(unsigned int x)
{if (x == 0)return 0;elsereturn Bad(x / 3 + 1) + x - 1;
}

乍一看貌似给出了x==0的基准情形,但实际上分析后发现 函数无法到达基准情形。由于x是无符号数,所以 \frac{x}{3}\geqslant 0,则\frac{x}{3} + 1\geqslant 1,也就是说除非我们给的参数是0(一开始就是基准情形),否则就会开始递归调用,一旦开始递归调用就永远达不到基准情形了。其实错误点在于此函数将Bad(1)定义为Bad(1),而Bad(1)究竟是多少,此定义给不出任何线索。

        经过上述讨论,递归有两个基本法则:

        1.基准情形(base case) 必须有不用递归就能求解的基准情形

        2.不断推进(making progress) 对需要递归求解的情形,递归调用必须能够朝着产生基准情形的方向推进

        作为一个非数学应用的例子,考虑查词典的情况,当查一个词的时候,词的解释中又有我们不认识的词,那么就不得不再去查这些词,当我们查到某一处,明白解释中的所有单词,然后按照查的顺序去理解之前的词,要么需要解释的词之间形成了循环解释,又或者解释中需要我们理解的某个单词不在这本词典里。

        理解其递归策略:若知道一个单词的含义,就成功,否则就去查找这个词。如果理解该词解释中的所有单词,就又算我们成功。否则,递归地查找不认识的单词来解释们要么词典编纂的完美无暇,那么这个过程能够终止;如果其中一个单词没查到或是形成循环定义(解释)

,那么此过程循环不定。

        打印输出数

        假设我们有一个正整数N并希望把它打印出来,且现在有一个现有的例程只能处理单个数字,如PrintDigit(4)输出一个"4"。

        递归对该问题提供了简洁的解。为打印"76234",先要打印"7623",在打印"4"。第二步用PrintDigit(N%10)能够完成,而第一步打印“7623”实际上和原问题是同一个问题,因此可以递归的解决它。

        我们还需要确定程序不是循环不定的,由于我们尚未定义一个基准情形,因此还有事情要做。如果0\leqslant N<10,基准情形就是PrintDigit(N)。现在PrintOut已对从0到9的正整数定义,更大的通过较小的正整数定义,因此不存在循环定义。

void PrintOut(unsigned int N)
{if (N >= 10)PrintOut(N / 10);PrintDigit(N % 10);
}

        递归和归纳

        定理1.4 对于N\geqslant 0,数字递归打印算法是正确的。

后记:我的初衷是想把书中涉及到的每一个细节都写出来,但是发现费时费力低效。因此之后的章节将只写出我认为的重点和理解,书中一些细节讨论不再机械地复述。


http://chatgpt.dhexx.cn/article/pIHqO2nb.shtml

相关文章

谭浩强老师C语言第五版第五章(上)

本文涉及字符宽度&#xff0c;暂不做讲解&#xff0c;不懂留言 仅代表个人看法 如有侵权请说明 题目1&#xff1a;请画出例 5.6 中给出的3个程序段的流程图。 程序如下1、 #include <stdio.h> int main() { int i, j, n 0; for (i 1; i < 4; i) …

谭浩强C语言程序设计(1-3章代码学习)

谭浩强C语言程序设计 参考书 C语言学习笔记记录&#xff0c;学习为主&#xff0c;新手小白入门 我所用的C语言在线编译器&#xff1a;lightly在线编译工具 可新建工程 谭浩强C语言程序设计书籍所包含的代码示例加注释说明如下&#xff1a; /*笔记记录者&#xff1a;xy;学习教…

谭浩强C语言第九章知识总结

第九章 shyu 结构体&#xff1a;用户自定义的数据类型 如&#xff1a;在描述一个学生的相关信息时&#xff0c;需要整型变量来记录学号&#xff0c;字符数组来记录名字&#xff0c;等等&#xff0c;物品们可以通过定义结构体改变变量的数据类型&#xff0c;把这些信息整成一…

谭浩强C语言第七章知识总结

第七章 定义函数 定义没有参数的函数&#xff0c; 类型名 函数名&#xff08;&#xff09; 类型名 函数名&#xff08;void&#xff09; { { 函数体 或 函数体 } …

C语言 谭浩强 题目 -第六章

文章目录 笔记字符数组字符数组输出字符串处理函数输入字符串的函数 gets&#xff08;&#xff09;字符串连接函数--strcat字符串赋值函数--strcpy字符串比较函数---strcmp测字符串长度的函数--strlen转换为大小写的函数 EG 1EG 2EG 3 排序 冒泡排序 不用函数EG 4EG 5EG 6EG 7E…

C语言 谭浩强 题目 -第八章

文章目录 笔记通过指针引用数组用数组名作函数参数以变量名和数组名作为函数参数的比较 例题【例8.2】【例8.6】【例8.3】【例 8.4】【例 8.5】【例 8.6】【例8.7】【例8.8】【例8.9】【例 8.10】选择法起泡法 【例 8.11】【例 8.12】【例 8.13】【例8.30】 用指向数组的指针作…

C语言 谭浩强 题目 -第七章

文章目录 笔记函数参数函数调用返回值函数的嵌套函数的递归数组作为函数参数多维数组名作函数参数局部变量和全局变量全局变量 变量的存储方式和生存期自动变量(auto变量)static静态局部变量寄存器变量(register变量) 全局变量在一个文件内扩展外部变量的作用域将外部变量的作用…

【C语言】谭浩强

1.分支选择结构 #include<stdio.h> int main(){ char grade; scanf(“%c”,&grade); printf(“Your score:”); switch(grade) { case’A’:printf(“85~100\n”);break; case’B’:printf(“70~84\n”);break; case’C’:printf(“60~69\n”);break; case’D’:prin…

C语言 谭浩强第五版 课后习题解答

第一章 1.什么是程序?什么是程序设计? 程序&#xff1a;就是一组能识别和执行的指令&#xff0c;每一条指令使计算机执行特定的操作 程序设计&#xff1a;是指从确定任务到得到结果、写出文档的全过程 2.为什么需要计算机语言?高级语言有哪些特点? 为什么需要计算机语言&am…

谭浩强c语言课后习题(更新中)

1.第三章 纯代公式题 #include<stdio.h>int main() {float p1.07; //第一年倍数for (int i 1; i < 10; i) //只用循环了9次&#xff0c;因为是从第一年开始{p p * 1.07;}printf("%f%%%",p*100); }第2题也是代进公式即可 其实也是代给出的公式&#xff0…

C语言学习笔记(C程序设计-谭浩强)

入门&#xff1a; 计算机程序&#xff1a; 一组计算机能够识别和执行的指令。计算机的每一个操作都是根据指令进行的&#xff0c;计算机的一切操作都是由程序控制的 计算机指令&#xff1a;指挥机器工作的指示和命令。 指令包含操作码和操作数&#xff0c;操作码决定要完成的…

清风数学建模笔记--熵权法

是一种可以客观赋权的方法&#xff08;我们可以从数据中查看权重&#xff09; 依据的原理&#xff1a;指标的变异程度越小&#xff0c;所反映的信息量也越少&#xff0c;其对应的权值也应该越低。 本文借鉴了数学建模清风老师的课件与视频&#xff0c;如果大家发现文章中有不正…

c语言计算文本信息熵,C语言求信息熵,条件熵,联合熵

C语言求信息熵,条件熵,联合熵 (3页) 本资源提供全文预览&#xff0c;点击全文预览即可全文预览,如果喜欢文档就下载吧&#xff0c;查找使用更方便哦&#xff01; 11.90 积分 #include#include#define u 20int i,j,n,m;float H_X,H_Y,H_XY,H_XpY,Pypx[u][u],Px[u],H_YpX,Py[u],…

谭浩强C语言笔记

文章目录 谭浩强C语言笔记1.C语言基础知识1.常量和变量1.1入门程序1.2 常量1.2.1 整型常量1.2.2 实型&#xff08;浮点型&#xff09;常量1.2.3 字符常量1.2.4 字符串常量1.2.5 符号常量 1.3 变量1.4 常变量 2.标识符和关键字2.1 标识符2.2 关键字2.3 小习题 3. 基本数据类型3.…

天池比赛总结1

这次参加天池的一场比赛 先把数据读取了如下 接下来准备使用YOLO框出图片中的字符&#xff0c;然后进行识别

比赛总结+近期总结

比赛总结&#xff1a; 这次比赛没考好 20(没加高精度)0&#xff08;文件输出写错&#xff09;1000120 T1&#xff1a;这一题的方法是分解质因数高精度 T2&#xff1a;明显就是一道spfa的题嘛 T3&#xff1a;强大的四维DP&#xff08;我的神啊&#xff01;&#xff09; T4&#…

计算机课件比赛总结,课件制作比赛活动总结

【www.gz85.com - 投篮比赛活动工作总结】 课件制作比赛&#xff0c;是对计算机多媒体等辅助手段的一次检阅&#xff0c;也有力地促进了制作多媒体课件技艺的提高。下面是小编为您整理的“课件制作比赛活动总结”&#xff0c;仅供参考&#xff0c;希望您喜欢&#xff01;更多详…

2018年全国邀请赛(江苏) 比赛总结

先吐槽一下中矿大。。。周六在食堂吃的午饭&#xff0c;肉菜一个鱼一个辣土豆炒牛肉&#xff0c;对于对鱼过敏又感冒比较严重的我来说。。。&#xff08;然后再也没去食堂吃饭&#xff09; 南湖校区大是真大&#xff0c;风景也不错&#xff0c;就是门口离体育馆有点远。。。&a…

比赛总结

比赛总结 比赛总结-a5165.png 初赛终于结束了&#xff0c;头一次如此投入去打比赛&#xff0c;这一个多月以来真是痛并快乐着。最大的感悟是&#xff1a;构造线下验证集并没有什么用&#xff0c;做了一堆工作还不如一个leak。首先取得这个成绩算是给自己一个交代了&#xff0c;…

关于全国大学生软件测试大赛总结与反思

关于全国大学生软件测试大赛总结与反思 文章目录 一、软件测试大赛简介二、可能出现的错误三、个人总结与反思四、谈谈软件测试工程师1、测试的三个阶段2、就业优势3、就业要求4、参考薪资 一、软件测试大赛简介 由教育部软件工程专业教学指导委员会、全国高等院校计算机基础教…