第1章数据结构绪论 1
1.1开场白 2
如果你交给某人一个程序,你将折磨他一整天;如果你教某人如何编写程序,你将折磨他一辈子。
1.2你数据结构怎么学的? 3
他完成开发并测试通过后,得意地提交了代码。项目经理看完代码后拍着桌子对他说:“你数据结构是怎么学的?”
1.3数据结构起源 4
1.4基本概念和术语 5
正所谓“巧妇难为无米之炊”,再强大的计算机,也要有“米”下锅才可以干活,否则就是一堆破铜烂铁。这个“米”就是数据。
1.4.1数据 5
1.4.2数据元素 5
1.4.3数据项 6
1.4.4数据对象 6
1.4.5数据结构 6
1.5逻辑结构与物理结构 7
1.5.1逻辑结构 7
1.5.2物理结构 9
1.6抽象数据类型 11
大家都需要房子住,但显然没钱考虑大房子是没有意义的。于是商品房就出现了各种各样的户型,有几百平米的别墅,也有仅两平米的胶囊公寓……
1.6.1数据类型 11
.1.6.2抽象数据类型 12
1.7总结回顾 14
1.8结尾语 15
最终的结果一定是,你对着别人很牛的说“数据结构——就那么回事。”
第2章算法 17
2.1开场白 18
2.2数据结构与算法关系 18
计算机界的前辈们,是一帮很牛很牛的人,他们使得很多看似没法解决或者很难解决的问题,变得如此美妙和神奇。
2.3两种算法的比较 19
高斯在上小学的一天,老师要求每个学生都计算1+2+…+100的结果,谁先算出来谁先回家……
2.4算法定义 20
现实世界中的算法千变万化,没有通用算法可以解决所有问题。甚至一个小问题,某个解决此类问题很优秀的算法却未必就适合它。
2.5算法的特性 21
2.5.1输入输出 21
2.5.2有穷性 21
2.5.3确定性 21
2.5.4可行性 21
2.6算法设计的要求 22
求100个人的高考成绩平均分与求全省所有考生的成绩平均分在占用时间和内存存储上有非常大的差异,我们自然追求高效率和低存储的算法来解决问题。
2.6.1正确性 22
2.6.2可读性 23
2.6.3健壮性 23
2.6.4时间效率高和存储量低 23
2.7算法效率的度量方法 24
随着n值越来越大,它们在时间效率上的差异也就越来越大。好比有些人每天都在学习,而另一些人,打打游戏、睡睡大觉,毕业后前者名企争着要,后者求职处处无门。
2.7.1事后统计方法 24
2.7.2事前分析估算方法 25
2.8函数的渐近增长 27
2.9算法时间复杂度 29
理解大o推导不算难,难的其实是对数列的一些相关运算,这考察的更多的是数学知识和能力。
2.9.1算法时间复杂度定义 29
2.9.2推导大o阶方法 30
2.9.3常数阶 30
2.9.4线性阶 31
2.9.5对数阶 32
2.9.6平方阶 32
2.10常见的时间复杂度 35
有些时候,告诉你某些东西不可以去尝试,也是一种知识的传递。总不能非要去被毒蛇咬一口才知道蛇不可以去招惹吧。
2.11最坏情况与平均情况 35
2.12算法空间复杂度 36
事先建立一个有2050大的数组,然后把所有年份按下标数字对应,如果是闰年,此数组项的值就是1,如果不是就是0。这样,所谓的判断某一年是否是闰年就变成了查找这个数组的某一项的值是多少的问题。
2.13总结回顾 37
2.14结尾语 38
愚公移山固然可敬,但发明炸药和推土机,可能更加实在和聪明。
第3章线性表 41
3.1开场白 42
门外家长都挤在大门口与门里的小孩子的井然有序,形成了鲜明对比。哎,有时大人的所作所为,其实还不如孩子。
3.2线性表的定义 42
3.3线性表的抽象数据类型 45
有时我们想知道某个小朋友(比如麦兜)是否是班级的同学,老师会告诉我说,没有,麦兜是在春田花花幼儿园里。这种查找某个元素是否存在的操作很常用。
3.4线性表的顺序存储结构 47
他每次一吃完早饭就冲着去了图书馆,挑一个好地儿,把他书包里的书,一本一本的按座位放好,长长一排,九个座硬是被他占了。
3.4.1顺序存储定义 47
3.4.2顺序存储方式 47
3.4.3数据长度与线性表长度区别 48
3.4.4地址计算方法 49
3.5顺序存储结构的插入与删除 50
春运时去买火车票,大家都排队排着好好的,这时来了一个美女:“可否让我排在你前面?”这可不得了,后面的人像蠕虫一样,全部都得退后一步。
3.5.1获得元素操作 50
3.5.2插入操作 51
3.5.3删除操作 52
3.5.4线性表顺序存储结构的优缺点 54
3.6线性表的链式存储结构 55
反正也是要让相邻元素间留有足够余地,那干脆所有元素都不要考虑相邻位置了,哪有空位就到哪里。而只是让每个元素知道它下一个元素的位置在哪里。
3.6.1顺序存储结构不足的解决
办法 55
3.6.2线性表链式存储结构定义 56
3.6.3头指针与头结点的异同 58
3.6.4线性表链式存储结构代码描述 58
3.7单链表的读取 60
3.8单链表的插入与删除 61
本来是爸爸左牵着妈妈的手、右牵着宝宝的手在马路边散步。突然迎面走来一美女,爸爸失神般地望着,此情景被妈妈逮个正着,于是扯开父子俩,拉起宝宝的左手就快步朝前走去。
3.8.1单链表的插入 61
3.8.2单链表的删除 64
3.9单链表的整表创建 66
3.10单链表的整表删除 69
3.11单链表结构与顺序存储结构优缺点 70
3.12静态链表 71
对于一些语言,如basic、fortran等早期的编程高级语言,由于没有指针,这链表结构,按照前面我们的讲法,它就没法实现了。怎么办呢?
3.12.1静态链表的插入操作 73
3.12.2静态链表的删除操作 75
3.12.3静态链表优缺点 77
3.13循环链表 78
这个轮回的思想很有意思。它强调了不管你今生是穷是富,如果持续行善积德,下辈子就会好过,反之就会遭到报应。
3.14双向链表 81
就像每个人的人生一样,欲收获就得付代价。双向链表既然是比单链表多了如可以反向遍历查找等的数据结构,那么也就需要付出一些小的代价。
3.15总结回顾 84
3.16结尾语 85
如果你觉得上学读书是受罪,假设你可以活到80岁,其实你最多也就吃了20年苦。用人生四分之一的时间来换取其余时间的幸福生活,这点苦不算啥。
第4章栈与队列 87
4.1开场白 88
想想看,在你准备用枪的时候,突然这手枪明明有子弹却打不出来,这不是要命吗。
4.2栈的定义 89
类似的很多软件,比如word、photoshop等,都有撤消(undo)的操作,也是用栈这种思想方式来实现的。
4.2.1栈的定义 89
4.2.2进栈出栈变化形式 90
4.3栈的抽象数据类型 91
4.4栈的顺序存储结构及实现 92
4.4.1栈的顺序存储结构 92
4.4.2栈的顺序存储结构进栈操作 93
4.4.3栈的顺序存储结构出栈操作 94
4.5两栈共享空间 94
两个大学室友毕业同时到北京工作,他们都希望租房时能找到独自住的一室户或一室一厅,可找来找去发现,实在是承受不起。
4.6栈的链式存储结构及实现 97
4.6.1栈的链式存储结构 97
4.6.2栈的链式存储结构进栈操作 98
4.6.3栈的链式存储结构出栈操作 99
4.7栈的作用 100
4.8栈的应用——递归 100
当你往镜子前面一站,镜子里面就有一个你的像。但你试过两面镜子一起照吗?如果a、b两面镜子相互面对面放着,你往中间一站,嘿,两面镜子里都有你的千百个“化身”。
4.8.1斐波那契数列实现 101
4.8.2递归定义 103
4.9栈的应用——四则运算表达式求值 104
4.9.1后缀(逆波兰)表示法定义 104
4.9.2后缀表达式计算结果 106
4.9.3中缀表达式转后缀表达式 108
4.10队列的定义 111
电脑有时会处于疑似死机的状态。就当你失去耐心,打算了reset时。突然它像酒醒了一样,把你刚才点击的所有操作全部都按顺序执行了一遍。
4.11队列的抽象数据类型 112
4.12循环队列 113
你上了公交车发现前排有两个空座位,而后排所有座位都已经坐满,你会怎么做?立马下车,并对自己说,后面没座了,我等下一辆?没这么笨的人,前面有座位,当然也是可以坐的。
4.12.1队列顺序存储的不足 112
4.12.2循环队列定义 114
4.13队列的链式存储结构及实现 117
4.13.1队列链式存储结构入队操作118
4.13.2队列链式存储结构出队操作 119
4.14总结回顾 120
4.15结尾语 121
人生,需要有队列精神的体现。南极到北极,不过是南纬90度到北纬90度的队列,如果你中途犹豫,临时转向,也许你就只能和企鹅相伴永远。可事实上,无论哪个方向,只要你坚持到底,你都可以到达终点。
第5章串 123
5.1开场白 124
“枯眼望遥山隔水,往来曾见几心知?壶空怕酌一杯酒,笔下难成和韵诗。途路阻人离别久,讯音无雁寄回迟。孤灯夜守长寥寂,夫忆妻兮父忆儿。”……可再仔细一读发现,这首诗竟然可以倒过来读。
5.2串的定义 124
……