数据结构之线性结构的汇总与分析(链表和栈以及队列)

  • 笔者对于数据结构的学习已经有相当一部分时间了,要温故而知新,才能更好地掌握学习过的知识,因此要对数据结构中的线性结构进行一次汇总,牢记其中的方法及其操作。

第一部分:链表
分类:单向链表,单向循环链表,双向链表,双向循环链表。

单向链表的分析:
单向链表在日常的应用是最为广泛的,也是链式结构的入门。
每一个结点具有数据域和指针域2部分,指针域保存着链表中下一个结点的地址,由于链表是由一个一个离散的内存空间构成的,不像数组是连续型空间,因此指针域对于寻找后续结点是很关键的部分。
单向链表的实现以及菜单测试在笔者的博客中有详细实现,在此不详述。

单向循环链表的分析:
单向循环链表相对于单向非循环链表来说,尾结点的指针域不是指向NULL空指针,而是指向了表头结点,因此无论访问链表中的某一个结点,都能够查找到任意一个结点的前驱和后继,而单向非循环链表中无法访问某一个结点的前驱,是被其指针的后指向性所限制,因此循环链表对于某些操作来说更加便捷,特别是有些情况下设置一个指向尾结点的指针时,能够简化算法的实现。
例子:合并2个单向循环链表,若是只有指向2个链表的头结点的指针,则算法的时间复杂度必为线性时间O(n),但当设置2个指向尾结点的指针时,算法的时间复杂度可降至为常数时间O(1)。
单向循环链表的实现以及菜单测试在笔者的博客中有详细实现,在此不详述。

双向链表的分析:
双向链表对于单向链表来说,增加了一个额外指针域指向其前驱结点,内存的使用更大,但是换来的好处是查找某个结点的前驱结点的时间复杂度为常数时间O(1),对比单向循环链表来说,后者若想找到某一结点的前驱结点必须经历一次循环从而才能找到目标结点,时间复杂度为O(n),从中可以看出,在某些情况下以空间换时间带来的好处是显而易见的,有些许动态规划的思想蕴含在其中。

双向循环链表的分析:
双向循环链表在原有双向链表中改变了其首结点和尾结点中NULL指针的指向,使得首结点的前驱指针域指向尾结点,尾结点的后继指针域指向链表首结点,大大降低了原双向非循环链表的限制,使得这种数据结构能够作为队列的底层结构来进行实现,令元素的入队以及出队的操作时间复杂度为常数时间O(1),若是采用双向非循环链表实现的话,时间复杂度是线性时间,非常缓慢,因此双向循环链表的用处相比于非循环链表来说作用更为广泛。

第二部分:栈
分类:数组栈,链表栈。

数组栈的分析:
数组栈这种数据结构的底层实现基于数组,栈数据结构的特点就是"后进先出"(LIFO),每次只能获取其栈顶结点元素的内容,对于栈的基本操作有:入栈(push),出栈(pop),判空(isempty),获取栈顶元素(top)。数组栈相比于链表栈来说,可进栈的元素数量是被限制的,因此在实际应用中,我们不常采用这种构造方式来解决实际问题。

链表栈的分析:
链表栈这种数据结构的底层实现基于链表,最方便的结构就是单向非循环链表,使用"头插法"添加元素可令入栈和出栈操作的时间复杂度降至O(1),对于解决实际问题来说,我们通常使用这种实现方式。

栈的实现以及菜单测试在笔者的博客中有详细实现,在此不详述。

栈的实际应用举例:
对于栈的"后进先出"(LIFO)特点来说,很适合解决某些复杂的非线性结构的问题,例如图的深度优先搜索以及树的前中后序遍历,而且部分问题可以用此数据结构简化操作。

第三部分:队列
分类:循环队列,链式队列。

扫描二维码关注公众号,回复: 12354438 查看本文章

循环队列的分析:
循环队列这种数据结构的底层实现基于数组,其特点是"先进先出"(FIFO),其中基本操作有:入队(enqueue),出队(dequeue),获取队头元素(front),判空(isempty)。队列采用数组实现时有"假溢出"的特殊情况发生,因此在实际实现中一般采取少用一个元素空间的方式来进行解决。

链式队列的分析:
链式队列这种数据结构的底层实现基于链表,若采用双向循环链表可把入队以及出队操作的时间复杂度降至O(1),并且在实际应用中的队列大部分都是采用链式实现从而解决了内存空间不足的问题。

队列的实际应用举例:
对于队列的"先进先出"(FIFO)特点来说,也很适合于解决某些复杂的非线性结构的问题,例如图的广度优先搜索以及树的层次遍历,某些实际应用中也有涉猎。
笔者在博客中有着程序实现,故在此不详述。

笔者:Winds_X_Clover
创作时间:2020年11月24日

猜你喜欢

转载自blog.csdn.net/m0_46181359/article/details/110087783