??数据结构是计算机存储、组织数据的方式。数据结构是指相互之间存在一种或多种特定关系的数据元素的集合。通常情况下,精心选择的数据结构可以带来更高的运行或者存储效率。数据结构往往同高效的检索算法和索引技术有关。 ??常见的数据结构可分为:线性结构、树形结构 和 图状结构。 ??线性结构是一个有序数据元素的集合。 ??常用的线性结构有:数组, 链表,栈 ,队列等。
一、数组
??数组是是由相同类型的元素(element)的集合所组成的数据结构,分配一块连续的内存来存储。利用元素的下标位置可以计算出该元素对应的存储地址。
1.1、优点:
??分配基于连续内存,是一种天生的索引结构,查询修改元素的效率O(1)。同时可以借助 CPU 的缓存机制,预读数组中的数据,所以访问效率更高。
1.2、缺点:
??数组的索引优点也是它的缺点,因为它的索引是基于一块连续内存元素存储的位置下标决定的,增删arr[i]时间复杂度O(n),需要整体移动数组arr[i-n-1]的位置。此外,分配大数组会占用较大的内存。
二、链表
??链表是一种物理存储单元上非连续、非顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针链接次序实现的。链表由一系列结点(链表中每一个元素称为结点)组成,结点可以在运行时动态生成。每个结点包括两个部分:一个是存储数据元素的数据域,另一个是存储下一个结点地址的指针域。 相比于线性表顺序结构,操作复杂。由于不必须按顺序存储,链表在插入的时候可以达到O(1)的复杂度,比另一种线性表顺序表快得多,但是查找一个节点或者访问特定编号的节点则需要O(n)的时间,而线性表和顺序表相应的时间复杂度分别是O(logn)和O(1)。 ??使用链表结构可以克服数组链表需要预先知道数据大小的缺点,链表结构可以充分利用计算机内存空间,实现灵活的内存动态管理。但是链表失去了数组随机读取的优点,同时链表由于增加了结点的指针域,空间开销比较大。链表最明显的好处就是,常规数组排列关联项目的方式可能不同于这些数据项目在记忆体或磁盘上顺序,数据的存取往往要在不同的排列顺序中转换。链表允许插入和移除表上任意位置上的节点,但是不允许随机存取。链表有很多种不同的类型:单向链表,双向链表以及循环链表。
2.1、优点:
??增删arr[i]时间复杂度O(1),使用链表本身没有大小的限制,天然地支持动态扩容。
2.2、缺点:
??没有“索引”,查询时间复杂度O(n)。需要维护指针,更占内存。同时内存不连续,容易造成内存碎片。
2.3、应用场景:
??数组和链表的运用很广泛,他们是构成 数据结构的基础。如栈,队列,集合等等。
三、栈
??栈(stack)又名堆栈,它是一种运算受限的线性表。限定仅在表尾进行插入和删除操作的线性表。这一端被称为栈顶,相对地,把另一端称为栈底。向一个栈插入新元素又称作进栈、入栈或压栈,它是把新元素放到栈顶元素的上面,使之成为新的栈顶元素;从一个栈删除元素又称作出栈或退栈,它是把栈顶元素删除掉,使其相邻的元素成为新的栈顶元素。 ??栈是一种受限制的线性数据结构。元素只可以在栈顶被访问。 符合先进后出的First-In-Last-Out的访问方式。
3.1、应用场景:
??1.编辑器的redo/undo操作。 ??2.浏览器的前进/后退操作。 ??3.编译器的括号匹配校验 ??4.数学计算中的表达式求值 ??5.函数调用 ??6.递归 ??7.字符串反转…
四、队列
??队列是一种特殊的线性表,特殊之处在于它只允许在表的前端(front)进行删除操作,而在表的后端(rear)进行插入操作,和栈一样,队列是一种操作受限制的线性表。进行插入操作的端称为队尾,进行删除操作的端称为队头。队列中没有元素时,称为空队列。 ??队列符合先进先出的First-In-First-Out 的访问方式。同样,用数组实现的队列叫作顺序队列,用链表实现的队列叫作链式队列。
4.1、顺序队列
??建立顺序队列结构必须为其静态分配或动态申请一片连续的存储空间,并设置两个指针进行管理。一个是队头指针front,它指向队头元素;另一个是队尾指针rear,它指向下一个入队元素的存储位置 ??每次在队尾插入一个元素是,rear增1;每次在队头删除一个元素时,front增1。随着插入和删除操作的进行,队列元素的个数不断变化,队列所占的存储空间也在为队列结构所分配的连续空间中移动。当front=rear时,队列中没有任何元素,称为空队列。当rear增加到指向分配的连续空间之外时,队列无法再插入新元素,但这时往往还有大量可用空间未被占用,这些空间是已经出队的队列元素曾经占用过得存储单元。
4.2、循环队列
??在实际使用队列时,为了使队列空间能重复使用,往往对队列的使用方法稍加改进:无论插入或删除,一旦rear指针增1或front指针增1 时超出了所分配的队列空间,就让它指向这片连续空间的起始位置。自己真从MaxSize-1增1变到0,可用取余运算rear%MaxSize和front%MaxSize来实现。这实际上是把队列空间想象成一个环形空间,环形空间中的存储单元循环使用,用这种方法管理的队列也就称为循环队列。除了一些简单应用之外,真正实用的队列是循环队列。 ??在循环队列中,当队列为空时,有front=rear,而当所有队列空间全占满时,也有front=rear。为了区别这两种情况,规定循环队列最多只能有MaxSize-1个队列元素,当循环队列中只剩下一个空存储单元时,队列就已经满了。因此,队列判空的条件时front=rear,而队列判满的条件时front=(rear+1)%MaxSize。
4.3、应用场景:
??队列的作用其实就是现实中的排队。当资源不足时,通过“队列” 这种结构来实现排队的效果。用于: ??1.任务调度存在的地方:CPU/磁盘/线程池/任务调度框架… ??2.两个进程中数据的传递:如pipe/file IO/IO Buffer… ??3.生产者消费者场景中… ??4.LRU
|