数组
-
定义
一种线性表数据结构,用一组连续的内存空间来存储数组,且数组中的数据都为相同类型。
因此访问数组的本质就是访问一段连续的内存,一维数组的寻址公式如下:
a[i]_address=base_address+kdata_type_size
注:base_address表示基地址
data_type_size表示数组中的一个数据占的内存大小
kdata_type_size就表示第k个数据的偏移量
二维数组的寻址公式:
在m行n列的二维数组,a[i,j](i<m,j<n)
a[i,j]_address=base_address+(i*n+j)*data_type_size -
特点
1、数组易随机访问,直接获取元素的下标即可以访问,因此时间复杂度为O(1)。
2、数组不易插入和删除。因为数组的存储空间是一组连续的存储空间,若直接根据下标删除数据/插入数据会导致存储空间不连续。因此插入和删除数据需要进行数据搬移。
3、插入操作: -
若数组中的数据是有序的,要在k处插入x,则需要把k~n的数据全部向后搬移一位,再把x插入在k处。时间复杂度为O(n)
-
若数组中的数据是无序的,要在k处插入x,可以直接把k处的数据放在数组的最后,然后x放在k处。时间复杂度为O(1)
4、删除操作: -
删除第一个元素,要把1~n的元素全部向前搬移。时间复杂度为O(n)
-
删除最后一个元素,则可以直接删除,不用搬移数据。时间复杂度为O(1)
-
删除第k个元素,需要将k~n的元素全部向前搬移
链表
- 定义
线性表结构,通过指针将零散的内存块串联起来使用 - 分类
1、单链表
图片来源于:王真——数据结构与算法之美
链表第一个结点称为头结点,最后一个结点为尾结点,尾结点指向null
2、循环链表
与单链表唯一的区别是,尾结点不指向null,而指向头结点。
3、双向链表
图片来源于:王真——数据结构与算法之美
其中prev表示前驱结点,next为后驱结点 - 区别
数组与链表的区别在于:
1、数组的查询速度优于链表,数组可以通过下标进行随机访问,而链表则需要依次遍历后才能找到结点(时间复杂度为O(n))
2、链表的删除、插入操作优于数组,上文已经说到数组的删除、插入涉及到数据的搬移。而链表可以通过指针的变换来进行删除和插入操作,时间复杂度为O(1)
图片来源于:王真——数据结构与算法之美
栈
- 定义/特点
线性表结构,先进后出,只能在一端(栈顶)对元素进行删除、插入操作,因此只需要一个栈顶指针即可。
其时间复杂度和空间复杂度都为O(1) - 顺序栈和链式栈
用数组实现的栈为顺序栈,用链表实现的栈为链式栈。 - 应用
1、栈在函数调用中的应用
1)a中调用方法b,将a、b先后压入栈
2)先运行b,b出栈,再运行a。就从b的作用栈回到了a的作用栈
2、栈在表达式求值的应用
1)一个栈X存储操作数,一个栈Y存储表达式
2)要入栈的运算符b优先级大于栈顶的运算符a,则b入栈;若b的优先级<=a,则在栈X取两个数与a运算,再将所得值压入X,将b与Y的下一个栈顶元素进行比较
3、栈在匹配表达式的括号的应用(不细说) - JVM的堆栈与数据结构的栈的区别
1)JVM中的堆、栈是两个虚拟空间,其中堆(heap)用来存储new出来的对象,栈(stack)用来存储临时变量/常量
2)数据结构中的堆、栈是一种抽象的数据结构,堆是二叉树结构,栈是一种线性表结构
之所以将JVM中的栈也叫做栈,可能是因为也具有先进后出的特点
队列
-
定义/特点
线性表结构,先进先出,从队头出列,从队尾进列,因此需要一个head(队头),一个tail(队尾)两个指针进行操作。
图片来源于:王真——数据结构与算法之美 -
顺序队列与链式队列
1、数组实现的为顺序队列,链表实现的为链式队列。
2、判断队满、队空(队列大小=n)
若head=tail,表示队空
若tail=n,表示队满 -
循环队列
1、定义:若存储空间的最后一个位置已被使用且需要入队新的元素,只要存储空间的第一个位置空闲,则可以将新元素放到第一个位置上
2、特点:入队是tail追赶head,出队是head追赶tail。
图片来源于:王真——数据结构与算法之美
入队的话,新元素就到7号位置,tail指向0号位置;出队的话head指向5号位置,出队的元素不需要被清除,因为后续用到这个空间元素会被覆盖掉。
3、判断队空、队满(n为队列长度)
队满:(tail+1)%n=head
队空:head==tail
4、循环队列最多存储(n-1)个数据 -
阻塞队列与并列队列
1、阻塞队列:在队列的基础上增加了阻塞操作
队空:取数阻塞
队满:存数阻塞
2、并发队列:线程安全的队列