前言:
学习完了MySQL之后,按照计划开始好好学习数据结构和算法,本科的时候有学过《数据结构》这门课,但是当时的我的学习态度只能说太烂,只求加权的结果就是所有的代码都是纸上实现,从来没有实际编写运行过,所以说那时候学习的东西压根就不行,到研究生的时候就只能记得几个数据结构的名字了。
在这本书之前,我也有买《算法导论》,大致翻了翻,感觉《算法导论》太理论了,数学推导太多,更加适合已经有了足够好基础的人来学习。《数据结构与算法分析》上的例子只给出了部分的代码,我自行将其补全,并且测试通过,全部源代码现在传到了我自己申请的github空间上:
https://github.com/YinWenAtBIT
链表:
简介:
链表是最基础的数据结构之一,由不连续的内存空间构成。链表节点由元素和指向下一个节点的指针构成。保存一个链表只需要保存链表的第一个元素(有些链表的实现带有头结点,那么保存头结点就行)。
在编写链表的实现程序时,需要注意对传入的指针进行判断,是否是NULL指针,否则容易程序将会崩溃。
除了最简单的链表之外,还有双链表,这种链表结点中还有一个指向前一个结点的指针,可以完成轻松的完成倒序扫描。让双链表的尾指针指向链表的第一个元素,第一个元素的前指针指向尾部,就变成了循环链表。
使用案例:
1.多项式:
在有很大的指数时,我们不再使用数组来储存多项式,因为这时候使用数组会浪费太多的空间。使用链表存储多项式的方式是:在链表结点中保存两个数值,系数和指数。并且按照指数递减的顺序来保存链表。这时用来处理多项式相加以及多项式相乘将会变得很简单(注意相乘时合并同类项即可,需要使用Find函数确实是否已有同样的指数)。
2.基数排序:
基数排序也是一种常用的排序方式,它是桶式排序的一种变种,桶式排序也可以用来用来统计一个数据出现的次数,不过这样使用的条件是可以用来保存数据的桶是可以估计。
基数排序的流程:
a.对最低有效位进行桶式排序,有相同的最低有效位的数据放在链表中
b.对次低有效位进行桶式排序,同样,有相同的最低有效位放在链表中
c.重复如上过程,直到达到最高有效位。
d.按照桶的顺序,依次取出链表中的所有数据,首尾相连,此时便得到了排序的结果(排序大小顺序与桶的顺序相同)。
3.多重表
多重表的例子比较复杂,该书给出的一个例子时40000名学生与2500门课程的条件下,生成两份报告,一个是每门课程有多少学生填报,另一个是每个学生填报了哪些课程。
这样条件下需要一个十字链表来完成数据连接,十字链表连接方式如下图所示,第一行代表学生,第一列代表课程。每一行,列的链表是首尾相连的。学生顺着链表往下,对应的每一个链表再往右,直到返回第一列的课程,此时学生就知道了他选的每一门课程。同样,课程顺着链表往右,每一个节点往下直到返回第一行,就知道了该课程有的学生。
不过对于这种关系表,用链表来实现确实麻烦,使用MySQL建立两个TABLE能很轻松的解决。
栈:
简介:
栈同样是非常基础的数据结构,他的特点是后进先出LIFO,只需要保存最顶层的指针即可,基础操作为push和pop。栈的实现可以使用链表节点的方式,节点结构中只保存数据和指向下一个节点的指针。同样也可以使用数组来实现,那么就需要一个栈的数据保存节点,该节点中记录数组大小,数组指针以及栈顶。实现起来同样很简单,在我的github中只给出了使用链表的实现。
使用案例:
1.平衡符号:
在检测程序语法错误的时候,需要匹配括号,当遇到左括号时push,遇到右括号时pop,当结束读取的时候,栈应该是空的,如果非空,那么括号不平衡。
2.求解计算表达式:
用来求解计算表达式,需要两个过程,第一个过程将中缀表达式转换成后缀表达式,然后读取后缀表达式求解。两个过程都使用栈来完成。
中缀表达式转换为后缀表达式的过程相对复杂,在此不细说。
后缀表达式求解的方式:遇到操作数压入栈,遇到操作符的时候弹出两个操作数,计算出结果再压入栈,直到读完所有数据,此时栈中只剩下最后一个数,即是求解的结果。
3.函数调用:
这个用处是属于计算机系统实现的方法了,相对难,我只懂原理,还不知道如何实现。
当遇到函数调用的时候,将所有重要的信息,例如寄存器的值,变量的名字,返回地址压入栈,放在一个堆(pile)的顶部。然后控制转移到新的函数,新函数结束之后,查看堆顶部,并且复原所有寄存器,返回控制。
队列:
简介:
队列是一个先进先出的数据结构,实现的方式可以通过链表,也可以通过数组来实现。需要注意的事情是需要一个单独的QueueRecord节点,用来保存队列的头指针和未指针。链表节点中只需要保存数据和指向下一个节点的指针。无论是否使用头结点,都需要特别注意链表为空时的Enqueue和Dequeue操作,避免对空指针进行了操作。
使用案例:
1.队列的应用一般是用在排队的过程中,例如排队买票或者打印机排队打印。
总结:
在实际实现链表,栈,以及队列的过程中,其实还是遇到了不少的问题,一是忘记对空指针进行判断,这点是由于对于数据结构实现还不够敏感导致,另一点就是对于头结点的处理感到无所适从,总是想编写出一个简练的代码,结果最后发现头结点是必须特殊处理的,想好了不要头结点,就能轻松的完成编码的工作了。